import React, { useState, useEffect, useRef } from 'react'; import { useLoaderData, useNavigate, useParams } from "@remix-run/react"; import { useSocket } from "../context"; import { L33tADSPLCImpl } from "l33t-lib"; import { loaderPLCById } from '../loaders'; export const loader = loaderPLCById; export default function PlcDetail() { const navigate = useNavigate(); const { id } = useParams<{ id: string }>(); const initialPLC = useLoaderData(); const socket = useSocket(); const timeoutRef = useRef(); const [selectedPLC, setSelectedPLC] = useState(initialPLC); const [plcId, setPlcId] = useState(id || ''); const [ipAddress, setIpAddress] = useState(initialPLC?.ip || ''); const [boundVariables, setBoundVariables] = useState( initialPLC ? initialPLC.boundVariables : [] ); useEffect(() => { if (initialPLC) { setSelectedPLC(initialPLC); setPlcId(id || ''); setIpAddress(initialPLC.ip || ''); setBoundVariables(initialPLC.boundVariables || []); } }, [id, initialPLC]); useEffect(() => { if (!socket) return; const handlePlcUpdate = (updatedId: string, updatedPlc: L33tADSPLCImpl | null) => { if (updatedId === id && updatedPlc) { setSelectedPLC(updatedPlc); setIpAddress(updatedPlc.ip); setBoundVariables(updatedPlc.boundVariables || []); } }; socket.on("l33t_plc_update", handlePlcUpdate); return () => { socket.off("l33t_plc_update", handlePlcUpdate); }; }, [socket, id]); useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") navigate(".."); }; document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("keydown", handleKeyDown); }; }, [navigate]); const handleChangeId = (newId: string) => { setPlcId(newId); // Clear any existing timeout if (timeoutRef.current) { clearTimeout(timeoutRef.current); } // Set new timeout timeoutRef.current = setTimeout(() => { if (socket && selectedPLC && newId !== id) { socket.emit("l33t_delete_plc", { plcId: id }); socket.emit("l33t_add_plc", newId, { ...selectedPLC, ip: ipAddress, }); socket.emit("l33t_db_persist"); navigate(`/plcs/${newId}`, { replace: true }); } }, 1000); }; const handleChangeIP = (value: string) => { setIpAddress(value); if (socket && selectedPLC) { const updatedPLC: Partial = { ...selectedPLC, ip: value }; socket.emit("l33t_plc_update", id, updatedPLC); socket.emit("l33t_db_persist"); } }; // Cleanup timeout on unmount useEffect(() => { return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, []); if (!id) return
Error: No PLC ID provided
; if (!selectedPLC) return
No PLC selected
; return (

PLC Details

handleChangeId(e.target.value)} placeholder="e.g., carroponte" className="w-full bg-gray-700 rounded px-3 py-2" />
handleChangeIP(e.target.value)} className="w-full bg-gray-700 rounded px-3 py-2" />
{selectedPLC.connected ? 'Connected' : 'Disconnected'}
{selectedPLC.description && (

{selectedPLC.description}

)} {boundVariables && boundVariables.length > 0 ? (

Bound Variables

    {boundVariables.map((variable, index) => (
  • {variable} {selectedPLC.values[variable]?.toString() || 'N/A'}
  • ))}
) : (

No bound variables

)}
); }