From 5b1599250b46df4d64968474c9a18691c9d8f576 Mon Sep 17 00:00:00 2001 From: YouQam Date: Fri, 13 Oct 2023 08:56:17 +0200 Subject: [PATCH 1/5] single device page - initial impl. --- app/routes/device.$deviceId.tsx | 251 ++++++++++++++++++++++++++++++++ app/utils.ts | 27 ++++ package.json | 3 +- 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 app/routes/device.$deviceId.tsx diff --git a/app/routes/device.$deviceId.tsx b/app/routes/device.$deviceId.tsx new file mode 100644 index 00000000..c0016444 --- /dev/null +++ b/app/routes/device.$deviceId.tsx @@ -0,0 +1,251 @@ +import type { LinksFunction } from "@remix-run/node"; +import { NavBar } from "~/components/nav-bar"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "~/components/ui/card"; +import { Map, MapProvider, Marker } from "react-map-gl"; +import mapboxgl from "mapbox-gl/dist/mapbox-gl.css"; +import { Cloudy, Droplets, Thermometer } from "lucide-react"; +import { diffFromCreateDate, getMinuteFormattedString } from "~/utils"; +import { Badge } from "~/components/ui/badge"; +import moment from "moment"; + +let deviceData = { + _id: "5b411d0e5dc1ec001b4f11c8", + createdAt: "2022-03-30T11:25:43.557Z", + updatedAt: "2023-10-13T06:28:23.033Z", + name: "Bahnhofstraße", + currentLocation: { + timestamp: "2018-07-07T20:05:34.723Z", + coordinates: [7.478471, 52.083515, 3.65], + type: "Point", + }, + exposure: "outdoor", + sensors: [ + { + title: "PM10", + unit: "µg/m³", + sensorType: "SDS 011", + icon: "osem-cloud", + _id: "5b411d0e5dc1ec001b4f11cc", + lastMeasurement: { + value: "23.73", + createdAt: "2023-10-13T06:28:23.027Z", + }, + }, + { + title: "PM2.5", + unit: "µg/m³", + sensorType: "SDS 011", + icon: "osem-cloud", + _id: "5b411d0e5dc1ec001b4f11cb", + lastMeasurement: { + value: "20.43", + createdAt: "2023-10-13T06:28:23.027Z", + }, + }, + { + title: "Temperatur", + unit: "°C", + sensorType: "DHT22", + icon: "osem-thermometer", + _id: "5b411d0e5dc1ec001b4f11ca", + lastMeasurement: { + value: "20.80", + createdAt: "2022-07-12T07:02:41.061Z", + }, + }, + { + title: "rel. Luftfeuchte", + unit: "%", + sensorType: "DHT22", + icon: "osem-humidity", + _id: "5b411d0e5dc1ec001b4f11c9", + lastMeasurement: { + value: "99.90", + createdAt: "2022-07-12T07:02:41.061Z", + }, + }, + ], + model: "luftdaten_sds011_dht22", + description: + "Mounted at the street side of my house. Traffic: approx. 8.000 vehicles/d", + image: "5b411d0e5dc1ec001b4f11c8_pblauf.jpg", + lastMeasurementAt: "2023-10-13T06:28:23.027Z", + grouptag: [""], + loc: [ + { + geometry: { + timestamp: "2018-07-07T20:05:34.723Z", + coordinates: [7.478471, 52.083515, 3.65], + type: "Point", + }, + type: "Feature", + }, + ], +}; + +//***************************************** +//* required to view mapbox proberly (Y.Q.) +export const links: LinksFunction = () => { + return [ + { + rel: "stylesheet", + href: mapboxgl, + }, + ]; +}; + +//********************************** +export default function DeviceDashboard() { + //* map marker + const marker = { + longitude: deviceData.currentLocation.coordinates[0], + latitude: deviceData.currentLocation.coordinates[1], + }; + + return ( +
+ + + {/* Left side - device info */} +
+ + + {deviceData.name} + {deviceData._id} + + + {/* properties */} +
+ + {deviceData.exposure.toUpperCase()} + + + {`${deviceData.sensors.length} SENSOR(S)`} + + + {/* Created {deviceData.createdAt.slice(0, 10)} */} + {diffFromCreateDate(deviceData.createdAt)} + + + {moment().diff(moment(deviceData.updatedAt), "days") > 3 ? ( + + INACTIVE + + ) : ( + + ACTIVE + + )} +
+ + {/* image */} +
+
+ {"name"} +
+

+ Mounted at the street side of my house. Traffic: approx. 8.000 + vehicles/d +

+
+ + {/* Map view */} +
+ + + + + +
+
+
+ + {/* Right side - measurements */} + + +
+ {deviceData.sensors.map((sensor: any) => ( + + + + + {sensor.lastMeasurement.value} {sensor.unit} + + + + {sensor.title}{" "} + + + {sensor.sensorType} + + + + +
+ {/*

5 minutes ago

*/} + {sensor.lastMeasurement?.createdAt === undefined || + moment().diff( + moment(sensor.lastMeasurement.createdAt), + "hours", + ) > 25 ? ( +

+ INACTIVE +

+ ) : ( +

+ {getMinuteFormattedString( + sensor.lastMeasurement.createdAt, + )} +

+ )} +
+
+ ))} +
+
+
+
+
+ ); +} diff --git a/app/utils.ts b/app/utils.ts index 95e0ac42..0c69486c 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -1,4 +1,5 @@ import { useMatches } from "@remix-run/react"; +import moment from "moment"; import { useMemo } from "react"; import type { User } from "~/models/user.server"; @@ -142,3 +143,29 @@ export function getFilteredDevices(devices: any, filterParams: URLSearchParams) } } } + +//* Get Minute Formatted String - last sensor measurement update +export function getMinuteFormattedString(lastMeasurementAt: string) { + const secondsAgo = moment().diff( + moment(lastMeasurementAt), + "seconds"); + + if (secondsAgo === null || secondsAgo === undefined) { + return "-"; + } else { + if (secondsAgo < 120) { + return "now"; + } + return `${Math.floor(secondsAgo / 60)} minutes ago`; + } +} + +export function diffFromCreateDate(DeviceCreatedAt: string) { + const createDate = moment(DeviceCreatedAt); + const yearsFromCreate = moment().diff(createDate, "years"); + return `Created ${ + yearsFromCreate === 0 + ? `${moment().diff(createDate, "days")} day(s)` + : `${yearsFromCreate} year` + (yearsFromCreate > 1 ? "s" : "") + } ago`; +} diff --git a/package.json b/package.json index 62a46cd6..7c87417f 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "lodash.debounce": "^4.0.8", "lucide-react": "^0.263.1", "mapbox-gl": "^2.14.1", + "moment": "^2.29.4", "morgan": "^1.10.0", "node-fetch": "^3.3.1", "postcss-import": "^15.1.0", @@ -151,8 +152,8 @@ "@types/mapbox__mapbox-gl-geocoder": "^4.7.4", "@types/morgan": "^1.9.4", "@types/node": "^18.17.6", - "@types/react": "^18.2.20", "@types/node-fetch": "^2.6.4", + "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", "@types/react-lottie": "^1.2.6", "@types/source-map-support": "^0.5.7", From 592084058b6fe5a51ad266e30180171d5043a96c Mon Sep 17 00:00:00 2001 From: YouQam Date: Fri, 13 Oct 2023 09:07:45 +0200 Subject: [PATCH 2/5] some updates --- app/routes/device.$deviceId.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes/device.$deviceId.tsx b/app/routes/device.$deviceId.tsx index c0016444..c4a46ff1 100644 --- a/app/routes/device.$deviceId.tsx +++ b/app/routes/device.$deviceId.tsx @@ -113,7 +113,7 @@ export default function DeviceDashboard() { {/* Left side - device info */} -
+
{deviceData.name} From 055a242b7ad57bc2a52d918c918314de23548275 Mon Sep 17 00:00:00 2001 From: YouQam Date: Fri, 13 Oct 2023 09:08:45 +0200 Subject: [PATCH 3/5] some updates --- app/routes/device.$deviceId.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/routes/device.$deviceId.tsx b/app/routes/device.$deviceId.tsx index c4a46ff1..b00fb3ae 100644 --- a/app/routes/device.$deviceId.tsx +++ b/app/routes/device.$deviceId.tsx @@ -9,7 +9,6 @@ import { } from "~/components/ui/card"; import { Map, MapProvider, Marker } from "react-map-gl"; import mapboxgl from "mapbox-gl/dist/mapbox-gl.css"; -import { Cloudy, Droplets, Thermometer } from "lucide-react"; import { diffFromCreateDate, getMinuteFormattedString } from "~/utils"; import { Badge } from "~/components/ui/badge"; import moment from "moment"; From b041ba4b2b659a13d225e22d3f50a9abbe6d36cd Mon Sep 17 00:00:00 2001 From: YouQam Date: Thu, 26 Oct 2023 11:49:29 +0200 Subject: [PATCH 4/5] update dark mode style --- app/routes/device.$deviceId.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/routes/device.$deviceId.tsx b/app/routes/device.$deviceId.tsx index b00fb3ae..12296820 100644 --- a/app/routes/device.$deviceId.tsx +++ b/app/routes/device.$deviceId.tsx @@ -113,7 +113,7 @@ export default function DeviceDashboard() { {/* Left side - device info */}
- + {deviceData.name} {deviceData._id} @@ -201,27 +201,27 @@ export default function DeviceDashboard() { {/* Right side - measurements */} - +
{deviceData.sensors.map((sensor: any) => ( - + {sensor.lastMeasurement.value} {sensor.unit} - + {sensor.title}{" "} - + {sensor.sensorType} -
+
{/*

5 minutes ago

*/} {sensor.lastMeasurement?.createdAt === undefined || moment().diff( From fb05060eda905d32832f3e75e98e5de5a6d18b41 Mon Sep 17 00:00:00 2001 From: YouQam Date: Thu, 26 Oct 2023 11:59:59 +0200 Subject: [PATCH 5/5] some updates --- app/routes/device.$deviceId.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/routes/device.$deviceId.tsx b/app/routes/device.$deviceId.tsx index 12296820..c4cf35ce 100644 --- a/app/routes/device.$deviceId.tsx +++ b/app/routes/device.$deviceId.tsx @@ -16,7 +16,7 @@ import moment from "moment"; let deviceData = { _id: "5b411d0e5dc1ec001b4f11c8", createdAt: "2022-03-30T11:25:43.557Z", - updatedAt: "2023-10-13T06:28:23.033Z", + updatedAt: "2023-10-26T06:28:23.033Z", name: "Bahnhofstraße", currentLocation: { timestamp: "2018-07-07T20:05:34.723Z", @@ -138,7 +138,7 @@ export default function DeviceDashboard() { {moment().diff(moment(deviceData.updatedAt), "days") > 3 ? ( INACTIVE @@ -146,7 +146,7 @@ export default function DeviceDashboard() { ACTIVE