40 lines
2.6 KiB
TypeScript
40 lines
2.6 KiB
TypeScript
"use client"
|
|
|
|
import { Alert, AlertDescription, AlertTitle } from "@/components/reui/alert"
|
|
import { Button } from "@/components/ui/button"
|
|
import { DASHBOARD_SOURCES, type DashboardSource, type DashboardSources } from "@/lib/dashboard-source-state"
|
|
|
|
export function DashboardDataStatus({ sources, refreshing, onRefresh }: {
|
|
sources: DashboardSources
|
|
refreshing: boolean
|
|
onRefresh: () => void
|
|
}) {
|
|
const failed = Object.values(sources).filter(source => source.error)
|
|
const summary = failed.length ? `Не обновлены источники: ${failed.length}` : "Состояние источников"
|
|
return <div className="flex flex-col gap-2">
|
|
{failed.length > 0 && <Alert variant="destructive">
|
|
<AlertTitle>{summary}</AlertTitle>
|
|
<AlertDescription>Последние полученные данные сохранены. Если источник ещё не загрузился, его показатели неизвестны.</AlertDescription>
|
|
</Alert>}
|
|
<div className="flex flex-wrap items-start justify-between gap-2">
|
|
<details className="min-w-0 text-sm" open={failed.length > 0 || undefined}>
|
|
<summary className="cursor-pointer">Источники и время получения</summary>
|
|
<ul className="mt-2 flex flex-col gap-1 text-xs">
|
|
{(Object.keys(DASHBOARD_SOURCES) as DashboardSource[]).map(key => {
|
|
const source = sources[key]
|
|
return <li key={key} data-source={key} className={`break-words ${source?.error ? "text-destructive" : "text-muted-foreground"}`}>
|
|
{DASHBOARD_SOURCES[key]}: {source?.error ? `ошибка обновления — ${source.error}. ` : ""}
|
|
{source?.receivedAt != null ? <>Получено <time dateTime={new Date(source.receivedAt).toISOString()}>{new Date(source.receivedAt).toLocaleString("ru-RU")}</time>{source.error ? " · данные могут быть устаревшими" : ""}</> : "Успешных загрузок ещё нет"}
|
|
{source?.sampledAt && Number.isFinite(Date.parse(source.sampledAt)) && <> · замер <time dateTime={source.sampledAt}>{new Date(source.sampledAt).toLocaleString("ru-RU")}</time></>}
|
|
</li>
|
|
})}
|
|
</ul>
|
|
</details>
|
|
<div className="flex items-center gap-2">
|
|
<span role="status" className="text-xs text-muted-foreground">{refreshing ? "Обновление данных…" : "Обновление завершено"}</span>
|
|
<Button type="button" size="sm" variant="outline" onClick={onRefresh} disabled={refreshing}>Обновить данные</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|