147 lines
4.0 KiB
TypeScript
147 lines
4.0 KiB
TypeScript
export type TCreateResourcePayload = Record<string, unknown>;
|
|
|
|
/**
|
|
* Transforms create payload to convert string numbers to actual numbers
|
|
* for fields that should be numeric (e.g., rate, limit, etc.)
|
|
*/
|
|
function transformCreatePayload(
|
|
payload: TCreateResourcePayload
|
|
): TCreateResourcePayload {
|
|
const transformed: TCreateResourcePayload = { ...payload };
|
|
|
|
for (const [key, value] of Object.entries(transformed)) {
|
|
// Convert string numbers to actual numbers for common numeric fields
|
|
if (typeof value === "string" && value.trim() !== "") {
|
|
const numericValue = Number(value);
|
|
// Only convert if it's a valid number and the key suggests it should be numeric
|
|
if (
|
|
!Number.isNaN(numericValue) &&
|
|
(key.toLowerCase().includes("rate") ||
|
|
key.toLowerCase().includes("price") ||
|
|
key.toLowerCase().includes("amount") ||
|
|
key.toLowerCase().includes("limit") ||
|
|
key.toLowerCase().includes("count"))
|
|
) {
|
|
transformed[key] = numericValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return transformed;
|
|
}
|
|
|
|
export async function createResourceApi(
|
|
endpointBase: string,
|
|
payload: TCreateResourcePayload,
|
|
resourceName: string
|
|
) {
|
|
// Transform the payload to convert string numbers to actual numbers
|
|
const transformedPayload = transformCreatePayload(payload);
|
|
|
|
const response = await fetch(`${endpointBase}/create`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(transformedPayload),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response
|
|
.json()
|
|
.catch(() => ({ message: `Failed to create ${resourceName}` }));
|
|
throw new Error(errorData?.message || `Failed to create ${resourceName}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
export async function deleteResourceApi(
|
|
endpointBase: string,
|
|
id: number | string,
|
|
resourceName: string
|
|
) {
|
|
const response = await fetch(`${endpointBase}/${id}`, {
|
|
method: "DELETE",
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response
|
|
.json()
|
|
.catch(() => ({ message: `Failed to delete ${resourceName}` }));
|
|
throw new Error(errorData?.message || `Failed to delete ${resourceName}`);
|
|
}
|
|
|
|
try {
|
|
return await response.json();
|
|
} catch {
|
|
return { success: true };
|
|
}
|
|
}
|
|
|
|
export type TUpdateResourcePayload = Record<string, unknown>;
|
|
|
|
/**
|
|
* Converts a key to PascalCase (e.g., "enabled" -> "Enabled", "first_name" -> "FirstName")
|
|
*/
|
|
function toPascalCase(key: string): string {
|
|
return key
|
|
.split("_")
|
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
.join("");
|
|
}
|
|
|
|
/**
|
|
* Transforms frontend data to backend format
|
|
* - data object uses lowercase keys (matching API response)
|
|
* - fields array uses PascalCase (required by backend)
|
|
*/
|
|
function transformResourceUpdateData(updates: Record<string, unknown>): {
|
|
data: Record<string, unknown>;
|
|
fields: string[];
|
|
} {
|
|
const data: Record<string, unknown> = {};
|
|
const fields: string[] = [];
|
|
|
|
for (const [key, value] of Object.entries(updates)) {
|
|
// Skip undefined/null values
|
|
if (value === undefined || value === null) {
|
|
continue;
|
|
}
|
|
|
|
// Use the key as-is for data (matching API response casing)
|
|
data[key] = value;
|
|
// Convert to PascalCase for fields array (required by backend)
|
|
fields.push(toPascalCase(key));
|
|
}
|
|
|
|
return { data, fields };
|
|
}
|
|
|
|
export async function updateResourceApi(
|
|
endpointBase: string,
|
|
id: number | string,
|
|
payload: TUpdateResourcePayload,
|
|
resourceName: string
|
|
) {
|
|
// Transform the payload to match backend format
|
|
const transformedPayload = transformResourceUpdateData(payload);
|
|
|
|
const response = await fetch(`${endpointBase}/${id}`, {
|
|
method: "PUT",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(transformedPayload),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response
|
|
.json()
|
|
.catch(() => ({ message: `Failed to update ${resourceName}` }));
|
|
throw new Error(errorData?.message || `Failed to update ${resourceName}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|