diff --git a/AspNetServer/Data/AppDb.db b/AspNetServer/Data/AppDb.db
index 5bf4ec1..353915a 100644
Binary files a/AspNetServer/Data/AppDb.db and b/AspNetServer/Data/AppDb.db differ
diff --git a/AspNetServer/bin/Debug/net6.0/Data/AppDb.db b/AspNetServer/bin/Debug/net6.0/Data/AppDb.db
index 5bf4ec1..353915a 100644
Binary files a/AspNetServer/bin/Debug/net6.0/Data/AppDb.db and b/AspNetServer/bin/Debug/net6.0/Data/AppDb.db differ
diff --git a/react-client/package-lock.json b/react-client/package-lock.json
index 63e6f08..d768ef6 100644
--- a/react-client/package-lock.json
+++ b/react-client/package-lock.json
@@ -8,11 +8,16 @@
"name": "react-client",
"version": "0.1.0",
"dependencies": {
+ "@babel/core": "^7.15.8",
+ "@babel/preset-env": "^7.15.8",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "babel-core": "^7.0.0-bridge.0",
"boxicons": "^2.1.4",
+ "chart.js": "^4.0.0",
"react": "^18.2.0",
+ "react-chartjs-2": "^5.0.0",
"react-dom": "^18.2.0",
"react-icons": "^4.10.1",
"react-router-dom": "^6.15.0",
@@ -3125,6 +3130,11 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@kurkle/color": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
+ "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
+ },
"node_modules/@leichtgewicht/ip-codec": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
@@ -5304,6 +5314,14 @@
"dequal": "^2.0.3"
}
},
+ "node_modules/babel-core": {
+ "version": "7.0.0-bridge.0",
+ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
+ "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==",
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/babel-jest": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz",
@@ -5990,6 +6008,17 @@
"node": ">=10"
}
},
+ "node_modules/chart.js": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.0.tgz",
+ "integrity": "sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==",
+ "dependencies": {
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=7"
+ }
+ },
"node_modules/check-types": {
"version": "11.2.2",
"resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz",
@@ -14651,6 +14680,15 @@
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
+ "node_modules/react-chartjs-2": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz",
+ "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==",
+ "peerDependencies": {
+ "chart.js": "^4.1.1",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/react-dev-utils": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
diff --git a/react-client/package.json b/react-client/package.json
index cdd1ca1..1755a5a 100644
--- a/react-client/package.json
+++ b/react-client/package.json
@@ -3,11 +3,16 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@babel/core": "^7.15.8",
+ "@babel/preset-env": "^7.15.8",
+ "babel-core": "^7.0.0-bridge.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"boxicons": "^2.1.4",
+ "chart.js": "^4.0.0",
"react": "^18.2.0",
+ "react-chartjs-2": "^5.0.0",
"react-dom": "^18.2.0",
"react-icons": "^4.10.1",
"react-router-dom": "^6.15.0",
diff --git a/react-client/src/components/BarDiagram.js b/react-client/src/components/BarDiagram.js
new file mode 100644
index 0000000..e3778ae
--- /dev/null
+++ b/react-client/src/components/BarDiagram.js
@@ -0,0 +1,57 @@
+import React from "react";
+import {
+ CategoryScale,
+ Chart as ChartJS,
+ Legend,
+ LinearScale,
+ LineElement,
+ PointElement,
+ Title,
+ Tooltip,
+} from "chart.js";
+import {Line} from "react-chartjs-2";
+
+ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ Tooltip,
+ Legend
+);
+
+ChartJS.defaults.color = "white";
+
+export default function BarDiagram(dataset, labels, titleDates) {
+ const options = {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: "none",
+ },
+ title: {
+ display: true,
+ text: `Средние сахара за ${titleDates}`,
+ color: "white",
+ }
+ }
+ };
+
+ const data = {
+ labels,
+ datasets: [
+ {
+ data: dataset,
+ borderColor: "rgba(116, 33, 72, 1)",
+ backgroundColor: "rgba(116, 33, 72, 0.5)",
+ }
+ ],
+ };
+
+ return (
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/react-client/src/index.css b/react-client/src/index.css
index 2b707ae..396fc2e 100644
--- a/react-client/src/index.css
+++ b/react-client/src/index.css
@@ -85,7 +85,7 @@ main {
position: relative;
margin-top: 2ex;
left: 68px;
- width: calc(100% - 56.8px);
+ width: calc(100% - 68px);
display: flex;
justify-content: space-evenly;
height: 100%;
@@ -93,6 +93,7 @@ main {
.board-view-centered {
align-items: center;
+ flex-direction: column;
}
.input-stats-area {
@@ -119,6 +120,12 @@ main {
margin-top: 2ex;
}
+.text-stats {
+ display: flex;
+ flex-direction: row;
+ gap: 3ex;
+}
+
.input-single-date {
display: flex;
flex-direction: column;
@@ -322,6 +329,22 @@ ul {
list-style-type: none;
}
+.single-diagram-wrapper {
+ padding: 2ex;
+ box-shadow: inset 0 0 0 3000px rgba(150, 150, 150, 0.292);
+ backdrop-filter: blur(10px);
+ border-radius: 2ex;
+}
+
+.single-diagram {
+ width: 450px;
+ height: 200px;
+ padding: 1ex;
+ background: rgba(255, 255, 255, 0.192);
+ backdrop-filter: blur(10px);
+ border-radius: 1ex;
+}
+
@media screen and (max-width: 1180px) {
.board-view {
display: flex;
diff --git a/react-client/src/pages/Stats.js b/react-client/src/pages/Stats.js
index d5c397a..765d725 100644
--- a/react-client/src/pages/Stats.js
+++ b/react-client/src/pages/Stats.js
@@ -1,250 +1,298 @@
import React, {useEffect, useState} from "react"
import Constants from "../utilities/Constants";
+import BarDiagram from "../components/BarDiagram";
export default function Stats() {
- //#region Константы
- const initialFormData = Object.freeze({
- date1: null,
- date2: null,
- });
-
- const [sugars, setSugars] = useState(0);
- const [daySugars, setDaySugars] = useState(0);
- const [weekSugars, setWeekSugars] = useState(0);
- const [monthSugars, setMonthSugars] = useState(0);
- const [insulins, setInsulins] = useState([]);
- const [catheters, setCatheters] = useState([]);
- const [dates, setDates] = useState("date1:date2");
- const [formData, setFormData] = useState(initialFormData);
-
- //#endregion
-
- //#region Работа с датами
- function getToday(plusDays = 0) {
- let today = new Date();
- today = new Date(today.getFullYear(), today.getMonth(), today.getDate() + plusDays)
- let dd = String(today.getDate()).padStart(2, "0");
- let mm = String(today.getMonth() + 1).padStart(2, "0"); //January is 0!
- let yyyy = today.getFullYear();
-
- return dd + "." + mm + "." + yyyy;
- }
-
- function toShortDateString(date = getToday()) {
- let d = date.split("-")
- return d[2] + "." + d[1];
- }
+ //#region Константы
+ const initialFormData = Object.freeze({
+ date1: null,
+ date2: null,
+ });
+
+ const [sugars, setSugars] = useState(0);
+ const [diagramSugars, setDiagramSugars] = useState([])
+ const [diagramDates, setDiagramDates] = useState([])
+ const [daySugars, setDaySugars] = useState(0);
+ const [weekSugars, setWeekSugars] = useState(0);
+ const [monthSugars, setMonthSugars] = useState(0);
+ const [insulins, setInsulins] = useState([]);
+ const [catheters, setCatheters] = useState([]);
+ const [dates, setDates] = useState("date1:date2");
+ const [formData, setFormData] = useState(initialFormData);
+
+ //#endregion
+
+ //#region Работа с датами
+ function getToday(plusDays = 0) {
+ let today = new Date();
+ today = new Date(today.getFullYear(), today.getMonth(), today.getDate() + plusDays)
+ let dd = String(today.getDate()).padStart(2, "0");
+ let mm = String(today.getMonth() + 1).padStart(2, "0"); //January is 0!
+ let yyyy = today.getFullYear();
+
+ return dd + "." + mm + "." + yyyy;
+ }
+
+ function toShortDateString(date = getToday()) {
+ let d = date.split("-")
+ return d[2] + "." + d[1];
+ }
+
+ function toShortDateString2(date) {
+ let d = date.split(" ")
+ return d[1];
+ }
+
+
+ //#endregion
+
+ //#region Загрузка данных
+ useEffect(() => {
+ let url = Constants.API_URL_GET_LAST_INSULIN;
+
+ fetch(url, {
+ method: "GET"
+ }).then(response => response.json())
+ .then(insulinFromServer => {
+ setInsulins(insulinFromServer);
+ })
+ .catch((error) => {
+ console.log(error);
+ alert(error)
+ })
+
+ url = Constants.API_URL_GET_LAST_CATHETER;
+
+ fetch(url, {
+ method: "GET"
+ }).then(response => response.json())
+ .then(cathetersFromServer => {
+ setCatheters(cathetersFromServer);
+ })
+ .catch((error) => {
+ console.log(error);
+ alert(error)
+ })
+
+ url = `${Constants.API_URL_GET_AVG_SUGARS}/?date1=${getToday()}`;
+
+ fetch(url, {
+ method: "GET"
+ }).then(response => response.json())
+ .then(sugarsFromServer => {
+ setDaySugars(sugarsFromServer);
+ })
+ .catch((error) => {
+ console.log(error);
+ alert(error)
+ })
+
+ url = `${Constants.API_URL_GET_AVG_SUGARS}/?date1=${getToday(-7)}&date2=${getToday()}`;
+
+ fetch(url, {
+ method: "GET"
+ }).then(response => response.json())
+ .then(sugarsFromServer => {
+ setWeekSugars(sugarsFromServer);
+ })
+ .catch((error) => {
+ console.log(error);
+ alert(error)
+ })
+
+ url = `${Constants.API_URL_GET_AVG_SUGARS}/?date1=${getToday(-30)}&date2=${getToday()}`;
+
+ fetch(url, {
+ method: "GET"
+ }).then(response => response.json())
+ .then(sugarsFromServer => {
+ setMonthSugars(sugarsFromServer);
+ })
+ .catch((error) => {
+ console.log(error);
+ alert(error)
+ })
+ }, []);
+ //#endregion
+
+ //#region Отображение данных на странице
+ function renderSugarTable() {
+ return (
+
+
+
+ {daySugars !== 0 &&
+ -
+
+ Сегодня: {daySugars}
+
+ }
+ -
+
+ Неделя: {weekSugars}
+
+ -
+
+ Месяц: {monthSugars}
+
+ {sugars !== 0 &&
+ -
+
+ {dates}: {sugars}
+
+ }
+
+
+
+ )
+ }
+ function renderInsulinTable() {
+ return (
+
+ )
+ }
- //#endregion
-
- //#region Загрузка данных
- useEffect(() => {
- let url = Constants.API_URL_GET_LAST_INSULIN;
-
- fetch(url, {
- method: "GET"
- }).then(response => response.json())
- .then(insulinFromServer => {
- setInsulins(insulinFromServer);
- })
- .catch((error) => {
- console.log(error);
- alert(error)
- })
-
- url = Constants.API_URL_GET_LAST_CATHETER;
-
- fetch(url, {
- method: "GET"
- }).then(response => response.json())
- .then(cathetersFromServer => {
- setCatheters(cathetersFromServer);
- })
- .catch((error) => {
- console.log(error);
- alert(error)
- })
-
- url = `${Constants.API_URL_GET_AVG_SUGARS}/?date1=${getToday()}`;
-
- fetch(url, {
- method: "GET"
- }).then(response => response.json())
- .then(sugarsFromServer => {
- setDaySugars(sugarsFromServer);
- })
- .catch((error) => {
- console.log(error);
- alert(error)
- })
-
- url = `${Constants.API_URL_GET_AVG_SUGARS}/?date1=${getToday(-7)}&date2=${getToday()}`;
-
- fetch(url, {
- method: "GET"
- }).then(response => response.json())
- .then(sugarsFromServer => {
- setWeekSugars(sugarsFromServer);
- })
- .catch((error) => {
- console.log(error);
- alert(error)
- })
-
- url = `${Constants.API_URL_GET_AVG_SUGARS}/?date1=${getToday(-30)}&date2=${getToday()}`;
-
- fetch(url, {
- method: "GET"
- }).then(response => response.json())
- .then(sugarsFromServer => {
- setMonthSugars(sugarsFromServer);
- })
- .catch((error) => {
- console.log(error);
- alert(error)
- })
- }, []);
- //#endregion
-
- //#region Отображение данных на странице
- function renderSugarTable() {
- return (
-
-
-
- {daySugars !== 0 &&
- -
-
- Сегодня: {daySugars}
-
- }
- -
-
- Неделя: {weekSugars}
-
- -
-
- Месяц: {monthSugars}
-
- {sugars !== 0 &&
- -
-
- {dates}: {sugars}
-
- }
-
-
-
- )
+ function renderCathetersTable() {
+ return (
+
+ )
+ }
+
+ //#endregion
+
+ const handleChange = (event) => {
+ setFormData({
+ ...formData,
+ [event.target.name]: event.target.value,
+ })
+ };
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+
+ let date1 = formData.date1;
+ let date2 = formData.date2;
+
+ if (formData.date1 == null && formData.date2 == null) {
+ date1 = getToday();
+ date2 = getToday();
+ } else if (formData.date1 == null) {
+ date1 = date2;
+ } else if (formData.date2 == null) {
+ date2 = date1;
}
- function renderInsulinTable() {
- return (
-
-
+ let url = `${Constants.API_URL_GET_AVG_SUGARS}?date1=${date1}&date2=${date2}`;
+ setDates(`${toShortDateString(date1)} - ${toShortDateString(date2)}`)
+
+ fetch(url, {
+ method: "GET"
+ }).then(response => response.json())
+ .then(sugarsFromServer => {
+ setSugars(sugarsFromServer);
+ })
+ .catch((error) => {
+ console.log(error);
+ alert(error)
+ })
+
+ url = `${Constants.API_URL_GET_SUGARS}?date1=${date1}&date2=${date2}`;
+
+ fetch(url, {
+ method: "GET"
+ }).then(response => response.json())
+ .then(sugarsFromServer => {
+ let uniqueDates = sugarsFromServer.map(q => toShortDateString2(q.time));
+ uniqueDates = [...new Set(uniqueDates)];
+ setDiagramDates(uniqueDates);
+
+ let datesMap = new Map([]);
+ uniqueDates.forEach(q => datesMap.set(q, [0, 0]))
+
+ // q: дата
+ // [x, y]: x - сумма сахара за дату, y - количество сложенных сахаров
+ //
+ // условно, если 15.08.2023 было занесено два сахара: 3.0 и 4.0, то:
+ // datesMap = {"15.08.2023": [7.0, 2]}
+ sugarsFromServer.forEach(q => {
+ let tempDate = toShortDateString2(q.time);
+ let sugarSum = datesMap.get(tempDate)[0] + q.sugar;
+ let sugarCount = datesMap.get(tempDate)[1] + 1;
+ datesMap.set(tempDate, [sugarSum, sugarCount])
+ });
+
+ setDiagramSugars([...datesMap.values()].map(q => (q[0] / q[1]).toFixed(1)));
+ })
+ .catch((error) => {
+ console.log(error);
+ alert(error)
+ })
+ };
+
+ return (
+
+
+
+
+ Дата 1
+
+
+
+ Дата 2
+
+
+
+
+
+
+
+
+
+
+
Средний сахар
- )
- }
- function renderCathetersTable() {
- return (
-
-
+ {renderSugarTable()}
+
+
+
+
+
Последний инсулин
- )
- }
- //#endregion
-
- const handleChange = (event) => {
- setFormData({
- ...formData,
- [event.target.name]: event.target.value,
- })
- };
-
- const handleSubmit = (event) => {
- event.preventDefault();
-
- let date1 = formData.date1;
- let date2 = formData.date2;
-
- if (formData.date1 == null && formData.date2 == null) {
- date1 = getToday();
- date2 = getToday();
- } else if (formData.date1 == null) {
- date1 = date2;
- } else if (formData.date2 == null) {
- date2 = date1;
- }
-
- let url = `${Constants.API_URL_GET_AVG_SUGARS}?date1=${date1}&date2=${date2}`;
- setDates(`${toShortDateString(date1)} - ${toShortDateString(date2)}`)
-
- fetch(url, {
- method: "GET"
- }).then(response => response.json())
- .then(sugarsFromServer => {
- setSugars(sugarsFromServer);
- })
- .catch((error) => {
- console.log(error);
- alert(error)
- })
- };
+ {renderInsulinTable()}
+
- return (
-
-
-
-
- Дата 1
-
-
-
- Дата 2
-
-
-
-
-
-
-
-
-
-
Средний сахар
-
-
- {renderSugarTable()}
-
-
-
-
-
Последний инсулин
-
-
- {renderInsulinTable()}
-
-
-
-
-
Последний катетер
-
-
- {renderCathetersTable()}
-
+
+
+
Последний катетер
-
- )
+
+ {renderCathetersTable()}
+
+
+
+
+ {diagramSugars !== [] &&
+ BarDiagram(diagramSugars, diagramDates, dates)
+ }
+
+
+
+ )
}