- Domain: NotificationLog/NotificationPreference entities, repositories, channel value object - Infrastructure: EmailService (nodemailer/SMTP), FcmService (firebase-admin), TemplateService (Handlebars) - Application: SendNotification CQRS command, UserRegistered + AgentVerified event listeners - Presentation: NotificationsController with history, preferences, and templates endpoints - Prisma: NotificationLog and NotificationPreference models with proper indexes - Templates: Vietnamese notification templates for user.registered, agent.verified, listing.approved, inquiry.received, password.reset Co-Authored-By: Paperclip <noreply@paperclip.ing>
40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
const phoneRegex = /^(0|\+84)(3[2-9]|5[2689]|7[06-9]|8[1-9]|9[0-9])\d{7}$/;
|
|
|
|
export const loginSchema = z.object({
|
|
phone: z
|
|
.string()
|
|
.min(1, 'Vui lòng nhập số điện thoại')
|
|
.regex(phoneRegex, 'Số điện thoại không hợp lệ'),
|
|
password: z.string().min(1, 'Vui lòng nhập mật khẩu'),
|
|
});
|
|
|
|
export const registerSchema = z
|
|
.object({
|
|
fullName: z
|
|
.string()
|
|
.min(1, 'Vui lòng nhập họ tên')
|
|
.min(2, 'Họ tên phải có ít nhất 2 ký tự'),
|
|
phone: z
|
|
.string()
|
|
.min(1, 'Vui lòng nhập số điện thoại')
|
|
.regex(phoneRegex, 'Số điện thoại không hợp lệ'),
|
|
email: z
|
|
.string()
|
|
.email('Email không hợp lệ')
|
|
.optional()
|
|
.or(z.literal('')),
|
|
password: z
|
|
.string()
|
|
.min(8, 'Mật khẩu phải có ít nhất 8 ký tự'),
|
|
confirmPassword: z.string().min(1, 'Vui lòng xác nhận mật khẩu'),
|
|
})
|
|
.refine((data) => data.password === data.confirmPassword, {
|
|
message: 'Mật khẩu xác nhận không khớp',
|
|
path: ['confirmPassword'],
|
|
});
|
|
|
|
export type LoginFormData = z.infer<typeof loginSchema>;
|
|
export type RegisterFormData = z.infer<typeof registerSchema>;
|