/** * Reset Password Client Component * * Handles client-side reset password flow. */ 'use client'; import { useState } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { ResetPasswordViewData } from '@/lib/builders/view-data/types/ResetPasswordViewData'; import { ResetPasswordTemplate } from '@/templates/auth/ResetPasswordTemplate'; import { ResetPasswordMutation } from '@/lib/mutations/auth/ResetPasswordMutation'; import { ResetPasswordViewModelBuilder } from '@/lib/builders/view-models/ResetPasswordViewModelBuilder'; import { ResetPasswordViewModel } from '@/lib/view-models/auth/ResetPasswordViewModel'; import { routes } from '@/lib/routing/RouteConfig'; interface ResetPasswordClientProps { viewData: ResetPasswordViewData; } export function ResetPasswordClient({ viewData }: ResetPasswordClientProps) { const router = useRouter(); const searchParams = useSearchParams(); // Build ViewModel from ViewData const [viewModel, setViewModel] = useState(() => ResetPasswordViewModelBuilder.build(viewData) ); const [formData, setFormData] = useState({ newPassword: '', confirmPassword: '' }); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); // Validate passwords match if (formData.newPassword !== formData.confirmPassword) { setViewModel(prev => prev.withMutationState(false, 'Passwords do not match')); return; } // Update submitting state setViewModel(prev => prev.withMutationState(true, null)); try { const token = searchParams.get('token'); if (!token) { setViewModel(prev => prev.withMutationState(false, 'Invalid reset link')); return; } // Execute reset password mutation const mutation = new ResetPasswordMutation(); const result = await mutation.execute({ token, newPassword: formData.newPassword, }); if (result.isErr()) { const error = result.getError(); setViewModel(prev => prev.withMutationState(false, error)); return; } // Success const data = result.unwrap(); setViewModel(prev => prev.withSuccess(data.message)); // Redirect to login after a delay setTimeout(() => { router.push(routes.auth.login); }, 3000); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Failed to reset password'; setViewModel(prev => prev.withMutationState(false, errorMessage)); } }; // Toggle password visibility const togglePassword = () => { setViewModel(prev => prev.withUIState({ ...prev.uiState, showPassword: !prev.uiState.showPassword, })); }; const toggleConfirmPassword = () => { setViewModel(prev => prev.withUIState({ ...prev.uiState, showConfirmPassword: !prev.uiState.showConfirmPassword, })); }; // Build viewData for template const templateViewData: ResetPasswordViewData = { ...viewData, showSuccess: viewModel.showSuccess, successMessage: viewModel.successMessage || undefined, formState: viewModel.formState, isSubmitting: viewModel.isSubmitting, submitError: viewModel.submitError, }; return ( { if (!show) { // Reset to initial state setViewModel(() => ResetPasswordViewModelBuilder.build(viewData)); } }, setShowPassword: togglePassword, setShowConfirmPassword: toggleConfirmPassword, }} uiState={{ showPassword: viewModel.uiState.showPassword, showConfirmPassword: viewModel.uiState.showConfirmPassword, }} mutationState={{ isPending: viewModel.mutationPending, error: viewModel.mutationError, }} /> ); }