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,
  });
}