@battle-racing/br-common-lib
Version:
Common library for all Battle Racing Repositorios
111 lines (91 loc) • 3.13 kB
text/typescript
import { z } from 'zod';
import { userRoleSchema } from '../role';
import { USER_TYPE } from './User.const';
export const userTypeSchema = z.enum(USER_TYPE);
export const PHONE_REGEX = /^([+]?[\\s0-9]+)?(\\d{3}|[(]?[0-9]+[)])?([-]?[\\s]?[0-9])+$/;
const MIN_PASSWORD_LENGTH = 6;
export const emailOrPhoneSchema = z
.string()
.min(1, 'Email or phone is required')
.refine(
(val) => {
const isEmail = z.email().safeParse(val).success;
const isPhone = PHONE_REGEX.test(val);
return isEmail || isPhone;
},
{ message: 'Must be a valid email or phone number' },
);
const baseUserObj = z.object({
id: z.uuidv4(),
name: z.string(),
lastName: z.string(),
email: z.email().toLowerCase().optional().nullable(),
phoneNumber: z.string().regex(PHONE_REGEX, 'Invalid phone number format').optional().nullable(),
// --- ACCESS CONTROL ---
role: userRoleSchema,
type: userTypeSchema,
isActive: z.boolean().default(true),
// TODO: Implement mechanism to validate users later by email or phone
isEmailVerified: z.boolean().default(false),
isPhoneVerified: z.boolean().default(false),
defaultPlayerId: z.uuidv4().optional(),
createdAt: z.date(),
lastLoginAt: z.date().optional(),
});
export const userSchema = baseUserObj.refine((data) => data.email || data.phoneNumber, {
message: 'User must have either an email or a phone number',
path: ['email', 'phoneNumber'],
});
/**
* The schema for the user returned on login
*/
export const authUserSchema = baseUserObj.extend({
authToken: z.string(),
});
export const userWithPasswordSchema = userSchema.and(
z.object({
password: z.string().min(MIN_PASSWORD_LENGTH),
}),
);
export const userInitialRegistrationSchema = z.object({
emailOrPhone: emailOrPhoneSchema,
password: z.string().min(MIN_PASSWORD_LENGTH, `Password must be at least ${MIN_PASSWORD_LENGTH} characters`),
});
export const userVerifySchema = z.object({
emailOrPhone: emailOrPhoneSchema,
code: z.string().min(6, 'Code must be at least 6 characters').max(10, 'Code is too long'),
});
export const userCompleteProfileSchema = baseUserObj
.pick({
name: true,
})
.extend({
lastName: z.string().optional(),
nickname: z.string().min(2),
birthDate: z.coerce.date(),
waiverSignature: z.boolean().refine((val) => val === true, {
message: 'You must accept the waiver signature',
}),
teamName: z.string().optional(),
});
// Deprecated in favor of multi-step registration
export const userRegistrationInputSchema = baseUserObj
.pick({
name: true,
lastName: true,
email: true,
phoneNumber: true,
})
.extend({
password: z.string().min(6),
nickname: z.string().min(2),
birthDate: z.coerce.date(),
})
.refine((data) => data.email || data.phoneNumber, {
message: 'User must have either an email or a phone number',
path: ['email', 'phoneNumber'],
});
export const userLoginInputSchema = z.object({
emailOrPhone: emailOrPhoneSchema,
password: z.string().min(MIN_PASSWORD_LENGTH, `Password must be at least ${MIN_PASSWORD_LENGTH} characters`),
});