All files / src/hooks/useEmailVerification useEmailVerification.ts

100% Statements 21/21
66.66% Branches 8/12
100% Functions 7/7
100% Lines 21/21

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                                            1x 12x   6x   6x   4x 4x               4x 4x     2x     2x     4x                 1x 6x   3x   3x   1x 1x           1x 1x     2x       1x        
/**
 * useEmailVerification Hook (TDD - GREEN Phase)
 * Story 1.2.4: Email Verification Flow - Task 4
 * Handles email verification via AWS Cognito confirmSignUp
 */
 
import { useMutation } from '@tanstack/react-query';
import {
  verifyEmail,
  resendVerificationCode,
  VerifyEmailInput,
} from '@/services/auth/emailVerificationService';
 
interface UseEmailVerificationOptions {
  onSuccess?: () => void;
  onError?: (error: Error) => void;
}
 
/**
 * Hook for email verification mutation
 * Returns React Query mutation with success/error handling
 */
export const useEmailVerification = (options?: UseEmailVerificationOptions) => {
  return useMutation({
    mutationFn: async (input: VerifyEmailInput) => {
      const result = await verifyEmail(input);
 
      if (!result.success) {
        // Map error codes to user-friendly error keys
        const errorCode = result.error?.code || 'UNKNOWN_ERROR';
        const errorMap: Record<string, string> = {
          INVALID_CODE: 'invalidCode',
          EXPIRED_CODE: 'expiredCode',
          TOO_MANY_ATTEMPTS: 'tooManyAttempts',
          ALREADY_VERIFIED: 'alreadyVerified',
          USER_NOT_FOUND: 'userNotFound',
        };
 
        const mappedError = errorMap[errorCode] || 'networkError';
        throw new Error(mappedError);
      }
 
      return result;
    },
    onSuccess: () => {
      options?.onSuccess?.();
    },
    onError: (error: Error) => {
      options?.onError?.(error);
    },
  });
};
 
/**
 * Hook for resending verification code
 * Returns React Query mutation with cooldown handling
 */
export const useResendVerification = () => {
  return useMutation({
    mutationFn: async (email: string) => {
      const result = await resendVerificationCode(email);
 
      if (!result.success) {
        // Map error codes to user-friendly error keys
        const errorCode = result.error?.code || 'UNKNOWN_ERROR';
        const errorMap: Record<string, string> = {
          RATE_LIMITED: 'rateLimited',
          USER_NOT_FOUND: 'userNotFound',
          INVALID_PARAMETER: 'invalidParameter',
        };
 
        const mappedError = errorMap[errorCode] || 'networkError';
        throw new Error(mappedError);
      }
 
      return result;
    },
    onError: (error: Error) => {
      // Error is already mapped to user-friendly key
      console.error('[useResendVerification] Resend failed:', error.message);
    },
  });
};