Uecko_ERP/modules/customers/src/web/shared/hooks/customer-cache-strategy.ts
2026-04-05 17:25:38 +02:00

156 lines
4.4 KiB
TypeScript

import type { QueryClient, QueryKey } from "@tanstack/react-query";
import { CustomerToListRowPatchAdapter } from "../adapters";
import type { Customer, CustomerList, CustomerListRow } from "../entities";
import { CUSTOMER_QUERY_KEY, LIST_CUSTOMERS_QUERY_KEY_PREFIX } from "./keys";
/**
* Estrategias de caché para las consultas relacionadas con clientes.
* Incluye funciones para cancelar, invalidar, actualizar y eliminar cachés de clientes,
* así como para manejar actualizaciones optimistas al eliminar clientes.
*/
export interface CustomerListCacheSnapshot {
key: QueryKey;
page?: CustomerList;
}
export interface DeleteCustomerCacheContext {
snapshots: CustomerListCacheSnapshot[];
}
export function cancelCustomerListQueries(queryClient: QueryClient) {
return queryClient.cancelQueries({
queryKey: LIST_CUSTOMERS_QUERY_KEY_PREFIX,
});
}
export function invalidateCustomerListQueries(queryClient: QueryClient) {
return queryClient.invalidateQueries({
queryKey: LIST_CUSTOMERS_QUERY_KEY_PREFIX,
});
}
export function invalidateCustomerDetailQuery(queryClient: QueryClient, customerId: string) {
return queryClient.invalidateQueries({
queryKey: CUSTOMER_QUERY_KEY(customerId),
exact: true,
});
}
export function setCustomerDetailCache(
queryClient: QueryClient,
customerId: string,
customer: Customer
) {
queryClient.setQueryData<Customer>(CUSTOMER_QUERY_KEY(customerId), customer);
}
export function removeCustomerDetailCache(queryClient: QueryClient, customerId: string) {
queryClient.removeQueries({
queryKey: CUSTOMER_QUERY_KEY(customerId),
exact: true,
});
}
export function getAllCustomerListQueryKeys(queryClient: QueryClient): QueryKey[] {
const entries = queryClient.getQueriesData<CustomerList>({
queryKey: LIST_CUSTOMERS_QUERY_KEY_PREFIX,
});
return entries.map(([key]) => key);
}
export function upsertCustomerInListCaches(
queryClient: QueryClient,
customer: Pick<CustomerListRow, "id"> & Partial<CustomerListRow>
) {
const keys = getAllCustomerListQueryKeys(queryClient);
for (const key of keys) {
const page = queryClient.getQueryData<CustomerList>(key);
if (!page) continue;
const index = page.items.findIndex((row) => row.id === customer.id);
if (index === -1) continue;
const nextItems = page.items.slice();
nextItems[index] = {
...page.items[index],
...customer,
};
queryClient.setQueryData<CustomerList>(key, {
...page,
items: nextItems,
});
}
}
export function removeCustomerFromListCaches(
queryClient: QueryClient,
customerId: string
): CustomerListCacheSnapshot[] {
const snapshots = getAllCustomerListQueryKeys(queryClient).map((key) => ({
key,
page: queryClient.getQueryData<CustomerList>(key),
}));
for (const { key, page } of snapshots) {
if (!page) continue;
queryClient.setQueryData<CustomerList>(key, {
...page,
items: page.items.filter((row) => row.id !== customerId),
totalItems: Math.max(0, page.totalItems - 1),
});
}
return snapshots;
}
export function restoreCustomerListCaches(
queryClient: QueryClient,
snapshots: CustomerListCacheSnapshot[]
) {
for (const snapshot of snapshots) {
queryClient.setQueryData(snapshot.key, snapshot.page);
}
}
export function syncCreatedCustomerCaches(queryClient: QueryClient, customer: Customer) {
setCustomerDetailCache(queryClient, customer.id, customer);
return invalidateCustomerListQueries(queryClient);
}
export function syncUpdatedCustomerCaches(queryClient: QueryClient, customer: Customer) {
setCustomerDetailCache(queryClient, customer.id, customer);
upsertCustomerInListCaches(queryClient, CustomerToListRowPatchAdapter.fromCustomer(customer));
return invalidateCustomerListQueries(queryClient);
}
export async function prepareDeleteCustomerOptimisticUpdate(
queryClient: QueryClient,
customerId: string
): Promise<DeleteCustomerCacheContext> {
await cancelCustomerListQueries(queryClient);
const snapshots = removeCustomerFromListCaches(queryClient, customerId);
return { snapshots };
}
export function rollbackDeleteCustomerOptimisticUpdate(
queryClient: QueryClient,
context?: DeleteCustomerCacheContext
) {
if (!context) return;
restoreCustomerListCaches(queryClient, context.snapshots);
}
export function finalizeDeletedCustomerCaches(queryClient: QueryClient, customerId: string) {
removeCustomerDetailCache(queryClient, customerId);
return invalidateCustomerListQueries(queryClient);
}