GdzieWjade/src/components/AboutView.tsx
2026-10-03 13:33:50 +02:00

78 lines
4 KiB
TypeScript

import { useState, type ReactNode } from 'react';
import { useI18n } from '../lib/i18n';
import type { Confidence } from '../lib/types';
import { Alert, ConfidenceTag } from './ui';
function AccordionSection({ id, title, children, open, toggle }: { id: string; title: string; children: ReactNode; open: string; toggle: (id: string) => void }) {
return (
<>
<h3 className="usa-accordion__heading">
<button type="button" className="usa-accordion__button" aria-expanded={open === id} aria-controls={`acc-${id}`} onClick={() => toggle(id)}>
{title}
</button>
</h3>
<div id={`acc-${id}`} className="usa-accordion__content usa-prose" hidden={open !== id}>{children}</div>
</>
);
}
const CONFS: Confidence[] = ['verified', 'mapped', 'stale', 'inferred', 'user', 'none'];
interface Props {
snapshotDate: string;
counts: Record<string, number>;
simulateOutage: boolean;
onSimulate: (v: boolean) => void;
onReset: () => void;
resetDone: boolean;
}
export function AboutView({ snapshotDate, counts, simulateOutage, onSimulate, onReset, resetDone }: Props) {
const { t, date } = useI18n();
const [open, setOpen] = useState<string>('data');
const toggle = (id: string) => setOpen((cur) => (cur === id ? '' : id));
return (
<div className="grid-container padding-y-4 kbb-narrow">
<h1 className="margin-top-0">{t('about.title')}</h1>
<p className="usa-intro">{t('about.intro')}</p>
<p className="font-sans-xs text-base-dark">
{t('banner.data', { date: date(snapshotDate) })} {Object.entries(counts).map(([k, v]) => `${k}: ${v}`).join(' · ')}
</p>
<div className="usa-accordion usa-accordion--bordered margin-top-3">
<AccordionSection open={open} toggle={toggle} id="data" title={t('about.data')}>
<p>{t('about.data.body1')}</p>
<p>{t('about.data.body2')}</p>
<p>{t('about.data.body3')}</p>
<h4>{t('about.legend')}</h4>
<ul className="usa-list--unstyled">
{CONFS.map((c) => (
<li key={c} className="margin-bottom-1">
<ConfidenceTag confidence={c} /> <span>{t(`conf.${c}.help`)}</span>
</li>
))}
</ul>
</AccordionSection>
<AccordionSection open={open} toggle={toggle} id="missing" title={t('about.missing')}><p>{t('about.missing.body')}</p></AccordionSection>
<AccordionSection open={open} toggle={toggle} id="arch" title={t('about.arch')}><p>{t('about.arch.body')}</p></AccordionSection>
<AccordionSection open={open} toggle={toggle} id="refresh" title={t('about.refresh')}><p>{t('about.refresh.body')}</p></AccordionSection>
<AccordionSection open={open} toggle={toggle} id="privacy" title={t('about.privacy')}><p>{t('about.privacy.body')}</p></AccordionSection>
<AccordionSection open={open} toggle={toggle} id="a11y" title={t('about.a11y')}><p>{t('about.a11y.body')}</p></AccordionSection>
<AccordionSection open={open} toggle={toggle} id="biz" title={t('about.biz')}><p>{t('about.biz.body')}</p></AccordionSection>
<AccordionSection open={open} toggle={toggle} id="limits" title={t('about.limits')}><p>{t('about.limits.body')}</p></AccordionSection>
</div>
<h2 className="margin-top-4">{t('about.demo')}</h2>
<div className="usa-checkbox">
<input className="usa-checkbox__input" id="simulate" type="checkbox" checked={simulateOutage} onChange={(e) => onSimulate(e.target.checked)} aria-describedby="simulate-help" />
<label className="usa-checkbox__label" htmlFor="simulate">{t('about.simulate')}</label>
</div>
<p id="simulate-help" className="usa-hint">{t('about.simulate.help')}</p>
<button type="button" className="usa-button usa-button--secondary margin-top-2" onClick={onReset}>{t('about.reset')}</button>
<div aria-live="polite" className="margin-top-1">{resetDone && <Alert kind="success" slim>{t('about.resetDone')}</Alert>}</div>
<p className="font-sans-xs text-base-dark margin-top-4">{t('about.attr')}</p>
</div>
);
}