Files
Investidor-V2/resources/js/lib/simulation-api.ts
T

78 lines
2.7 KiB
TypeScript

import { isApiErrorV1 } from './simulation-contract.ts';
export type SimulationApiChoice = { id: string; label: string };
function scalar(value: unknown): string {
return typeof value === 'string' ||
(typeof value === 'number' && Number.isFinite(value))
? String(value)
: '';
}
/** Parse API bodies without leaking JSON parser errors into the public form. */
export async function readSimulationApiJson(
response: Response,
): Promise<unknown> {
try {
return await response.json();
} catch {
return null;
}
}
/** Prefer field validation details, falling back to the shared API message. */
export function simulationApiErrorMessage(value: unknown): string | undefined {
if (!isApiErrorV1(value)) return undefined;
const validationMessages = Object.values(value.errors ?? {}).flat();
return validationMessages.length
? validationMessages.join(' ')
: value.message;
}
/** Keep snapshot field errors attached to their original form fields. */
export function simulationApiFieldErrors(
value: unknown,
): Record<string, string> {
if (!isApiErrorV1(value)) return {};
const fields: Record<string, string> = {};
for (const [path, messages] of Object.entries(value.errors ?? {})) {
const key = path
.replace(/^(economic_snapshot|personal_snapshot)\./, '')
.split('.')[0];
if (/^[a-z][a-z0-9_]*$/.test(key) && messages.length)
fields[key] = messages.join(' ');
}
return fields;
}
/** Explain a failed status check without implying the accepted job was lost. */
export function simulationPollingFailureMessage(value: unknown): string {
return (
simulationApiErrorMessage(value) ??
'O cenário foi recebido, mas não foi possível confirmar o estado do cálculo. Consulte o histórico antes de tentar novamente.'
);
}
/** Validate and normalize the public reference catalog envelope. */
export function simulationCatalogChoices(
value: unknown,
): SimulationApiChoice[] {
if (
!value ||
typeof value !== 'object' ||
Array.isArray(value) ||
!Array.isArray((value as Record<string, unknown>).data)
)
throw new Error('O servidor devolveu opções com formato inválido.');
return (value as { data: unknown[] }).data.flatMap((row) => {
if (!row || typeof row !== 'object' || Array.isArray(row)) return [];
const record = row as Record<string, unknown>;
const choice = {
id: scalar(record.id ?? record.value),
label: scalar(record.label ?? record.name),
};
return choice.id && choice.label ? [choice] : [];
});
}