import { forwardRef, useState } from 'react'; import { useI18n } from '../lib/i18n'; import { DEMO_PLACES } from '../lib/demo'; import type { Assessment, Place, ReportAttr, UserReport } from '../lib/types'; import { Alert, FactCard, Icon, VERDICT_STYLE, VerdictTag } from './ui'; import { ReportForm } from './ReportForm'; export type RefreshState = | { kind: 'idle' } | { kind: 'loading' } | { kind: 'ok'; at: string } | { kind: 'fail' }; interface Props { place: Place; assessment: Assessment; reports: UserReport[]; snapshotDate: string; refresh: RefreshState; onBack: () => void; onRouteTo: () => void; onShowOnMap: () => void; onRefresh: () => void; onAddReport: (r: Omit) => void; onRemoveReport: (id: string) => void; } export const PlaceDetail = forwardRef(function PlaceDetail(p, headingRef) { const { t, tm, date } = useI18n(); const [reporting, setReporting] = useState(null); const [thanks, setThanks] = useState(false); const { place, assessment } = p; const demo = DEMO_PLACES.find((d) => d.id === place.id); const address = [place.tags['addr:street'], place.tags['addr:housenumber']].filter(Boolean).join(' '); const mine = p.reports.filter((r) => r.placeId === place.id); return (

{place.name ?? t('common.noName')}

{address &&

{address}

} {demo && (
{t('detail.demo')}

{t('detail.demoNote', { state: t(`verdict.${demoState(demo.demoState)}`) })}

)}

{t(`verdict.${assessment.verdict}.long`)}

{t('detail.facts')}

    {assessment.facts.map((f) => ( { setReporting(f.key as ReportAttr); setThanks(false); }} /> ))}
{thanks && {t('rep.thanks')}} {reporting && ( setReporting(null)} onSubmit={(r) => { p.onAddReport(r); setReporting(null); setThanks(true); }} /> )}

{t('detail.reports')}

{t('detail.reports.note')}

{mine.length === 0 ? (

{t('detail.reports.none')}

) : (
    {mine.map((r) => (
  • {t(`rep.attr.${r.attr}`)}:{' '} {typeof r.value === 'number' ? `${r.value} ${t('unit.cm')}` : t(`rep.${r.value}`)} {r.demo && {t('detail.reports.demo')}} — {date(r.createdAt.slice(0, 10))} {r.note &&
    {r.note}
    } {!r.demo && ( )}
  • ))}
)}
{!place.demo && ( <> {t('detail.openOsm')} )} {place.demo &&

{t('detail.refreshDemo')}

}
{p.refresh.kind === 'ok' && {t('detail.refreshed', { time: new Date(p.refresh.at).toLocaleTimeString() })}} {p.refresh.kind === 'fail' && {t('detail.refreshFail', { date: date(p.snapshotDate) })}}
); }); const demoState = (s: string) => (s === 'verified' ? 'match' : s === 'conflict' ? 'conflict' : 'incomplete'); function osmPath(id: string) { const kind = id[0] === 'n' ? 'node' : id[0] === 'w' ? 'way' : 'relation'; return `${kind}/${id.slice(1)}`; }