Files
gridpilot.gg/apps/website/app/auth/signup/SignupClient.tsx
2026-01-14 02:02:24 +01:00

123 lines
3.5 KiB
TypeScript

/**
* Signup Client Component
*
* Handles client-side signup flow.
*/
'use client';
import { useState } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useAuth } from '@/lib/auth/AuthContext';
import { SignupViewData } from '@/lib/builders/view-data/SignupViewDataBuilder';
import { SignupTemplate } from '@/templates/auth/SignupTemplate';
import { SignupMutation } from '@/lib/mutations/auth/SignupMutation';
import { SignupViewModelBuilder } from '@/lib/builders/view-models/SignupViewModelBuilder';
import { SignupViewModel } from '@/lib/view-models/auth/SignupViewModel';
interface SignupClientProps {
viewData: SignupViewData;
}
export function SignupClient({ viewData }: SignupClientProps) {
const router = useRouter();
const searchParams = useSearchParams();
const { refreshSession } = useAuth();
// Build ViewModel from ViewData
const [viewModel, setViewModel] = useState<SignupViewModel>(() =>
SignupViewModelBuilder.build(viewData)
);
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: '',
password: '',
confirmPassword: ''
});
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// Validate passwords match
if (formData.password !== formData.confirmPassword) {
setViewModel(prev => prev.withMutationState(false, 'Passwords do not match'));
return;
}
// Update submitting state
setViewModel(prev => prev.withMutationState(true, null));
try {
// Transform to DTO format
const displayName = `${formData.firstName} ${formData.lastName}`.trim();
// Execute signup mutation
const mutation = new SignupMutation();
const result = await mutation.execute({
email: formData.email,
password: formData.password,
displayName: displayName || formData.firstName || formData.lastName,
});
if (result.isErr()) {
const error = result.getError();
setViewModel(prev => prev.withMutationState(false, error));
return;
}
// Success - refresh session and redirect
await refreshSession();
const returnTo = searchParams.get('returnTo') ?? '/onboarding';
router.push(returnTo);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Signup failed';
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: SignupViewData = {
...viewData,
formState: viewModel.formState,
isSubmitting: viewModel.isSubmitting,
submitError: viewModel.submitError,
};
return (
<SignupTemplate
viewData={templateViewData}
formActions={{
setFormData,
handleSubmit,
setShowPassword: togglePassword,
setShowConfirmPassword: toggleConfirmPassword,
}}
uiState={{
showPassword: viewModel.uiState.showPassword,
showConfirmPassword: viewModel.uiState.showConfirmPassword,
}}
mutationState={{
isPending: viewModel.mutationPending,
error: viewModel.mutationError,
}}
/>
);
}