diff --git a/web/src/authorities/authorities-page.tsx b/web/src/authorities/authorities-page.tsx index d9b5d05..06d03f2 100644 --- a/web/src/authorities/authorities-page.tsx +++ b/web/src/authorities/authorities-page.tsx @@ -1,37 +1,32 @@ import { useState, type FormEvent } from "react"; -import { NavLink, useParams } from "react-router-dom"; +import { NavLink, Navigate, useParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; import type { components } from "../api/schema"; import { useAuthorities, useCreateAuthority } from "../api/queries"; import { LabelEditor } from "../components/label-editor"; import { Button } from "@/components/ui/button"; +import { labelText } from "../lib/labels"; type LabelInput = components["schemas"]["LabelInput"]; -type LabelView = components["schemas"]["LabelView"]; const KINDS = ["person", "organisation", "place"] as const; -function labelText(labels: LabelView[], lang: string): string { - return ( - labels.find((l) => l.lang === lang)?.label ?? - labels.find((l) => l.lang === "en")?.label ?? - labels[0]?.label ?? - "" - ); -} - export function AuthoritiesPage() { const { t, i18n } = useTranslation(); - const { kind = "person" } = useParams(); + const { kind } = useParams(); const lang = i18n.language.startsWith("sv") ? "sv" : "en"; - const { data: authorities } = useAuthorities(kind); + const isValidKind = (KINDS as readonly string[]).includes(kind ?? ""); + + const { data: authorities } = useAuthorities(isValidKind ? (kind as string) : "person"); const create = useCreateAuthority(); const [labels, setLabels] = useState([]); const [error, setError] = useState(false); + if (!isValidKind) return ; + const onCreate = (event: FormEvent) => { event.preventDefault(); @@ -42,7 +37,7 @@ export function AuthoritiesPage() { setError(false); create.mutate( - { kind, external_uri: null, labels }, + { kind: kind as string, external_uri: null, labels }, { onSuccess: () => setLabels([]) }, ); }; diff --git a/web/src/authorities/authorities.test.tsx b/web/src/authorities/authorities.test.tsx index d9b45d0..58e49c3 100644 --- a/web/src/authorities/authorities.test.tsx +++ b/web/src/authorities/authorities.test.tsx @@ -35,3 +35,23 @@ test("kind tabs link to the other kinds", async () => { renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByRole("link", { name: /place/i })).toHaveAttribute("href", "/authorities/place"); }); + +test("create without EN label shows required alert and does not POST", async () => { + let posted = false; + server.use( + http.post("/api/admin/authorities", () => { + posted = true; + return HttpResponse.json({ id: "a-x" }, { status: 201 }); + }), + ); + renderApp(tree(), { route: "/authorities/person" }); + expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument(); + await userEvent.click(screen.getByRole("button", { name: /create/i })); + expect(screen.getByRole("alert")).toBeInTheDocument(); + expect(posted).toBe(false); +}); + +test("unknown kind redirects to person list", async () => { + renderApp(tree(), { route: "/authorities/banana" }); + expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument(); +}); diff --git a/web/src/lib/labels.ts b/web/src/lib/labels.ts new file mode 100644 index 0000000..6485cd5 --- /dev/null +++ b/web/src/lib/labels.ts @@ -0,0 +1,12 @@ +import type { components } from "../api/schema"; + +type LabelView = components["schemas"]["LabelView"]; + +export function labelText(labels: LabelView[], lang: string): string { + return ( + labels.find((l) => l.lang === lang)?.label ?? + labels.find((l) => l.lang === "en")?.label ?? + labels[0]?.label ?? + "" + ); +} diff --git a/web/src/vocab/vocabulary-terms.tsx b/web/src/vocab/vocabulary-terms.tsx index 7c9d95b..f6cb86f 100644 --- a/web/src/vocab/vocabulary-terms.tsx +++ b/web/src/vocab/vocabulary-terms.tsx @@ -8,18 +8,9 @@ import { LabelEditor } from "../components/label-editor"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { labelText } from "../lib/labels"; type LabelInput = components["schemas"]["LabelInput"]; -type LabelView = components["schemas"]["LabelView"]; - -function labelText(labels: LabelView[], lang: string): string { - return ( - labels.find((l) => l.lang === lang)?.label ?? - labels.find((l) => l.lang === "en")?.label ?? - labels[0]?.label ?? - "" - ); -} export function VocabularyTerms() { const { t, i18n } = useTranslation();