68 lines
2.7 KiB
TypeScript
68 lines
2.7 KiB
TypeScript
import type { ReactNode } from 'react';
|
|
import { useI18n, type Key } from '../lib/i18n';
|
|
import { usePhoto } from '../lib/usePhoto';
|
|
import type { UserReport } from '../lib/types';
|
|
import { Icon, VettingSummary } from './ui';
|
|
|
|
interface Props {
|
|
report: UserReport;
|
|
/** Queue view: the place is the heading and the claim sits below it. Place view: the claim is the heading. */
|
|
placeName?: string | undefined;
|
|
headingLevel?: 'h2' | 'h3';
|
|
/** Show the full automatic assessment (city panel) instead of the short tags. */
|
|
detailed?: boolean;
|
|
children?: ReactNode;
|
|
}
|
|
|
|
const STATUS_TAG = {
|
|
pending: 'bg-base-lighter text-ink',
|
|
accepted: 'bg-success-dark text-white',
|
|
rejected: 'bg-error-dark text-white',
|
|
} as const;
|
|
|
|
/** One layout for every user report, with or without a photo, in the place view and in the city inbox. */
|
|
export function ReportCard({ report: r, placeName, headingLevel = 'h3', detailed = false, children }: Props) {
|
|
const { t, date } = useI18n();
|
|
const photo = usePhoto(r.photoId);
|
|
const Heading = headingLevel;
|
|
const claim = (
|
|
<>
|
|
{t(`rep.attr.${r.attr}` as Key)}: <strong>{typeof r.value === 'number' ? `${r.value} ${t('unit.cm')}` : t(`rep.${r.value}` as Key)}</strong>
|
|
</>
|
|
);
|
|
const status = r.status ?? 'pending';
|
|
|
|
return (
|
|
<article className="kbb-rcard">
|
|
<div className={`kbb-rcard__media ${photo ? '' : 'is-empty'}`}>
|
|
{photo ? (
|
|
<img src={photo} alt={t('rep.photo.alt')} />
|
|
) : (
|
|
<>
|
|
<Icon name="visibility_off" size={4} />
|
|
<span>{t('vet.flag.no-photo')}</span>
|
|
</>
|
|
)}
|
|
</div>
|
|
<div className="kbb-rcard__body">
|
|
<div className="kbb-rcard__top">
|
|
<Heading className="kbb-rcard__title">{placeName ?? claim}</Heading>
|
|
<span className={`usa-tag ${STATUS_TAG[status]}`}>{t(status === 'pending' ? 'detail.reports.pending' : (`dash.queue.status.${status}` as Key))}</span>
|
|
</div>
|
|
{placeName && <p className="kbb-rcard__claim">{claim}</p>}
|
|
<p className="kbb-rcard__meta">
|
|
{date(r.createdAt.slice(0, 10))}
|
|
{r.demo && <span className="usa-tag bg-ink text-white margin-left-1">{t('detail.reports.demo')}</span>}
|
|
</p>
|
|
{r.measure && (
|
|
<p className="kbb-rcard__line">
|
|
{t(`vet.measure.${r.measure.kind}` as Key)}: <strong>{r.measure.value} {r.measure.unit === 'cm' ? 'cm' : '%'}</strong> ({t(`vet.method.${r.measure.method}` as Key)})
|
|
</p>
|
|
)}
|
|
{r.note && <p className="kbb-rcard__note">{r.note}</p>}
|
|
<VettingSummary v={r.vetting} detailed={detailed} />
|
|
{children && <div className="kbb-rcard__actions">{children}</div>}
|
|
</div>
|
|
</article>
|
|
);
|
|
}
|