import { useMemo, useState } from 'react' import { Settings } from 'lucide-react' import { useQueryClient } from '@tanstack/react-query' import { useStats } from './hooks/useStats' import { useTests } from './hooks/useTests' import { useConfig } from './hooks/useConfig' import { useAuth } from './hooks/useAuth' import cgw453Image from './assets/CGW453.PNG' import StatCard from './components/StatCard' import CompletionBar from './components/CompletionBar' import TimeDisplay from './components/TimeDisplay' import FilterPanel from './components/FilterPanel' import TestTable from './components/TestTable' import ConfigModal from './components/ConfigModal' function hasCoePairs(value) { if (!value) return false if (Array.isArray(value)) return value.length > 0 if (typeof value !== 'string') return false try { const parsed = JSON.parse(value) return Array.isArray(parsed) && parsed.length > 0 } catch { return false } } export default function App() { const queryClient = useQueryClient() const { user, isReady, isAuthenticated, isAdmin, login, logout } = useAuth() const [showConfig, setShowConfig] = useState(false) const [filters, setFilters] = useState({}) const [username, setUsername] = useState('') const [password, setPassword] = useState('') const [loginError, setLoginError] = useState('') const [isLoggingIn, setIsLoggingIn] = useState(false) const { data: stats, isLoading: statsLoading } = useStats(isAuthenticated) const { data: allTests = [], isLoading: testsLoading } = useTests({}, isAuthenticated) const { data: config, isLoading: configLoading } = useConfig(isAuthenticated && isAdmin) // Apply filters client-side const filteredTests = useMemo(() => { return allTests.filter(t => { if (filters.completed !== undefined && filters.completed !== '') { const want = filters.completed === 'true' ? 1 : 0 if (t.completed !== want) return false } const strFields = ['interference', 'device', 'rotation', 'test_point', 'rssi', 'station', 'band', 'channel', 'bandwidth', 'direction', 'throttled'] for (const f of strFields) { if (filters[f] && t[f] !== filters[f]) return false } if (filters.coePair === 'yes' || filters.coePair === 'no') { const paired = hasCoePairs(t.coe_pair) if (filters.coePair === 'yes' && !paired) return false if (filters.coePair === 'no' && paired) return false } return true }) }, [allTests, filters]) const noConfig = isAdmin && !configLoading && !config?.target_dir && !config?.results_dir const configuredButEmpty = isAdmin && !configLoading && config?.target_dir && config?.results_dir && !statsLoading && stats?.overall.total === 0 async function handleLogin(e) { e.preventDefault() setLoginError('') setIsLoggingIn(true) try { await login(username.trim(), password) setPassword('') } catch (err) { setLoginError(err?.message ?? 'Login failed') } finally { setIsLoggingIn(false) } } function handleLogout() { logout() queryClient.clear() setShowConfig(false) setFilters({}) } if (!isReady) { return (

Checking session...

) } if (!isAuthenticated) { return (

Sign in

{loginError && (
{loginError}
)}
) } return (
{/* Top bar */}

CGW453 Test Dashboard

{user?.username} ({user?.role}) {isAdmin && ( )}
{/* No-config prompt */} {noConfig && (
No directories configured.{' '} {' '} to point the dashboard at your target and results directories.
)} {/* Configured but no tests found */} {configuredButEmpty && (
Directories are configured but no tests were found.{' '} Ensure the target directory contains subdirectories with TC_WIFI_*.ini files.{' '}
)} {/* Stats row */} {!statsLoading && stats && (
CGW453 test object
{stats.devices.map(d => (
{ const typeStats = d.byType?.[type] ?? { completed: 0, total: 0 } return `${type}: ${typeStats.completed}/${typeStats.total} tests` })} />
))}
)} {/* Filters + Table */}

Showing {filteredTests.length} of {allTests.length} tests

{isAdmin && showConfig && setShowConfig(false)} />}
) }