task-d complate
This commit is contained in:
74
src/features/crm/enquiries/api/mutations.ts
Normal file
74
src/features/crm/enquiries/api/mutations.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { mutationOptions } from '@tanstack/react-query';
|
||||
import { getQueryClient } from '@/lib/query-client';
|
||||
import {
|
||||
createEnquiry,
|
||||
createEnquiryFollowup,
|
||||
deleteEnquiry,
|
||||
deleteEnquiryFollowup,
|
||||
updateEnquiry,
|
||||
updateEnquiryFollowup
|
||||
} from './service';
|
||||
import { enquiryKeys } from './queries';
|
||||
import type { EnquiryFollowupMutationPayload, EnquiryMutationPayload } from './types';
|
||||
|
||||
export const createEnquiryMutation = mutationOptions({
|
||||
mutationFn: (data: EnquiryMutationPayload) => createEnquiry(data),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.all });
|
||||
}
|
||||
});
|
||||
|
||||
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) });
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteEnquiryMutation = mutationOptions({
|
||||
mutationFn: (id: string) => deleteEnquiry(id),
|
||||
onSuccess: () => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.all });
|
||||
}
|
||||
});
|
||||
|
||||
export const createEnquiryFollowupMutation = mutationOptions({
|
||||
mutationFn: ({
|
||||
enquiryId,
|
||||
values
|
||||
}: {
|
||||
enquiryId: string;
|
||||
values: EnquiryFollowupMutationPayload;
|
||||
}) => createEnquiryFollowup(enquiryId, values),
|
||||
onSuccess: (_data, variables) => {
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.followups(variables.enquiryId) });
|
||||
getQueryClient().invalidateQueries({ queryKey: enquiryKeys.detail(variables.enquiryId) });
|
||||
}
|
||||
});
|
||||
|
||||
export const updateEnquiryFollowupMutation = mutationOptions({
|
||||
mutationFn: ({
|
||||
enquiryId,
|
||||
followupId,
|
||||
values
|
||||
}: {
|
||||
enquiryId: string;
|
||||
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) });
|
||||
}
|
||||
});
|
||||
|
||||
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) });
|
||||
}
|
||||
});
|
||||
28
src/features/crm/enquiries/api/queries.ts
Normal file
28
src/features/crm/enquiries/api/queries.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { queryOptions } from '@tanstack/react-query';
|
||||
import { getEnquiries, getEnquiryById, getEnquiryFollowups } from './service';
|
||||
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
|
||||
};
|
||||
|
||||
export const enquiriesQueryOptions = (filters: EnquiryFilters) =>
|
||||
queryOptions({
|
||||
queryKey: enquiryKeys.list(filters),
|
||||
queryFn: () => getEnquiries(filters)
|
||||
});
|
||||
|
||||
export const enquiryByIdOptions = (id: string) =>
|
||||
queryOptions({
|
||||
queryKey: enquiryKeys.detail(id),
|
||||
queryFn: () => getEnquiryById(id)
|
||||
});
|
||||
|
||||
export const enquiryFollowupsOptions = (id: string) =>
|
||||
queryOptions({
|
||||
queryKey: enquiryKeys.followups(id),
|
||||
queryFn: () => getEnquiryFollowups(id)
|
||||
});
|
||||
83
src/features/crm/enquiries/api/service.ts
Normal file
83
src/features/crm/enquiries/api/service.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { apiClient } from '@/lib/api-client';
|
||||
import type {
|
||||
EnquiryDetailResponse,
|
||||
EnquiryFilters,
|
||||
EnquiryFollowupMutationPayload,
|
||||
EnquiryFollowupsResponse,
|
||||
EnquiryListResponse,
|
||||
EnquiryMutationPayload,
|
||||
MutationSuccessResponse
|
||||
} from './types';
|
||||
|
||||
export async function getEnquiries(filters: EnquiryFilters): Promise<EnquiryListResponse> {
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
if (filters.page) searchParams.set('page', String(filters.page));
|
||||
if (filters.limit) searchParams.set('limit', String(filters.limit));
|
||||
if (filters.search) searchParams.set('search', filters.search);
|
||||
if (filters.status) searchParams.set('status', filters.status);
|
||||
if (filters.productType) searchParams.set('productType', filters.productType);
|
||||
if (filters.priority) searchParams.set('priority', filters.priority);
|
||||
if (filters.branch) searchParams.set('branch', filters.branch);
|
||||
if (filters.customer) searchParams.set('customer', filters.customer);
|
||||
if (filters.sort) searchParams.set('sort', filters.sort);
|
||||
|
||||
const query = searchParams.toString();
|
||||
|
||||
return apiClient<EnquiryListResponse>(`/crm/enquiries${query ? `?${query}` : ''}`);
|
||||
}
|
||||
|
||||
export async function getEnquiryById(id: string): Promise<EnquiryDetailResponse> {
|
||||
return apiClient<EnquiryDetailResponse>(`/crm/enquiries/${id}`);
|
||||
}
|
||||
|
||||
export async function createEnquiry(data: EnquiryMutationPayload) {
|
||||
return apiClient<MutationSuccessResponse>('/crm/enquiries', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateEnquiry(id: string, data: EnquiryMutationPayload) {
|
||||
return apiClient<MutationSuccessResponse>(`/crm/enquiries/${id}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteEnquiry(id: string) {
|
||||
return apiClient<MutationSuccessResponse>(`/crm/enquiries/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
}
|
||||
|
||||
export async function getEnquiryFollowups(id: string): Promise<EnquiryFollowupsResponse> {
|
||||
return apiClient<EnquiryFollowupsResponse>(`/crm/enquiries/${id}/followups`);
|
||||
}
|
||||
|
||||
export async function createEnquiryFollowup(
|
||||
enquiryId: string,
|
||||
data: EnquiryFollowupMutationPayload
|
||||
) {
|
||||
return apiClient<MutationSuccessResponse>(`/crm/enquiries/${enquiryId}/followups`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateEnquiryFollowup(
|
||||
enquiryId: string,
|
||||
followupId: string,
|
||||
data: EnquiryFollowupMutationPayload
|
||||
) {
|
||||
return apiClient<MutationSuccessResponse>(`/crm/enquiries/${enquiryId}/followups/${followupId}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteEnquiryFollowup(enquiryId: string, followupId: string) {
|
||||
return apiClient<MutationSuccessResponse>(`/crm/enquiries/${enquiryId}/followups/${followupId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
}
|
||||
189
src/features/crm/enquiries/api/types.ts
Normal file
189
src/features/crm/enquiries/api/types.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
export interface EnquiryOption {
|
||||
id: string;
|
||||
code: string;
|
||||
label: string;
|
||||
value: string | null;
|
||||
}
|
||||
|
||||
export interface EnquiryBranchOption {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
value: string | null;
|
||||
}
|
||||
|
||||
export interface EnquiryCustomerLookup {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
branchId: string | null;
|
||||
}
|
||||
|
||||
export interface EnquiryContactLookup {
|
||||
id: string;
|
||||
customerId: string;
|
||||
name: string;
|
||||
email: string | null;
|
||||
mobile: string | null;
|
||||
isPrimary: boolean;
|
||||
}
|
||||
|
||||
export interface EnquiryRecord {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
branchId: string | null;
|
||||
code: string;
|
||||
customerId: string;
|
||||
contactId: string | null;
|
||||
title: string;
|
||||
description: string | null;
|
||||
requirement: string | null;
|
||||
projectName: string | null;
|
||||
projectLocation: string | null;
|
||||
productType: string;
|
||||
status: string;
|
||||
priority: string;
|
||||
leadChannel: string | null;
|
||||
estimatedValue: number | null;
|
||||
chancePercent: number | null;
|
||||
expectedCloseDate: string | null;
|
||||
competitor: string | null;
|
||||
source: string | null;
|
||||
notes: string | null;
|
||||
isHotProject: boolean;
|
||||
isActive: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
createdBy: string;
|
||||
updatedBy: string;
|
||||
}
|
||||
|
||||
export interface EnquiryListItem extends EnquiryRecord {
|
||||
customerName: string;
|
||||
contactName: string | null;
|
||||
followupCount: number;
|
||||
}
|
||||
|
||||
export interface EnquiryFollowupRecord {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
enquiryId: string;
|
||||
followupDate: string;
|
||||
followupType: string;
|
||||
contactId: string | null;
|
||||
outcome: string | null;
|
||||
notes: string | null;
|
||||
nextFollowupDate: string | null;
|
||||
nextAction: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
createdBy: string;
|
||||
updatedBy: string;
|
||||
}
|
||||
|
||||
export interface EnquiryActivityRecord {
|
||||
id: string;
|
||||
action: string;
|
||||
entityType: string;
|
||||
entityId: string;
|
||||
createdAt: string;
|
||||
userId: string;
|
||||
actorName: string | null;
|
||||
}
|
||||
|
||||
export interface EnquiryReferenceData {
|
||||
branches: EnquiryBranchOption[];
|
||||
statuses: EnquiryOption[];
|
||||
productTypes: EnquiryOption[];
|
||||
priorities: EnquiryOption[];
|
||||
leadChannels: EnquiryOption[];
|
||||
followupTypes: EnquiryOption[];
|
||||
customers: EnquiryCustomerLookup[];
|
||||
contacts: EnquiryContactLookup[];
|
||||
}
|
||||
|
||||
export interface EnquiryFilters {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
status?: string;
|
||||
productType?: string;
|
||||
priority?: string;
|
||||
branch?: string;
|
||||
customer?: string;
|
||||
sort?: string;
|
||||
}
|
||||
|
||||
export interface EnquiryListResponse {
|
||||
success: boolean;
|
||||
time: string;
|
||||
message: string;
|
||||
totalItems: number;
|
||||
offset: number;
|
||||
limit: number;
|
||||
items: EnquiryListItem[];
|
||||
}
|
||||
|
||||
export interface EnquiryDetailResponse {
|
||||
success: boolean;
|
||||
time: string;
|
||||
message: string;
|
||||
enquiry: EnquiryRecord;
|
||||
activity: EnquiryActivityRecord[];
|
||||
}
|
||||
|
||||
export interface EnquiryFollowupsResponse {
|
||||
success: boolean;
|
||||
time: string;
|
||||
message: string;
|
||||
items: EnquiryFollowupRecord[];
|
||||
}
|
||||
|
||||
export interface EnquiryMutationPayload {
|
||||
customerId: string;
|
||||
contactId?: string | null;
|
||||
title: string;
|
||||
description?: string;
|
||||
requirement?: string;
|
||||
projectName?: string;
|
||||
projectLocation?: string;
|
||||
branchId?: string | null;
|
||||
productType: string;
|
||||
status: string;
|
||||
priority: string;
|
||||
leadChannel?: string | null;
|
||||
estimatedValue?: number | null;
|
||||
chancePercent?: number | null;
|
||||
expectedCloseDate?: string | null;
|
||||
competitor?: string;
|
||||
source?: string;
|
||||
isHotProject?: boolean;
|
||||
notes?: string;
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
export interface EnquiryFollowupMutationPayload {
|
||||
followupDate: string;
|
||||
followupType: string;
|
||||
contactId?: string | null;
|
||||
outcome?: string;
|
||||
notes?: string;
|
||||
nextFollowupDate?: string | null;
|
||||
nextAction?: string;
|
||||
}
|
||||
|
||||
export interface EnquiryCustomerRelationItem {
|
||||
id: string;
|
||||
code: string;
|
||||
title: string;
|
||||
status: string;
|
||||
productType: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface MutationSuccessResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
Reference in New Issue
Block a user