Files
KIS-TOiR/client/src/dataProvider.ts
MaKarin 05946a51b5 push
2026-04-04 20:37:56 +03:00

195 lines
6.0 KiB
TypeScript

import type { DataProvider } from "react-admin";
import { env } from "./config/env";
import { getAccessToken } from "./auth/keycloak";
async function fetchJson(
url: string,
options: RequestInit = {},
): Promise<{ json: any; headers: Headers; status: number }> {
const headers = new Headers(
options.headers ?? { Accept: "application/json" },
);
const token = await getAccessToken();
if (token) {
headers.set('Authorization', `Bearer ${token}`);
}
if (!headers.has("Content-Type") && options.body) {
headers.set("Content-Type", "application/json");
}
const response = await fetch(url, { ...options, headers });
if (!response.ok) {
const error = new Error(
"Request failed with status " + response.status,
) as Error & { status?: number; body?: unknown };
error.status = response.status;
try {
error.body = await response.json();
} catch {
error.body = null;
}
throw error;
}
if (response.status === 204) {
return { json: null, headers: response.headers, status: response.status };
}
const json = await response.json();
return { json, headers: response.headers, status: response.status };
}
function appendSearchParam(
searchParams: URLSearchParams,
key: string,
value: unknown,
): void {
if (Array.isArray(value)) {
value.forEach((entry) => appendSearchParam(searchParams, key, entry));
return;
}
if (value === undefined || value === null || value === "") {
return;
}
searchParams.append(key, String(value));
}
function parseListBody(json: unknown): { rows: unknown[]; totalHint?: number } {
if (Array.isArray(json)) {
return { rows: json };
}
if (
json !== null &&
typeof json === "object" &&
"data" in json &&
Array.isArray((json as { data: unknown }).data)
) {
const body = json as { data: unknown[]; total?: unknown };
const totalHint =
typeof body.total === "number" && Number.isFinite(body.total)
? body.total
: undefined;
return { rows: body.data, totalHint };
}
return { rows: [] };
}
function buildListUrl(resource: string, params: any): string {
const resourcePath = resource === "equipment" ? "equipments" : resource;
const searchParams = new URLSearchParams();
searchParams.set(
"_start",
String((params.pagination.page - 1) * params.pagination.perPage),
);
searchParams.set(
"_end",
String(params.pagination.page * params.pagination.perPage),
);
searchParams.set("_sort", params.sort.field);
searchParams.set("_order", params.sort.order);
Object.entries(params.filter ?? {}).forEach(([key, value]) => {
appendSearchParam(searchParams, key, value);
});
const queryString = searchParams.toString();
return (
env.apiUrl + "/" + resourcePath + (queryString ? "?" + queryString : "")
);
}
export const dataProvider: DataProvider = {
getList: async (resource, params) => {
if (resource === "price-list") {
const { json } = await fetchJson(env.apiUrl + "/price-list");
return { data: [json], total: 1 };
}
const { json, headers } = await fetchJson(buildListUrl(resource, params));
const { rows, totalHint } = parseListBody(json);
const contentRange = headers.get("Content-Range");
const total = contentRange
? Number(
contentRange.split("/").pop() ??
totalHint ??
rows.length,
)
: (totalHint ?? rows.length);
return { data: rows as any[], total };
},
getOne: async (resource, params) => {
const resourcePath = resource === "equipment" ? "equipments" : resource;
const url =
resource === "price-list"
? env.apiUrl + "/price-list"
: env.apiUrl + "/" + resourcePath + "/" + params.id;
const { json } = await fetchJson(url);
return { data: json };
},
getMany: async (resource, params) => {
if (resource === "price-list") {
const { json } = await fetchJson(env.apiUrl + "/price-list");
return { data: params.ids.includes("price-list") ? [json] : [] };
}
const records = await Promise.all(
params.ids.map((id) =>
dataProvider.getOne(resource, { id, meta: params.meta } as any),
),
);
return { data: records.map((result) => result.data) };
},
getManyReference: async (resource, params) =>
dataProvider.getList(resource, {
pagination: params.pagination,
sort: params.sort,
filter: { ...(params.filter ?? {}), [params.target]: params.id },
meta: params.meta,
} as any),
create: async (resource, params) => {
const resourcePath = resource === "equipment" ? "equipments" : resource;
const { json } = await fetchJson(env.apiUrl + "/" + resourcePath, {
method: "POST",
body: JSON.stringify(params.data),
});
return { data: json };
},
update: async (resource, params) => {
const resourcePath = resource === "equipment" ? "equipments" : resource;
const { json } = await fetchJson(
env.apiUrl + "/" + resourcePath + "/" + params.id,
{ method: "PATCH", body: JSON.stringify(params.data) },
);
return { data: json };
},
updateMany: async (resource, params) => {
const results = await Promise.all(
params.ids.map((id) =>
dataProvider.update(resource, {
id,
data: params.data,
previousData: {},
meta: params.meta,
} as any),
),
);
return { data: results.map((result) => result.data.id) };
},
delete: async (resource, params) => {
const resourcePath = resource === "equipment" ? "equipments" : resource;
const { json } = await fetchJson(
env.apiUrl + "/" + resourcePath + "/" + params.id,
{ method: "DELETE" },
);
return { data: json ?? { id: params.id } };
},
deleteMany: async (resource, params) => {
const results = await Promise.all(
params.ids.map((id) =>
dataProvider.delete(resource, {
id,
previousData: {},
meta: params.meta,
} as any),
),
);
return { data: results.map((result) => result.data.id) };
},
};