cde7be9f2a
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
|
|
import type { components } from "../api/schema";
|
|
import { useTerms, useAuthorities } from "../api/queries";
|
|
import { labelText } from "../lib/labels";
|
|
import { formatDate } from "../lib/format-date";
|
|
|
|
type FieldDefinitionView = components["schemas"]["FieldDefinitionView"];
|
|
|
|
/** Renders one flexible field value as human-readable text, resolving term/authority ids
|
|
* to labels and localized_text to the active language. */
|
|
export function FlexibleFieldValue({
|
|
def,
|
|
value,
|
|
lang,
|
|
}: {
|
|
def: FieldDefinitionView;
|
|
value: unknown;
|
|
lang: string;
|
|
}) {
|
|
switch (def.data_type) {
|
|
case "term":
|
|
return <TermValue vocabularyId={def.vocabulary_id ?? null} value={value} lang={lang} />;
|
|
case "authority":
|
|
return <AuthorityValue kind={def.authority_kind ?? null} value={value} lang={lang} />;
|
|
case "localized_text":
|
|
return <>{pickLocalized(value, lang)}</>;
|
|
case "date":
|
|
return <>{formatDate(value, lang)}</>;
|
|
case "boolean":
|
|
return <BooleanValue value={value} />;
|
|
default:
|
|
return <>{value == null ? "—" : String(value)}</>;
|
|
}
|
|
}
|
|
|
|
function TermValue({
|
|
vocabularyId,
|
|
value,
|
|
lang,
|
|
}: {
|
|
vocabularyId: string | null;
|
|
value: unknown;
|
|
lang: string;
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const { data: terms, isLoading } = useTerms(vocabularyId ?? undefined);
|
|
|
|
if (typeof value !== "string") return <>—</>;
|
|
const term = terms?.find((x) => x.id === value);
|
|
if (term) return <>{labelText(term.labels, lang)}</>;
|
|
if (isLoading) return <span className="text-muted-foreground">…</span>;
|
|
return (
|
|
<span className="text-muted-foreground">
|
|
{value} {t("objects.unknownRef")}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function AuthorityValue({
|
|
kind,
|
|
value,
|
|
lang,
|
|
}: {
|
|
kind: string | null;
|
|
value: unknown;
|
|
lang: string;
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const { data: authorities, isLoading } = useAuthorities(kind ?? undefined);
|
|
|
|
if (typeof value !== "string") return <>—</>;
|
|
const authority = authorities?.find((x) => x.id === value);
|
|
if (authority) return <>{labelText(authority.labels, lang)}</>;
|
|
if (isLoading) return <span className="text-muted-foreground">…</span>;
|
|
return (
|
|
<span className="text-muted-foreground">
|
|
{value} {t("objects.unknownRef")}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function BooleanValue({ value }: { value: unknown }) {
|
|
const { t } = useTranslation();
|
|
return <>{value ? t("common.yes") : t("common.no")}</>;
|
|
}
|
|
|
|
function pickLocalized(value: unknown, lang: string): string {
|
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
const map = value as Record<string, string>;
|
|
return map[lang] ?? map.en ?? Object.values(map)[0] ?? "—";
|
|
}
|
|
return value == null ? "—" : String(value);
|
|
}
|