Files
frontend/src/entities/bank-card/api/queries.ts
T
ksv741 f9f0f6921e
Frontend verify / commits (pull_request) Failing after 1m19s
Frontend verify / security (pull_request) Skipped
Frontend verify / verify (pull_request) Skipped
refactor: clarify frontend module ownership
2026-09-29 07:07:36 +03:00

169 lines
4.2 KiB
TypeScript

import {
apiClient,
apiQueryClient,
useAuthenticatedQuery,
} from "@/shared/api";
import type { BankOperation, BankOperations, BankSummary } from "./types";
import { moneyCents } from "../model/money";
const OPERATIONS_PAGE_SIZE = 100;
function sortBankSummary(data: BankSummary): BankSummary {
return {
...data,
categories: data.categories.toSorted((a, b) => {
const left = moneyCents(a.net.value);
const right = moneyCents(b.net.value);
if (left === null || right === null)
throw new Error("Invalid bank summary amount");
if (left > right) return -1;
return left < right ? 1 : 0;
}),
};
}
function useBankCard(id?: string) {
return useAuthenticatedQuery({
...apiQueryClient.queryOptions("get", "/api/v1/bank-cards/{id}", {
params: { path: { id: id ?? "" } },
}),
enabled: Boolean(id),
});
}
function useBankCards(isIncludeArchived = false) {
return useAuthenticatedQuery(
apiQueryClient.queryOptions("get", "/api/v1/bank-cards", {
params: {
query: { includeArchived: isIncludeArchived ? "true" : "false" },
},
}),
);
}
function useBankCategories() {
return useAuthenticatedQuery(
apiQueryClient.queryOptions("get", "/api/v1/bank-cards/categories"),
);
}
function useBankExpenses(
id: string | undefined,
query: { limit?: number; page: number },
) {
return useAuthenticatedQuery({
...apiQueryClient.queryOptions("get", "/api/v1/bank-cards/{id}/expenses", {
params: { path: { id: id ?? "" }, query },
}),
enabled: Boolean(id),
});
}
function useBankOperation(id?: string) {
return useAuthenticatedQuery({
...apiQueryClient.queryOptions(
"get",
"/api/v1/bank-cards/operations/{id}",
{ params: { path: { id: id ?? "" } } },
),
enabled: Boolean(id),
});
}
function useBankOperations(
id: string | undefined,
query: {
from?: string;
limit?: "all" | number;
page: number;
to?: string;
},
) {
const isAll = query.limit === "all";
const parameters = {
path: { id: id ?? "" },
query: {
...query,
limit: query.limit === "all" ? OPERATIONS_PAGE_SIZE : query.limit,
page: isAll ? 1 : query.page,
},
};
const options = apiQueryClient.queryOptions(
"get",
"/api/v1/bank-cards/{id}/operations",
{ params: parameters },
);
// eslint-disable-next-line @tanstack/query/exhaustive-deps -- Generated options.queryKey already contains params; retain the shared cache identity.
return useAuthenticatedQuery({
enabled: Boolean(id && query.from && query.to),
placeholderData: (
previousData: BankOperations | undefined,
previousQuery,
) => {
const previous = previousQuery?.queryKey[2]?.params;
return !isAll
&& previousQuery?.queryKey.length === options.queryKey.length
&& previous?.path.id === id
&& previous?.query?.from === query.from
&& previous?.query?.to === query.to
&& previous?.query?.limit === query.limit
? previousData
: undefined;
},
queryFn: async ({ signal }) => {
const items: BankOperation[] = [];
for (let page = parameters.query.page; ; page++) {
const { data, error } = await apiClient.GET(
"/api/v1/bank-cards/{id}/operations",
{
params: { ...parameters, query: { ...parameters.query, page } },
signal,
},
);
// eslint-disable-next-line @typescript-eslint/only-throw-error -- Preserve generated ProblemDetails for apiErrorCode and field-error consumers.
if (error) throw error;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- An empty HTTP body can violate the generated response contract.
if (!data) throw new Error("Missing bank operations response");
if (!isAll) return data;
items.push(...data.items);
if (!data.hasNext) return { ...data, hasNext: false, items, page: 1 };
}
},
queryKey: isAll
? ([...options.queryKey, "all"] as const)
: options.queryKey,
});
}
function useBankSummary(
period: { from: string; to: string },
cardId?: string,
) {
return useAuthenticatedQuery({
...apiQueryClient.queryOptions("get", "/api/v1/bank-cards/summary", {
params: { query: { ...period, cardId } },
}),
select: sortBankSummary,
});
}
export {
sortBankSummary,
useBankCard,
useBankCards,
useBankCategories,
useBankExpenses,
useBankOperation,
useBankOperations,
useBankSummary,
};