ifixkart-admin/lib/validation.ts

97 lines
3.7 KiB
TypeScript

/**
* iFixKart India-specific field validators & input utilities
* Centralised validation rules for phone, email, pincode, and address fields.
*/
// ─── Regex Patterns ────────────────────────────────────────────────────────────
/** Exactly 10 digits starting with 6-9 */
export const PHONE_DIGITS_REGEX = /^[6-9]\d{9}$/;
/** Accepts formats: 9876543210 | +919876543210 | 09876543210 */
export const PHONE_FULL_REGEX = /^(?:\+91|0)?[6-9]\d{9}$/;
/** Standard email address validation */
export const EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
/** Gmail specific validation */
export const GMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@gmail\.com$/i;
/** Indian 6-digit pincode starting with 1-9 */
export const PINCODE_REGEX = /^[1-9]\d{5}$/;
// ─── Validators (return error string or null) ──────────────────────────────────
export function validatePhone(raw: string, required = false): string | null {
const stripped = raw.replace(/[\s\-()]/g, '');
if (!stripped) {
return required ? 'Phone number is required' : null;
}
// Extract digits
let digits = stripped;
if (digits.startsWith('+91')) digits = digits.slice(3);
else if (digits.startsWith('91') && digits.length === 12) digits = digits.slice(2);
else if (digits.startsWith('0') && digits.length === 11) digits = digits.slice(1);
if (digits.length !== 10) {
return 'Phone number must be exactly 10 digits';
}
if (!/^[6-9]/.test(digits)) {
return 'Mobile number must start with 6, 7, 8, or 9';
}
if (!PHONE_DIGITS_REGEX.test(digits)) {
return 'Enter a valid 10-digit Indian mobile number';
}
return null;
}
export function validateEmail(raw: string, required = false, gmailOnly = false): string | null {
const stripped = raw.trim();
if (!stripped) {
return required ? 'Email address is required' : null;
}
if (gmailOnly && !GMAIL_REGEX.test(stripped)) {
return 'Please enter a valid Gmail address (e.g. user@gmail.com)';
}
if (!EMAIL_REGEX.test(stripped)) {
return 'Enter a valid email address (e.g. name@example.com)';
}
return null;
}
export function validatePincode(raw: string, required = false): string | null {
const stripped = raw.trim();
if (!stripped) {
return required ? 'PIN code is required' : null;
}
if (stripped.length !== 6) {
return 'PIN code must be exactly 6 digits';
}
if (!PINCODE_REGEX.test(stripped)) {
return 'Enter a valid 6-digit Indian PIN code (cannot start with 0)';
}
return null;
}
export function validateAddress(raw: string, required = false, minLength = 10): string | null {
const stripped = raw.trim();
if (!stripped) {
return required ? 'Address is required' : null;
}
if (stripped.length < minLength) {
return `Address must be at least ${minLength} characters long`;
}
return null;
}
// ─── Normalizers ──────────────────────────────────────────────────────────────
export function normalizePhone(raw: string): string {
const stripped = raw.replace(/[\s\-().]/g, '');
if (stripped.startsWith('+91') && stripped.length === 13) return stripped.slice(3);
if (stripped.startsWith('91') && stripped.length === 12) return stripped.slice(2);
if (stripped.startsWith('0') && stripped.length === 11) return stripped.slice(1);
return stripped;
}
export function formatPhoneE164(raw: string): string {
const digits = normalizePhone(raw);
if (PHONE_DIGITS_REGEX.test(digits)) return `+91${digits}`;
return raw;
}