All files / src/hooks/useCompanyMutations useCompanyMutations.ts

100% Statements 25/25
100% Branches 4/4
100% Functions 12/12
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119                                                  5x 16x   16x 8x     5x                                   5x 19x   19x   10x         10x     10x     10x 3x             10x         6x 6x         3x 2x                                   5x 26x   26x 9x     5x     5x        
/**
 * useCompanyMutations Hooks
 *
 * React Query mutation hooks for company CRUD operations with optimistic updates
 * AC 3 (Create Company), AC 4 (Edit Company), AC 10 (Performance), AC 14 (State Management)
 */
 
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { companyApiClient } from '@/services/api/companyApi';
import type { components } from '@/types/generated/company-api.types';
 
type Company = components['schemas']['CompanyResponse'];
type CreateCompanyRequest = components['schemas']['CreateCompanyRequest'];
type UpdateCompanyRequest = components['schemas']['UpdateCompanyRequest'];
 
/**
 * Create new company mutation
 *
 * Features:
 * - Automatic cache invalidation of companies list
 * - Support for draft mode (partial validation)
 * - Error handling with correlation IDs
 *
 * @returns Mutation hook for creating companies
 */
export const useCreateCompany = () => {
  const queryClient = useQueryClient();
 
  return useMutation({
    mutationFn: (data: CreateCompanyRequest) => companyApiClient.createCompany(data),
    onSuccess: () => {
      // Invalidate companies list to refetch with new company
      queryClient.invalidateQueries({ queryKey: ['companies'] });
    },
  });
};
 
/**
 * Update existing company mutation with optimistic updates
 *
 * Features:
 * - Optimistic UI updates (immediate feedback)
 * - Rollback on error
 * - Cache invalidation of both list and detail
 * - Partial update support (only changed fields)
 *
 * Story 1.16.2: Uses company name as identifier instead of UUID
 *
 * @returns Mutation hook for updating companies
 */
export const useUpdateCompany = () => {
  const queryClient = useQueryClient();
 
  return useMutation({
    mutationFn: ({ name, data }: { name: string; data: UpdateCompanyRequest }) =>
      companyApiClient.updateCompany(name, data),
 
    // Optimistic update (AC 14 - State Management with immediate UI feedback)
    onMutate: async ({ name, data }) => {
      // Cancel any outgoing refetches to prevent overwriting optimistic update
      await queryClient.cancelQueries({ queryKey: ['company', name] });
 
      // Snapshot the previous value for rollback
      const previousCompany = queryClient.getQueryData(['company', name, undefined]);
 
      // Optimistically update to the new value
      if (previousCompany) {
        queryClient.setQueryData(['company', name, undefined], (old: Company) => ({
          ...old,
          ...data,
        }));
      }
 
      // Return context with snapshot for rollback
      return { previousCompany };
    },
 
    // On success, invalidate caches to refetch fresh data
    onSuccess: (_, { name }) => {
      queryClient.invalidateQueries({ queryKey: ['companies'] });
      queryClient.invalidateQueries({ queryKey: ['company', name] });
    },
 
    // Rollback on error (AC 14 - Error handling with rollback)
    onError: (_error, { name }, context) => {
      if (context?.previousCompany) {
        queryClient.setQueryData(['company', name, undefined], context.previousCompany);
      }
    },
  });
};
 
/**
 * Delete company mutation
 *
 * Features:
 * - Cache invalidation of companies list
 * - Removal of deleted company from detail cache
 * - Error handling for permission/dependency issues
 *
 * Story 1.16.2: Uses company name as identifier instead of UUID
 *
 * @returns Mutation hook for deleting companies
 */
export const useDeleteCompany = () => {
  const queryClient = useQueryClient();
 
  return useMutation({
    mutationFn: (name: string) => companyApiClient.deleteCompany(name),
    onSuccess: (_, name) => {
      // Invalidate companies list
      queryClient.invalidateQueries({ queryKey: ['companies'] });
 
      // Remove deleted company from cache
      queryClient.removeQueries({ queryKey: ['company', name] });
    },
  });
};