// components/IndividualClientPage.tsx "use client"; import React, { useState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; import { API_BASE_URL } from '@/constants/api'; import { ErrorResponse, NodeStatusResponse, System } from '@/types'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Label } from '@/components/ui/label'; interface IndividualClientPageProps { clientId: string; // Now received as a prop token: string; } const IndividualClientPage: React.FC = ({ clientId, token }) => { const [message, setMessage] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const [currentClientDiscordStatus, setCurrentClientDiscordStatus] = useState('Unknown'); const [currentClientOp25Status, setCurrentClientOp25Status] = useState('Unknown'); // OP25 Set Config Popup States const [selectedSystem, setSelectedSystem] = useState(null); const [isSetConfigDialogOpen, setIsSetConfigDialogOpen] = useState(false); const [availableSystems, setAvailableSystems] = useState([]); const fetchClientStatus = async () => { try { setLoading(true); const response = await fetch(`${API_BASE_URL}/nodes/${clientId}/status`, { headers: { Authorization: `Bearer ${token}` }, }); if (response.ok) { const data: NodeStatusResponse = await response.json(); console.log(data) setCurrentClientDiscordStatus(data.status.discord_status); setCurrentClientOp25Status(data.status.op25_status) } else { setCurrentClientDiscordStatus('Failed to fetch status'); setCurrentClientOp25Status('Failed to fetch status'); } } catch (err) { setCurrentClientDiscordStatus('Error fetching status'); setCurrentClientOp25Status('Error fetching status'); } finally { setLoading(false); } }; const fetchSystems = async (): Promise => { setError(''); try { const response = await fetch(`${API_BASE_URL}/systems/`, { headers: { Authorization: `Bearer ${token}` }, }); if (response.ok) { const data: System[] = await response.json(); // Filter systems to those available on the current clientId const filteredSystems = data.filter(system => system.avail_on_nodes.includes(clientId)); setAvailableSystems(filteredSystems); } else { let errorMsg = `Failed to fetch systems (${response.status})`; try { const errorData: ErrorResponse = await response.json(); errorMsg += `: ${errorData.message || (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail)) || response.statusText}`; } catch (e) { errorMsg += `: ${response.statusText}`; } setError(errorMsg); } } catch (err: any) { setError('Failed to fetch systems. Check server connection or console.'); console.error(err); } }; useEffect(() => { fetchClientStatus(); fetchSystems(); // Fetch systems when the component mounts or clientId/token changes }, [clientId, token]); const handleAction = async (action: 'join' | 'leave' | 'op25_start' | 'op25_stop' | 'op25_set'): Promise => { setMessage(''); setError(''); setLoading(true); try { const httpOptions: RequestInit = { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, } } if (action === "op25_set") { if (!selectedSystem) { setError("Please select a system to set configuration."); setLoading(false); return; } httpOptions.body = JSON.stringify({ "system_id": selectedSystem }); } const response = await fetch(`${API_BASE_URL}/nodes/${clientId}/${action}`, httpOptions); const data = await response.json(); if (response.ok) { setMessage(`Client "${clientId}" successfully ${action === 'op25_set' ? 'set config for system ' + selectedSystem : action + 'ed'}.`); fetchClientStatus(); setIsSetConfigDialogOpen(false); // Close dialog on success } else { const errorData = data as ErrorResponse; setError(`Failed to ${action} client "${clientId}": ${errorData.message || (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail)) || response.statusText}`); } } catch (err: any) { setError(`Network error during ${action} client: ${err.message}`); console.error(err); } finally { setLoading(false); } }; return ( Manage Client: {clientId}

Current Discord Status: {currentClientDiscordStatus}

Current OP25 Status: {currentClientOp25Status}

{message &&

{message}

} {error &&

{error}

} {loading &&

Processing request...

}
{/* Set Config Dialog */} Set OP25 System Configuration
); }; export default IndividualClientPage;