use-crm.ts8.6 KBView on GitHub /**
* React hooks for CRM operations
*/
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useTRPC } from '@/providers/query-provider';
export function useContact(contactId: string | null) {
const trpc = useTRPC();
return useQuery({
...trpc.crm.getContact.queryOptions({ id: contactId! }),
enabled: !!contactId,
});
}
export function useCreateContact() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.createContact.mutationOptions(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [['crm', 'listContacts']] });
},
});
}
export function useUpdateContact() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.updateContact.mutationOptions(),
onSuccess: (data) => {
queryClient.invalidateQueries({
queryKey: [['crm', 'getContact'], { input: { id: data.id } }],
});
queryClient.invalidateQueries({ queryKey: [['crm', 'listContacts']] });
},
});
}
export function useDeleteContact() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.deleteContact.mutationOptions(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [['crm', 'listContacts']] });
},
});
}
// ============================================
// COMPANIES
// ============================================
export function useCompanies(options?: { search?: string; industry?: string; enabled?: boolean }) {
const trpc = useTRPC();
return useQuery({
...trpc.crm.listCompanies.queryOptions({
search: options?.search,
industry: options?.industry,
limit: 50,
offset: 0,
}),
enabled: options?.enabled !== false,
});
}
export function useCompany(companyId: string | null) {
const trpc = useTRPC();
return useQuery({
...trpc.crm.getCompany.queryOptions({ id: companyId! }),
enabled: !!companyId,
});
}
export function useCreateCompany() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.createCompany.mutationOptions(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [['crm', 'listCompanies']] });
},
});
}
export function useUpdateCompany() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.updateCompany.mutationOptions(),
onSuccess: (data) => {
queryClient.invalidateQueries({
queryKey: [['crm', 'getCompany'], { input: { id: data.id } }],
});
queryClient.invalidateQueries({ queryKey: [['crm', 'listCompanies']] });
},
});
}
export function useCreateConversation() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.createConversation.mutationOptions(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [['crm', 'listConversations']] });
},
});
}
export function useUpdateConversation() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.updateConversation.mutationOptions(),
onSuccess: (data) => {
// Show toast if external CRM was synced
if (data.externalCrmSynced) {
}
queryClient.invalidateQueries({
queryKey: [['crm', 'getConversation'], { input: { id: data.conversation.id } }],
});
queryClient.invalidateQueries({ queryKey: [['crm', 'listConversations']] });
},
});
}
export function useDeleteConversation() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.deleteConversation.mutationOptions(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [['crm', 'listConversations']] });
},
});
}
export function useCreateNoteEvent() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.createNoteEvent.mutationOptions(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [['crm', 'getTimeline']] });
},
});
}
// ============================================
// CUSTOM FIELDS
// ============================================
// ============================================
// FIELD DEFINITIONS
// ============================================
export function useConversationFieldDefinitions(aopId?: string) {
const trpc = useTRPC();
return useQuery({
...trpc.crm.getConversationFieldDefinitions.queryOptions({ aopId }),
enabled: !!aopId,
});
}
export function useConversationEnumOptions(
aopId: string | undefined,
fieldKey=[redacted] | 'priority',
) {
const trpc = useTRPC();
return useQuery({
...trpc.crm.getConversationFieldDefinitions.queryOptions({ aopId }),
enabled: !!aopId,
select: (data) => {
if (!data?.definitions) return null;
const fieldDef = data.definitions[fieldKey];
if (!fieldDef?.options) return null;
return {
options: [...fieldDef.options].sort((a, b) => a.enumOrder - b.enumOrder),
};
},
});
}
export function useCustomFieldDefinitions(aopId?: string) {
const trpc = useTRPC();
return useQuery({
...trpc.crm.getCustomFieldDefinitions.queryOptions({ aopId }),
enabled: !!aopId,
});
}
export function useAllConversationEnumOptions(fieldKey=[redacted] | 'priority') {
const trpc = useTRPC();
return useQuery({
...trpc.crm.getAllConversationEnumOptions.queryOptions({ fieldKey }),
});
}
export function useMergeCompanies() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.mergeCompanies.mutationOptions(),
onSuccess: () => {
// Invalidate relevant queries to refresh the UI
queryClient.invalidateQueries({ queryKey: [['crm', 'listConversations']] });
queryClient.invalidateQueries({ queryKey: [['crm', 'listCompanies']] });
queryClient.invalidateQueries({ queryKey: [['crm', 'getConversation']] });
queryClient.invalidateQueries({ queryKey: [['crm', 'getCompany']] });
// Invalidate timeline queries which show events
queryClient.invalidateQueries({ queryKey: [['crm', 'getTimeline']] });
},
});
}
export function useChangeConversationCompany() {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation({
...trpc.crm.changeConversationCompany.mutationOptions(),
onSuccess: (_data, variables) => {
// Invalidate relevant queries to refresh the UI
queryClient.invalidateQueries({ queryKey: [['crm', 'listConversations']] });
queryClient.invalidateQueries({ queryKey: [['crm', 'listCompanies']] });
queryClient.invalidateQueries({
queryKey: [['crm', 'getConversation'], { input: { id: variables.conversationId } }],
});
// Also invalidate without specific input since some queries may not have exact key match
queryClient.invalidateQueries({ queryKey: [['crm', 'getConversation']] });
// Re-pointing the company rewrites the company record and the deal's link to it, so
// every surface that reads the company — not just the ones that read the conversation
// — is stale. `getCompany` backs the enrichment panel; `loadCalendarConversation` is
// what EventConversationBadge renders from, and it was the one left showing the old
// company until the page was reloaded. Same set `useMergeCompanies` invalidates.
queryClient.invalidateQueries({ queryKey: [['crm', 'getCompany']] });
queryClient.invalidateQueries({ queryKey: [['crm', 'loadCalendarConversation']] });
queryClient.invalidateQueries({ queryKey: [['crm', 'getTimeline']] });
},
});
}
// ============================================
// ANALYTICS
// ============================================
export function useContactStats() {
const trpc = useTRPC();
return useQuery(trpc.crm.getContactStats.queryOptions());
}
export function useRecentActivity(days: number = 7) {
const trpc = useTRPC();
return useQuery(
trpc.crm.getRecentActivity.queryOptions({
days,
limit: 20,
}),
);
}
// ============================================
// GLOBAL DATA (Read-only)
// ============================================
export function usePerson(email: string | null) {
const trpc = useTRPC();
return useQuery({
...trpc.crm.getPerson.queryOptions({ email: email! }),
enabled: !!email,
});
}
export function useCompanyGlobal(domain: string | null) {
const trpc = useTRPC();
return useQuery({
...trpc.crm.getCompanyGlobal.queryOptions({ domain: domain! }),
enabled: !!domain,
});
}