From fc837f851c89614f392e5a17cd6a2ceda3f706f3 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Mon, 11 Aug 2025 16:32:03 +0700 Subject: more vals in confirm page --- src-migrate/validations/tempo.ts | 124 +++++----- .../pengajuan-tempo/component/PengajuanTempo.jsx | 250 +++++++++++++-------- 2 files changed, 218 insertions(+), 156 deletions(-) diff --git a/src-migrate/validations/tempo.ts b/src-migrate/validations/tempo.ts index f0623b6a..38380d5a 100644 --- a/src-migrate/validations/tempo.ts +++ b/src-migrate/validations/tempo.ts @@ -13,7 +13,8 @@ export const TempoSchema = z.object({ .string() .min(1, { message: 'Nomor telepon harus diisi' }) .refine((val) => /^\d{10,12}$/.test(val), { - message: 'Format nomor telepon tidak valid, contoh: 081234567890 atau 021234567890', + message: + 'Format nomor telepon tidak valid, contoh: 081234567890 atau 021234567890', }), bankName: z.string().min(1, { message: 'Nama bank harus diisi' }), accountName: z.string().min(1, { message: 'Nama rekening harus diisi' }), @@ -69,8 +70,8 @@ export const TempoSchemaKontakPerson = z }) .refine( (data) => - !data.financeEmail || // Jika financeEmail kosong, tidak perlu validasi - data.financeEmail !== data.purchasingEmail, // Validasi jika financeEmail ada + !data.financeEmail || + data.financeEmail !== data.purchasingEmail, { message: 'Email Finance tidak boleh sama dengan Email Purchasing', path: ['financeEmail'], @@ -86,70 +87,37 @@ export const TempoSchemaKontakPerson = z 'Email Direktur tidak boleh sama dengan Email Finance atau Purchasing', path: ['direkturEmail'], } - ); -export const TempoSchemaPengiriman = z.object({ - PICTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), - PICName: z.string().min(1, { message: 'Nama harus diisi' }), - streetPengiriman: z.string().min(1, { message: 'Alamat harus diisi' }), - statePengiriman: z.string().min(1, { message: 'Provinsi harus dipilih' }), - cityPengiriman: z.string().min(1, { message: 'Kota harus dipilih' }), - districtPengiriman: z.string().min(1, { message: 'Kecamatan harus dipilih' }), - subDistrictPengiriman: z.string().optional(), - zipPengiriman: z.string().min(1, { message: 'Kode pos harus diisi' }), - PICBarangMobile: z - .string() - .min(1, { message: 'Nomor telepon harus diisi' }) - .refine((val) => /^\d{10,12}$/.test(val), { - message: 'Format nomor telepon tidak valid, contoh: 081234567890 atau 021234567890', - }), - invoicePicMobile: z - .string() - .min(1, { message: 'Nomor telepon harus diisi' }) - .refine((val) => /^\d{10,12}$/.test(val), { - message: 'Format nomor telepon tidak valid, contoh: 081234567890 atau 021234567890', - }), - invoicePicTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), - invoicePic: z.string().min(1, { message: 'Nama pic invoice harus diisi' }), - streetInvoice: z.string().min(1, { message: 'Alamat invoice harus diisi' }), - stateInvoice: z - .string() - .min(1, { message: 'Provinsi invoice harus dipilih' }), - cityInvoice: z.string().min(1, { message: 'Kota invoice harus dipilih' }), - districtInvoice: z - .string() - .min(1, { message: 'Kecamatan invoice harus dipilih' }), - subDistrictInvoice: z.string().optional(), - zipInvoice: z.string().min(1, { message: 'Kode pos harus diisi' }), - isSameAddrees: z.string(), - isSameAddreesStreet: z.string(), - tukarInvoiceInput: z - .string() - .min(1, { message: 'Jadwal Penukaran Invoice Harus Diisi' }), - tukarInvoiceInputPembayaran: z - .string() - .min(1, { message: 'Jadwal Pembayaran Harus Diisi' }), - dokumenPengiriman: z.string().optional(), - dokumenPengirimanInput: z.string().optional(), - dokumenKirimInput: z.string().optional(), - dokumenPengirimanInvoiceInput: z.string().optional(), - dokumenProsedur: z.object({ - name: z.string().optional(), - format: z.string().optional(), - base64: z.string().optional(), - }), -}); -export const TempoSchemaSupplier = z.object({ - supplier: z.string().min(1, { message: 'Nama supplier harus diisi' }), - pic: z.string().min(1, { message: 'Nama PIC harus diisi' }), - telepon: z - .string() - .min(1, { message: 'Nomor telepon harus diisi' }) - .refine((val) => /^\d{10,12}$/.test(val), { - message: 'Format nomor telepon tidak valid, contoh: 081234567890 atau 021234567890', - }), - durasiTempo: z.string().min(1, { message: 'Durasi tempo harus diisi' }), - creditLimit: z.string().min(1, { message: 'Limit Kredit harus diisi' }), -}); + ) + .superRefine((data, ctx) => { + const phones = [ + { key: 'direkturMobile', label: 'No. HP Direktur', value: data.direkturMobile }, + { key: 'purchasingMobile', label: 'No. HP Purchasing', value: data.purchasingMobile }, + { key: 'financeMobile', label: 'No. HP Finance', value: data.financeMobile }, + ]; + + const seen = new Map(); + + for (const phone of phones) { + if (!phone.value) continue; + + if (!seen.has(phone.value)) { + seen.set(phone.value, { key: phone.key, label: phone.label }); + } else { + const first = seen.get(phone.value)!; + ctx.addIssue({ + code: 'custom', + path: [phone.key], + message: `${phone.label} tidak boleh sama dengan ${first.label}`, + }); + ctx.addIssue({ + code: 'custom', + path: [first.key], + message: `${first.label} tidak boleh sama dengan ${phone.label}`, + }); + } + } + }); + export const TempoSchemaDokumen = z.object({ dokumenNib: z.object({ name: z.string().min(1, { message: 'Nama file harus diisi' }), @@ -217,3 +185,25 @@ export const TempoSchemaDokumen = z.object({ base64: z.string().optional(), }), }); + +export const TempoSchemaPengiriman = z + .object({ + PICBarangMobile: z + .string() + .min(1, { message: 'Nomor telepon harus diisi' }) + .refine((val) => /^\d{10,12}$/.test(val), { + message: + 'Format nomor telepon tidak valid, contoh: 081234567890 atau 021234567890', + }), + invoicePicMobile: z + .string() + .min(1, { message: 'Nomor telepon harus diisi' }) + .refine((val) => /^\d{10,12}$/.test(val), { + message: + 'Format nomor telepon tidak valid, contoh: 081234567890 atau 021234567890', + }), + }); + // .refine((data) => data.PICBarangMobile !== data.invoicePicMobile, { + // message: 'Nomor HP PIC Barang tidak boleh sama dengan Nomor HP PIC Invoice', + // path: ['invoicePicMobile'], // error akan tampil di bawah field invoicePicMobile + // }); diff --git a/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx b/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx index d59bfd75..5f3dd08c 100644 --- a/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx +++ b/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx @@ -38,7 +38,7 @@ const PengajuanTempo = () => { const [bigData, setBigData] = useState(); const [idTempo, setIdTempo] = useState(0); const { form, errors, validate, updateForm } = usePengajuanTempoStore(); - const { control, watch, setValue } = useForm(); + const { control, watch, setValue, setError } = useForm(); const auth = useAuth(); const router = useRouter(); const [BannerTempo, setBannerTempo] = useState(); @@ -426,111 +426,185 @@ const PengajuanTempo = () => { } }; - const handleDaftarTempo = async () => { - for (const error of stepDivsError) { - if (error.length > 0) { - return; +const handleDaftarTempo = async () => { + const phones = [ + { key: 'mobile', label: 'No. HP Perusahaan', value: form.mobile }, + { + key: 'direkturMobile', + label: 'No. HP Direktur', + value: formKontakPerson.direkturMobile, + }, + { + key: 'purchasingMobile', + label: 'No. HP Purchasing', + value: formKontakPerson.purchasingMobile, + }, + { + key: 'financeMobile', + label: 'No. HP Finance', + value: formKontakPerson.financeMobile, + }, + { + key: 'PICBarangMobile', + label: 'No. HP PIC Barang', + value: formKontakPerson.PICBarangMobile, + }, + { + key: 'invoicePicMobile', + label: 'No. HP PIC Invoice', + value: formKontakPerson.invoicePicMobile, + }, + ].filter((p) => p.value); + + const seen = new Map(); + let firstErrorField = null; + + // 🔹 Reset error manual sebelum cek ulang + phones.forEach((p) => setError(p.key, { type: 'manual', message: '' })); + + for (const phone of phones) { + if (!seen.has(phone.value)) { + seen.set(phone.value, phone); + } else { + const first = seen.get(phone.value); + + // 🔹 Tampilkan toast + toast.error(`${phone.label} tidak boleh sama dengan ${first.label}`); + + // 🔹 Tampilkan error merah di bawah input + setError(phone.key, { + type: 'manual', + message: `${phone.label} tidak boleh sama dengan ${first.label}`, + }); + + // 🔹 Juga beri error untuk pasangan duplikat pertama + setError(first.key, { + type: 'manual', + message: `${first.label} tidak boleh sama dengan ${phone.label}`, + }); + + // 🔹 Simpan field pertama yang salah untuk scroll + if (!firstErrorField) { + firstErrorField = phone.key; } } + } + + if (firstErrorField) { + setTimeout(() => { + const el = document.querySelector(`[name="${firstErrorField}"]`); + if (el) { + el.scrollIntoView({ behavior: 'smooth', block: 'center' }); + el.focus(); + } + }, 100); + return; // ⛔ hentikan proses submit + } - // Filter hanya dokumen dengan `format` yang tidak undefined - const formattedDokumen = Object.entries(formDokumen) - .filter(([_, doc]) => doc.format !== undefined) // Hanya dokumen dengan `format` tidak undefined - .map(([key, doc]) => ({ - documentName: key, - details: { - name: doc.name, - format: doc.format, - base64: doc.base64, - }, - })); + for (const error of stepDivsError) { + if (error.length > 0) { + return; + } + } + + const formattedDokumen = Object.entries(formDokumen) + .filter(([_, doc]) => doc.format !== undefined) + .map(([key, doc]) => ({ + documentName: key, + details: { + name: doc.name, + format: doc.format, + base64: doc.base64, + }, + })); - const toastId = toast.loading('Mengirimkan formulir pengajuan tempo...'); - setIsLoading(true); - try { - let address4; - let address3; - const address = await createPengajuanTempoApi({ - id: 0, + const toastId = toast.loading('Mengirimkan formulir pengajuan tempo...'); + setIsLoading(true); + + try { + let address4; + let address3; + const address = await createPengajuanTempoApi({ + id: 0, + partner_id: auth.partnerId, + user_id: auth.parentId ? auth.parentId : auth.partnerId, + tempo_request: false, + ...form, + }); + + if (address.id) { + const address2 = await createPengajuanTempoApi({ + id: address.id, partner_id: auth.partnerId, - user_id: auth.parentId ? auth.parentId : auth.partnerId, + user_id: address.userId, tempo_request: false, - ...form, + ...formKontakPerson, }); - if (address.id) { - const address2 = await createPengajuanTempoApi({ - id: address.id, + + if (address2.id) { + address3 = await createPengajuanTempoApi({ + id: address2.id, partner_id: auth.partnerId, - user_id: address.userId, + user_id: address2.userId, tempo_request: false, - ...formKontakPerson, - }); - if (address2.id) { - address3 = await createPengajuanTempoApi({ - id: address2.id, - partner_id: auth.partnerId, - user_id: address2.userId, - tempo_request: false, - ...formPengiriman, - formDokumenProsedur: formPengiriman.dokumenProsedur + ...formPengiriman, + formDokumenProsedur: formPengiriman.dokumenProsedur ? JSON.stringify(formPengiriman.dokumenProsedur) : false, + }); + + if (address3.id && formattedDokumen.length > 0) { + address4 = await createPengajuanTempoApi({ + id: address3.id, + partner_id: auth.partnerId, + user_id: address3.userId, + tempo_request: true, + formDocs: JSON.stringify(formattedDokumen), + }); + } else { + address4 = await createPengajuanTempoApi({ + id: address3.id, + partner_id: auth.partnerId, + user_id: address3.userId, + tempo_request: true, }); - if (address3.id && formattedDokumen.length > 0) { - // Kirim dokumen yang sudah difilter - address4 = await createPengajuanTempoApi({ - id: address3.id, - partner_id: auth.partnerId, - user_id: address3.userId, - tempo_request: true, - formDocs: JSON.stringify(formattedDokumen), - }); - } else { - address4 = await createPengajuanTempoApi({ - id: address3.id, - partner_id: auth.partnerId, - user_id: address3.userId, - tempo_request: true, - }); - } } } + } - if (address4?.id) { - toast.success('Pengajuan tempo berhasil dilakukan'); - const toastId = toast.loading('Mengubah status akun...'); - const isUpdated = await editAuthTempo(); - if (isUpdated?.user) { - const update = await setAuth(isUpdated.user); - if (update) { - toast.dismiss(toastId); - setIsLoading(false); - toast.success('Berhasil mengubah status akun', { duration: 1000 }); - router.push('/pengajuan-tempo/finish'); - } else { - toast.dismiss(toastId); - setIsLoading(false); - toast.success('Pengajuan tempo berhasil dilakukan'); - toast.error('Gagal mengubah status akun', { duration: 1000 }); - router.push('/pengajuan-tempo'); - } - removeFromLocalStorage(); - return; + if (address4?.id) { + toast.success('Pengajuan tempo berhasil dilakukan'); + const toastId2 = toast.loading('Mengubah status akun...'); + const isUpdated = await editAuthTempo(); + if (isUpdated?.user) { + const update = await setAuth(isUpdated.user); + if (update) { + toast.dismiss(toastId2); + setIsLoading(false); + toast.success('Berhasil mengubah status akun', { duration: 1000 }); + router.push('/pengajuan-tempo/finish'); + } else { + toast.dismiss(toastId2); + setIsLoading(false); + toast.success('Pengajuan tempo berhasil dilakukan'); + toast.error('Gagal mengubah status akun', { duration: 1000 }); + router.push('/pengajuan-tempo'); } - } else { - toast.dismiss(toastId); - setIsLoading(false); - - toast.error('Terjadi kesalahan dalam pengiriman formulir'); + removeFromLocalStorage(); + return; } - } catch (error) { + } else { toast.dismiss(toastId); setIsLoading(false); - toast.error('Terjadi kesalahan dalam pengiriman formulir'); - console.error(error); } - }; + } catch (error) { + toast.dismiss(toastId); + setIsLoading(false); + toast.error('Terjadi kesalahan dalam pengiriman formulir'); + console.error(error); + } +}; const removeFromLocalStorage = () => { for (const key of stepLabels) { @@ -660,10 +734,8 @@ const PengajuanTempo = () => { isDisabled={!isCheckedTNC || isLoading} onClick={handleDaftarTempo} > - {isLoading - ? 'Loading...' - : 'Daftar Tempo'} - {!isLoading && } + {isLoading ? 'Loading...' : 'Daftar Tempo'} + {!isLoading && } )} -- cgit v1.2.3