179 lines
5.3 KiB
TypeScript
179 lines
5.3 KiB
TypeScript
import { z } from 'zod'
|
|
|
|
const CommunicationBarrierSchema = z
|
|
.enum(['YA', 'TIDAK'], {
|
|
required_error: 'Mohon lengkapi Status Hambatan Berkomunikasi',
|
|
})
|
|
.transform((val) => val === 'YA')
|
|
|
|
const IsNewBornSchema = z
|
|
.enum(['YA', 'TIDAK'], {
|
|
required_error: 'Mohon lengkapi status pasien',
|
|
})
|
|
.transform((val) => val === 'YA')
|
|
|
|
const ACCEPTED_UPLOAD_TYPES = ['image/jpeg', 'image/png', 'application/pdf']
|
|
|
|
const PatientSchema = z
|
|
.object({
|
|
// Data Diri Pasien
|
|
identityNumber: z.string().optional(),
|
|
// .string({
|
|
// required_error: 'Mohon lengkapi NIK',
|
|
// })
|
|
// .min(16, 'NIK harus berupa angka 16 digit')
|
|
// .regex(/^\d+$/, 'NIK harus berupa angka 16 digit'),
|
|
residentIdentityFile: z
|
|
.any()
|
|
.optional()
|
|
.refine((f) => !f || f instanceof File, { message: 'Harus berupa file yang valid' })
|
|
.refine((f) => !f || ACCEPTED_UPLOAD_TYPES.includes(f.type), {
|
|
message: 'Format file harus JPG, PNG, atau PDF',
|
|
})
|
|
.refine((f) => !f || f.size <= 1 * 1024 * 1024, { message: 'Maksimal 1MB' }),
|
|
|
|
familyIdentityFile: z
|
|
.any()
|
|
.optional()
|
|
.refine((f) => !f || f instanceof File, { message: 'Harus berupa file yang valid' })
|
|
.refine((f) => !f || ACCEPTED_UPLOAD_TYPES.includes(f.type), {
|
|
message: 'Format file harus JPG, PNG, atau PDF',
|
|
})
|
|
.refine((f) => !f || f.size <= 1 * 1024 * 1024, { message: 'Maksimal 1MB' }),
|
|
// .refine(f => ['image/jpeg', 'image/png'].includes(f.type), 'Hanya JPG/PNG')
|
|
|
|
// Informasi Dasar
|
|
// alias: z.string({
|
|
// required_error: 'Mohon pilih sapaan',
|
|
// }),
|
|
fullName: z.string({
|
|
required_error: 'Mohon lengkapi Nama',
|
|
}),
|
|
birthPlace: z
|
|
.string({
|
|
required_error: 'Mohon lengkapi Tempat Lahir',
|
|
})
|
|
.min(1, 'Mohon lengkapi Tempat Lahir'),
|
|
birthDate: z
|
|
.string({
|
|
required_error: 'Mohon lengkapi Tanggal Lahir',
|
|
})
|
|
.refine(
|
|
(date) => {
|
|
// Jika kosong, return false untuk required validation
|
|
if (!date || date.trim() === '') return false
|
|
|
|
// Jika ada isi, validasi format tanggal
|
|
try {
|
|
const dateObj = new Date(date)
|
|
// Cek apakah tanggal valid dan tahun >= 1900
|
|
return !isNaN(dateObj.getTime()) && dateObj.getFullYear() >= 1900
|
|
} catch {
|
|
return false
|
|
}
|
|
},
|
|
{
|
|
message: 'Mohon lengkapi Tanggal Lahir dengan format yang valid',
|
|
},
|
|
)
|
|
.transform((dateStr) => new Date(dateStr).toISOString()),
|
|
|
|
// Jenis Kelamin & Status
|
|
gender: z.string({
|
|
required_error: 'Pilih Jenis Kelamin',
|
|
}),
|
|
maritalStatus: z.enum(['TIDAK_DIKETAHUI', 'BELUM_KAWIN', 'KAWIN', 'CERAI_HIDUP', 'CERAI_MATI'], {
|
|
required_error: 'Pilih Status Perkawinan',
|
|
}),
|
|
|
|
// Informasi Lokasi & Sosial
|
|
job: z
|
|
.string({
|
|
required_error: 'Mohon lengkapi Pekerjaan',
|
|
})
|
|
.min(1),
|
|
nationality: z.string({
|
|
required_error: 'Pilih Kebangsaan',
|
|
}),
|
|
isNewBorn: IsNewBornSchema,
|
|
language: z.string({
|
|
required_error: 'Mohon pilih Preferensi Bahasa',
|
|
}),
|
|
education: z
|
|
.string({
|
|
required_error: 'Mohon lengkapi Pendidikan',
|
|
})
|
|
.min(1),
|
|
religion: z
|
|
.string({
|
|
required_error: 'Pilih Kepercayaan',
|
|
})
|
|
.min(1),
|
|
ethnicity: z.string().optional(),
|
|
|
|
// Disabilitas
|
|
disability: z.enum(['YA', 'TIDAK'], {
|
|
required_error: 'Mohon lengkapi Status Disabilitas',
|
|
}),
|
|
disabilityType: z.string().optional(),
|
|
|
|
// Informasi Kontak
|
|
passportNumber: z.string().optional(),
|
|
communicationBarrier: CommunicationBarrierSchema,
|
|
|
|
note: z.string().optional(),
|
|
drivingLicenseNumber: z.string().optional(),
|
|
})
|
|
.refine(
|
|
(data) => {
|
|
// Jika disability = 'TIDAK', maka disabilityType harus kosong atau undefined
|
|
if (data.disability === 'TIDAK') {
|
|
return !data.disabilityType || data.disabilityType.trim() === ''
|
|
}
|
|
return true
|
|
},
|
|
{
|
|
message: "Jenis Disabilitas harus kosong jika Status Disabilitas = 'TIDAK'",
|
|
path: ['disabilityType'],
|
|
},
|
|
)
|
|
.refine(
|
|
(data) => {
|
|
// Jika disability = 'YA', maka disabilityType wajib diisi
|
|
if (data.disability === 'YA') {
|
|
return !!data.disabilityType?.trim()
|
|
}
|
|
return true
|
|
},
|
|
{
|
|
message: 'Mohon pilih Jenis Disabilitas',
|
|
path: ['disabilityType'],
|
|
},
|
|
)
|
|
// .refine((data) => {
|
|
// // Jika nationality = 'WNA', maka passportNumber wajib diisi
|
|
// if (data.nationality === 'WNA') {
|
|
// return !!data.passportNumber?.trim()
|
|
// }
|
|
// return true
|
|
// }, {
|
|
// message: 'Nomor Paspor wajib diisi untuk Warga Negara Asing',
|
|
// path: ['passportNumber'],
|
|
// })
|
|
.transform((data) => {
|
|
// Transform untuk backend: hanya kirim disabilityType sesuai kondisi
|
|
return {
|
|
...data,
|
|
// Jika disability = 'YA', kirim disabilityType
|
|
// Jika disability = 'TIDAK', kirim null untuk disabilityType
|
|
disabilityType: data.disability === 'YA' ? data.disabilityType : null,
|
|
// Hapus field disability karena yang dikirim ke backend adalah disabilityType
|
|
disability: undefined,
|
|
}
|
|
})
|
|
|
|
type PatientFormData = z.infer<typeof PatientSchema>
|
|
|
|
export { PatientSchema }
|
|
export type { PatientFormData }
|