CAR_GPS_REACT/src/app/page.tsx
2025-10-06 16:56:30 +11:00

95 lines
3.4 KiB
TypeScript

// In file: src/app/page.tsx some basic changes in order to test gitea
"use client";
import { useState, useEffect } from "react";
import dynamic from "next/dynamic";
import { getCommands, getLatestGPS, DeviceCommand, TelemetryPost, DeviceCommandType, postReceipt } from "~/lib/api"; // Assuming postCommand will be added later
import { CommandManager } from "~/app/_components/CommandManager";
// Dynamically import the map component with SSR turned OFF to prevent "window is not defined" errors
const DeviceMap = dynamic(
() => import("~/app/_components/DynamicDeviceMap").then((mod) => mod.DeviceMap),
{
ssr: false,
loading: () => <p>Loading map...</p>,
}
);
const DEFAULT_IMEI = "sim7080g-01"; // Or make this dynamic later
export default function Dashboard() {
const [selectedImei, setSelectedImei] = useState<string>(DEFAULT_IMEI);
const [telemetry, setTelemetry] = useState<TelemetryPost | null>(null);
const [commands, setCommands] = useState<DeviceCommand[]>([]);
const [fence, setFence] = useState<Array<{ lat: number; lng: number }>>([]);
const [commandType, setCommandType] = useState<DeviceCommandType>("sleep");
const [payload, setPayload] = useState<string>("");
useEffect(() => {
const pollData = async () => {
try {
const latest = await getLatestGPS(selectedImei);
setTelemetry(latest);
const cmds = await getCommands(selectedImei);
setCommands(cmds);
} catch (e) {
console.error("Poll error:", e);
}
};
pollData(); // Initial fetch
const interval = setInterval(pollData, 5000);
return () => clearInterval(interval);
}, [selectedImei]);
return (
<main className="flex min-h-screen flex-col gap-4 bg-gray-900 p-4 text-white">
<h1 className="text-2xl font-bold">Device Dashboard ({selectedImei})</h1>
<section className="grid grid-cols-1 gap-4 mt-4 md:grid-cols-2">
<div>
<h2 className="text-xl font-bold">Latest Telemetry</h2>
{telemetry ? (
<pre className="p-2 mt-2 text-sm text-white rounded-md bg-white/10">{JSON.stringify(telemetry, null, 2)}</pre>
) : (
<p>Loading telemetry...</p>
)}
</div>
<div>
<h2 className="text-xl font-bold">Map & Geo-Fence</h2>
<div className="mt-2 h-[300px] rounded-md overflow-hidden bg-gray-800 flex items-center justify-center">
{telemetry ? (
<DeviceMap latestGPS={telemetry} onFenceChange={setFence} />
) : (
<p className="text-gray-400">Waiting for GPS data...</p>
)}
</div>
<p>Geo-fence points: {fence.length}</p>
</div>
</section>
<section className="mt-6">
<h2 className="text-xl font-bold">Queued Commands</h2>
<pre className="p-2 mt-2 text-sm text-white rounded-md bg-white/10">{commands.length > 0 ? JSON.stringify(commands, null, 2) : "No commands queued."}</pre>
{commands.length > 0 && (
<button
className="px-4 py-2 mt-2 text-white bg-green-600 rounded-md hover:bg-green-700"
onClick={() => postReceipt(selectedImei, { command_id: commands[0]?.id ?? 0, result: "ok" })}
>
Acknowledge First Command
</button>
)}
</section>
<section className="mt-6">
<h2 className="text-xl font-bold">Command Center</h2>
<div className="mt-2">
<CommandManager selectedImei={selectedImei} /> {/* <-- ADD THE NEW COMPONENT HERE */}
</div>
</section>
</main>
);
}