From 27f8b1da20400f3256e0b6cfc2cd78235ce1beef Mon Sep 17 00:00:00 2001 From: sam rolfe Date: Tue, 9 Sep 2025 11:30:30 +1000 Subject: [PATCH] Added map and dashboard --- app/page.tsx | 110 ++++++++++++++++ lib/api.ts | 108 ++++++++++++++++ lib/map.tsx | 45 +++++++ lib/types.ts | 36 ++++++ package-lock.json | 47 +++++++ package.json | 4 + prisma/schema.prisma | 301 +++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 637 insertions(+), 14 deletions(-) create mode 100644 app/page.tsx create mode 100644 lib/map.tsx create mode 100644 lib/types.ts diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..f76e39c --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,110 @@ +import { useState, useEffect } from "react"; +import { MapContainer, TileLayer, Marker, useMapEvents } from "react-leaflet"; +import "leaflet/dist/leaflet.css"; +import L from "leaflet"; + +// Delete default Leaflet marker icon to avoid errors +delete (L.Icon.Default as any)._getIconUrl; + +// Helpers and types from lib/api.ts + +const IMEI = "your_device_imei_here"; // Replace with dynamic if multiple devices + +export default function Dashboard() { + const [telemetry, setTelemetry] = useState(null); + const [commands, setCommands] = useState([]); + const [fence, setFence] = useState<{ lat: number; lng: number }[]>([]); // Geo-fence points + const [commandType, setCommandType] = useState("sleep"); + const [payload, setPayload] = useState(""); // JSON string for form + + // Poll for latest telemetry and commands + useEffect(() => { + const interval = setInterval(async () => { + try { + const latestGPS = await getLatestGPS(IMEI); + setTelemetry(latestGPS); + const cmds = await getCommands(IMEI); + setCommands(cmds); + } catch (e) { + console.error(e); + } + }, 5000); // Poll every 5s; adjust + + return () => clearInterval(interval); + }, []); + + // Send command from form + const sendCommand = async () => { + try { + const parsedPayload = JSON.parse(payload); // Validate in real app + await postReceipt(IMEI, { command_id: 0, result: "ok" }); // Stub receipt (adjust) + // Send actual command via your API if needed + setPayload(""); + } catch (e) { + console.error(e); + } + }; + + // Map component (geo-fence drawing) + function FenceMap() { + const map = useMapEvents({ + click: (e) => setFence([...fence, { lat: e.latlng.lat, lng: e.latlng.lng }]), + }); + // Draw fence as polyline + if (fence.length > 1) L.polyline(fence, { color: "red" }).addTo(map); + // Marker for latest GPS + if (telemetry) L.marker([telemetry.lat, telemetry.lng]).addTo(map); + + return null; + } + + return ( +
+

Sams Home Network Device Dashboard

+ +
+
+

Latest Telemetry

+ {telemetry ? ( +
{JSON.stringify(telemetry, null, 2)}
+ ) : "Loading telemetry..."} +

WiFi: {telemetry?.raw?.wifiStatus ?? 'Unknown'}

+

Battery: {telemetry?.battery_percent ?? 'Unknown'}%

+

Car On: {telemetry?.is_car_on ? 'Yes' : 'No'}

+
+ +
+

Map & Geo-Fence

+ + + + +

Click map to add fence points: {fence.length}

+ {/* Example */} +
+
+ +
+

Queued Commands

+
{JSON.stringify(commands, null, 2)}
+ +
+ +
+

Send Command

+ +