Files
gridpilot.gg/apps/website/lib/utilities/authValidation.ts
2026-01-14 16:28:39 +01:00

146 lines
4.7 KiB
TypeScript

/**
* Auth Validation Utilities
*
* Pure functions for client-side validation of auth forms.
* No side effects, synchronous.
*/
export interface SignupFormData {
firstName: string;
lastName: string;
email: string;
password: string;
confirmPassword: string;
}
export interface ForgotPasswordFormData {
email: string;
}
export interface ResetPasswordFormData {
newPassword: string;
confirmPassword: string;
}
export interface SignupValidationError {
field: keyof SignupFormData;
message: string;
}
export interface ForgotPasswordValidationError {
field: keyof ForgotPasswordFormData;
message: string;
}
export interface ResetPasswordValidationError {
field: keyof ResetPasswordFormData;
message: string;
}
export class SignupFormValidation {
static validateForm(data: SignupFormData): SignupValidationError[] {
const errors: SignupValidationError[] = [];
// First name
if (!data.firstName.trim()) {
errors.push({ field: 'firstName', message: 'First name is required' });
} else if (data.firstName.trim().length < 2) {
errors.push({ field: 'firstName', message: 'First name must be at least 2 characters' });
}
// Last name
if (!data.lastName.trim()) {
errors.push({ field: 'lastName', message: 'Last name is required' });
} else if (data.lastName.trim().length < 2) {
errors.push({ field: 'lastName', message: 'Last name must be at least 2 characters' });
}
// Email
if (!data.email.trim()) {
errors.push({ field: 'email', message: 'Email is required' });
} else if (!this.isValidEmail(data.email)) {
errors.push({ field: 'email', message: 'Please enter a valid email address' });
}
// Password
if (!data.password) {
errors.push({ field: 'password', message: 'Password is required' });
} else if (data.password.length < 8) {
errors.push({ field: 'password', message: 'Password must be at least 8 characters' });
} else if (!this.hasValidPasswordComplexity(data.password)) {
errors.push({ field: 'password', message: 'Password must contain at least one uppercase letter, one lowercase letter, and one number' });
}
// Confirm password
if (!data.confirmPassword) {
errors.push({ field: 'confirmPassword', message: 'Please confirm your password' });
} else if (data.password !== data.confirmPassword) {
errors.push({ field: 'confirmPassword', message: 'Passwords do not match' });
}
return errors;
}
static generateDisplayName(firstName: string, lastName: string): string {
const trimmedFirst = firstName.trim();
const trimmedLast = lastName.trim();
return `${trimmedFirst} ${trimmedLast}`.trim() || trimmedFirst || trimmedLast;
}
private static isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
private static hasValidPasswordComplexity(password: string): boolean {
return /[a-z]/.test(password) && /[A-Z]/.test(password) && /\d/.test(password);
}
}
export class ForgotPasswordFormValidation {
static validateForm(data: ForgotPasswordFormData): ForgotPasswordValidationError[] {
const errors: ForgotPasswordValidationError[] = [];
// Email
if (!data.email.trim()) {
errors.push({ field: 'email', message: 'Email is required' });
} else if (!this.isValidEmail(data.email)) {
errors.push({ field: 'email', message: 'Please enter a valid email address' });
}
return errors;
}
private static isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
}
export class ResetPasswordFormValidation {
static validateForm(data: ResetPasswordFormData): ResetPasswordValidationError[] {
const errors: ResetPasswordValidationError[] = [];
// New password
if (!data.newPassword) {
errors.push({ field: 'newPassword', message: 'New password is required' });
} else if (data.newPassword.length < 8) {
errors.push({ field: 'newPassword', message: 'Password must be at least 8 characters' });
} else if (!this.hasValidPasswordComplexity(data.newPassword)) {
errors.push({ field: 'newPassword', message: 'Password must contain at least one uppercase letter, one lowercase letter, and one number' });
}
// Confirm password
if (!data.confirmPassword) {
errors.push({ field: 'confirmPassword', message: 'Please confirm your new password' });
} else if (data.newPassword !== data.confirmPassword) {
errors.push({ field: 'confirmPassword', message: 'Passwords do not match' });
}
return errors;
}
private static hasValidPasswordComplexity(password: string): boolean {
return /[a-z]/.test(password) && /[A-Z]/.test(password) && /\d/.test(password);
}
}