/* global React, Card, StatusBadge, StatusGlyph, STATUS_META, Ic, Button, Input, Breadcrumb, VS, LoadingState, ErrorState, statusFromAlarm, fmtInt */ function MeasurementsScreen({ onOpenSession }) { const [sites, setSites] = React.useState(null); const [siteId, setSiteId] = React.useState(() => { const saved = localStorage.getItem('vs_selected_site'); return saved ? parseInt(saved, 10) : null; }); const [machines, setMachines] = React.useState(null); const [loadingMachines, setLoadingMachines] = React.useState(false); const [query, setQuery] = React.useState(''); const [selectedMachine, setSelectedMachine] = React.useState(null); const [sessions, setSessions] = React.useState(null); const [loadingSessions, setLoadingSessions] = React.useState(false); const [err, setErr] = React.useState(''); const [logoBust, setLogoBust] = React.useState(0); const fileInputRef = React.useRef(null); const role = VS.getRole(); const isAdmin = role === 'admin'; React.useEffect(() => { VS.sites().then(s => { setSites(s); const existing = siteId && s.find(x => x.id === siteId); if (!existing) { const firstNonEmpty = s.find(x => (x.measurements_count || 0) > 0); const fallback = firstNonEmpty || s[0]; if (fallback) setSiteId(fallback.id); } }).catch(e => setErr(e.message)); }, []); React.useEffect(() => { if (!siteId) return; localStorage.setItem('vs_selected_site', String(siteId)); setMachines(null); setSelectedMachine(null); setSessions(null); setLoadingMachines(true); VS.siteMachines(siteId) .then(m => setMachines(m)) .catch(e => setErr(e.message)) .finally(() => setLoadingMachines(false)); }, [siteId]); async function selectMachine(m) { setSelectedMachine(m); setSessions(null); setLoadingSessions(true); try { const s = await VS.sessions(m.id, 50); setSessions(s); } catch (e) { setErr(e.message); } finally { setLoadingSessions(false); } } async function uploadLogo(e) { const file = e.target.files && e.target.files[0]; if (!file || !siteId) return; try { await VS.uploadSiteLogo(siteId, file); setLogoBust(x => x + 1); } catch (err) { setErr(err.message); } e.target.value = ''; } async function removeLogo() { if (!siteId) return; try { await VS.deleteSiteLogo(siteId); setLogoBust(x => x + 1); } catch (err) { setErr(err.message); } } const site = sites && sites.find(s => s.id === siteId); const filteredMachines = machines ? machines.filter(m => !query || m.name.toLowerCase().includes(query.toLowerCase()) || (m.hall || '').toLowerCase().includes(query.toLowerCase())) : []; if (err && !sites) return ; if (!sites) return ; return (
{err && (
{err}
)}
{!selectedMachine && } {selectedMachine && ( selectMachine(selectedMachine)} /> )}
); } function SiteHeader({ site, sites, onChange, logoBust, isAdmin, fileInputRef, onUpload, onRemove }) { const [logoErr, setLogoErr] = React.useState(false); React.useEffect(() => { setLogoErr(false); }, [site && site.id, logoBust]); return (
{site && !logoErr ? ( ) : ( {site ? site.name.slice(0, 3).toUpperCase() : '—'} )}
Zakład
{isAdmin && site && (
{!logoErr && ( )}
)}
); } function GlassDropdown({ site, sites, onChange }) { const [open, setOpen] = React.useState(false); const [q, setQ] = React.useState(''); const wrapRef = React.useRef(null); React.useEffect(() => { function onDoc(e) { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', onDoc); return () => document.removeEventListener('mousedown', onDoc); }, []); React.useEffect(() => { if (!open) setQ(''); }, [open]); const list = sites.filter(s => !q || s.name.toLowerCase().includes(q.toLowerCase())); return (
{open && (
} placeholder="Szukaj zakładu…" value={q} onChange={(e) => setQ(e.target.value)} autoFocus />
{list.length === 0 && (
Brak zakładów.
)} {list.map(s => { const active = site && site.id === s.id; const hasData = (s.measurements_count || 0) > 0; return (
{ onChange(s.id); setOpen(false); }} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 10px', borderRadius: 'var(--r-sm)', cursor: 'pointer', background: active ? 'var(--surface)' : 'transparent', border: active ? '1px solid var(--border-strong)' : '1px solid transparent', }} onMouseEnter={(e) => { if (!active) e.currentTarget.style.background = 'var(--bg-sunken)'; }} onMouseLeave={(e) => { if (!active) e.currentTarget.style.background = 'transparent'; }} > {s.name} {s.measurements_count || 0}
); })}
)}
); } function MachineList({ machines, selectedId, onSelect }) { const groups = React.useMemo(() => { const m = new Map(); for (const item of machines) { const key = item.hall || '—'; if (!m.has(key)) m.set(key, []); m.get(key).push(item); } return Array.from(m.entries()); }, [machines]); return (
{groups.map(([hall, items]) => (
{hall} · {items.length}
{items.map((m) => { const active = m.id === selectedId; const st = statusFromAlarm(m.max_alarm); return (
onSelect(m)} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', cursor: 'pointer', background: active ? 'var(--surface)' : 'transparent', borderLeft: active ? '2px solid var(--fg)' : '2px solid transparent', borderBottom: '1px solid var(--hairline)', }} onMouseEnter={(e) => { if (!active) e.currentTarget.style.background = 'var(--bg-sunken)'; }} onMouseLeave={(e) => { if (!active) e.currentTarget.style.background = 'transparent'; }} >
{m.name}
{m.sessions} {m.sessions === 1 ? 'sesja' : 'sesji'} {m.last_dtg && <> · ostatnia: {m.last_dtg}}
); })}
))}
); } function MachineDetail({ machine, siteName, sessions, loading, onOpenSession, onRefresh }) { return ( <>

{machine.name}

ID  {machine.id} {machine.hall && hala  {machine.hall}} sesji  {machine.sessions}
{loading && } {!loading && sessions && sessions.length === 0 && (
Brak sesji
Ta maszyna nie ma jeszcze wgranych pomiarów.
)} {!loading && sessions && sessions.length > 0 && (

Sesje pomiarowe

{sessions.length} sesji
Status
Data · godzina
Punkty
Urządzenie
Akcja
{sessions.map((s, i) => { const st = statusFromAlarm(s.max_alarm); const dateStr = s.session_date ? `${s.session_date.slice(0,4)}-${s.session_date.slice(4,6)}-${s.session_date.slice(6,8)}` : s.date_display; return (
onOpenSession && onOpenSession({ machine_id: machine.id, machine_name: machine.name, session_date: s.session_date })} style={{ display: 'grid', gridTemplateColumns: '110px 1fr 100px 160px 90px', padding: '12px 16px', borderBottom: i < sessions.length - 1 ? '1px solid var(--hairline)' : 'none', alignItems: 'center', fontSize: 12.5, cursor: 'pointer', }} onMouseEnter={(e) => e.currentTarget.style.background = 'var(--bg-sunken)'} onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'} >
{dateStr} {s.time_start && · {s.time_start}}
{s.point_count || 0}
{s.device_id || '—'}
); })}
)}
); } function EmptyPicker() { return (
Wybierz maszynę
Kliknij maszynę w liście po lewej żeby zobaczyć jej sesje pomiarowe.
); } Object.assign(window, { MeasurementsScreen });