'use client'; import React, { useEffect, useMemo, useState } from 'react'; import axios from 'axios'; type FnType = 'grid' | 'solar'; interface LoggingControlCardProps { siteId: string; projectLabel?: string; // nice display (e.g., CRM project_name) className?: string; } const API_URL = process.env.NEXT_PUBLIC_FASTAPI_URL; type FnState = { serial: string; isLogging: boolean; isBusy: boolean; // to block double clicks while calling API error?: string | null; }; const emptyFnState: FnState = { serial: '', isLogging: false, isBusy: false, error: null }; const storageKey = (siteId: string) => `logging_control_${siteId}`; export default function LoggingControlCard({ siteId, projectLabel, className = '', }: LoggingControlCardProps) { const [grid, setGrid] = useState(emptyFnState); const [solar, setSolar] = useState(emptyFnState); // Load persisted state (if any) useEffect(() => { try { const raw = localStorage.getItem(storageKey(siteId)); if (raw) { const parsed = JSON.parse(raw); setGrid({ ...emptyFnState, ...(parsed.grid ?? {}) }); setSolar({ ...emptyFnState, ...(parsed.solar ?? {}) }); } else { setGrid(emptyFnState); setSolar(emptyFnState); } } catch { setGrid(emptyFnState); setSolar(emptyFnState); } }, [siteId]); // Persist on any change useEffect(() => { const data = { grid, solar }; try { localStorage.setItem(storageKey(siteId), JSON.stringify(data)); } catch { // ignore storage errors } }, [siteId, grid, solar]); const title = useMemo( () => `Logging Control${projectLabel ? ` — ${projectLabel}` : ''}`, [projectLabel] ); const topicsFor = (fn: FnType, serial: string) => { return [`ADW300/${siteId}/${serial}/${fn}`]; }; const start = async (fn: FnType) => { const state = fn === 'grid' ? grid : solar; const setState = fn === 'grid' ? setGrid : setSolar; if (!state.serial.trim()) { setState((s) => ({ ...s, error: 'Please enter a meter serial number.' })); return; } setState((s) => ({ ...s, isBusy: true, error: null })); try { const topics = topicsFor(fn, state.serial.trim()); const res = await axios.post(`${API_URL}/start-logging`, { topics }); console.log('Start logging:', res.data); setState((s) => ({ ...s, isLogging: true, isBusy: false })); } catch (e: any) { console.error('Failed to start logging', e); setState((s) => ({ ...s, isBusy: false, error: e?.response?.data?.detail || e?.message || 'Failed to start logging', })); } }; const stop = async (fn: FnType) => { const state = fn === 'grid' ? grid : solar; const setState = fn === 'grid' ? setGrid : setSolar; if (!state.isLogging) return; const confirmed = window.confirm( `Stop logging for ${fn.toUpperCase()} meter "${state.serial}" at site ${siteId}?` ); if (!confirmed) return; setState((s) => ({ ...s, isBusy: true, error: null })); try { const topics = topicsFor(fn, state.serial.trim()); const res = await axios.post(`${API_URL}/stop-logging`, { topics }); console.log('Stop logging:', res.data); setState((s) => ({ ...s, isLogging: false, isBusy: false })); } catch (e: any) { console.error('Failed to stop logging', e); setState((s) => ({ ...s, isBusy: false, error: e?.response?.data?.detail || e?.message || 'Failed to stop logging', })); } }; // Responsive utility classes const field = 'w-full px-3 py-2 sm:py-2.5 border rounded-md text-sm sm:text-base placeholder:text-gray-400 dark:border-rtgray-700 dark:bg-rtgray-700 dark:text-white'; const label = 'text-gray-600 dark:text-white/85 font-medium text-sm sm:text-base mb-1 flex items-center justify-between mr-2.5'; const section = ( fn: FnType, labelText: string, state: FnState, setState: React.Dispatch> ) => (
{labelText} {state.isLogging && ( Logging )}
{/* Input + Button: stack on mobile, row on ≥sm */}
setState((s) => ({ ...s, serial: e.target.value }))} disabled={state.isLogging || state.isBusy} aria-label={`${labelText} serial number`} /> {!state.isLogging ? ( ) : ( )}
{!!state.error &&
{state.error}
}
); return (

{title}

{section('grid', 'Grid Meter', grid, setGrid)}
{section('solar', 'Solar Meter', solar, setSolar)}
• Inputs lock while logging is active. Stop to edit the serial.
• Topics follow{' '} ADW300/{'{'}siteId{'}'}/{'{'}serial{'}'}/(grid|solar) .
); }