146 lines
4.7 KiB
TypeScript
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);
|
|
}
|
|
} |