Hotfix Rule: Force Fresh Data After CRUD Mutation
Task-h not implements
This commit is contained in:
@@ -31,6 +31,11 @@ export default async function CustomerDetailRoute({ params }: PageProps) {
|
||||
(!!session?.user?.activeOrganizationId &&
|
||||
(session.user.activeMembershipRole === 'admin' ||
|
||||
session.user.activePermissions.includes(PERMISSIONS.crmContactCreate)));
|
||||
const canContactRead =
|
||||
session?.user?.systemRole === 'super_admin' ||
|
||||
(!!session?.user?.activeOrganizationId &&
|
||||
(session.user.activeMembershipRole === 'admin' ||
|
||||
session.user.activePermissions.includes(PERMISSIONS.crmContactRead)));
|
||||
const canContactUpdate =
|
||||
session?.user?.systemRole === 'super_admin' ||
|
||||
(!!session?.user?.activeOrganizationId &&
|
||||
@@ -45,6 +50,9 @@ export default async function CustomerDetailRoute({ params }: PageProps) {
|
||||
|
||||
if (canRead) {
|
||||
void queryClient.prefetchQuery(customerByIdOptions(id));
|
||||
}
|
||||
|
||||
if (canContactRead) {
|
||||
void queryClient.prefetchQuery(customerContactsOptions(id));
|
||||
}
|
||||
|
||||
@@ -78,6 +86,7 @@ export default async function CustomerDetailRoute({ params }: PageProps) {
|
||||
customerId={id}
|
||||
referenceData={referenceData}
|
||||
canUpdate={canUpdate}
|
||||
canReadContacts={canContactRead}
|
||||
canManageContacts={{
|
||||
create: canContactCreate,
|
||||
update: canContactUpdate,
|
||||
|
||||
@@ -11,26 +11,57 @@ import {
|
||||
import { customerKeys } from './queries';
|
||||
import type { CustomerContactMutationPayload, CustomerMutationPayload } from './types';
|
||||
|
||||
async function invalidateCustomerLists() {
|
||||
await getQueryClient().invalidateQueries({ queryKey: customerKeys.lists() });
|
||||
}
|
||||
|
||||
async function invalidateCustomerDetail(id: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: customerKeys.detail(id) });
|
||||
}
|
||||
|
||||
async function invalidateCustomerContacts(id: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: customerKeys.contacts(id) });
|
||||
}
|
||||
|
||||
export async function invalidateCustomerMutationQueries(id: string) {
|
||||
await Promise.all([invalidateCustomerLists(), invalidateCustomerDetail(id)]);
|
||||
}
|
||||
|
||||
export async function invalidateCustomerContactMutationQueries(customerId: string) {
|
||||
await Promise.all([
|
||||
invalidateCustomerLists(),
|
||||
invalidateCustomerDetail(customerId),
|
||||
invalidateCustomerContacts(customerId)
|
||||
]);
|
||||
}
|
||||
|
||||
export const createCustomerMutation = mutationOptions({
|
||||
mutationFn: (data: CustomerMutationPayload) => createCustomer(data),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.all });
|
||||
onSettled: async (_data, error) => {
|
||||
if (!error) {
|
||||
await invalidateCustomerLists();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const updateCustomerMutation = mutationOptions({
|
||||
mutationFn: ({ id, values }: { id: string; values: CustomerMutationPayload }) =>
|
||||
updateCustomer(id, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.all });
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.detail(variables.id) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateCustomerMutationQueries(variables.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteCustomerMutation = mutationOptions({
|
||||
mutationFn: (id: string) => deleteCustomer(id),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.all });
|
||||
onSettled: async (_data, error, id) => {
|
||||
if (!error) {
|
||||
getQueryClient().removeQueries({ queryKey: customerKeys.detail(id) });
|
||||
getQueryClient().removeQueries({ queryKey: customerKeys.contacts(id) });
|
||||
await invalidateCustomerLists();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -42,9 +73,10 @@ export const createCustomerContactMutation = mutationOptions({
|
||||
customerId: string;
|
||||
values: CustomerContactMutationPayload;
|
||||
}) => createCustomerContact(customerId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.contacts(variables.customerId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.detail(variables.customerId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateCustomerContactMutationQueries(variables.customerId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -58,17 +90,19 @@ export const updateCustomerContactMutation = mutationOptions({
|
||||
contactId: string;
|
||||
values: CustomerContactMutationPayload;
|
||||
}) => updateCustomerContact(customerId, contactId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.contacts(variables.customerId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.detail(variables.customerId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateCustomerContactMutationQueries(variables.customerId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteCustomerContactMutation = mutationOptions({
|
||||
mutationFn: ({ customerId, contactId }: { customerId: string; contactId: string }) =>
|
||||
deleteCustomerContact(customerId, contactId),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.contacts(variables.customerId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: customerKeys.detail(variables.customerId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateCustomerContactMutationQueries(variables.customerId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,9 +4,12 @@ import type { CustomerFilters } from './types';
|
||||
|
||||
export const customerKeys = {
|
||||
all: ['crm-customers'] as const,
|
||||
list: (filters: CustomerFilters) => [...customerKeys.all, 'list', filters] as const,
|
||||
detail: (id: string) => [...customerKeys.all, 'detail', id] as const,
|
||||
contacts: (id: string) => [...customerKeys.all, 'contacts', id] as const
|
||||
lists: () => [...customerKeys.all, 'list'] as const,
|
||||
list: (filters: CustomerFilters) => [...customerKeys.lists(), filters] as const,
|
||||
details: () => [...customerKeys.all, 'detail'] as const,
|
||||
detail: (id: string) => [...customerKeys.details(), id] as const,
|
||||
contactsRoot: () => [...customerKeys.all, 'contacts'] as const,
|
||||
contacts: (id: string) => [...customerKeys.contactsRoot(), id] as const
|
||||
};
|
||||
|
||||
export const customersQueryOptions = (filters: CustomerFilters) =>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { formatDateTime } from '@/lib/format';
|
||||
import { customerByIdOptions } from '../api/queries';
|
||||
import type { CustomerReferenceData } from '../api/types';
|
||||
import { CustomerFormSheet } from './customer-form-sheet';
|
||||
@@ -30,6 +31,7 @@ export function CustomerDetail({
|
||||
customerId,
|
||||
referenceData,
|
||||
canUpdate,
|
||||
canReadContacts,
|
||||
canManageContacts,
|
||||
relatedEnquiries,
|
||||
relatedQuotations
|
||||
@@ -37,6 +39,7 @@ export function CustomerDetail({
|
||||
customerId: string;
|
||||
referenceData: CustomerReferenceData;
|
||||
canUpdate: boolean;
|
||||
canReadContacts: boolean;
|
||||
canManageContacts: {
|
||||
create: boolean;
|
||||
update: boolean;
|
||||
@@ -113,7 +116,7 @@ export function CustomerDetail({
|
||||
<Tabs defaultValue='overview' className='gap-4'>
|
||||
<TabsList>
|
||||
<TabsTrigger value='overview'>Overview</TabsTrigger>
|
||||
<TabsTrigger value='contacts'>Contacts</TabsTrigger>
|
||||
{canReadContacts ? <TabsTrigger value='contacts'>Contacts</TabsTrigger> : null}
|
||||
<TabsTrigger value='activity'>Activity</TabsTrigger>
|
||||
<TabsTrigger value='related'>Related Documents</TabsTrigger>
|
||||
</TabsList>
|
||||
@@ -166,14 +169,16 @@ export function CustomerDetail({
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
<TabsContent value='contacts'>
|
||||
<CustomerContactsTab
|
||||
customerId={customerId}
|
||||
canCreate={canManageContacts.create}
|
||||
canUpdate={canManageContacts.update}
|
||||
canDelete={canManageContacts.delete}
|
||||
/>
|
||||
</TabsContent>
|
||||
{canReadContacts ? (
|
||||
<TabsContent value='contacts'>
|
||||
<CustomerContactsTab
|
||||
customerId={customerId}
|
||||
canCreate={canManageContacts.create}
|
||||
canUpdate={canManageContacts.update}
|
||||
canDelete={canManageContacts.delete}
|
||||
/>
|
||||
</TabsContent>
|
||||
) : null}
|
||||
<TabsContent value='activity'>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
@@ -202,7 +207,7 @@ export function CustomerDetail({
|
||||
</span>
|
||||
</div>
|
||||
<div className='text-muted-foreground text-xs'>
|
||||
{new Date(item.createdAt).toLocaleString()}
|
||||
{formatDateTime(item.createdAt)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -281,8 +286,8 @@ export function CustomerDetail({
|
||||
<CardContent className='space-y-4'>
|
||||
<FieldItem label='Created By' value={customer.createdBy} />
|
||||
<FieldItem label='Updated By' value={customer.updatedBy} />
|
||||
<FieldItem label='Created At' value={new Date(customer.createdAt).toLocaleString()} />
|
||||
<FieldItem label='Updated At' value={new Date(customer.updatedAt).toLocaleString()} />
|
||||
<FieldItem label='Created At' value={formatDateTime(customer.createdAt)} />
|
||||
<FieldItem label='Updated At' value={formatDateTime(customer.updatedAt)} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -11,26 +11,57 @@ import {
|
||||
import { enquiryKeys } from './queries';
|
||||
import type { EnquiryFollowupMutationPayload, EnquiryMutationPayload } from './types';
|
||||
|
||||
async function invalidateEnquiryLists() {
|
||||
await getQueryClient().invalidateQueries({ queryKey: enquiryKeys.lists() });
|
||||
}
|
||||
|
||||
async function invalidateEnquiryDetail(id: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: enquiryKeys.detail(id) });
|
||||
}
|
||||
|
||||
async function invalidateEnquiryFollowups(id: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: enquiryKeys.followups(id) });
|
||||
}
|
||||
|
||||
export async function invalidateEnquiryMutationQueries(id: string) {
|
||||
await Promise.all([invalidateEnquiryLists(), invalidateEnquiryDetail(id)]);
|
||||
}
|
||||
|
||||
export async function invalidateEnquiryFollowupMutationQueries(enquiryId: string) {
|
||||
await Promise.all([
|
||||
invalidateEnquiryLists(),
|
||||
invalidateEnquiryDetail(enquiryId),
|
||||
invalidateEnquiryFollowups(enquiryId)
|
||||
]);
|
||||
}
|
||||
|
||||
export const createEnquiryMutation = mutationOptions({
|
||||
mutationFn: (data: EnquiryMutationPayload) => createEnquiry(data),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.all });
|
||||
onSettled: async (_data, error) => {
|
||||
if (!error) {
|
||||
await invalidateEnquiryLists();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const updateEnquiryMutation = mutationOptions({
|
||||
mutationFn: ({ id, values }: { id: string; values: EnquiryMutationPayload }) =>
|
||||
updateEnquiry(id, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.all });
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.detail(variables.id) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateEnquiryMutationQueries(variables.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteEnquiryMutation = mutationOptions({
|
||||
mutationFn: (id: string) => deleteEnquiry(id),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.all });
|
||||
onSettled: async (_data, error, id) => {
|
||||
if (!error) {
|
||||
getQueryClient().removeQueries({ queryKey: enquiryKeys.detail(id) });
|
||||
getQueryClient().removeQueries({ queryKey: enquiryKeys.followups(id) });
|
||||
await invalidateEnquiryLists();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -42,9 +73,10 @@ export const createEnquiryFollowupMutation = mutationOptions({
|
||||
enquiryId: string;
|
||||
values: EnquiryFollowupMutationPayload;
|
||||
}) => createEnquiryFollowup(enquiryId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.followups(variables.enquiryId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.detail(variables.enquiryId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateEnquiryFollowupMutationQueries(variables.enquiryId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -58,17 +90,19 @@ export const updateEnquiryFollowupMutation = mutationOptions({
|
||||
followupId: string;
|
||||
values: EnquiryFollowupMutationPayload;
|
||||
}) => updateEnquiryFollowup(enquiryId, followupId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.followups(variables.enquiryId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.detail(variables.enquiryId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateEnquiryFollowupMutationQueries(variables.enquiryId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteEnquiryFollowupMutation = mutationOptions({
|
||||
mutationFn: ({ enquiryId, followupId }: { enquiryId: string; followupId: string }) =>
|
||||
deleteEnquiryFollowup(enquiryId, followupId),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.followups(variables.enquiryId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.detail(variables.enquiryId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateEnquiryFollowupMutationQueries(variables.enquiryId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,9 +4,12 @@ import type { EnquiryFilters } from './types';
|
||||
|
||||
export const enquiryKeys = {
|
||||
all: ['crm-enquiries'] as const,
|
||||
list: (filters: EnquiryFilters) => [...enquiryKeys.all, 'list', filters] as const,
|
||||
detail: (id: string) => [...enquiryKeys.all, 'detail', id] as const,
|
||||
followups: (id: string) => [...enquiryKeys.all, 'followups', id] as const
|
||||
lists: () => [...enquiryKeys.all, 'list'] as const,
|
||||
list: (filters: EnquiryFilters) => [...enquiryKeys.lists(), filters] as const,
|
||||
details: () => [...enquiryKeys.all, 'detail'] as const,
|
||||
detail: (id: string) => [...enquiryKeys.details(), id] as const,
|
||||
followupsRoot: () => [...enquiryKeys.all, 'followups'] as const,
|
||||
followups: (id: string) => [...enquiryKeys.followupsRoot(), id] as const
|
||||
};
|
||||
|
||||
export const enquiriesQueryOptions = (filters: EnquiryFilters) =>
|
||||
|
||||
@@ -32,43 +32,104 @@ import type {
|
||||
QuotationTopicMutationPayload
|
||||
} from './types';
|
||||
|
||||
function invalidateQuotationDocumentQueries(quotationId: string) {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationDocumentKeys.data(quotationId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationDocumentKeys.preview(quotationId) });
|
||||
async function invalidateQuotationLists() {
|
||||
await getQueryClient().invalidateQueries({ queryKey: quotationKeys.lists() });
|
||||
}
|
||||
|
||||
async function invalidateQuotationDetail(quotationId: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(quotationId) });
|
||||
}
|
||||
|
||||
async function invalidateQuotationDocumentQueries(quotationId: string) {
|
||||
await Promise.all([
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationDocumentKeys.data(quotationId) }),
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationDocumentKeys.preview(quotationId) })
|
||||
]);
|
||||
}
|
||||
|
||||
async function invalidateQuotationHeaderQueries(quotationId: string) {
|
||||
await Promise.all([
|
||||
invalidateQuotationLists(),
|
||||
invalidateQuotationDetail(quotationId),
|
||||
invalidateQuotationDocumentQueries(quotationId)
|
||||
]);
|
||||
}
|
||||
|
||||
async function invalidateQuotationItems(quotationId: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: quotationKeys.items(quotationId) });
|
||||
}
|
||||
|
||||
async function invalidateQuotationCustomers(quotationId: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: quotationKeys.customers(quotationId) });
|
||||
}
|
||||
|
||||
async function invalidateQuotationTopics(quotationId: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: quotationKeys.topics(quotationId) });
|
||||
}
|
||||
|
||||
async function invalidateQuotationFollowups(quotationId: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: quotationKeys.followups(quotationId) });
|
||||
}
|
||||
|
||||
async function invalidateQuotationAttachments(quotationId: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: quotationKeys.attachments(quotationId) });
|
||||
}
|
||||
|
||||
async function invalidateQuotationRevisions(quotationId: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: quotationKeys.revisions(quotationId) });
|
||||
}
|
||||
|
||||
async function removeQuotationDetailQueries(quotationId: string) {
|
||||
getQueryClient().removeQueries({ queryKey: quotationKeys.detail(quotationId) });
|
||||
getQueryClient().removeQueries({ queryKey: quotationKeys.items(quotationId) });
|
||||
getQueryClient().removeQueries({ queryKey: quotationKeys.customers(quotationId) });
|
||||
getQueryClient().removeQueries({ queryKey: quotationKeys.topics(quotationId) });
|
||||
getQueryClient().removeQueries({ queryKey: quotationKeys.followups(quotationId) });
|
||||
getQueryClient().removeQueries({ queryKey: quotationKeys.attachments(quotationId) });
|
||||
getQueryClient().removeQueries({ queryKey: quotationKeys.revisions(quotationId) });
|
||||
getQueryClient().removeQueries({ queryKey: quotationDocumentKeys.data(quotationId) });
|
||||
getQueryClient().removeQueries({ queryKey: quotationDocumentKeys.preview(quotationId) });
|
||||
}
|
||||
|
||||
export const createQuotationMutation = mutationOptions({
|
||||
mutationFn: (data: QuotationMutationPayload) => createQuotation(data),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.all });
|
||||
onSettled: async (_data, error) => {
|
||||
if (!error) {
|
||||
await invalidateQuotationLists();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const updateQuotationMutation = mutationOptions({
|
||||
mutationFn: ({ id, values }: { id: string; values: QuotationMutationPayload }) =>
|
||||
updateQuotation(id, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.all });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.id) });
|
||||
invalidateQuotationDocumentQueries(variables.id);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await invalidateQuotationHeaderQueries(variables.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteQuotationMutation = mutationOptions({
|
||||
mutationFn: (id: string) => deleteQuotation(id),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.all });
|
||||
onSettled: async (_data, error, id) => {
|
||||
if (!error) {
|
||||
await removeQuotationDetailQueries(id);
|
||||
await invalidateQuotationLists();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const createQuotationItemMutation = mutationOptions({
|
||||
mutationFn: ({ quotationId, values }: { quotationId: string; values: QuotationItemMutationPayload }) =>
|
||||
createQuotationItem(quotationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.items(variables.quotationId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.all });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationItems(variables.quotationId),
|
||||
invalidateQuotationHeaderQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -82,22 +143,26 @@ export const updateQuotationItemMutation = mutationOptions({
|
||||
itemId: string;
|
||||
values: QuotationItemMutationPayload;
|
||||
}) => updateQuotationItem(quotationId, itemId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.items(variables.quotationId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.all });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationItems(variables.quotationId),
|
||||
invalidateQuotationHeaderQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteQuotationItemMutation = mutationOptions({
|
||||
mutationFn: ({ quotationId, itemId }: { quotationId: string; itemId: string }) =>
|
||||
deleteQuotationItem(quotationId, itemId),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.items(variables.quotationId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.all });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationItems(variables.quotationId),
|
||||
invalidateQuotationHeaderQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -109,12 +174,13 @@ export const createQuotationCustomerMutation = mutationOptions({
|
||||
quotationId: string;
|
||||
values: QuotationCustomerMutationPayload;
|
||||
}) => createQuotationCustomer(quotationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.customers(variables.quotationId)
|
||||
});
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationCustomers(variables.quotationId),
|
||||
invalidateQuotationHeaderQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -128,51 +194,68 @@ export const updateQuotationCustomerMutation = mutationOptions({
|
||||
relationId: string;
|
||||
values: QuotationCustomerMutationPayload;
|
||||
}) => updateQuotationCustomer(quotationId, relationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.customers(variables.quotationId)
|
||||
});
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationCustomers(variables.quotationId),
|
||||
invalidateQuotationHeaderQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteQuotationCustomerMutation = mutationOptions({
|
||||
mutationFn: ({ quotationId, relationId }: { quotationId: string; relationId: string }) =>
|
||||
deleteQuotationCustomer(quotationId, relationId),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.customers(variables.quotationId)
|
||||
});
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationCustomers(variables.quotationId),
|
||||
invalidateQuotationHeaderQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const createQuotationTopicMutation = mutationOptions({
|
||||
mutationFn: ({ quotationId, values }: { quotationId: string; values: QuotationTopicMutationPayload }) =>
|
||||
createQuotationTopic(quotationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.topics(variables.quotationId) });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationTopics(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId),
|
||||
invalidateQuotationDocumentQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const updateQuotationTopicMutation = mutationOptions({
|
||||
mutationFn: ({ quotationId, values }: { quotationId: string; values: QuotationTopicMutationPayload }) =>
|
||||
updateQuotationTopic(quotationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.topics(variables.quotationId) });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationTopics(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId),
|
||||
invalidateQuotationDocumentQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteQuotationTopicMutation = mutationOptions({
|
||||
mutationFn: ({ quotationId, topicId }: { quotationId: string; topicId: string }) =>
|
||||
deleteQuotationTopic(quotationId, topicId),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.topics(variables.quotationId) });
|
||||
invalidateQuotationDocumentQueries(variables.quotationId);
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationTopics(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId),
|
||||
invalidateQuotationDocumentQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -184,11 +267,13 @@ export const createQuotationFollowupMutation = mutationOptions({
|
||||
quotationId: string;
|
||||
values: QuotationFollowupMutationPayload;
|
||||
}) => createQuotationFollowup(quotationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.followups(variables.quotationId)
|
||||
});
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationFollowups(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -200,22 +285,26 @@ export const updateQuotationFollowupMutation = mutationOptions({
|
||||
quotationId: string;
|
||||
values: QuotationFollowupMutationPayload;
|
||||
}) => updateQuotationFollowup(quotationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.followups(variables.quotationId)
|
||||
});
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationFollowups(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteQuotationFollowupMutation = mutationOptions({
|
||||
mutationFn: ({ quotationId, followupId }: { quotationId: string; followupId: string }) =>
|
||||
deleteQuotationFollowup(quotationId, followupId),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.followups(variables.quotationId)
|
||||
});
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.detail(variables.quotationId) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationFollowups(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -227,10 +316,13 @@ export const createQuotationAttachmentMutation = mutationOptions({
|
||||
quotationId: string;
|
||||
values: QuotationAttachmentMutationPayload;
|
||||
}) => createQuotationAttachment(quotationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.attachments(variables.quotationId)
|
||||
});
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationAttachments(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -242,20 +334,26 @@ export const updateQuotationAttachmentMutation = mutationOptions({
|
||||
quotationId: string;
|
||||
values: QuotationAttachmentMutationPayload;
|
||||
}) => updateQuotationAttachment(quotationId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.attachments(variables.quotationId)
|
||||
});
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationAttachments(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteQuotationAttachmentMutation = mutationOptions({
|
||||
mutationFn: ({ quotationId, attachmentId }: { quotationId: string; attachmentId: string }) =>
|
||||
deleteQuotationAttachment(quotationId, attachmentId),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({
|
||||
queryKey: quotationKeys.attachments(variables.quotationId)
|
||||
});
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationAttachments(variables.quotationId),
|
||||
invalidateQuotationDetail(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -267,8 +365,12 @@ export const createQuotationRevisionMutation = mutationOptions({
|
||||
quotationId: string;
|
||||
revisionRemark?: string;
|
||||
}) => createQuotationRevision(quotationId, revisionRemark),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.revisions(variables.quotationId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: quotationKeys.all });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateQuotationRevisions(variables.quotationId),
|
||||
invalidateQuotationHeaderQueries(variables.quotationId)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,14 +13,22 @@ import type { QuotationFilters } from './types';
|
||||
|
||||
export const quotationKeys = {
|
||||
all: ['crm-quotations'] as const,
|
||||
list: (filters: QuotationFilters) => [...quotationKeys.all, 'list', filters] as const,
|
||||
detail: (id: string) => [...quotationKeys.all, 'detail', id] as const,
|
||||
items: (id: string) => [...quotationKeys.all, 'items', id] as const,
|
||||
customers: (id: string) => [...quotationKeys.all, 'customers', id] as const,
|
||||
topics: (id: string) => [...quotationKeys.all, 'topics', id] as const,
|
||||
followups: (id: string) => [...quotationKeys.all, 'followups', id] as const,
|
||||
attachments: (id: string) => [...quotationKeys.all, 'attachments', id] as const,
|
||||
revisions: (id: string) => [...quotationKeys.all, 'revisions', id] as const
|
||||
lists: () => [...quotationKeys.all, 'list'] as const,
|
||||
list: (filters: QuotationFilters) => [...quotationKeys.lists(), filters] as const,
|
||||
details: () => [...quotationKeys.all, 'detail'] as const,
|
||||
detail: (id: string) => [...quotationKeys.details(), id] as const,
|
||||
itemsRoot: () => [...quotationKeys.all, 'items'] as const,
|
||||
items: (id: string) => [...quotationKeys.itemsRoot(), id] as const,
|
||||
customersRoot: () => [...quotationKeys.all, 'customers'] as const,
|
||||
customers: (id: string) => [...quotationKeys.customersRoot(), id] as const,
|
||||
topicsRoot: () => [...quotationKeys.all, 'topics'] as const,
|
||||
topics: (id: string) => [...quotationKeys.topicsRoot(), id] as const,
|
||||
followupsRoot: () => [...quotationKeys.all, 'followups'] as const,
|
||||
followups: (id: string) => [...quotationKeys.followupsRoot(), id] as const,
|
||||
attachmentsRoot: () => [...quotationKeys.all, 'attachments'] as const,
|
||||
attachments: (id: string) => [...quotationKeys.attachmentsRoot(), id] as const,
|
||||
revisionsRoot: () => [...quotationKeys.all, 'revisions'] as const,
|
||||
revisions: (id: string) => [...quotationKeys.revisionsRoot(), id] as const
|
||||
};
|
||||
|
||||
export const quotationsQueryOptions = (filters: QuotationFilters) =>
|
||||
|
||||
@@ -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)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -9,35 +9,61 @@ import {
|
||||
import { documentTemplateKeys } from './queries';
|
||||
import type { DocumentTemplateMutationPayload, DocumentTemplateVersionMutationPayload } from './types';
|
||||
|
||||
async function invalidateDocumentTemplateLists() {
|
||||
await getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.lists() });
|
||||
}
|
||||
|
||||
async function invalidateDocumentTemplateDetail(id: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.detail(id) });
|
||||
}
|
||||
|
||||
async function invalidateDocumentTemplateVersions(id: string) {
|
||||
await getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.versions(id) });
|
||||
}
|
||||
|
||||
export const createDocumentTemplateMutation = mutationOptions({
|
||||
mutationFn: (data: DocumentTemplateMutationPayload) => createDocumentTemplate(data),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.all });
|
||||
onSettled: async (_data, error) => {
|
||||
if (!error) {
|
||||
await invalidateDocumentTemplateLists();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const updateDocumentTemplateMutation = mutationOptions({
|
||||
mutationFn: ({ id, values }: { id: string; values: Partial<DocumentTemplateMutationPayload> }) =>
|
||||
updateDocumentTemplate(id, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.all });
|
||||
getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.detail(variables.id) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateDocumentTemplateLists(),
|
||||
invalidateDocumentTemplateDetail(variables.id)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteDocumentTemplateMutation = mutationOptions({
|
||||
mutationFn: (id: string) => deleteDocumentTemplate(id),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.all });
|
||||
onSettled: async (_data, error, id) => {
|
||||
if (!error) {
|
||||
getQueryClient().removeQueries({ queryKey: documentTemplateKeys.detail(id) });
|
||||
getQueryClient().removeQueries({ queryKey: documentTemplateKeys.versions(id) });
|
||||
await invalidateDocumentTemplateLists();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const createDocumentTemplateVersionMutation = mutationOptions({
|
||||
mutationFn: ({ id, values }: { id: string; values: DocumentTemplateVersionMutationPayload }) =>
|
||||
createDocumentTemplateVersion(id, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.all });
|
||||
getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.detail(variables.id) });
|
||||
getQueryClient().invalidateQueries({ queryKey: documentTemplateKeys.versions(variables.id) });
|
||||
onSettled: async (_data, error, variables) => {
|
||||
if (!error) {
|
||||
await Promise.all([
|
||||
invalidateDocumentTemplateLists(),
|
||||
invalidateDocumentTemplateDetail(variables.id),
|
||||
invalidateDocumentTemplateVersions(variables.id)
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,10 +4,13 @@ import type { DocumentTemplateFilters } from './types';
|
||||
|
||||
export const documentTemplateKeys = {
|
||||
all: ['crm-document-templates'] as const,
|
||||
lists: () => [...documentTemplateKeys.all, 'list'] as const,
|
||||
list: (filters: DocumentTemplateFilters) =>
|
||||
[...documentTemplateKeys.all, 'list', filters] as const,
|
||||
detail: (id: string) => [...documentTemplateKeys.all, 'detail', id] as const,
|
||||
versions: (id: string) => [...documentTemplateKeys.all, 'versions', id] as const
|
||||
[...documentTemplateKeys.lists(), filters] as const,
|
||||
details: () => [...documentTemplateKeys.all, 'detail'] as const,
|
||||
detail: (id: string) => [...documentTemplateKeys.details(), id] as const,
|
||||
versionsRoot: () => [...documentTemplateKeys.all, 'versions'] as const,
|
||||
versions: (id: string) => [...documentTemplateKeys.versionsRoot(), id] as const
|
||||
};
|
||||
|
||||
export const documentTemplatesQueryOptions = (filters: DocumentTemplateFilters = {}) =>
|
||||
|
||||
@@ -16,6 +16,29 @@ export function formatDate(
|
||||
}
|
||||
}
|
||||
|
||||
export function formatDateTime(
|
||||
date: Date | string | number | undefined,
|
||||
opts: Intl.DateTimeFormatOptions = {}
|
||||
) {
|
||||
if (!date) return '';
|
||||
|
||||
try {
|
||||
return new Intl.DateTimeFormat('th-TH-u-ca-gregory-nu-latn', {
|
||||
day: opts.day ?? '2-digit',
|
||||
month: opts.month ?? '2-digit',
|
||||
year: opts.year ?? 'numeric',
|
||||
hour: opts.hour ?? '2-digit',
|
||||
minute: opts.minute ?? '2-digit',
|
||||
second: opts.second ?? '2-digit',
|
||||
hour12: opts.hour12 ?? false,
|
||||
timeZone: opts.timeZone ?? 'Asia/Bangkok',
|
||||
...opts
|
||||
}).format(new Date(date));
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date to YYYY-MM-DD format (ISO date).
|
||||
* This is used to prevent hydration mismatches between server and client.
|
||||
|
||||
Reference in New Issue
Block a user