76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
|
import { useSiteSelection } from '../context/SiteSelectionContext'
|
|
import { getJson } from '../api/postgrest'
|
|
import type { SiteStatusRow } from '../types/ems'
|
|
|
|
const POLL_MS = 30_000
|
|
|
|
export function useSiteStatus() {
|
|
const { selectedSiteId, ready: selectionReady, error: selectionError } = useSiteSelection()
|
|
const [row, setRow] = useState<SiteStatusRow | null>(null)
|
|
const [statusReady, setStatusReady] = useState(false)
|
|
const [fetchError, setFetchError] = useState<string | null>(null)
|
|
const selectedSiteIdRef = useRef(selectedSiteId)
|
|
selectedSiteIdRef.current = selectedSiteId
|
|
|
|
const load = useCallback(async () => {
|
|
if (!selectionReady) {
|
|
return
|
|
}
|
|
if (selectedSiteId == null) {
|
|
setRow(null)
|
|
setFetchError(null)
|
|
setStatusReady(true)
|
|
return
|
|
}
|
|
const sid = selectedSiteId
|
|
try {
|
|
const rows = await getJson<SiteStatusRow[]>('/vw_site_status', {
|
|
site_id: `eq.${sid}`,
|
|
})
|
|
if (selectedSiteIdRef.current !== sid) return
|
|
setRow(Array.isArray(rows) && rows.length > 0 ? rows[0]! : null)
|
|
setFetchError(null)
|
|
} catch {
|
|
if (selectedSiteIdRef.current !== sid) return
|
|
setRow(null)
|
|
setFetchError('Stav lokality se nepodařilo načíst')
|
|
} finally {
|
|
if (selectedSiteIdRef.current === sid) {
|
|
setStatusReady(true)
|
|
}
|
|
}
|
|
}, [selectionReady, selectedSiteId])
|
|
|
|
useEffect(() => {
|
|
if (!selectionReady) return
|
|
setStatusReady(false)
|
|
}, [selectionReady, selectedSiteId])
|
|
|
|
useEffect(() => {
|
|
void load()
|
|
const id = window.setInterval(() => void load(), POLL_MS)
|
|
return () => window.clearInterval(id)
|
|
}, [load])
|
|
|
|
const ready = selectionReady && statusReady
|
|
const error = selectionError ?? fetchError
|
|
|
|
const hasTelemetry =
|
|
row != null &&
|
|
(row.pv_power_w != null ||
|
|
row.battery_power_w != null ||
|
|
row.grid_power_w != null ||
|
|
row.battery_soc_percent != null)
|
|
|
|
return {
|
|
site: row,
|
|
ready,
|
|
error,
|
|
/** Máme řádek lokality a alespoň jednu telemetrickou hodnotu (jinak skeleton). */
|
|
hasLiveData: row != null && hasTelemetry,
|
|
reload: load,
|
|
}
|
|
}
|