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 + + + + + + {equipment.map((item) => ( + + + + {item.name} + + + ))} + + + + + {selectedEquip && ( + + Operation + + + + + + {selectedEquip.supported_operations.map((op) => ( + + {op} + + ))} + + + + )} + + {selectedEquip && selectedOperation && ( + + + MQTT Topic + + {selectedEquip.mqtt_topic} + + + + )} + + + {selectedEquip && selectedOperation && ( + + Preview + + Sending {selectedOperation} command to{" "} + {selectedEquip.name} via MQTT + + + )} + + + { + setSelectedEquipmentId(""); + setSelectedOperation(""); + }} + disabled={isDispatching || !selectedEquipmentId} + > + Clear + + + {isDispatching ? ( + <> + + Dispatching... + > + ) : ( + <> + + Dispatch Command + > + )} + + + + + ); +} + 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
+ {selectedEquip.mqtt_topic} +
Preview
+ Sending {selectedOperation} command to{" "} + {selectedEquip.name} via MQTT +