Hotfix Rule: Force Fresh Data After CRUD Mutation

Task-h not implements
This commit is contained in:
phaichayon
2026-06-16 11:59:41 +07:00
parent 357414c247
commit 56683ee7b9
16 changed files with 763 additions and 186 deletions

View File

@@ -13,75 +13,104 @@ import { approvalKeys } from './queries';
import { quotationKeys } from '@/features/crm/quotations/api/queries';
import type { ApprovalActionPayload, SubmitApprovalPayload } from './types';
function invalidateQuotationQueries(quotationId: string) {
const queryClient = getQueryClient();
queryClient.invalidateQueries({ queryKey: quotationKeys.all });
queryClient.invalidateQueries({ queryKey: quotationKeys.detail(quotationId) });
queryClient.invalidateQueries({ queryKey: quotationDocumentKeys.data(quotationId) });
queryClient.invalidateQueries({ queryKey: quotationDocumentKeys.preview(quotationId) });
async function invalidateApprovalLists() {
await getQueryClient().invalidateQueries({ queryKey: approvalKeys.lists() });
}
function invalidateRelatedEntityQueries(approvalId: string) {
async function invalidateApprovalDetail(id: string) {
await getQueryClient().invalidateQueries({ queryKey: approvalKeys.detail(id) });
}
async function invalidateQuotationQueries(quotationId: string) {
const queryClient = getQueryClient();
await Promise.all([
queryClient.invalidateQueries({ queryKey: quotationKeys.lists() }),
queryClient.invalidateQueries({ queryKey: quotationKeys.detail(quotationId) }),
queryClient.invalidateQueries({ queryKey: quotationDocumentKeys.data(quotationId) }),
queryClient.invalidateQueries({ queryKey: quotationDocumentKeys.preview(quotationId) })
]);
}
async function invalidateRelatedEntityQueries(approvalId: string) {
const queryClient = getQueryClient();
const cachedDetail = queryClient.getQueryData<{ approval: { request: { entityType: string; entityId: string } } }>(
approvalKeys.detail(approvalId)
);
if (cachedDetail?.approval.request.entityType === 'quotation') {
invalidateQuotationQueries(cachedDetail.approval.request.entityId);
await invalidateQuotationQueries(cachedDetail.approval.request.entityId);
}
}
export const submitApprovalMutation = mutationOptions({
mutationFn: (data: SubmitApprovalPayload) => submitApproval(data),
onSuccess: () => {
getQueryClient().invalidateQueries({ queryKey: approvalKeys.all });
onSettled: async (_data, error) => {
if (!error) {
await invalidateApprovalLists();
}
}
});
export const submitQuotationApprovalMutation = mutationOptions({
mutationFn: ({ id, remark }: { id: string; remark?: string }) => submitQuotationForApproval(id, remark),
onSuccess: (_data, variables) => {
getQueryClient().invalidateQueries({ queryKey: approvalKeys.all });
invalidateQuotationQueries(variables.id);
onSettled: async (_data, error, variables) => {
if (!error) {
await Promise.all([invalidateApprovalLists(), invalidateQuotationQueries(variables.id)]);
}
}
});
export const cancelApprovalMutation = mutationOptions({
mutationFn: (id: string) => cancelApproval(id),
onSuccess: (_data, id) => {
getQueryClient().invalidateQueries({ queryKey: approvalKeys.all });
getQueryClient().invalidateQueries({ queryKey: approvalKeys.detail(id) });
invalidateRelatedEntityQueries(id);
onSettled: async (_data, error, id) => {
if (!error) {
await Promise.all([
invalidateApprovalLists(),
invalidateApprovalDetail(id),
invalidateRelatedEntityQueries(id)
]);
}
}
});
export const approveApprovalMutation = mutationOptions({
mutationFn: ({ id, values }: { id: string; values: ApprovalActionPayload }) =>
approveApproval(id, values),
onSuccess: (_data, variables) => {
getQueryClient().invalidateQueries({ queryKey: approvalKeys.all });
getQueryClient().invalidateQueries({ queryKey: approvalKeys.detail(variables.id) });
invalidateRelatedEntityQueries(variables.id);
onSettled: async (_data, error, variables) => {
if (!error) {
await Promise.all([
invalidateApprovalLists(),
invalidateApprovalDetail(variables.id),
invalidateRelatedEntityQueries(variables.id)
]);
}
}
});
export const rejectApprovalMutation = mutationOptions({
mutationFn: ({ id, values }: { id: string; values: ApprovalActionPayload }) =>
rejectApproval(id, values),
onSuccess: (_data, variables) => {
getQueryClient().invalidateQueries({ queryKey: approvalKeys.all });
getQueryClient().invalidateQueries({ queryKey: approvalKeys.detail(variables.id) });
invalidateRelatedEntityQueries(variables.id);
onSettled: async (_data, error, variables) => {
if (!error) {
await Promise.all([
invalidateApprovalLists(),
invalidateApprovalDetail(variables.id),
invalidateRelatedEntityQueries(variables.id)
]);
}
}
});
export const returnApprovalMutation = mutationOptions({
mutationFn: ({ id, values }: { id: string; values: ApprovalActionPayload }) =>
returnApproval(id, values),
onSuccess: (_data, variables) => {
getQueryClient().invalidateQueries({ queryKey: approvalKeys.all });
getQueryClient().invalidateQueries({ queryKey: approvalKeys.detail(variables.id) });
invalidateRelatedEntityQueries(variables.id);
onSettled: async (_data, error, variables) => {
if (!error) {
await Promise.all([
invalidateApprovalLists(),
invalidateApprovalDetail(variables.id),
invalidateRelatedEntityQueries(variables.id)
]);
}
}
});

View File

@@ -4,8 +4,10 @@ import type { ApprovalFilters } from './types';
export const approvalKeys = {
all: ['crm-approvals'] as const,
list: (filters: ApprovalFilters) => [...approvalKeys.all, 'list', filters] as const,
detail: (id: string) => [...approvalKeys.all, 'detail', id] as const
lists: () => [...approvalKeys.all, 'list'] as const,
list: (filters: ApprovalFilters) => [...approvalKeys.lists(), filters] as const,
details: () => [...approvalKeys.all, 'detail'] as const,
detail: (id: string) => [...approvalKeys.details(), id] as const
};
export const approvalsQueryOptions = (filters: ApprovalFilters) =>