195 lines
6.0 KiB
TypeScript
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) };
|
|
},
|
|
};
|