fix(frontend): parse department api validation errors
This commit is contained in:
parent
5adbf27097
commit
858448512e
29
frontend/src/components/departments/api-error.js
Normal file
29
frontend/src/components/departments/api-error.js
Normal file
@ -0,0 +1,29 @@
|
||||
export function extractDepartmentApiErrorMessage(error, fallback) {
|
||||
const raw = String(error?.message || fallback || "").trim();
|
||||
const prefix = "API Error:";
|
||||
if (!raw.startsWith(prefix)) return raw || fallback;
|
||||
|
||||
const payload = raw.slice(prefix.length).trim();
|
||||
const jsonStart = payload.indexOf("{");
|
||||
if (jsonStart >= 0) {
|
||||
try {
|
||||
const parsed = JSON.parse(payload.slice(jsonStart));
|
||||
const detail = parsed.detail;
|
||||
if (typeof detail === "string" && detail.trim()) return detail;
|
||||
const firstEntry = Object.entries(parsed)[0];
|
||||
if (firstEntry) {
|
||||
const value = firstEntry[1];
|
||||
if (Array.isArray(value) && value[0]) return String(value[0]);
|
||||
if (typeof value === "string" && value.trim()) return value;
|
||||
}
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
const plainMessage = payload.replace(/^\d+\s+/, "").trim();
|
||||
if (/^\d+$/.test(plainMessage || payload)) {
|
||||
return fallback;
|
||||
}
|
||||
return plainMessage || fallback;
|
||||
}
|
||||
35
frontend/src/components/departments/api-error.test.js
Normal file
35
frontend/src/components/departments/api-error.test.js
Normal file
@ -0,0 +1,35 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { extractDepartmentApiErrorMessage } from "./api-error.js";
|
||||
|
||||
test("extracts plain API error text after status code", () => {
|
||||
const error = new Error(
|
||||
"API Error: 400 Employee already belongs to another active department: Бухгалтерия.",
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
extractDepartmentApiErrorMessage(error, "fallback"),
|
||||
"Employee already belongs to another active department: Бухгалтерия.",
|
||||
);
|
||||
});
|
||||
|
||||
test("extracts first field error from JSON payload", () => {
|
||||
const error = new Error(
|
||||
'API Error: 400 {"employee_id":["Employee already belongs to another active department: Бухгалтерия."]}',
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
extractDepartmentApiErrorMessage(error, "fallback"),
|
||||
"Employee already belongs to another active department: Бухгалтерия.",
|
||||
);
|
||||
});
|
||||
|
||||
test("falls back for unparsable payload", () => {
|
||||
const error = new Error("API Error: 500");
|
||||
|
||||
assert.equal(
|
||||
extractDepartmentApiErrorMessage(error, "fallback"),
|
||||
"fallback",
|
||||
);
|
||||
});
|
||||
@ -3,6 +3,7 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { extractDepartmentApiErrorMessage } from "@/components/departments/api-error";
|
||||
import { getDepartmentMemberModalError } from "@/components/departments/member-modal-state";
|
||||
import { useUser } from "@/contexts/UserContext";
|
||||
import { apiClient } from "@/lib/api";
|
||||
@ -96,31 +97,7 @@ const EMPTY_USER_PERMS: DepartmentUserPermissions = {
|
||||
can_assign_roles: false,
|
||||
};
|
||||
|
||||
function getErrorMessage(error: unknown, fallback: string) {
|
||||
const raw = String((error as Error)?.message || fallback).trim();
|
||||
const prefix = "API Error:";
|
||||
if (!raw.startsWith(prefix)) return raw || fallback;
|
||||
|
||||
const payload = raw.slice(prefix.length).trim();
|
||||
const jsonStart = payload.indexOf("{");
|
||||
if (jsonStart >= 0) {
|
||||
try {
|
||||
const parsed = JSON.parse(payload.slice(jsonStart)) as Record<string, unknown>;
|
||||
const detail = parsed.detail;
|
||||
if (typeof detail === "string" && detail.trim()) return detail;
|
||||
const firstEntry = Object.entries(parsed)[0];
|
||||
if (firstEntry) {
|
||||
const value = firstEntry[1];
|
||||
if (Array.isArray(value) && value[0]) return String(value[0]);
|
||||
if (typeof value === "string" && value.trim()) return value;
|
||||
}
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
const getErrorMessage = extractDepartmentApiErrorMessage;
|
||||
|
||||
function sortEmployeesByName(items: User[]) {
|
||||
return [...items].sort((a, b) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user