All files / lib/validations profile.ts

100% Statements 60/60
100% Branches 1/1
100% Functions 0/0
100% Lines 60/60

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 1031x                 1x 1x 1x 1x 1x 1x 1x 1x         1x 1x 1x 1x 1x         1x 1x 1x 1x 1x         1x 1x 1x 1x 1x 1x         1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x         1x         1x 1x 1x 1x 1x         1x 1x 1x              
import { z } from 'zod';
 
/**
 * Username validation rules:
 * - 3-20 characters
 * - Lowercase alphanumeric and underscores only
 * - Cannot start or end with underscore
 * - Cannot have consecutive underscores
 */
export const usernameSchema = z
  .string()
  .min(3, 'Username must be at least 3 characters')
  .max(20, 'Username must be at most 20 characters')
  .regex(/^[a-z0-9_]+$/, 'Username can only contain lowercase letters, numbers, and underscores')
  .regex(/^[a-z0-9]/, 'Username must start with a letter or number')
  .regex(/[a-z0-9]$/, 'Username must end with a letter or number')
  .refine((val) => !val.includes('__'), 'Username cannot have consecutive underscores');
 
/**
 * Phone number validation (supports Indian and international formats)
 */
export const phoneSchema = z
  .string()
  .regex(/^\+?[1-9]\d{6,14}$/, 'Invalid phone number format')
  .optional()
  .nullable();
 
/**
 * WhatsApp number (same as phone but required for contact)
 */
export const whatsappSchema = z
  .string()
  .regex(/^\+?[1-9]\d{9,14}$/, 'WhatsApp number must include country code (e.g., +919876543210)')
  .optional()
  .nullable();
 
/**
 * URL validation with custom message
 */
export const urlSchema = z
  .string()
  .url('Please enter a valid URL')
  .optional()
  .nullable()
  .or(z.literal(''));
 
/**
 * Create profile schema (during onboarding)
 */
export const createProfileSchema = z.object({
  username: usernameSchema,
  display_name: z
    .string()
    .min(2, 'Display name must be at least 2 characters')
    .max(50, 'Display name must be at most 50 characters'),
  bio: z
    .string()
    .max(500, 'Bio must be at most 500 characters')
    .optional()
    .nullable()
    .or(z.literal('')),
  role: z
    .string()
    .min(2, 'Role must be at least 2 characters')
    .max(50, 'Role must be at most 50 characters')
    .optional()
    .nullable()
    .or(z.literal('')),
  whatsapp: whatsappSchema.or(z.literal('')),
  email_public: z.string().email('Invalid email address').optional().nullable().or(z.literal('')),
  linkedin_url: urlSchema,
  website_url: urlSchema,
  twitter_url: urlSchema,
  github_url: urlSchema,
});
 
/**
 * Update profile schema (allows partial updates)
 */
export const updateProfileSchema = createProfileSchema.partial().omit({ username: true });
 
/**
 * Profile settings schema
 */
export const profileSettingsSchema = z.object({
  is_published: z.boolean().default(false),
  show_whatsapp: z.boolean().default(true),
  show_email: z.boolean().default(true),
});
 
/**
 * Check username availability request
 */
export const checkUsernameSchema = z.object({
  username: usernameSchema,
});
 
// Type exports
export type CreateProfileInput = z.infer<typeof createProfileSchema>;
export type UpdateProfileInput = z.infer<typeof updateProfileSchema>;
export type ProfileSettingsInput = z.infer<typeof profileSettingsSchema>;
export type CheckUsernameInput = z.infer<typeof checkUsernameSchema>;