From f11441fb1118bf84c9860cf278fd1db7dd3edea2 Mon Sep 17 00:00:00 2001 From: H4S1NTH4 Date: Sat, 2 May 2026 04:20:08 +0530 Subject: [PATCH] feat: add Manual Dispatch Panel for triggering equipment operations via MQTT --- .../app/(dashboard)/admin/equipment/page.tsx | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/client/app/(dashboard)/admin/equipment/page.tsx b/client/app/(dashboard)/admin/equipment/page.tsx index 4e0cb2f..1491a01 100644 --- a/client/app/(dashboard)/admin/equipment/page.tsx +++ b/client/app/(dashboard)/admin/equipment/page.tsx @@ -631,6 +631,153 @@ function TableSkeleton() { ); } +function ManualDispatchPanel({ equipment }: { equipment: Equipment[] }) { + const [selectedEquipmentId, setSelectedEquipmentId] = useState(""); + const [selectedOperation, setSelectedOperation] = useState(""); + const [isDispatching, setIsDispatching] = useState(false); + + const selectedEquip = equipment.find((e) => e.id === selectedEquipmentId); + + const handleDispatch = async () => { + if (!selectedEquipmentId || !selectedOperation) { + toast.error("Please select equipment and operation"); + return; + } + + setIsDispatching(true); + try { + await hardwareApi.controlEquipment(selectedEquipmentId, { + operation: selectedOperation, + }); + + toast.success("Command dispatched", { + description: `${selectedOperation} command sent to ${selectedEquip?.name}`, + }); + + mutate("equipment"); + setSelectedEquipmentId(""); + setSelectedOperation(""); + } catch (err) { + if (err instanceof ApiError) { + toast.error("Dispatch failed", { + description: err.message, + }); + } else { + toast.error("Dispatch failed", { + description: "An unexpected error occurred", + }); + } + } finally { + setIsDispatching(false); + } + }; + + return ( + + + + + Manual Equipment Dispatch + + + Directly trigger equipment operations via MQTT + + + +
+ + Select Equipment + + + + {selectedEquip && ( + + Operation + + + )} + + {selectedEquip && selectedOperation && ( +
+
+ MQTT Topic + + {selectedEquip.mqtt_topic} + +
+
+ )} +
+ + {selectedEquip && selectedOperation && ( +
+

Preview

+

+ Sending {selectedOperation} command to{" "} + {selectedEquip.name} via MQTT +

+
+ )} + +
+ + +
+
+
+ ); +} + export default function EquipmentPage() { const { isLoading: authLoading } = useRequireAuth("Admin"); const { data: equipment, isLoading: equipmentLoading } = useEquipment(); @@ -649,6 +796,10 @@ export default function EquipmentPage() { + {!isLoading && equipment && equipment.length > 0 && ( + + )} + Registered Equipment