diff --git a/components/cards/KitCard.js b/components/cards/KitCard.js
index 5688636..7deafaf 100644
--- a/components/cards/KitCard.js
+++ b/components/cards/KitCard.js
@@ -5,6 +5,7 @@ import Button from "../Button";
import InProgress from "../InProgress";
import Card from "./Card";
import PeripheralCard from "./PeripheralCard";
+import Link from "next/link";
const Container = styled(Card)`
flex-flow: column;
@@ -47,14 +48,16 @@ export default function KitCard(props) {
{props.kit.name}
-
+
+
+
{props.kit.config?.peripherals?.map(peripheral => {
peripheral.measures = props.kit.measures?.measures?.filter(measure => measure.peripheralId === peripheral.id);
- return peripheral.details.expectedQuantityTypes?.map(quantityType => {
- return
+ return peripheral.details.expectedQuantityTypes?.map((quantityType, i) => {
+ return
})
})}
diff --git a/components/cards/PeripheralCard.js b/components/cards/PeripheralCard.js
index 16aa00d..7f645e0 100644
--- a/components/cards/PeripheralCard.js
+++ b/components/cards/PeripheralCard.js
@@ -2,6 +2,9 @@ import styled from "styled-components";
import propTypes from "prop-types";
import Theme from "../../styles/theme";
import moment from "moment";
+import { observer } from "mobx-react-lite"
+import { useContext } from "react";
+import { measurementCtx } from "../../stores/measurements";
const Container = styled.div`
background: ${props => props.theme.dark};
@@ -40,25 +43,38 @@ const TimeSince = styled.p`
align-self: flex-end;
`
-export default function PeripheralCard(props) {
+function PeripheralCard(props) {
+ const measurementsStore = useContext(measurementCtx);
const { peripheral } = props;
+
const quantityType = peripheral.details.quantityTypes.find(quantityType => quantityType.id === props.expectedQuantityType);
- const measurement = peripheral.measures.find(measurement => measurement.quantityTypeId === props.expectedQuantityType);
- if (!measurement) return null;
+ let measurement = Object.assign([], measurementsStore.measurements)
+ .sort((a, b) => moment(a.datetime).valueOf() > moment(b.datetime).valueOf() ? -1 : 1)
+ .find(measurement => measurement.quantityType === props.expectedQuantityType);
+
+ // Fallback incase the WS does not send us anything
+ if (!measurement) {
+ const oldMeasurement = peripheral.measures.sort((a, b) => moment(a.endDatetime).valueOf() > moment(b.endDatetime).valueOf() ? -1 : 1).find(measurement => measurement.quantityTypeId === props.expectedQuantityType);
+ measurement = {
+ value: oldMeasurement.values.average,
+ datetime: oldMeasurement.endDatetime
+ }
+ }
+ if (!measurement) return null;
return (
{quantityType?.physicalQuantity || "-"}
- {(measurement.values.average.toFixed(2)) || "-"}
- {quantityType.physicalUnitSymbol}
+ {(measurement.value.toFixed(2)) || "-"}
+ {quantityType?.physicalUnitSymbol}
{peripheral.name}
- {moment(measurement.datetimeEnd).fromNow()}
+ {moment(measurement.datetime).fromNow()}
)
}
@@ -72,4 +88,6 @@ PeripheralCard.propTypes = {
PeripheralCard.defaultProps = {
color: Theme.greyDark,
peripheral: {}
-};
\ No newline at end of file
+};
+
+export default observer(PeripheralCard);
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 8a8644b..37f529f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5441,6 +5441,15 @@
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
},
+ "bufferutil": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz",
+ "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==",
+ "optional": true,
+ "requires": {
+ "node-gyp-build": "^4.3.0"
+ }
+ },
"builtin-status-codes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
@@ -5690,6 +5699,11 @@
"safe-buffer": "^5.0.1"
}
},
+ "circular-json": {
+ "version": "0.5.9",
+ "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz",
+ "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ=="
+ },
"class-utils": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
@@ -7078,6 +7092,11 @@
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
+ "eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ },
"events": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
@@ -10161,6 +10180,16 @@
"minimist": "^1.2.5"
}
},
+ "mobx": {
+ "version": "6.3.6",
+ "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.3.6.tgz",
+ "integrity": "sha512-TeCp8BTco5cmXKY7Zt5VSL5fHBEAHTSA6xs+KWmcxi3cFN1C+Xqs2m3giyGT/e6TSjtdDysVX5+cCZZhEyiJmA=="
+ },
+ "mobx-react-lite": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.2.2.tgz",
+ "integrity": "sha512-FxJJMqmHcnQYOVVs2DdjNHioGlFsXF5/9VHztS9NAfIT3DYrxNZzVi119Zr/OmlWKkWNkAsssSNzPkqautfL4A=="
+ },
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
@@ -10571,6 +10600,12 @@
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
+ "node-gyp-build": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
+ "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==",
+ "optional": true
+ },
"node-html-parser": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.3.1.tgz",
@@ -15258,6 +15293,15 @@
"object-assign": "^4.1.1"
}
},
+ "utf-8-validate": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz",
+ "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==",
+ "optional": true,
+ "requires": {
+ "node-gyp-build": "^4.3.0"
+ }
+ },
"util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
@@ -15326,8 +15370,7 @@
"uuid": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
- "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==",
- "dev": true
+ "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg=="
},
"vary": {
"version": "1.1.2",
@@ -15783,6 +15826,11 @@
"typedarray-to-buffer": "^3.1.5"
}
},
+ "ws": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
+ "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w=="
+ },
"x-is-string": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
@@ -15840,4 +15888,4 @@
"dev": true
}
}
-}
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 24b3e1a..1492188 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,8 @@
"formik": "^2.1.7",
"jwt-decode": "^2.2.0",
"leaflet": "^1.6.0",
+ "mobx": "^6.3.6",
+ "mobx-react-lite": "^3.2.2",
"moment": "^2.29.1",
"next": "9.5.4",
"react": "16.13.1",
@@ -39,4 +41,4 @@
"babel-plugin-styled-components": "^1.11.1",
"prop-types": "^15.7.2"
}
-}
+}
\ No newline at end of file
diff --git a/pages/dashboard/[serial].js b/pages/dashboard/[serial].js
new file mode 100644
index 0000000..bec021f
--- /dev/null
+++ b/pages/dashboard/[serial].js
@@ -0,0 +1,45 @@
+import styled from "styled-components";
+import PageLayout from "../../components/layouts/PageLayout";
+import { getLoggedUser, useAuth } from "../../providers/Auth";
+import { getFullKit, getKitMeasures, getUserDetails, getUserMemberships } from "../../services/data-api";
+
+function Dashboard({ }) {
+ const { user, isLogged } = useAuth();
+
+ return (
+
+
+ );
+}
+
+export async function getServerSideProps(ctx) {
+ let mainKit = null;
+ const user = getLoggedUser(ctx.req.headers.cookie);
+
+ let completeUser = null;
+ let memberships = null;
+
+ if (user) {
+ completeUser = await getUserDetails(user.username);
+ memberships = await getUserMemberships(user.username);
+
+ if (Array.isArray(memberships) && memberships[0]?.kit) {
+ const kit = await getFullKit(memberships[0].kit.serial);
+ kit.measures = await getKitMeasures(memberships[0].kit.serial, {});
+ mainKit = kit;
+ }
+ }
+
+ return {
+ props: {
+ mainKit: mainKit,
+ },
+ };
+}
+
+export default Dashboard;
diff --git a/pages/index.js b/pages/index.js
index 0cbd6bf..b50c32b 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -1,3 +1,4 @@
+import { useContext, useEffect } from "react";
import styled from "styled-components";
import ChallengeCard from "../components/cards/ChallengeCard";
import DashboardLinkCard from "../components/cards/DashboardLinkCard";
@@ -12,6 +13,7 @@ import HelpIcon from "../public/icons/help.svg";
import LibraryIcon from "../public/icons/library.svg";
import SlackIcon from "../public/icons/slack.svg";
import { getFullKit, getKitMeasures, getUserDetails, getUserMemberships } from "../services/data-api";
+import { measurementCtx } from "../stores/measurements";
import Breaks from "../utils/breakpoints";
const WelcomeMessage = styled.h1`
@@ -24,6 +26,13 @@ const WelcomeMessage = styled.h1`
function Home({ mainKit }) {
const { user, isLogged } = useAuth();
+ const measurementsStore = useContext(measurementCtx);
+
+ useEffect(() => {
+ if (mainKit) {
+ measurementsStore.setSerial(mainKit.serial);
+ }
+ }, [mainKit, measurementsStore])
return (
{
+ this.measurements = measurements;
+ }
+
+ addMeasurement = (measurement) => {
+ this.measurements = this.measurements.concat(measurement);
+ }
+
+ connect = () => {
+
+ if (this.socket?.readyState < 2) {
+ this.disconnect();
+ }
+
+ this.socket = new WebSocket(WS_API_URL);
+
+ this.socket?.addEventListener("open", () => {
+
+ if (!this.serial) return;
+
+ this.socket.send(JSON.stringify({
+ id: 1,
+ jsonrpc: "2.0",
+ method: "subscribe_rawMeasurements",
+ params: { kitSerial: this.serial }
+ }));
+
+ this.socket.addEventListener("message", (event) => {
+ const data = JSON.parse(event.data);
+ if (data.method === "rawMeasurements" && data.params.result) {
+ this.addMeasurement(data.params.result);
+ }
+ })
+ })
+ }
+
+ disconnect = () => {
+ this.socket?.close();
+ }
+
+ setSerial = (newSerial) => {
+ this.serial = newSerial;
+ this.connect();
+ }
+}
+
+export const measurementsStore = new Measurements();
+export const measurementCtx = createContext(measurementsStore);
\ No newline at end of file