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 | 1x 20x 10x 10x 10x 6x 6x 6x 1x 1x 1x 1x 2x | /**
* useResetPassword Hook - Amplify v6 Direct Integration
* Story 1.2.2a: Reset Password Confirmation
*
* GREEN Phase: Full implementation with Cognito error mapping
*/
import { useMutation } from '@tanstack/react-query';
import { confirmResetPassword } from 'aws-amplify/auth';
import { ensureAmplifyConfigured } from '@/config/amplify';
interface ResetPasswordInput {
email: string;
code: string;
newPassword: string;
}
interface UseResetPasswordOptions {
onSuccess?: () => void;
onError?: (error: ResetPasswordError) => void;
}
export interface ResetPasswordError extends Error {
type: 'invalidCode' | 'expiredCode' | 'invalidPassword' | 'rateLimitExceeded' | 'unknownError';
statusCode?: number;
}
export const useResetPassword = (options?: UseResetPasswordOptions) => {
return useMutation<void, ResetPasswordError, ResetPasswordInput>({
mutationFn: async ({ email, code, newPassword }: ResetPasswordInput) => {
try {
// Amplify is configured lazily (perf/public-homepage-followup #2) — ensure before use.
await ensureAmplifyConfigured();
// Amplify v6: confirmResetPassword updates password with code
await confirmResetPassword({
username: email,
confirmationCode: code,
newPassword: newPassword,
});
} catch (error: unknown) {
console.error('[useResetPassword] Password reset failed:', error);
const errorCode =
(error as { code?: string; name?: string }).code ||
(error as { code?: string; name?: string }).name ||
'UNKNOWN_ERROR';
// Map Cognito errors to app errors
switch (errorCode) {
case 'CodeMismatchException':
throw Object.assign(new Error('Invalid verification code'), {
type: 'invalidCode' as const,
statusCode: 400,
});
case 'ExpiredCodeException':
throw Object.assign(new Error('Verification code has expired'), {
type: 'expiredCode' as const,
statusCode: 400,
});
case 'InvalidPasswordException':
throw Object.assign(new Error('Password does not meet requirements'), {
type: 'invalidPassword' as const,
statusCode: 400,
});
case 'LimitExceededException':
throw Object.assign(new Error('Too many password reset attempts'), {
type: 'rateLimitExceeded' as const,
statusCode: 429,
});
default:
throw Object.assign(
new Error((error as { message?: string }).message || 'Password reset failed'),
{
type: 'unknownError' as const,
statusCode: 500,
}
);
}
}
},
onSuccess: options?.onSuccess,
onError: options?.onError,
});
};
|