mediahub-fe/types/registration.ts

247 lines
7.0 KiB
TypeScript
Raw Normal View History

import { z } from "zod";
// Base schemas for validation
export const registrationSchema = z.object({
firstName: z
.string()
.min(1, { message: "Full name is required" })
.min(2, { message: "Full name must be at least 2 characters" })
.max(100, { message: "Full name must be less than 100 characters" })
.regex(/^[a-zA-Z\s]+$/, { message: "Full name can only contain letters and spaces" }),
username: z
.string()
.min(1, { message: "Username is required" })
.min(3, { message: "Username must be at least 3 characters" })
.max(50, { message: "Username must be less than 50 characters" })
.regex(/^[a-zA-Z0-9._-]+$/, { message: "Username can only contain letters, numbers, dots, underscores, and hyphens" }),
phoneNumber: z
.string()
.min(1, { message: "Phone number is required" })
.regex(/^[0-9+\-\s()]+$/, { message: "Please enter a valid phone number" }),
email: z
.string()
.min(1, { message: "Email is required" })
.email({ message: "Please enter a valid email address" }),
address: z
.string()
.min(1, { message: "Address is required" })
.min(10, { message: "Address must be at least 10 characters" })
.max(500, { message: "Address must be less than 500 characters" }),
provinsi: z
.string()
.min(1, { message: "Province is required" }),
kota: z
.string()
.min(1, { message: "City is required" }),
kecamatan: z
.string()
.min(1, { message: "Subdistrict is required" }),
password: z
.string()
.min(1, { message: "Password is required" })
.min(8, { message: "Password must be at least 8 characters" })
.max(100, { message: "Password must be less than 100 characters" })
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/, {
message: "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character"
}),
passwordConf: z
.string()
.min(1, { message: "Password confirmation is required" }),
}).refine((data) => data.password === data.passwordConf, {
message: "Passwords don't match",
path: ["passwordConf"],
});
export const journalistRegistrationSchema = z.object({
journalistCertificate: z
.string()
.min(1, { message: "Journalist certificate number is required" })
.min(5, { message: "Journalist certificate number must be at least 5 characters" }),
association: z
.string()
.min(1, { message: "Association is required" }),
email: z
.string()
.min(1, { message: "Email is required" })
.email({ message: "Please enter a valid email address" }),
});
export const personnelRegistrationSchema = z.object({
policeNumber: z
.string()
.min(1, { message: "Police number is required" })
.min(5, { message: "Police number must be at least 5 characters" }),
email: z
.string()
.min(1, { message: "Email is required" })
.email({ message: "Please enter a valid email address" }),
});
export const generalRegistrationSchema = z.object({
email: z
.string()
.min(1, { message: "Email is required" })
.email({ message: "Please enter a valid email address" }),
});
export const instituteSchema = z.object({
2025-07-14 10:14:20 +00:00
id: z.string(),
name: z
.string()
.min(1, { message: "Institute name is required" })
.min(2, { message: "Institute name must be at least 2 characters" }),
address: z
.string()
.min(1, { message: "Institute address is required" })
.min(10, { message: "Institute address must be at least 10 characters" }),
});
// Inferred types from schemas
export type RegistrationFormData = z.infer<typeof registrationSchema>;
export type JournalistRegistrationData = z.infer<typeof journalistRegistrationSchema>;
export type PersonnelRegistrationData = z.infer<typeof personnelRegistrationSchema>;
export type GeneralRegistrationData = z.infer<typeof generalRegistrationSchema>;
export type InstituteData = z.infer<typeof instituteSchema>;
// API response types
export interface RegistrationResponse {
data?: {
id: string;
message: string;
};
error?: boolean;
message?: string;
}
export interface OTPRequestResponse {
data?: {
message: string;
};
error?: boolean;
message?: string;
}
export interface OTPVerificationResponse {
data?: {
message: string;
userData?: any;
};
error?: boolean;
message?: string;
}
export interface InstituteResponse {
data?: {
data: InstituteData[];
};
error?: boolean;
message?: string;
}
export interface LocationData {
id: number;
name: string;
provName?: string;
cityName?: string;
disName?: string;
}
export interface LocationResponse {
data?: {
data: LocationData[];
};
error?: boolean;
message?: string;
}
// Registration step types
export type RegistrationStep = "identity" | "otp" | "profile";
// User category types
export type UserCategory = "6" | "7" | "general"; // 6=Journalist, 7=Personnel, general=Public
// Component props types
export interface RegistrationLayoutProps {
children: React.ReactNode;
currentStep: RegistrationStep;
totalSteps: number;
className?: string;
}
export interface IdentityFormProps {
category: UserCategory;
onSuccess: (data: JournalistRegistrationData | PersonnelRegistrationData | GeneralRegistrationData) => void;
onError: (error: string) => void;
className?: string;
}
export interface RegistrationOTPFormProps {
email: string;
category: UserCategory;
memberIdentity?: string;
onSuccess: (userData: any) => void;
onError: (error: string) => void;
onResend: () => void;
className?: string;
}
export interface ProfileFormProps {
userData: any;
category: UserCategory;
onSuccess: (data: RegistrationFormData) => void;
onError: (error: string) => void;
className?: string;
}
export interface InstituteFormProps {
onInstituteChange: (institute: InstituteData | null) => void;
className?: string;
}
export interface LocationSelectorProps {
onProvinceChange: (provinceId: string) => void;
onCityChange: (cityId: string) => void;
onDistrictChange: (districtId: string) => void;
selectedProvince?: string;
selectedCity?: string;
selectedDistrict?: string;
className?: string;
}
// Registration state types
export interface RegistrationState {
currentStep: RegistrationStep;
category: UserCategory;
identityData: JournalistRegistrationData | PersonnelRegistrationData | GeneralRegistrationData | null;
userData: any;
loading: boolean;
error: string | null;
}
export interface RegistrationContextType extends RegistrationState {
setStep: (step: RegistrationStep) => void;
setIdentityData: (data: JournalistRegistrationData | PersonnelRegistrationData | GeneralRegistrationData) => void;
setUserData: (data: any) => void;
reset: () => void;
}
// Association types
export interface Association {
id: string;
name: string;
value: string;
}
// Timer types
export interface TimerState {
countdown: number;
isActive: boolean;
isExpired: boolean;
}
// Password validation types
export interface PasswordValidation {
isValid: boolean;
errors: string[];
strength: 'weak' | 'medium' | 'strong';
}