- Auth: pessimistic locking on login tokens and refresh token rotation, backup code attempt counter, rate limiting verification - Schema: unique constraints on business numbers, FK relations, unsigned/signed alignment, attendance duplicate prevention - Invoices/PDFs: DOMPurify sanitization, bounded queries in stats and alerts, VAT rounding, Puppeteer error handling - Orders/Offers: transactional parent+child creation, Zod NaN refinement, status enums, uniqueness checks - Projects/Files: path traversal protection, streamed uploads, permission guards, query param validation - Attendance/HR: duplicate checks, ownership validation, GPS restrictions, trip distance validation - Frontend: modal lock reference counting, XSS escaping in print HTML, ref mutation fixes, accessibility attributes Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
import { useCallback, useRef } from "react";
|
|
import { useAlert } from "../context/AlertContext";
|
|
import apiFetch from "../utils/api";
|
|
|
|
interface ApiCallResult<T> {
|
|
data: T | null;
|
|
ok: boolean;
|
|
response: Response | null;
|
|
}
|
|
|
|
export default function useApiCall() {
|
|
const alert = useAlert();
|
|
const abortRef = useRef<AbortController | null>(null);
|
|
|
|
const call = useCallback(
|
|
async <T = unknown>(
|
|
url: string,
|
|
options: RequestInit = {},
|
|
errorMsg = "Chyba při načítání dat",
|
|
): Promise<ApiCallResult<T>> => {
|
|
if (abortRef.current) abortRef.current.abort();
|
|
const controller = new AbortController();
|
|
abortRef.current = controller;
|
|
|
|
try {
|
|
const { signal: _, ...restOptions } = options;
|
|
const response = await apiFetch(url, {
|
|
...restOptions,
|
|
signal: controller.signal,
|
|
});
|
|
const data = await response.json();
|
|
if (!response.ok || !data.success) {
|
|
alert.error(data.error || errorMsg);
|
|
return { data: null, ok: false, response };
|
|
}
|
|
return { data: data.data as T, ok: true, response };
|
|
} catch (err: unknown) {
|
|
if (err instanceof Error && err.name === "AbortError") {
|
|
return { data: null, ok: false, response: null };
|
|
}
|
|
alert.error(errorMsg);
|
|
return { data: null, ok: false, response: null };
|
|
}
|
|
},
|
|
[alert],
|
|
);
|
|
|
|
return { call };
|
|
}
|