mirror of
https://github.com/Sea-Haven-Industries/proposal-system.git
synced 2026-10-04 11:22:02 +00:00
69 lines
2.7 KiB
TypeScript
69 lines
2.7 KiB
TypeScript
|
|
// Customers domain — TanStack Query hooks + query keys (the only public surface).
|
||
|
|
import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||
|
|
import { toast } from 'react-toastify';
|
||
|
|
import { customersApi } from './api';
|
||
|
|
import type { CreateCustomerRequest, CustomerListParams, UpdateCustomerRequest } from './types';
|
||
|
|
|
||
|
|
export const customersKeys = {
|
||
|
|
all: ['customers'] as const,
|
||
|
|
lists: () => [...customersKeys.all, 'list'] as const,
|
||
|
|
list: (params: CustomerListParams) => [...customersKeys.lists(), params] as const,
|
||
|
|
search: (query: string) => [...customersKeys.all, 'search', query] as const,
|
||
|
|
};
|
||
|
|
|
||
|
|
/** Name autocomplete (ProposalFormPage). Call with the debounced input;
|
||
|
|
* disabled below 2 characters, matching current page behavior. */
|
||
|
|
export function useCustomerSearch(query: string) {
|
||
|
|
return useQuery({
|
||
|
|
queryKey: customersKeys.search(query),
|
||
|
|
queryFn: () => customersApi.search(query),
|
||
|
|
enabled: query.trim().length >= 2,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Paginated management list (CustomerManagementPage). keepPreviousData
|
||
|
|
* keeps rows/totalCount rendered while a new page/search fetches (matches
|
||
|
|
* the old usePaginatedList behavior and keeps TablePagination's count from
|
||
|
|
* collapsing to 0 mid-fetch). */
|
||
|
|
export function useCustomerList(params: CustomerListParams = {}) {
|
||
|
|
return useQuery({
|
||
|
|
queryKey: customersKeys.list(params),
|
||
|
|
queryFn: () => customersApi.list(params),
|
||
|
|
placeholderData: keepPreviousData,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useCreateCustomer() {
|
||
|
|
const queryClient = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: (data: CreateCustomerRequest) => customersApi.create(data),
|
||
|
|
onSuccess: () => {
|
||
|
|
// Invalidate the whole domain: lists AND cached search-autocomplete
|
||
|
|
// results (['customers','search',q]), which lists() would not cover —
|
||
|
|
// otherwise a just-created customer is invisible in New Proposal's
|
||
|
|
// autocomplete for the 5-minute staleTime.
|
||
|
|
queryClient.invalidateQueries({ queryKey: customersKeys.all });
|
||
|
|
toast.success('Customer created');
|
||
|
|
},
|
||
|
|
onError: (error: Error) => {
|
||
|
|
toast.error(`Failed to create customer: ${error.message}`);
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useUpdateCustomer() {
|
||
|
|
const queryClient = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: ({ id, data }: { id: string; data: UpdateCustomerRequest }) =>
|
||
|
|
customersApi.update(id, data),
|
||
|
|
onSuccess: () => {
|
||
|
|
// Whole-domain invalidation — see useCreateCustomer.
|
||
|
|
queryClient.invalidateQueries({ queryKey: customersKeys.all });
|
||
|
|
toast.success('Customer updated');
|
||
|
|
},
|
||
|
|
onError: (error: Error) => {
|
||
|
|
toast.error(`Failed to update customer: ${error.message}`);
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|