Files
biggus-dickus/web/src/objects/flexible-field-value.tsx
T
2026-06-07 14:15:54 +02:00

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);
}