// ============================================================ // CRM – React Query Hooks // ============================================================ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { contactsApi, dealsApi, pipelinesApi, activitiesApi, companiesApi, industriesApi, accountTypesApi, relationshipTypesApi, companyRelationshipsApi, usersApi, lexwareContactsApi, lexwareVouchersApi, } from './api'; import type { ContactsQueryParams, DealsQueryParams, ActivitiesQueryParams, CreateContactPayload, UpdateContactPayload, CreateDealPayload, UpdateDealPayload, CreatePipelinePayload, UpdatePipelinePayload, CreateStagePayload, UpdateStagePayload, CreateActivityPayload, UpdateActivityPayload, CompaniesQueryParams, CreateCompanyPayload, UpdateCompanyPayload, CreateIndustryPayload, UpdateIndustryPayload, CreateAccountTypePayload, UpdateAccountTypePayload, CreateRelationshipTypePayload, UpdateRelationshipTypePayload, CreateCompanyRelationshipPayload, LexwareContactSearchParams, LexwareVouchersQueryParams, } from './types'; // --- Query Key Factory --- export const crmKeys = { contacts: { all: ['crm', 'contacts'] as const, list: (params: ContactsQueryParams) => ['crm', 'contacts', 'list', params] as const, detail: (id: string) => ['crm', 'contacts', 'detail', id] as const, }, deals: { all: ['crm', 'deals'] as const, list: (params: DealsQueryParams) => ['crm', 'deals', 'list', params] as const, detail: (id: string) => ['crm', 'deals', 'detail', id] as const, }, pipelines: { all: ['crm', 'pipelines'] as const, list: () => ['crm', 'pipelines', 'list'] as const, detail: (id: string) => ['crm', 'pipelines', 'detail', id] as const, }, activities: { all: ['crm', 'activities'] as const, list: (params: ActivitiesQueryParams) => ['crm', 'activities', 'list', params] as const, detail: (id: string) => ['crm', 'activities', 'detail', id] as const, }, companies: { all: ['crm', 'companies'] as const, list: (params: CompaniesQueryParams) => ['crm', 'companies', 'list', params] as const, detail: (id: string) => ['crm', 'companies', 'detail', id] as const, }, industries: { all: ['crm', 'industries'] as const, list: () => ['crm', 'industries', 'list'] as const, }, accountTypes: { all: ['crm', 'accountTypes'] as const, list: () => ['crm', 'accountTypes', 'list'] as const, }, relationshipTypes: { all: ['crm', 'relationshipTypes'] as const, list: () => ['crm', 'relationshipTypes', 'list'] as const, }, companyRelationships: { all: ['crm', 'companyRelationships'] as const, list: (companyId: string) => ['crm', 'companyRelationships', 'list', companyId] as const, }, users: { all: ['crm', 'users'] as const, list: () => ['crm', 'users', 'list'] as const, }, lexware: { all: ['crm', 'lexware'] as const, contactSearch: (params: LexwareContactSearchParams) => ['crm', 'lexware', 'contacts', 'search', params] as const, contactList: (params: LexwareContactSearchParams) => ['crm', 'lexware', 'contacts', 'list', params] as const, vouchersCompany: (companyId: string, params?: LexwareVouchersQueryParams) => ['crm', 'lexware', 'vouchers', 'company', companyId, params] as const, vouchersContact: (contactId: string, params?: LexwareVouchersQueryParams) => ['crm', 'lexware', 'vouchers', 'contact', contactId, params] as const, vouchersDeal: (dealId: string) => ['crm', 'lexware', 'vouchers', 'deal', dealId] as const, }, }; // ============================================================ // Contacts // ============================================================ export function useContacts(params: ContactsQueryParams) { return useQuery({ queryKey: crmKeys.contacts.list(params), queryFn: () => contactsApi.list(params), }); } export function useContact(id: string) { return useQuery({ queryKey: crmKeys.contacts.detail(id), queryFn: () => contactsApi.getById(id), enabled: !!id, }); } export function useCreateContact() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreateContactPayload) => contactsApi.create(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } export function useUpdateContact() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: UpdateContactPayload }) => contactsApi.update(id, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } export function useDeleteContact() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => contactsApi.delete(id), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } // ============================================================ // Deals // ============================================================ export function useDeals(params: DealsQueryParams) { return useQuery({ queryKey: crmKeys.deals.list(params), queryFn: () => dealsApi.list(params), }); } export function useDeal(id: string) { return useQuery({ queryKey: crmKeys.deals.detail(id), queryFn: () => dealsApi.getById(id), enabled: !!id, }); } export function useCreateDeal() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreateDealPayload) => dealsApi.create(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.deals.all }); qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } export function useUpdateDeal() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: UpdateDealPayload }) => dealsApi.update(id, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.deals.all }); qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } export function useDeleteDeal() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => dealsApi.delete(id), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.deals.all }); qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } // ============================================================ // Pipelines // ============================================================ export function usePipelines() { return useQuery({ queryKey: crmKeys.pipelines.list(), queryFn: () => pipelinesApi.list(), staleTime: 10 * 60 * 1000, // Pipelines aendern sich selten }); } export function usePipeline(id: string) { return useQuery({ queryKey: crmKeys.pipelines.detail(id), queryFn: () => pipelinesApi.getById(id), enabled: !!id, }); } export function useCreatePipeline() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreatePipelinePayload) => pipelinesApi.create(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.pipelines.all }); }, }); } export function useUpdatePipeline() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, data, }: { id: string; data: UpdatePipelinePayload; }) => pipelinesApi.update(id, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.pipelines.all }); }, }); } export function useDeletePipeline() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => pipelinesApi.delete(id), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.pipelines.all }); }, }); } export function useUpdateStage() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ pipelineId, stageId, data, }: { pipelineId: string; stageId: string; data: UpdateStagePayload; }) => pipelinesApi.updateStage(pipelineId, stageId, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.pipelines.all }); }, }); } export function useAddStage() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ pipelineId, data, }: { pipelineId: string; data: CreateStagePayload; }) => pipelinesApi.addStage(pipelineId, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.pipelines.all }); }, }); } export function useRemoveStage() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ pipelineId, stageId, }: { pipelineId: string; stageId: string; }) => pipelinesApi.removeStage(pipelineId, stageId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.pipelines.all }); }, }); } // ============================================================ // Activities // ============================================================ export function useActivities(params: ActivitiesQueryParams) { return useQuery({ queryKey: crmKeys.activities.list(params), queryFn: () => activitiesApi.list(params), }); } export function useCreateActivity() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreateActivityPayload) => activitiesApi.create(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.activities.all }); qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); }, }); } export function useUpdateActivity() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, data, }: { id: string; data: UpdateActivityPayload; }) => activitiesApi.update(id, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.activities.all }); qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); }, }); } export function useDeleteActivity() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => activitiesApi.delete(id), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.activities.all }); qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); }, }); } // ============================================================ // Companies // ============================================================ export function useCompanies(params: CompaniesQueryParams) { return useQuery({ queryKey: crmKeys.companies.list(params), queryFn: () => companiesApi.list(params), }); } export function useCompany(id: string) { return useQuery({ queryKey: crmKeys.companies.detail(id), queryFn: () => companiesApi.getById(id), enabled: !!id, }); } export function useCreateCompany() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreateCompanyPayload) => companiesApi.create(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } export function useUpdateCompany() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: UpdateCompanyPayload }) => companiesApi.update(id, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } export function useDeleteCompany() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => companiesApi.delete(id), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } // ============================================================ // Industries // ============================================================ export function useIndustries() { return useQuery({ queryKey: crmKeys.industries.list(), queryFn: () => industriesApi.list(), staleTime: 10 * 60 * 1000, }); } export function useCreateIndustry() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreateIndustryPayload) => industriesApi.create(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.industries.all }); }, }); } export function useUpdateIndustry() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: UpdateIndustryPayload }) => industriesApi.update(id, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.industries.all }); }, }); } export function useDeleteIndustry() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => industriesApi.delete(id), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.industries.all }); }, }); } // ============================================================ // Account Types // ============================================================ export function useAccountTypes() { return useQuery({ queryKey: crmKeys.accountTypes.list(), queryFn: () => accountTypesApi.list(), staleTime: 10 * 60 * 1000, }); } export function useCreateAccountType() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreateAccountTypePayload) => accountTypesApi.create(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.accountTypes.all }); }, }); } export function useUpdateAccountType() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, data, }: { id: string; data: UpdateAccountTypePayload; }) => accountTypesApi.update(id, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.accountTypes.all }); }, }); } export function useDeleteAccountType() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => accountTypesApi.delete(id), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.accountTypes.all }); }, }); } // ============================================================ // Relationship Types // ============================================================ export function useRelationshipTypes() { return useQuery({ queryKey: crmKeys.relationshipTypes.list(), queryFn: () => relationshipTypesApi.list(), staleTime: 10 * 60 * 1000, }); } export function useCreateRelationshipType() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: CreateRelationshipTypePayload) => relationshipTypesApi.create(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.relationshipTypes.all }); }, }); } export function useUpdateRelationshipType() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, data, }: { id: string; data: UpdateRelationshipTypePayload; }) => relationshipTypesApi.update(id, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.relationshipTypes.all }); }, }); } export function useDeleteRelationshipType() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => relationshipTypesApi.delete(id), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.relationshipTypes.all }); }, }); } // ============================================================ // Company Relationships // ============================================================ export function useCompanyRelationships(companyId: string) { return useQuery({ queryKey: crmKeys.companyRelationships.list(companyId), queryFn: () => companyRelationshipsApi.list(companyId), enabled: !!companyId, }); } export function useCreateCompanyRelationship() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ companyId, data, }: { companyId: string; data: CreateCompanyRelationshipPayload; }) => companyRelationshipsApi.create(companyId, data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companyRelationships.all }); qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } export function useDeleteCompanyRelationship() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ companyId, relationshipId, }: { companyId: string; relationshipId: string; }) => companyRelationshipsApi.delete(companyId, relationshipId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companyRelationships.all }); qc.invalidateQueries({ queryKey: crmKeys.companies.all }); }, }); } // ============================================================ // Tenant Users // ============================================================ export function useTenantUsers() { return useQuery({ queryKey: crmKeys.users.list(), queryFn: () => usersApi.list(), staleTime: 10 * 60 * 1000, }); } // ============================================================ // Company Activities (Aggregated Feed) // ============================================================ export function useCompanyActivities( companyId: string, params: Omit = {}, ) { const fullParams: ActivitiesQueryParams = { ...params, companyId, includeContacts: true, pageSize: params.pageSize ?? 50, }; return useQuery({ queryKey: crmKeys.activities.list(fullParams), queryFn: () => activitiesApi.list(fullParams), enabled: !!companyId, }); } // ============================================================ // Lexware Office — Contacts // ============================================================ export function useLexwareContactSearch( params: LexwareContactSearchParams, enabled = true, ) { return useQuery({ queryKey: crmKeys.lexware.contactSearch(params), queryFn: () => lexwareContactsApi.search(params), enabled: enabled && !!(params.name || params.email), }); } /** Fetch Lexware contacts (paginated, no search filter required) */ export function useLexwareContacts( params: LexwareContactSearchParams = {}, enabled = true, ) { return useQuery({ queryKey: crmKeys.lexware.contactList(params), queryFn: () => lexwareContactsApi.search(params), enabled, }); } export function useLinkLexwareCompany() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: { lexwareContactId: string; companyId: string }) => lexwareContactsApi.linkCompany(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companies.all }); qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); }, }); } export function useLinkLexwareContact() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: { lexwareContactId: string; contactId: string }) => lexwareContactsApi.linkContact(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); }, }); } export function useUnlinkLexwareCompany() { const qc = useQueryClient(); return useMutation({ mutationFn: (companyId: string) => lexwareContactsApi.unlinkCompany(companyId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companies.all }); qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); }, }); } export function useUnlinkLexwareContact() { const qc = useQueryClient(); return useMutation({ mutationFn: (contactId: string) => lexwareContactsApi.unlinkContact(contactId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); }, }); } export function usePushToLexware() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ entityType, entityId, }: { entityType: 'company' | 'contact'; entityId: string; }) => lexwareContactsApi.push(entityType, entityId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companies.all }); qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); }, }); } export function useSyncFromLexware() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ entityType, entityId, }: { entityType: 'company' | 'contact'; entityId: string; }) => lexwareContactsApi.sync(entityType, entityId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companies.all }); qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); }, }); } export function useImportLexwareAsCompany() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: { lexwareContactId: string }) => lexwareContactsApi.importCompany(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.companies.all }); qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); }, }); } export function useImportLexwareAsContact() { const qc = useQueryClient(); return useMutation({ mutationFn: (data: { lexwareContactId: string }) => lexwareContactsApi.importContact(data), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.contacts.all }); qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); }, }); } // ============================================================ // Lexware Office — Vouchers // ============================================================ export function useCompanyVouchers( companyId: string, params?: LexwareVouchersQueryParams, ) { return useQuery({ queryKey: crmKeys.lexware.vouchersCompany(companyId, params), queryFn: () => lexwareVouchersApi.getForCompany(companyId, params), enabled: !!companyId, }); } export function useContactVouchers( contactId: string, params?: LexwareVouchersQueryParams, ) { return useQuery({ queryKey: crmKeys.lexware.vouchersContact(contactId, params), queryFn: () => lexwareVouchersApi.getForContact(contactId, params), enabled: !!contactId, }); } export function useDealVouchers(dealId: string) { return useQuery({ queryKey: crmKeys.lexware.vouchersDeal(dealId), queryFn: () => lexwareVouchersApi.getForDeal(dealId), enabled: !!dealId, }); } export function useLinkVoucherToDeal() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ dealId, voucherId }: { dealId: string; voucherId: string }) => lexwareVouchersApi.linkToDeal(dealId, voucherId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); qc.invalidateQueries({ queryKey: crmKeys.deals.all }); }, }); } export function useUnlinkVoucherFromDeal() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ dealId, voucherId }: { dealId: string; voucherId: string }) => lexwareVouchersApi.unlinkFromDeal(dealId, voucherId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); qc.invalidateQueries({ queryKey: crmKeys.deals.all }); }, }); } export function useRefreshCompanyVouchers() { const qc = useQueryClient(); return useMutation({ mutationFn: (companyId: string) => lexwareVouchersApi.refreshCompany(companyId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); }, }); } export function useRefreshContactVouchers() { const qc = useQueryClient(); return useMutation({ mutationFn: (contactId: string) => lexwareVouchersApi.refreshContact(contactId), onSuccess: () => { qc.invalidateQueries({ queryKey: crmKeys.lexware.all }); }, }); }