Ver código fonte

RHL-022 feat(errorMapping): implement centralized error mapping for Explorer with German translations and tests

Code_Uwe 1 mês atrás
pai
commit
a0e7ce09f8

+ 75 - 0
lib/frontend/explorer/errorMapping.js

@@ -0,0 +1,75 @@
+import { ApiClientError } from "@/lib/frontend/apiClient";
+
+/**
+ * mapExplorerError
+ *
+ * Centralized error-to-UI mapping for the Explorer.
+ *
+ * Important:
+ * - All returned strings are user-facing => German.
+ * - We intentionally do NOT expose raw backend messages to the UI.
+ *
+ * @param {unknown} err
+ * @returns {null | {
+ *   kind: "unauthenticated"|"forbidden"|"notfound"|"generic",
+ *   title: string,
+ *   description: string
+ * }}
+ */
+export function mapExplorerError(err) {
+	if (!err) return null;
+
+	// Standard backend/client errors
+	if (err instanceof ApiClientError) {
+		if (err.code === "AUTH_UNAUTHENTICATED") {
+			return {
+				kind: "unauthenticated",
+				title: "Sitzung abgelaufen",
+				description:
+					"Ihre Sitzung ist abgelaufen. Sie werden zum Login weitergeleitet.",
+			};
+		}
+
+		if (err.code === "AUTH_FORBIDDEN_BRANCH") {
+			return {
+				kind: "forbidden",
+				title: "Kein Zugriff",
+				description:
+					"Sie haben keine Berechtigung, diese Niederlassung zu öffnen.",
+			};
+		}
+
+		if (err.code === "FS_NOT_FOUND") {
+			return {
+				kind: "notfound",
+				title: "Nicht gefunden",
+				description:
+					"Dieser Pfad existiert nicht (mehr). Bitte wählen Sie eine andere Ebene.",
+			};
+		}
+
+		if (err.code === "CLIENT_NETWORK_ERROR") {
+			return {
+				kind: "generic",
+				title: "Netzwerkfehler",
+				description:
+					"Bitte prüfen Sie Ihre Verbindung und versuchen Sie es erneut.",
+			};
+		}
+
+		return {
+			kind: "generic",
+			title: "Fehler",
+			description:
+				"Beim Laden ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.",
+		};
+	}
+
+	// Unknown errors
+	return {
+		kind: "generic",
+		title: "Fehler",
+		description:
+			"Beim Laden ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.",
+	};
+}

+ 38 - 0
lib/frontend/explorer/errorMapping.test.js

@@ -0,0 +1,38 @@
+/* @vitest-environment node */
+
+import { describe, it, expect } from "vitest";
+import { ApiClientError } from "@/lib/frontend/apiClient";
+import { mapExplorerError } from "./errorMapping";
+
+describe("lib/frontend/explorer/errorMapping", () => {
+	it("maps unauthenticated", () => {
+		const err = new ApiClientError({
+			status: 401,
+			code: "AUTH_UNAUTHENTICATED",
+			message: "Unauthorized",
+		});
+		expect(mapExplorerError(err)?.kind).toBe("unauthenticated");
+	});
+
+	it("maps forbidden", () => {
+		const err = new ApiClientError({
+			status: 403,
+			code: "AUTH_FORBIDDEN_BRANCH",
+			message: "Forbidden",
+		});
+		expect(mapExplorerError(err)?.kind).toBe("forbidden");
+	});
+
+	it("maps not found", () => {
+		const err = new ApiClientError({
+			status: 404,
+			code: "FS_NOT_FOUND",
+			message: "Not found",
+		});
+		expect(mapExplorerError(err)?.kind).toBe("notfound");
+	});
+
+	it("maps unknown to generic", () => {
+		expect(mapExplorerError(new Error("boom"))?.kind).toBe("generic");
+	});
+});