diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js | 14 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/Dokumen.jsx | 952 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/FinishTempo.jsx | 78 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/Konfirmasi.jsx | 263 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/KonfirmasiDokumen.jsx | 1202 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/KontakPerusahaan.jsx | 586 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/PengajuanTempo.jsx | 352 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/Pengiriman.jsx | 1489 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/Referensi.jsx | 548 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/Stepper.jsx | 65 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/informasiPerusahaan.jsx | 1401 |
11 files changed, 6950 insertions, 0 deletions
diff --git a/src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js b/src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js new file mode 100644 index 00000000..af1d6c3a --- /dev/null +++ b/src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js @@ -0,0 +1,14 @@ +import odooApi from '@/core/api/odooApi'; +import { getAuth } from '@/core/utils/auth'; + +const createPengajuanTempoApi = async (data) => { + const auth = getAuth(); + const dataPengajuanTempo = await odooApi( + 'POST', + `/api/v1/partner/pengajuan_tempo`, + data + ); + return dataPengajuanTempo; +}; + +export default createPengajuanTempoApi; diff --git a/src/lib/pengajuan-tempo/component/Dokumen.jsx b/src/lib/pengajuan-tempo/component/Dokumen.jsx new file mode 100644 index 00000000..0873df66 --- /dev/null +++ b/src/lib/pengajuan-tempo/component/Dokumen.jsx @@ -0,0 +1,952 @@ +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { Controller, set, useForm } from 'react-hook-form'; +import { usePengajuanTempoStoreDokumen } from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import ProgressBar from '@ramonak/react-progress-bar'; +import { UseToastOptions } from '@chakra-ui/react'; +import { toast } from 'react-hot-toast'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import useDevice from '@/core/hooks/useDevice'; +const Dokumen = ({ chekValid, buttonSubmitClick, isKonfirmasi }) => { + const { control, watch } = useForm(); + const { + formDokumen, + errorsDokumen, + validateDokumen, + updateFormDokumen, + getJumlahDokumenDiisi, + } = usePengajuanTempoStoreDokumen(); + const { isDesktop, isMobile } = useDevice(); + // const handleInputChange = (event) => { + // const { name, value } = event.target; + // updateFormDokumen(name, value); + // validateDokumen(); + // }; + const handleInputChange = async (event) => { + let fileBase64 = ''; + const { name } = event.target; + const file = event.target.files?.[0]; + // Allowed file extensions + const allowedExtensions = ['pdf', 'png', 'jpg', 'jpeg']; + let fileExtension = ''; + if (file) { + fileExtension = file.name.split('.').pop()?.toLowerCase(); // Extract file extension + + // Check if the file extension is allowed + if (!fileExtension || !allowedExtensions.includes(fileExtension)) { + toast.error( + 'Format file yang diijinkan adalah .pdf, .png, .jpg, atau .jpeg', + { duration: 4000 } + ); + + event.target.value = ''; + return; + } + + // Check for file size + if (file.size > 2000000) { + toast.error('Maksimal ukuran file adalah 2MB', { duration: 4000 }); + + event.target.value = ''; + return; + } + + // Convert file to Base64 + fileBase64 = await getFileBase64(file); + updateFormDokumen(name, file.name, fileExtension, fileBase64); + validateDokumen(); + } + }; + + const isFormValid = useMemo( + () => Object.keys(errorsDokumen).length === 0, + [errorsDokumen] + ); + const dokumenNibRef = useRef(null); + const dokumenNpwpRef = useRef(null); + const dokumenSppkpRef = useRef(null); + const dokumenAktaPerubahanRef = useRef(null); + const dokumenKtpDirutRef = useRef(null); + const dokumenAktaPendirianRef = useRef(null); + const dokumenLaporanKeuanganRef = useRef(null); + const dokumenFotoKantorRef = useRef(null); + const dokumenTempatBekerjaRef = useRef(null); + + useEffect(() => { + const loadIndustries = async () => { + if (!isFormValid) { + const options = { + behavior: 'smooth', + block: 'center', + }; + if (errorsDokumen.dokumenNib && dokumenNibRef.current) { + dokumenNibRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenNpwp && dokumenNpwpRef.current) { + dokumenNpwpRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenSppkp && dokumenSppkpRef.current) { + dokumenSppkpRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenAktaPerubahan && + dokumenAktaPerubahanRef.current + ) { + dokumenAktaPerubahanRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenKtpDirut && dokumenKtpDirutRef.current) { + dokumenKtpDirutRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenAktaPendirian && + dokumenAktaPendirianRef.current + ) { + dokumenAktaPendirianRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenLaporanKeuangan && + dokumenLaporanKeuanganRef.current + ) { + dokumenLaporanKeuanganRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenFotoKantor && dokumenFotoKantorRef.current) { + dokumenFotoKantorRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenTempatBekerja && + dokumenTempatBekerjaRef.current + ) { + dokumenTempatBekerjaRef.current.scrollIntoView(options); + return; + } + } + }; + loadIndustries(); + }, [buttonSubmitClick, chekValid]); + + useEffect(() => { + validateDokumen(); + }, [buttonSubmitClick]); + return ( + <> + {isDesktop && ( + <div> + <h1 className={`font-bold ${isKonfirmasi ? 'text-xl' : ''}`}> + Dokumen + </h1> + <form className='flex mt-4 flex-col w-full '> + <div className='w-full grid grid-cols-[1fr_auto_1fr] gap-5'> + <div className='kolom-kiri w-full grid grid-rows-2 gap-7 '> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'> + NIB (SIUP/TDP/SKDP) + </label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenNib' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenNib' + name='dokumenNib' + type='file' + title=' ' + ref={dokumenNibRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenNib} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenNib?.name} + </span> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenNib} + </div> + )} + </div> + </div> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'> + NPWP Perusahaan + </label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenNpwp' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenNpwp' + name='dokumenNpwp' + type='file' + ref={dokumenNpwpRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenNpwp} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenNpwp?.name} + </span> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenNpwp} + </div> + )} + </div> + </div> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'>SPPKP</label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenSppkp' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen.dokumenSppkp} + id='dokumenSppkp' + name='dokumenSppkp' + type='file' + ref={dokumenSppkpRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenSppkp} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenSppkp?.name} + </span> + </div> + + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenSppkp} + </div> + )} + </div> + </div> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'> + Akta Perubahan{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenAktaPerubahan' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen.dokumenAktaPerubahan} + id='dokumenAktaPerubahan' + name='dokumenAktaPerubahan' + type='file' + ref={dokumenAktaPerubahanRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenAktaPerubahan} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenAktaPerubahan?.name} + </span> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenAktaPerubahan} + </div> + )} + </div> + </div> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'> + KTP Dirut/Direktur{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenKtpDirut' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen.dokumenKtpDirut} + id='dokumenKtpDirut' + name='dokumenKtpDirut' + type='file' + ref={dokumenKtpDirutRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenKtpDirut} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenKtpDirut?.name} + </span> + </div> + + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenKtpDirut} + </div> + )} + </div> + </div> + </div> + <div className='w-px bg-gray-300'></div> + <div className='kolom kanan w-full grid grid-rows-2 gap-10 '> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'> + Akta Pendirian{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenAktaPendirian' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen.dokumenAktaPendirian} + id='dokumenAktaPendirian' + name='dokumenAktaPendirian' + type='file' + ref={dokumenAktaPendirianRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenAktaPendirian} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenAktaPendirian?.name} + </span> + </div> + + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenAktaPendirian} + </div> + )} + </div> + </div> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'> + Laporan Keuangan + <span className=' opacity-60'>(Opsional)</span> + </label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenLaporanKeuangan' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen.dokumenLaporanKeuangan} + id='dokumenLaporanKeuangan' + name='dokumenLaporanKeuangan' + type='file' + ref={dokumenLaporanKeuanganRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenLaporanKeuangan} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenLaporanKeuangan?.name} + </span> + </div> + + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenLaporanKeuangan} + </div> + )} + </div> + </div> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'> + Foto Kantor (Tampak Depan) + </label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenFotoKantor' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen.dokumenFotoKantor} + id='dokumenFotoKantor' + name='dokumenFotoKantor' + type='file' + ref={dokumenFotoKantorRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenFotoKantor} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenFotoKantor?.name} + </span> + </div> + + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenFotoKantor} + </div> + )} + </div> + </div> + <div className='w-full grid grid-cols-2 gap-5'> + <div> + <label className='form-label text-nowrap'> + Tempat Bekerja + </label> + <span className='text-xs opacity-60'> + Pastikan dokumen yang anda upload sudah benar + </span> + </div> + <div className=''> + <div className='flex flex-col items-start'> + <label + htmlFor='dokumenTempatBekerja' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + Upload Dokumen + </label> + <input + // value={formDokumen.dokumenTempatBekerja} + id='dokumenTempatBekerja' + name='dokumenTempatBekerja' + type='file' + ref={dokumenTempatBekerjaRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenTempatBekerja} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600'> + {formDokumen?.dokumenTempatBekerja?.name} + </span> + </div> + + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenTempatBekerja} + </div> + )} + </div> + </div> + <div></div> + </div> + </div> + </form> + <div className='w-1/2 mt-8 flex gap-3 flex-col'> + <div className='flex justify-between'> + <p className='font-bold'>Upload Progress</p> + <p> + <span className='text-red-500 font-bold'> + {parseInt((getJumlahDokumenDiisi() / 9) * 100)} % + </span> + <span className='ml-2 opacity-60'> + {getJumlahDokumenDiisi() >= 4 + ? getJumlahDokumenDiisi() == 9 + ? 'Selesai' + : 'Sedikit Lagi' + : ''} + </span> + </p> + </div> + {/* 50 keatas baru muncul kata kata sedikit lagi */} + <ProgressBar + completed={getJumlahDokumenDiisi()} + bgColor='#ef4444' + labelAlignment='outside' + isLabelVisible={false} + baseBgColor='#E5E7EB' + labelColor='#e80909' + labelSize='0' + maxCompleted={9} + height='14 px' + /> + <span className='opacity-75'> + Tingkatin sedikit lagi agar pengajuan tempo kamu dapat kami proses + dengan cepat + </span> + </div> + </div> + )} + {isMobile && ( + <div> + <h1 + className={`font-bold py-4 mt-8 ${ + isKonfirmasi ? 'text-xl' : 'text-xl' + }`} + > + Dokumen + </h1> + <form className='flex mt-4 flex-col w-full '> + <div className='w-full flex flex-col gap-4'> + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + NIB (SIUP/TDP/SKDP) + </label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenNib' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenNib?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenNib' + name='dokumenNib' + type='file' + title=' ' + ref={dokumenNibRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenNib} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenNib?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenNib} + </div> + )} + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + NPWP Perusahaan + </label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenNpwp' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenNpwp?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenNpwp' + name='dokumenNpwp' + type='file' + ref={dokumenNpwpRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenNpwp} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenNpwp?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenNpwp} + </div> + )} + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'>SPPKP</label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenSppkp' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenSppkp?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenSppkp' + name='dokumenSppkp' + type='file' + ref={dokumenSppkpRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenSppkp} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenSppkp?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenSppkp} + </div> + )} + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + Akta Perubahan <span className=' opacity-60'>(Opsional)</span> + </label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenAktaPerubahan' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenAktaPerubahan?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenAktaPerubahan' + name='dokumenAktaPerubahan' + type='file' + ref={dokumenAktaPerubahanRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenAktaPerubahan} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenAktaPerubahan?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenAktaPerubahan} + </div> + )} + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + KTP Dirut/Direktur{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenKtpDirut' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenKtpDirut?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenKtpDirut' + name='dokumenKtpDirut' + type='file' + ref={dokumenKtpDirutRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenKtpDirut} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenKtpDirut?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenKtpDirut} + </div> + )} + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + Akta Pendirian <span className=' opacity-60'>(Opsional)</span> + </label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenAktaPendirian' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenAktaPendirian?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenAktaPendirian' + name='dokumenAktaPendirian' + type='file' + ref={dokumenAktaPendirianRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenAktaPendirian} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenAktaPendirian?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenAktaPendirian} + </div> + )} + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + Laporan Keuangan{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenLaporanKeuangan' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenLaporanKeuangan?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenLaporanKeuangan' + name='dokumenLaporanKeuangan' + type='file' + ref={dokumenLaporanKeuanganRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenLaporanKeuangan} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenLaporanKeuangan?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenLaporanKeuangan} + </div> + )} + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + Foto Kantor (Tampak Depan) + </label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenFotoKantor' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenFotoKantor?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenFotoKantor' + name='dokumenFotoKantor' + type='file' + ref={dokumenFotoKantorRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenFotoKantor} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenFotoKantor?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenFotoKantor} + </div> + )} + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + Tempat Bekerja + </label> + <div className='flex flex-row gap-2'> + <label + htmlFor='dokumenTempatBekerja' + className='cursor-pointer bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded w-fit min-w-40 text-nowrap text-center flex items-center justify-center' + > + {formDokumen?.dokumenTempatBekerja?.name + ? 'Sudah Upload' + : 'Upload Dokumen'} + </label> + <input + // value={formDokumen.dokumenNpwp} + id='dokumenTempatBekerja' + name='dokumenTempatBekerja' + type='file' + ref={dokumenTempatBekerjaRef} + title=' ' + className='hidden' + aria-invalid={errorsDokumen.dokumenTempatBekerja} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <span className='mt-2 text-gray-600 truncate'> + {formDokumen?.dokumenTempatBekerja?.name} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenTempatBekerja} + </div> + )} + </div> + </div> + </form> + <div className='w-full mt-8 flex gap-3 flex-col'> + <div className='flex justify-between'> + <p className='font-bold'>Upload Progress</p> + <p> + <span className='text-red-500 font-bold'> + {parseInt((getJumlahDokumenDiisi() / 9) * 100)} % + </span> + <span className='ml-2 opacity-60'> + {getJumlahDokumenDiisi() >= 4 + ? getJumlahDokumenDiisi() == 9 + ? 'Selesai' + : 'Sedikit Lagi' + : ''} + </span> + </p> + </div> + {/* 50 keatas baru muncul kata kata sedikit lagi */} + <ProgressBar + completed={getJumlahDokumenDiisi()} + bgColor='#ef4444' + labelAlignment='outside' + isLabelVisible={false} + baseBgColor='#E5E7EB' + labelColor='#e80909' + labelSize='0' + maxCompleted={9} + height='10px' + /> + <span className='opacity-75 text-xs text-red-500'> + Tingkatin sedikit lagi agar pengajuan tempo kamu dapat kami proses + dengan cepat + </span> + </div> + </div> + )} + </> + ); +}; + +export default Dokumen; diff --git a/src/lib/pengajuan-tempo/component/FinishTempo.jsx b/src/lib/pengajuan-tempo/component/FinishTempo.jsx new file mode 100644 index 00000000..1670314d --- /dev/null +++ b/src/lib/pengajuan-tempo/component/FinishTempo.jsx @@ -0,0 +1,78 @@ +import Link from 'next/link'; +import Image from '~/components/ui/image'; +import whatsappUrl from '@/core/utils/whatsappUrl'; +import { useEffect, useState } from 'react'; +import odooApi from '@/core/api/odooApi'; +import useDevice from '@/core/hooks/useDevice'; +import useAuth from '@/core/hooks/useAuth'; +import axios from 'axios'; +import { toast } from 'react-hot-toast'; +import { ChevronRightIcon, ChevronLeftIcon } from '@heroicons/react/24/outline'; + +const FinishTempo = ({ query }) => { + const [data, setData] = useState(); + const [transactionData, setTransactionData] = useState(); + const { isDesktop, isMobile } = useDevice(); + const auth = useAuth(); + + const so_order = query?.order_id?.replaceAll('-', '/'); + useEffect(() => { + const fetchData = async () => { + const fetchedData = await odooApi( + 'GET', + `/api/v1/sale_order_number?sale_number=${so_order}` + ); + setData(fetchedData[0]); + }; + fetchData(); + }, [query]); + + // Kirim email ketika komponen ini dimount atau sesuai kondisi + const sendEmail = async () => { + try { + const send = await axios.post( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/finish-checkout?orderName=${query?.order_id}`, + {} + ); + if (send.status === 200) { + toast.success('Berhasil mengirim rincian pesanan'); + } else { + toast.error('Gagal mengirimkan rincian pesanan'); + } + } catch (error) { + console.error(error); + toast.error('Gagal mengirimkan rincian pesanan'); + } + }; + + return ( + <div className='container flex flex-col items-center gap-4'> + <div className='flex w-2/3 justify-center items-center'> + <h1 className='text-red-500 text-center font-semibold text-3xl'> + Form Pengajuan Tempo kamu Telah Berhasil Didaftarkan Mohon menunggu + hingga Proses Selesai + </h1> + </div> + <Image + src='/images/REGISTRASI-TEMPO.svg' + alt='Checkout Pesanan' + width={isMobile ? 300 : 450} + height={isMobile ? 300 : 450} + /> + + <div className='mt-2 text-center leading-6 text-base p-4 md:p-0 w-4/5'> + Mohon menunggu untuk verifikasi dokumen dan kelengkapan data yang telah + anda berikan. Proses approval pembayaran tempo kamu berhasil atau tidak + akan diinfokan melalui email perusahaan / email yang mendaftar + </div> + <Link + href={`/my/quotations/${data?.id}`} + className='btn-solid-red rounded-md text-base flex flex-row' + > + Lihat Status Pendaftaran <ChevronRightIcon className='w-5' /> + </Link> + </div> + ); +}; + +export default FinishTempo; diff --git a/src/lib/pengajuan-tempo/component/Konfirmasi.jsx b/src/lib/pengajuan-tempo/component/Konfirmasi.jsx new file mode 100644 index 00000000..80845a8f --- /dev/null +++ b/src/lib/pengajuan-tempo/component/Konfirmasi.jsx @@ -0,0 +1,263 @@ +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { Controller, set, useForm } from 'react-hook-form'; +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'; +import { + usePengajuanTempoStoreDokumen, + usePengajuanTempoStore, +} from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import KontakPerusahaan from './KontakPerusahaan'; +import ProgressBar from '@ramonak/react-progress-bar'; +import { UseToastOptions } from '@chakra-ui/react'; +import odooApi from '~/libs/odooApi'; +import { toast } from 'react-hot-toast'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import { CheckCircleIcon } from '@heroicons/react/24/outline'; +import InformasiPerusahaan from './informasiPerusahaan'; +import Pengiriman from './Pengiriman'; +import KonfirmasiDokumen from './KonfirmasiDokumen'; +import useDevice from '@/core/hooks/useDevice'; +import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline'; +const Konfirmasi = ({ chekValid, buttonSubmitClick }) => { + const { control, watch, setValue, getValues } = useForm(); + const { isDesktop, isMobile } = useDevice(); + const [isOpen, setIsOpen] = useState(false); + const [industries, setIndustries] = useState([]); + const { + formDokumen, + errorsDokumen, + validateDokumen, + updateFormDokumen, + getJumlahDokumenDiisi, + } = usePengajuanTempoStoreDokumen(); + const { form, errors, validate, updateForm } = usePengajuanTempoStore(); + const handleInputChange = async (event) => { + let fileBase64 = ''; + const { name } = event.target; + const file = event.target.files?.[0]; + // Allowed file extensions + const allowedExtensions = ['pdf', 'png', 'jpg', 'jpeg']; + let fileExtension = ''; + if (file) { + fileExtension = file.name.split('.').pop()?.toLowerCase(); + + if (!fileExtension || !allowedExtensions.includes(fileExtension)) { + toast.error( + 'Format file yang diijinkan adalah .pdf, .png, .jpg, atau .jpeg', + { duration: 4000 } + ); + + event.target.value = ''; + return; + } + if (file.size > 2000000) { + toast.error('Maksimal ukuran file adalah 2MB', { duration: 4000 }); + + event.target.value = ''; + return; + } + + fileBase64 = await getFileBase64(file); + updateFormDokumen(name, file.name, fileExtension, fileBase64); + validateDokumen(); + } + }; + + const isFormValid = useMemo( + () => Object.keys(errorsDokumen).length === 0, + [errorsDokumen] + ); + const dokumenNibRef = useRef(null); + const dokumenNpwpRef = useRef(null); + const dokumenSppkpRef = useRef(null); + const dokumenAktaPerubahanRef = useRef(null); + const dokumenKtpDirutRef = useRef(null); + const dokumenAktaPendirianRef = useRef(null); + const dokumenLaporanKeuanganRef = useRef(null); + const dokumenFotoKantorRef = useRef(null); + const dokumenTempatBekerjaRef = useRef(null); + + useEffect(() => { + const loadIndustries = async () => { + if (!isFormValid) { + const options = { + behavior: 'smooth', + block: 'center', + }; + if (errorsDokumen.dokumenNib && dokumenNibRef.current) { + dokumenNibRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenNpwp && dokumenNpwpRef.current) { + dokumenNpwpRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenSppkp && dokumenSppkpRef.current) { + dokumenSppkpRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenAktaPerubahan && + dokumenAktaPerubahanRef.current + ) { + dokumenAktaPerubahanRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenKtpDirut && dokumenKtpDirutRef.current) { + dokumenKtpDirutRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenAktaPendirian && + dokumenAktaPendirianRef.current + ) { + dokumenAktaPendirianRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenLaporanKeuangan && + dokumenLaporanKeuanganRef.current + ) { + dokumenLaporanKeuanganRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenFotoKantor && dokumenFotoKantorRef.current) { + dokumenFotoKantorRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenTempatBekerja && + dokumenTempatBekerjaRef.current + ) { + dokumenTempatBekerjaRef.current.scrollIntoView(options); + return; + } + } + }; + loadIndustries(); + }, [buttonSubmitClick, chekValid]); + + useEffect(() => { + validateDokumen(); + }, [buttonSubmitClick]); + + useEffect(() => { + const loadIndustries = async () => { + const dataIndustries = await odooApi('GET', '/api/v1/partner/industry'); + setIndustries( + dataIndustries?.map((o) => ({ + value: o.id, + label: o.name, + category: o.category, + })) + ); + }; + loadIndustries(); + }, []); + + useEffect(() => { + const selectedIndustryType = industries.find( + (industry) => industry.value === watch('industry_id') + ); + if (selectedIndustryType) { + updateForm('industry_id', `${selectedIndustryType?.value}`); + validate(); + } + }, [watch('industry_id'), industries]); + + useEffect(() => { + if (form.industry_id) { + setValue('industry_id', parseInt(form.industry_id)); + } + }, [form]); + const handleLabelClick = () => { + setIndustriesOpen(!industriesOpen); + }; + return ( + <> + {isDesktop && ( + <form className='flex mt-4 flex-col w-full '> + <div className='w-full grid grid-cols-[1fr_auto_1fr] gap-5'> + <div className='w-full flex flex-col gap-5 '> + <div className=''> + <InformasiPerusahaan isKonfirmasi={true} /> + </div> + <div className='h-px bg-gray-300'></div> + <div className=''> + <KontakPerusahaan isKonfirmasi={true} /> + </div> + </div> + + <div className='w-px bg-gray-300'></div> + <div className='w-full grid grid-rows-[1fc_auto_1fc] gap-5'> + <div> + <Pengiriman isKonfirmasi={true} /> + </div> + <div className='h-px bg-gray-300'></div> + <div> + <KonfirmasiDokumen isKonfirmasi={true} /> + </div> + </div> + </div> + </form> + )} + {isMobile && ( + <form className='flex mt-8 py-4 flex-col w-full gap-4'> + <div className='flex flex-col gap-4'> + <div className='flex flex-row justify-between'> + <p className='font-semibold text-lg'>Informasi Perusahaan</p> + <div className='p-2 bg-gray-200'> + {isOpen ? ( + <ChevronUpIcon className='w-4' /> + ) : ( + <ChevronDownIcon className='w-4' /> + )} + </div> + </div> + <InformasiPerusahaan isKonfirmasi={true} /> + </div> + <div className='flex flex-col gap-4'> + <div className='flex flex-row justify-between'> + <p className='font-semibold text-lg'>Kontak Person</p> + <div className='p-2 bg-gray-200'> + {isOpen ? ( + <ChevronUpIcon className='w-4' /> + ) : ( + <ChevronDownIcon className='w-4' /> + )} + </div> + </div> + <KontakPerusahaan isKonfirmasi={true} /> + </div> + <div className='flex flex-col gap-4'> + <div className='flex flex-row justify-between'> + <p className='font-semibold text-lg'>Pengiriman</p> + <div className='p-2 bg-gray-200'> + {isOpen ? ( + <ChevronUpIcon className='w-4' /> + ) : ( + <ChevronDownIcon className='w-4' /> + )} + </div> + </div> + <Pengiriman isKonfirmasi={true} /> + </div> + <div className='flex flex-col gap-4'> + <div className='flex flex-row justify-between'> + <p className='font-semibold text-lg'>Dokumen</p> + <div className='p-2 bg-gray-200'> + {isOpen ? ( + <ChevronUpIcon className='w-4' /> + ) : ( + <ChevronDownIcon className='w-4' /> + )} + </div> + </div> + <KonfirmasiDokumen isKonfirmasi={true} /> + </div> + </form> + )} + </> + ); +}; + +export default Konfirmasi; diff --git a/src/lib/pengajuan-tempo/component/KonfirmasiDokumen.jsx b/src/lib/pengajuan-tempo/component/KonfirmasiDokumen.jsx new file mode 100644 index 00000000..9b0f1d8f --- /dev/null +++ b/src/lib/pengajuan-tempo/component/KonfirmasiDokumen.jsx @@ -0,0 +1,1202 @@ +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { Controller, set, useForm } from 'react-hook-form'; +import { usePengajuanTempoStoreDokumen } from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import ProgressBar from '@ramonak/react-progress-bar'; +import { UseToastOptions } from '@chakra-ui/react'; +import { toast } from 'react-hot-toast'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import Image from 'next/image'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import { EyeIcon } from '@heroicons/react/24/outline'; +import useDevice from '@/core/hooks/useDevice'; +const KonfirmasiDokumen = ({ chekValid, buttonSubmitClick, isKonfirmasi }) => { + const { control, watch } = useForm(); + const [isExample, setIsExample] = useState(false); + const { isDesktop, isMobile } = useDevice(); + const [base64, setBase64] = useState(); + const [pdfData, setPdfData] = useState(); + const [format, setFormat] = useState(); + const [popUpSource, setSource] = useState(); + const { + formDokumen, + errorsDokumen, + validateDokumen, + updateFormDokumen, + getJumlahDokumenDiisi, + } = usePengajuanTempoStoreDokumen(); + + const handleConfirmSubmit = (format, base64) => { + if (format == 'pdf') { + setFormat(`application/${format}`); + } else { + setFormat(`image/${format}`); + } + setBase64( + base64.trim().replace(/^"+/, '').replace(/"+$/, '').replaceAll('\\', '') + ); + setIsExample(!isExample); + }; + const handleInputChange = async (event) => { + let fileBase64 = ''; + const { name } = event.target; + const file = event.target.files?.[0]; + const allowedExtensions = ['pdf', 'png', 'jpg', 'jpeg']; + let fileExtension = ''; + if (file) { + fileExtension = file.name.split('.').pop()?.toLowerCase(); + + if (!fileExtension || !allowedExtensions.includes(fileExtension)) { + toast.error( + 'Format file yang diijinkan adalah .pdf, .png, .jpg, atau .jpeg', + { duration: 4000 } + ); + + event.target.value = ''; + return; + } + + if (file.size > 2000000) { + toast.error('Maksimal ukuran file adalah 2MB', { duration: 4000 }); + + event.target.value = ''; + return; + } + + fileBase64 = await getFileBase64(file); + updateFormDokumen(name, file.name, fileExtension, fileBase64); + validateDokumen(); + } + }; + + const isFormValid = useMemo( + () => Object.keys(errorsDokumen).length === 0, + [errorsDokumen] + ); + const dokumenNibRef = useRef(null); + const dokumenNpwpRef = useRef(null); + const dokumenSppkpRef = useRef(null); + const dokumenAktaPerubahanRef = useRef(null); + const dokumenKtpDirutRef = useRef(null); + const dokumenAktaPendirianRef = useRef(null); + const dokumenLaporanKeuanganRef = useRef(null); + const dokumenFotoKantorRef = useRef(null); + const dokumenTempatBekerjaRef = useRef(null); + + useEffect(() => { + const loadIndustries = async () => { + if (!isFormValid) { + const options = { + behavior: 'smooth', + block: 'center', + }; + if (errorsDokumen.dokumenNib && dokumenNibRef.current) { + dokumenNibRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenNpwp && dokumenNpwpRef.current) { + dokumenNpwpRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenSppkp && dokumenSppkpRef.current) { + dokumenSppkpRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenAktaPerubahan && + dokumenAktaPerubahanRef.current + ) { + dokumenAktaPerubahanRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenKtpDirut && dokumenKtpDirutRef.current) { + dokumenKtpDirutRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenAktaPendirian && + dokumenAktaPendirianRef.current + ) { + dokumenAktaPendirianRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenLaporanKeuangan && + dokumenLaporanKeuanganRef.current + ) { + dokumenLaporanKeuanganRef.current.scrollIntoView(options); + return; + } + if (errorsDokumen.dokumenFotoKantor && dokumenFotoKantorRef.current) { + dokumenFotoKantorRef.current.scrollIntoView(options); + return; + } + if ( + errorsDokumen.dokumenTempatBekerja && + dokumenTempatBekerjaRef.current + ) { + dokumenTempatBekerjaRef.current.scrollIntoView(options); + return; + } + } + }; + loadIndustries(); + }, [buttonSubmitClick, chekValid]); + + useEffect(() => { + validateDokumen(); + }, [buttonSubmitClick]); + + return ( + <> + {isDesktop && ( + <div> + <h1 className={`font-bold ${isKonfirmasi ? 'text-xl' : ''}`}> + Dokumen + </h1> + <form className='flex flex-col w-full gap-5'> + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + NIB (SIUP/TDP/SKDP) + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenNib?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenNib' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenNib' + name='dokumenNib' + type='file' + title=' ' + ref={dokumenNibRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenNib} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenNib.format, + formDokumen.dokumenNib.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenNib} + </div> + )} + </div> + </div> + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + NPWP Perusahaan + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenNpwp?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenNpwp' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenNpwp' + name='dokumenNpwp' + type='file' + title=' ' + ref={dokumenNpwpRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenNpwp} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenNpwp.format, + formDokumen.dokumenNpwp.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenNpwp} + </div> + )} + </div> + </div> + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'>SPPKP</label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenSppkp?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenSppkp' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenSppkp' + name='dokumenSppkp' + type='file' + title=' ' + ref={dokumenSppkpRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenSppkp} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenSppkp.format, + formDokumen.dokumenSppkp.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenSppkp} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + {' '} + Akta Perubahan <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenAktaPerubahan?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenAktaPerubahan' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenAktaPerubahan' + name='dokumendokumenAktaPerubahanSppkp' + type='file' + title=' ' + ref={dokumenAktaPerubahanRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenAktaPerubahan} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenAktaPerubahan.format, + formDokumen.dokumenAktaPerubahan.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenAktaPerubahan} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + KTP Dirut/Direktur{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenKtpDirut?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenKtpDirut' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenKtpDirut' + name='dokumenKtpDirut' + type='file' + title=' ' + ref={dokumenKtpDirutRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenKtpDirut} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenKtpDirut.format, + formDokumen.dokumenKtpDirut.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenKtpDirut} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Akta Pendirian <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenAktaPendirian?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenAktaPendirian' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenAktaPendirian' + name='dokumenAktaPendirian' + type='file' + title=' ' + ref={dokumenAktaPendirianRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenAktaPendirian} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenAktaPendirian.format, + formDokumen.dokumenAktaPendirian.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenAktaPendirian} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Laporan Keuangan + <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenLaporanKeuangan?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenLaporanKeuangan' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenLaporanKeuangan' + name='dokumenLaporanKeuangan' + type='file' + title=' ' + ref={dokumenLaporanKeuanganRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenLaporanKeuangan} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenLaporanKeuangan.format, + formDokumen.dokumenLaporanKeuangan.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenLaporanKeuangan} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Foto Kantor (Tampak Depan) + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenFotoKantor?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenFotoKantor' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenFotoKantor' + name='dokumenFotoKantor' + type='file' + title=' ' + ref={dokumenFotoKantorRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenFotoKantor} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenFotoKantor.format, + formDokumen.dokumenFotoKantor.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenFotoKantor} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Tempat Bekerja + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenTempatBekerja?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenTempatBekerja' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenTempatBekerja' + name='dokumenTempatBekerja' + type='file' + title=' ' + ref={dokumenTempatBekerjaRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenTempatBekerja} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenTempatBekerja.format, + formDokumen.dokumenTempatBekerja.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + {/* <Image + src={`data:image/png;base64, ${formDokumen.dokumenNib.base64}`} + alt='Contoh SPPKP' + className='w-full h-full ' + width={800} + height={800} + quality={85} + /> */} + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenTempatBekerja} + </div> + )} + </div> + </div> + </form> + </div> + )} + {isMobile && ( + <div> + <h1 className={`font-bold ${isKonfirmasi ? 'hidden' : 'text-xl'}`}> + Dokumen + </h1> + <form className='flex flex-col w-full gap-5 text-sm'> + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'> + NIB (SIUP/TDP/SKDP) + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-center justify-start'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenNib?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenNib' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenNib' + name='dokumenNib' + type='file' + title=' ' + ref={dokumenNibRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenNib} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenNib.format, + formDokumen.dokumenNib.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenNib} + </div> + )} + </div> + </div> + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'>NPWP Perusahaan</label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenNpwp?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenNpwp' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenNpwp' + name='dokumenNpwp' + type='file' + title=' ' + ref={dokumenNpwpRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenNpwp} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenNpwp.format, + formDokumen.dokumenNpwp.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenNpwp} + </div> + )} + </div> + </div> + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'>SPPKP</label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenSppkp?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenSppkp' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenSppkp' + name='dokumenSppkp' + type='file' + title=' ' + ref={dokumenSppkpRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenSppkp} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenSppkp.format, + formDokumen.dokumenSppkp.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenSppkp} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'> + {' '} + Akta Perubahan <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenAktaPerubahan?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenAktaPerubahan' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenAktaPerubahan' + name='dokumendokumenAktaPerubahanSppkp' + type='file' + title=' ' + ref={dokumenAktaPerubahanRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenAktaPerubahan} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenAktaPerubahan.format, + formDokumen.dokumenAktaPerubahan.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenAktaPerubahan} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'> + KTP Dirut/Direktur{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenKtpDirut?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenKtpDirut' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenKtpDirut' + name='dokumenKtpDirut' + type='file' + title=' ' + ref={dokumenKtpDirutRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenKtpDirut} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenKtpDirut.format, + formDokumen.dokumenKtpDirut.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenKtpDirut} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'> + Akta Pendirian <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenAktaPendirian?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenAktaPendirian' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenAktaPendirian' + name='dokumenAktaPendirian' + type='file' + title=' ' + ref={dokumenAktaPendirianRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenAktaPendirian} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenAktaPendirian.format, + formDokumen.dokumenAktaPendirian.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenAktaPendirian} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'> + Laporan Keuangan + <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenLaporanKeuangan?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenLaporanKeuangan' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenLaporanKeuangan' + name='dokumenLaporanKeuangan' + type='file' + title=' ' + ref={dokumenLaporanKeuanganRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenLaporanKeuangan} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenLaporanKeuangan.format, + formDokumen.dokumenLaporanKeuangan.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenLaporanKeuangan} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'> + Foto Kantor (Tampak Depan) + </label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenFotoKantor?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenFotoKantor' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenFotoKantor' + name='dokumenFotoKantor' + type='file' + title=' ' + ref={dokumenFotoKantorRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenFotoKantor} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenFotoKantor.format, + formDokumen.dokumenFotoKantor.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenFotoKantor} + </div> + )} + </div> + </div> + + <div className='w-full flex flex-row items-center '> + <div className='w-2/5'> + <label className='form-label text-wrap'>Tempat Bekerja</label> + </div> + <div className='w-3/5'> + <div className='flex flex-row items-start justify-between'> + <span className='w-3/5 text-gray-600 truncate'> + {formDokumen?.dokumenTempatBekerja?.name} + </span> + <div className='w-2/5 flex flex-row gap-2'> + <label + htmlFor='dokumenTempatBekerja' + className='cursor-pointer bg-red-500 hover:bg-red-600 text-white py-1 px-3 text-sm rounded' + > + Ubah + </label> + <input + // value={formDokumen?.dokumenNib?.name} + id='dokumenTempatBekerja' + name='dokumenTempatBekerja' + type='file' + title=' ' + ref={dokumenTempatBekerjaRef} + className='hidden' + aria-invalid={errorsDokumen.dokumenTempatBekerja} + onChange={handleInputChange} + accept='.pdf,.png,.jpg,.jpeg' + /> + <button + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + type='button' + onClick={() => + handleConfirmSubmit( + formDokumen.dokumenTempatBekerja.format, + formDokumen.dokumenTempatBekerja.base64 + ) + } + > + <EyeIcon className={`w-4 ${isDesktop && ''}`} /> + </button> + </div> + {/* <Image + src={`data:image/png;base64, ${formDokumen.dokumenNib.base64}`} + alt='Contoh SPPKP' + className='w-full h-full ' + width={800} + height={800} + quality={85} + /> */} + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsDokumen.dokumenTempatBekerja} + </div> + )} + </div> + </div> + </form> + </div> + )} + {isDesktop && ( + <BottomPopup + className='!container' + title='Dokumen' + active={isExample} + close={() => setIsExample(false)} + > + <div className='flex justify-center items-center p-2'> + {/* <embed + src={`data:${format};base64,${base64}`} + type={format} + width='100%' + height='600px' + /> */} + <iframe + src={`data:${format};base64,${base64}`} + width='100%' + height='100%' + title='Document' + ></iframe> + </div> + </BottomPopup> + )} + {isMobile && ( + <BottomPopup + className='!container' + title='Dokumen' + active={isExample} + close={() => setIsExample(false)} + > + <div className='flex justify-center items-center p-2'> + {/* <embed + src={`data:${format};base64,${base64}`} + type={format} + width='100%' + height='100%' + /> */} + <object + data={`data:${format};base64,${base64}`} + type={format} + width='100%' + height='100%' + onError={(e) => { + // Jika <object> gagal menampilkan PDF, unduh otomatis + const link = document.createElement('a'); + link.href = `data:${format};base64,${base64}`; + link.download = 'document.pdf'; + link.click(); + }} + > + PDF tidak dapat ditampilkan. + <a + href={`data:${format};base64,${base64}`} + download='document.pdf' + > + {' '} + Klik <span className='text-red-500'>di sini</span> untuk + mengunduh PDF + </a> + </object> + </div> + </BottomPopup> + )} + </> + ); +}; + +export default KonfirmasiDokumen; + +{ + /* <iframe + src={`data:application/octet-stream;base64, ${base64}`} + // src={`data:application/${format};base64, ${base64}`} + width='800px' + height='600px' + title='NPWP File' + frameBorder='0' + sandbox +></iframe> */ +} +{ + /* <Image + src={`data:image/${format};base64, ${base64}`} + alt='Contoh SPPKP' + className='w-full h-full ' + width={1200} + height={1200} + quality={85} +/> */ +} diff --git a/src/lib/pengajuan-tempo/component/KontakPerusahaan.jsx b/src/lib/pengajuan-tempo/component/KontakPerusahaan.jsx new file mode 100644 index 00000000..e7bfdbbe --- /dev/null +++ b/src/lib/pengajuan-tempo/component/KontakPerusahaan.jsx @@ -0,0 +1,586 @@ +import React, { useEffect, useMemo, useRef } from 'react'; +import { usePengajuanTempoStoreKontakPerson } from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import useDevice from '@/core/hooks/useDevice'; +const KontakPerusahaan = ({ chekValid, buttonSubmitClick, isKonfirmasi }) => { + const { + formKontakPerson, + errorsKontakPerson, + validateKontakPerson, + updateFormKontakPerson, + } = usePengajuanTempoStoreKontakPerson(); + const { isDesktop, isMobile } = useDevice(); + const handleInputChange = (event) => { + const { name, value } = event.target; + updateFormKontakPerson(name, value); + validateKontakPerson(); + }; + + const isFormValid = useMemo( + () => Object.keys(errorsKontakPerson).length === 0, + [errorsKontakPerson] + ); + + const direkturNameRef = useRef(null); + const direkturMobileRef = useRef(null); + const direkturEmailRef = useRef(null); + const purchasingNameRef = useRef(null); + const purchasingEmailRef = useRef(null); + const purchasingMobileRef = useRef(null); + const financeNameRef = useRef(null); + const financeMobileRef = useRef(null); + const financeEmailRef = useRef(null); + + useEffect(() => { + const loadIndustries = async () => { + if (!isFormValid) { + const options = { + behavior: 'smooth', + block: 'center', + }; + if (errorsKontakPerson.direkturName && direkturNameRef.current) { + direkturNameRef.current.scrollIntoView(options); + return; + } + if (errorsKontakPerson.direkturMobile && direkturMobileRef.current) { + direkturMobileRef.current.scrollIntoView(options); + return; + } + if (errorsKontakPerson.direkturEmail && direkturEmailRef.current) { + direkturEmailRef.current.scrollIntoView(options); + return; + } + if (errorsKontakPerson.purchasingName && purchasingNameRef.current) { + purchasingNameRef.current.scrollIntoView(options); + return; + } + if ( + errorsKontakPerson.purchasingMobile && + purchasingMobileRef.current + ) { + purchasingMobileRef.current.scrollIntoView(options); + return; + } + if (errorsKontakPerson.purchasingEmail && purchasingEmailRef.current) { + purchasingEmailRef.current.scrollIntoView(options); + return; + } + if (errorsKontakPerson.financeName && financeNameRef.current) { + financeNameRef.current.scrollIntoView(options); + return; + } + if (errorsKontakPerson.financeMobile && financeMobileRef.current) { + financeMobileRef.current.scrollIntoView(options); + return; + } + if (errorsKontakPerson.financeEmail && financeEmailRef.current) { + financeEmailRef.current.scrollIntoView(options); + return; + } + } + }; + loadIndustries(); + }, [buttonSubmitClick, chekValid]); + + useEffect(() => { + validateKontakPerson(); + }, [buttonSubmitClick]); + return ( + <> + {isDesktop && ( + <div className=''> + <h1 className={`font-bold ${isKonfirmasi ? 'text-xl' : ''}`}> + Kontak Person + </h1> + <form className='flex flex-col w-full '> + <div className='w-full grid grid-row-2 gap-5'> + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Lengkap Direktur + </label> + </div> + <div className='w-3/5'> + <input + value={formKontakPerson.direkturName} + id='direkturName' + name='direkturName' + placeholder='Masukkan nama direktur anda' + type='text' + className='form-input' + aria-invalid={errorsKontakPerson.direkturName} + ref={direkturNameRef} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.direkturName} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + No. Telpon Direktur + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi nomor telpon direktur di perusahaan kamu + </span> + )} + </div> + <div className='w-3/5'> + <input + id='direkturMobile' + name='direkturMobile' + ref={direkturMobileRef} + placeholder='Masukkan nomor direktur anda' + type='tel' + value={formKontakPerson.direkturMobile} + className='form-input' + aria-invalid={errorsKontakPerson.direkturMobile} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.direkturMobile} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Email Direktur + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi email Direktur yang sesuai + </span> + )} + </div> + <div className='w-3/5'> + <input + id='direkturEmail' + name='direkturEmail' + ref={direkturEmailRef} + placeholder='contoh@email.com' + type='email' + value={formKontakPerson.direkturEmail} + className='form-input' + aria-invalid={errorsKontakPerson.direkturEmail} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.direkturEmail} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Purchasing + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi nama purchasing yang bertanggung jawab di perusahaan + anda + </span> + )} + </div> + <div className='w-3/5'> + <input + id='purchasingName' + name='purchasingName' + ref={purchasingNameRef} + placeholder='Masukkan nama purchasing anda' + value={formKontakPerson.purchasingName} + type='text' + className='form-input' + aria-invalid={errorsKontakPerson.purchasingName} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.purchasingName} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + No. Telpon Purchasing + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi nomor purchasing yang bertanggung jawab di perusahaan + anda + </span> + )} + </div> + <div className='w-3/5'> + <input + id='purchasingMobile' + name='purchasingMobile' + ref={financeMobileRef} + placeholder='Masukkan nomor purchasing anda' + value={formKontakPerson.purchasingMobile} + type='tel' + className='form-input' + aria-invalid={errorsKontakPerson.purchasingMobile} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.purchasingMobile} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Email Purchasing + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi email purchasing dengan benar + </span> + )} + </div> + <div className='w-3/5'> + <input + id='purchasingEmail' + name='purchasingEmail' + ref={purchasingEmailRef} + placeholder='contoh@email.com' + value={formKontakPerson.purchasingEmail} + type='email' + className='form-input' + aria-invalid={errorsKontakPerson.purchasingEmail} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.purchasingEmail} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Finance + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi nama finance yang bertanggung jawab di perusahaan anda + </span> + )} + </div> + <div className='w-3/5'> + <input + id='financeName' + name='financeName' + ref={financeNameRef} + placeholder='Masukkan nama finance' + value={formKontakPerson.financeName} + type='text' + className='form-input' + aria-invalid={errorsKontakPerson.financeName} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.financeName} + </div> + )} + </div> + </div> + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + No. Telpon Finance + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi nomor finance yang bertanggung jawab di perusahaan + anda + </span> + )} + </div> + <div className='w-3/5'> + <input + id='financeMobile' + name='financeMobile' + ref={financeMobileRef} + placeholder='Masukkan nomor finance' + value={formKontakPerson.financeMobile} + type='tel' + className='form-input' + aria-invalid={errorsKontakPerson.financeMobile} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.financeMobile} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Email Finance + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi email finance dengan benar + </span> + )} + </div> + <div className='w-3/5'> + <input + id='financeEmail' + name='financeEmail' + ref={financeEmailRef} + placeholder='contoh@email.com' + type='email' + value={formKontakPerson.financeEmail} + className='form-input' + aria-invalid={errorsKontakPerson.financeEmail} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.financeEmail} + </div> + )} + </div> + </div> + </div> + </form> + </div> + )} + {isMobile && ( + <div className='text-sm'> + <h1 + className={`font-bold py-4 mt-8 ${ + isKonfirmasi ? 'hidden' : 'text-xl' + }`} + > + Kontak Person + </h1> + <form className='flex flex-col w-full '> + <div className='w-full grid grid-row-2 gap-4'> + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Nama Lengkap Direktur + </label> + <input + value={formKontakPerson.direkturName} + id='direkturName' + name='direkturName' + placeholder='Masukkan nama direktur anda' + type='text' + className='form-input' + aria-invalid={errorsKontakPerson.direkturName} + ref={direkturNameRef} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.direkturName} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + No. Telpon Direktur + </label> + <input + id='direkturMobile' + name='direkturMobile' + ref={direkturMobileRef} + placeholder='Masukkan nomor direktur anda' + type='tel' + value={formKontakPerson.direkturMobile} + className='form-input' + aria-invalid={errorsKontakPerson.direkturMobile} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.direkturMobile} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Email Direktur + </label> + <input + id='direkturEmail' + name='direkturEmail' + ref={direkturEmailRef} + placeholder='contoh@email.com' + type='email' + value={formKontakPerson.direkturEmail} + className='form-input' + aria-invalid={errorsKontakPerson.direkturEmail} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.direkturEmail} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Nama Purchasing + </label> + <input + id='purchasingName' + name='purchasingName' + ref={purchasingNameRef} + placeholder='Masukkan nama purchasing anda' + value={formKontakPerson.purchasingName} + type='text' + className='form-input' + aria-invalid={errorsKontakPerson.purchasingName} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.purchasingName} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + No. Telpon Purchasing + </label> + <input + id='purchasingMobile' + name='purchasingMobile' + ref={financeMobileRef} + placeholder='Masukkan nomor purchasing anda' + value={formKontakPerson.purchasingMobile} + type='tel' + className='form-input' + aria-invalid={errorsKontakPerson.purchasingMobile} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.purchasingMobile} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Email Purchasing + </label> + <input + id='purchasingEmail' + name='purchasingEmail' + ref={purchasingEmailRef} + placeholder='contoh@email.com' + value={formKontakPerson.purchasingEmail} + type='email' + className='form-input' + aria-invalid={errorsKontakPerson.purchasingEmail} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.purchasingEmail} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'>Nama Finance</label> + <input + id='financeName' + name='financeName' + ref={financeNameRef} + placeholder='Masukkan nama finance' + value={formKontakPerson.financeName} + type='text' + className='form-input' + aria-invalid={errorsKontakPerson.financeName} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.financeName} + </div> + )} + </div> + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + No. Telpon Finance + </label> + <input + id='financeMobile' + name='financeMobile' + ref={financeMobileRef} + placeholder='Masukkan nomor finance' + value={formKontakPerson.financeMobile} + type='tel' + className='form-input' + aria-invalid={errorsKontakPerson.financeMobile} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.financeMobile} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'>Email Finance</label> + <input + id='financeEmail' + name='financeEmail' + ref={financeEmailRef} + placeholder='contoh@email.com' + type='email' + value={formKontakPerson.financeEmail} + className='form-input' + aria-invalid={errorsKontakPerson.financeEmail} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsKontakPerson.financeEmail} + </div> + )} + </div> + </div> + </form> + </div> + )} + </> + ); +}; + +export default KontakPerusahaan; diff --git a/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx b/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx new file mode 100644 index 00000000..d0e1fcc6 --- /dev/null +++ b/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx @@ -0,0 +1,352 @@ +import React from 'react'; +import { useMemo, useState, useEffect, useRef } from 'react'; +import Stepper from './Stepper'; +import InformasiPerusahaan from './informasiPerusahaan'; +import KontakPerusahaan from './KontakPerusahaan'; +import Pengiriman from './Pengiriman'; +import Referensi from './Referensi'; +import Dokumen from './Dokumen'; +import Konfirmasi from './Konfirmasi'; +import useAuth from '@/core/hooks/useAuth'; +import { useRouter } from 'next/router'; +import { Controller, useForm } from 'react-hook-form'; +import { + usePengajuanTempoStore, + usePengajuanTempoStoreKontakPerson, + usePengajuanTempoStorePengiriman, + usePengajuanTempoStoreSupplier, + usePengajuanTempoStoreDokumen, +} from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import { ChevronRightIcon, ChevronLeftIcon } from '@heroicons/react/24/outline'; +import createPengajuanTempoApi from '../api/createPengajuanTempoApi'; +import { Button, Checkbox, Spinner, Tooltip } from '@chakra-ui/react'; +import clsxm from '~/libs/clsxm'; +import { toast } from 'react-hot-toast'; +import useDevice from '@/core/hooks/useDevice'; +const PengajuanTempo = () => { + const { isDesktop, isMobile } = useDevice(); + const [currentStep, setCurrentStep] = React.useState(0); + const NUMBER_OF_STEPS = 6; + const [isLoading, setIsLoading] = useState(false); + const { form, errors, validate, updateForm } = usePengajuanTempoStore(); + const { control, watch, setValue } = useForm(); + const auth = useAuth(); + const router = useRouter(); + const { formDokumen, errorsDokumen, validateDokumen, updateFormDokumen } = + usePengajuanTempoStoreDokumen(); + const { + formKontakPerson, + errorsKontakPerson, + validateKontakPerson, + updateFormKontakPerson, + } = usePengajuanTempoStoreKontakPerson(); + const { + formSupplier, + errorsSupplier, + validateSupplier, + updateFormSupplier, + hasSavedata, + updateHasSave, + } = usePengajuanTempoStoreSupplier(); + const { + formPengiriman, + errorsPengiriman, + validatePengiriman, + updateFormPengiriman, + } = usePengajuanTempoStorePengiriman(); + const [notValid, setNotValid] = useState(false); + const [buttonSubmitClick, setButtonSubmitClick] = useState(false); + const stepDivs = [ + <InformasiPerusahaan + key='informasi-perusahaan' + chekValid={notValid} + buttonSubmitClick={buttonSubmitClick} + />, + <KontakPerusahaan + key='kontak-perusahaan' + chekValid={notValid} + buttonSubmitClick={buttonSubmitClick} + />, + <Pengiriman + key='pengiriman' + chekValid={notValid} + buttonSubmitClick={buttonSubmitClick} + />, + <Referensi + key='referensi' + chekValid={notValid} + buttonSubmitClick={buttonSubmitClick} + />, + <Dokumen + key='dokumen' + chekValid={notValid} + buttonSubmitClick={buttonSubmitClick} + />, + <Konfirmasi + key='konfirmasi' + chekValid={notValid} + buttonSubmitClick={buttonSubmitClick} + />, + ]; + + const stepDivsError = [ + errors, + errorsKontakPerson, + errorsPengiriman, + errorsSupplier, + errorsDokumen, + <div key='konfirmasi'>Konfirmasi</div>, + ]; + const stepDivsForm = [ + form, + formKontakPerson, + formPengiriman, + formSupplier, + formDokumen, + '', + ]; + const stepDivsUpdateForm = [ + updateForm, + updateFormKontakPerson, + updateFormPengiriman, + updateFormSupplier, + updateFormDokumen, + <div key='konfirmasi'>Konfirmasi</div>, + ]; + const stepLabels = [ + 'informasi_perusahaan', + 'kontak_person', + 'Pengiriman', + 'Referensi', + 'Dokumen', + 'Konfirmasi', + ]; + const isFormValid = useMemo( + () => Object.keys(stepDivsError[currentStep]).length === 0, + [stepDivsError[currentStep]] + ); + useEffect(() => { + validate(); + validateKontakPerson(); + validatePengiriman(); + validateDokumen(); + updateHasSave(false); + + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + }, [currentStep, buttonSubmitClick]); + + useEffect(() => { + const cachedData = getFromLocalStorage(stepLabels[currentStep]); + if (cachedData) { + if (currentStep == 3) { + stepDivsUpdateForm[currentStep](cachedData); + } else if (currentStep == 4) { + Object.keys(cachedData).forEach((key) => { + const { name, format, base64 } = cachedData[key]; + stepDivsUpdateForm[currentStep](key, name, format, base64); + }); + } else { + Object.keys(cachedData).forEach((key) => { + stepDivsUpdateForm[currentStep](key, cachedData[key]); + }); + } + } + validate(); + validateKontakPerson(); + validatePengiriman(); + validateDokumen(); + updateHasSave(false); + }, [currentStep]); + const goToNextStep = () => { + if (!isFormValid) { + setNotValid(true); + setButtonSubmitClick(!buttonSubmitClick); + return; + } else { + saveToLocalStorage(stepLabels[currentStep], stepDivsForm[currentStep]); + setButtonSubmitClick(!buttonSubmitClick); + setNotValid(false); + } + setCurrentStep((prev) => (prev === NUMBER_OF_STEPS - 1 ? prev : prev + 1)); + }; + + const handleDaftarTempo = async () => { + for (const error of stepDivsError) { + if (error.length > 0) { + return; + } + } + const productOrder = formSupplier.map((product) => ({ + supplier: product.supplier, + pic: product.pic, + telepon: product.telepon, + durasiTempo: product.durasiTempo, + creditLimit: product.creditLimit, + })); + + const formattedDokumen = Object.entries(formDokumen).map(([key, doc]) => ({ + documentName: key, + details: { + name: doc.name, + format: doc.format, + base64: doc.base64, + }, + })); + + const data2 = { + user_id: auth.id, + ...form, + ...formKontakPerson, + ...formPengiriman, + formDocs: JSON.stringify(formattedDokumen), + formSupplier: JSON.stringify(productOrder), + }; + const toastId = toast.loading('Mengirimkan formulir pengajuan tempo...'); + setIsLoading(true); + try { + let address5; + const address = await createPengajuanTempoApi({ + id: '0', + user_id: auth.id, + ...form, + }); + if (address.id) { + const address2 = await createPengajuanTempoApi({ + id: address.id, + user_id: address.userId, + ...formKontakPerson, + }); + if (address2.id) { + const address3 = await createPengajuanTempoApi({ + id: address2.id, + user_id: address2.userId, + ...formPengiriman, + }); + if (address3.id) { + const address4 = await createPengajuanTempoApi({ + id: address3.id, + user_id: address3.userId, + formDocs: JSON.stringify(formattedDokumen), + }); + if (address4.id) { + address5 = await createPengajuanTempoApi({ + id: address4.id, + user_id: address4.userId, + tempo_request: true, + formSupplier: JSON.stringify(productOrder), + }); + } + } + } + } + toast.dismiss(toastId); + setIsLoading(false); + + if (address5.id) { + toast.success('Pengajuan tempo berhasil dilakukan'); + // removeFromLocalStorage(); + router.push('/pengajuan-tempo/finish?tempo_id=SO-2023-06480'); + } + } catch (error) { + toast.dismiss(toastId); + setIsLoading(false); + + toast.error('Terjadi kesalahan dalam pengiriman formulir'); + console.error(error); + } + }; + + const goToPreviousStep = () => { + setCurrentStep((prev) => (prev <= 0 ? prev : prev - 1)); + }; + + const saveToLocalStorage = (key, form) => { + localStorage.setItem(key, JSON.stringify(form)); + }; + + const getFromLocalStorage = (key) => { + const itemStr = localStorage.getItem(key); + if (!itemStr) return null; + + const item = JSON.parse(itemStr); + return item; + }; + const removeFromLocalStorage = () => { + for (const key of stepLabels) { + localStorage.removeItem(key); + } + }; + + return ( + <> + <div className='container flex flex-col items-center '> + <h1 className='text-h-sm md:text-title-sm font-semibold text-center mb-6'> + Form Pengajuan Tempo + </h1> + <p className='text-center mb-4'> + Lorem ipsum dolor sit amet consectetur. Commodo suspendisse at enim + magnis ut quisque rhoncus. Felis volutpat fringilla sollicitudin + ultricies. Enim non eget in lorem netus. Nisl pharetra accumsan diam + suspendisse. + </p> + </div> + <div className='h-[2px] w-full mb-20 bg-gray_r-3' /> + + <div className='container mt-10 flex flex-col'> + <div className='flex items-center justify-center'> + <Stepper currentStep={currentStep} numberOfSteps={NUMBER_OF_STEPS} /> + </div> + <div>{stepDivs[currentStep]}</div> + {isDesktop && <section className='flex gap-10 mt-10'></section>} + {isMobile && ( + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 mt-4 mb-4 relative transform -translate-x-5'></div> + )} + <div + className={`flex ${ + isMobile + ? 'flex-col justify-start items-start' + : 'flex-row justify-end items-center' + } gap-4 mb-8`} + > + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + {currentStep < 5 && ( + <Tooltip + label={clsxm({ + 'Klik simpan data terlebih dahulu': + currentStep === 3 && !hasSavedata, + })} + > + <Button + colorScheme='red' + w={`${isMobile ? 'full' : 'fit'}`} + isDisabled={ + (currentStep === 3 && !hasSavedata) || + currentStep === NUMBER_OF_STEPS - 1 + } + onClick={goToNextStep} + > + Langkah Selanjutnya {<ChevronRightIcon className='w-5' />} + </Button> + </Tooltip> + )} + {currentStep == 5 && ( + <Button + colorScheme='red' + w={`${isMobile ? 'full' : 'fit'}`} + onClick={handleDaftarTempo} + > + Daftar Tempo {<ChevronRightIcon className='w-5' />} + </Button> + )} + </div> + </div> + </> + ); +}; + +export default PengajuanTempo; diff --git a/src/lib/pengajuan-tempo/component/Pengiriman.jsx b/src/lib/pengajuan-tempo/component/Pengiriman.jsx new file mode 100644 index 00000000..842e43ef --- /dev/null +++ b/src/lib/pengajuan-tempo/component/Pengiriman.jsx @@ -0,0 +1,1489 @@ +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { Controller, set, useForm } from 'react-hook-form'; +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'; +import odooApi from '~/libs/odooApi'; +import stateApi from '@/lib/address/api/stateApi.js'; +import cityApi from '@/lib/address/api/cityApi'; +import { Radio, RadioGroup, Stack, Checkbox } from '@chakra-ui/react'; +import { usePengajuanTempoStorePengiriman } from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import useDevice from '@/core/hooks/useDevice'; +const Pengiriman = ({ chekValid, buttonSubmitClick, isKonfirmasi }) => { + const { control, watch, setValue } = useForm(); + const { isDesktop, isMobile } = useDevice(); + const { + formPengiriman, + errorsPengiriman, + validatePengiriman, + updateFormPengiriman, + } = usePengajuanTempoStorePengiriman(); + const [states, setState] = useState([]); + const [cities, setCities] = useState([]); + const [sameAddress, setSameAddress] = useState(false); + const [everyWeekday, setEveryWeekday] = useState(false); + const [everyWeek, setEveryWeek] = useState(false); + const [tukarInvoice, setTukarInvoice] = useState(false); + const [everyWeekdayPembayaran, setEveryWeekdayPembayaran] = useState(false); + const [everyWeekPembayaran, setEveryWeekPembayaran] = useState(false); + const [tukarInvoicePembayaran, setTukarInvoicePembayaran] = useState(false); + const [selectedIds, setSelectedIds] = useState( + formPengiriman.dokumenPengiriman + ? formPengiriman.dokumenPengiriman.split(',').map(Number) + : [] + ); + const [selectedIdsDokumenInvoice, setSelectedIdsselectedIdsDokumenInvoice] = + useState( + formPengiriman.dokumenPengirimanInvoice + ? formPengiriman.dokumenPengirimanInvoice.split(',').map(Number) + : [] + ); + + const handleCheckboxChange = (id) => { + const updatedSelected = selectedIds.includes(id) + ? selectedIds.filter((selectedId) => selectedId !== id) + : [...selectedIds, id]; + + setSelectedIds(updatedSelected); + + // Jika checkbox 'Lainnya' dipilih, aktifkan input custom + + updateFormPengiriman('dokumenPengiriman', updatedSelected.join(',')); + validatePengiriman(); + }; + const handleCheckboxChangeDokumenPengirimanInvoice = (id) => { + const updatedSelected = selectedIdsDokumenInvoice.includes(id) + ? selectedIdsDokumenInvoice.filter((selectedId) => selectedId !== id) + : [...selectedIdsDokumenInvoice, id]; + + setSelectedIdsselectedIdsDokumenInvoice(updatedSelected); + + // Jika checkbox 'Lainnya' dipilih, aktifkan input custom + + updateFormPengiriman('dokumenPengirimanInvoice', updatedSelected.join(',')); + validatePengiriman(); + }; + + useEffect(() => { + if (formPengiriman.dokumenPengiriman) { + setSelectedIds(formPengiriman.dokumenPengiriman.split(',').map(Number)); // Parse string menjadi array angka + } + }, [formPengiriman.dokumenPengiriman]); + useEffect(() => { + if (formPengiriman.dokumenPengirimanInvoice) { + setSelectedIdsselectedIdsDokumenInvoice( + formPengiriman.dokumenPengirimanInvoice.split(',').map(Number) + ); // Parse string menjadi array angka + } + }, [formPengiriman.dokumenPengirimanInvoice]); + + // Fungsi untuk memeriksa apakah item sudah dipilih + const isChecked = (id) => selectedIds.includes(id); + const isCheckedInvoice = (id) => selectedIdsDokumenInvoice.includes(id); + + useEffect(() => { + const loadState = async () => { + let dataState = await stateApi(); + dataState = dataState.map((state) => ({ + value: state.id, + label: state.name, + })); + setState(dataState); + }; + loadState(); + }, []); + + const watchState = watch('statePengiriman'); + useEffect(() => { + updateFormPengiriman('cityPengiriman', ''); + if (watchState) { + updateFormPengiriman('statePengiriman', `${watchState}`); + validatePengiriman(); + const loadCities = async () => { + let dataCities = await cityApi({ stateId: watchState }); + dataCities = dataCities.map((city) => ({ + value: city.id, + label: city.name, + })); + setCities(dataCities); + }; + loadCities(); + } + }, [watchState]); + + const watchCity = watch('cityPengiriman'); + useEffect(() => { + if (watchCity) { + updateFormPengiriman('cityPengiriman', `${watchCity}`); + validatePengiriman(); + } + }, [watchCity]); + const handleInputChange = (event) => { + const { name, value } = event.target; + updateFormPengiriman(name, value); + validatePengiriman(); + }; + + const handleEveryWeekday = () => { + setEveryWeekday(!everyWeekday); + }; + const handleEveryWeek = () => { + setEveryWeek(!everyWeek); + }; + const handleTukarInvoice = () => { + setTukarInvoice(!tukarInvoice); + }; + const handleEveryWeekdayPembayaran = () => { + setEveryWeekdayPembayaran(!everyWeekdayPembayaran); + }; + const handleEveryWeekPembayaran = () => { + setEveryWeekPembayaran(!everyWeekPembayaran); + }; + const handleTukarInvoicePembayaran = () => { + setTukarInvoicePembayaran(!tukarInvoicePembayaran); + }; + + useEffect(() => { + updateFormPengiriman('everyWeekday', everyWeekday); + updateFormPengiriman('everyWeek', everyWeek); + updateFormPengiriman('tukarInvoice', tukarInvoice); + updateFormPengiriman('everyWeekdayPembayaran', everyWeekdayPembayaran); + updateFormPengiriman('everyWeekPembayaran', everyWeekPembayaran); + updateFormPengiriman('tukarInvoicePembayaran', tukarInvoicePembayaran); + validatePengiriman(); + }, [ + everyWeekday, + everyWeek, + tukarInvoice, + everyWeekdayPembayaran, + everyWeekPembayaran, + tukarInvoicePembayaran, + ]); + + const isFormValid = useMemo( + () => Object.keys(errorsPengiriman).length === 0, + [errorsPengiriman] + ); + + const PICNameRef = useRef(null); + const streetPengirimanRef = useRef(null); + const statePengirimanRef = useRef(null); + const cityPengirimanRef = useRef(null); + const zipRef = useRef(null); + const invoicePicRef = useRef(null); + const streetInvoiceRef = useRef(null); + const stateInvoiceRef = useRef(null); + const cityInvoiceRef = useRef(null); + const everyWeekdayInputRef = useRef(null); + const everyWeekInputRef = useRef(null); + const dokumenPengirimanRef = useRef(null); + const dokumenPengirimanInputRef = useRef(null); + const dokumenPengirimanInvoiceRef = useRef(null); + const dokumenPengirimanInvoiceInputRef = useRef(null); + + useEffect(() => { + const loadIndustries = async () => { + if (!isFormValid) { + const options = { + behavior: 'smooth', + block: 'center', + }; + if (errorsPengiriman.PICName && PICNameRef.current) { + PICNameRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.streetPengiriman && streetPengirimanRef.current) { + streetPengirimanRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.statePengiriman && statePengirimanRef.current) { + statePengirimanRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.cityPengiriman && cityPengirimanRef.current) { + cityPengirimanRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.zip && zipRef.current) { + zipRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.invoicePic && invoicePicRef.current) { + invoicePicRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.streetInvoice && streetInvoiceRef.current) { + streetInvoiceRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.stateInvoice && stateInvoiceRef.current) { + stateInvoiceRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.cityInvoice && cityInvoiceRef.current) { + cityInvoiceRef.current.scrollIntoView(options); + return; + } + if ( + errorsPengiriman.everyWeekdayInput && + everyWeekdayInputRef.current + ) { + everyWeekdayInputRef.current.scrollIntoView(options); + return; + } + if (errorsPengiriman.everyWeekInput && everyWeekInputRef.current) { + everyWeekInputRef.current.scrollIntoView(options); + return; + } + if ( + errorsPengiriman.dokumenPengiriman && + dokumenPengirimanRef.current + ) { + dokumenPengirimanRef.current.scrollIntoView(options); + return; + } + if ( + errorsPengiriman.dokumenInvoice && + dokumenPengirimanInvoiceRef.current + ) { + dokumenPengirimanInvoiceRef.current.scrollIntoView(options); + return; + } + if ( + selectedIds && + formPengiriman.dokumenPengirimanInput === '' && + dokumenPengirimanInputRef.current + ) { + dokumenPengirimanInputRef.current.scrollIntoView(options); + return; + } + if ( + selectedIdsDokumenInvoice && + formPengiriman.dokumenPengirimanInvoiceInput === '' && + dokumenPengirimanInvoiceInputRef.current + ) { + dokumenPengirimanInvoiceInputRef.current.scrollIntoView(options); + return; + } + } + }; + loadIndustries(); + }, [buttonSubmitClick, chekValid]); + + useEffect(() => { + validatePengiriman(); + if (formPengiriman.isSameAddrees) { + const isSame = formPengiriman.isSameAddrees; + if (isSame == 'true') { + setSameAddress(true); + } else { + setSameAddress(false); + } + } + }, [buttonSubmitClick]); + useEffect(() => { + if (formPengiriman.isSameAddrees) { + const isSame = formPengiriman.isSameAddrees; + if (isSame == 'true') { + setSameAddress(true); + } else { + setSameAddress(false); + } + } + }, [formPengiriman.isSameAddrees]); + useEffect(() => { + if (sameAddress) { + updateFormPengiriman('streetInvoice', formPengiriman.streetPengiriman); + updateFormPengiriman('stateInvoice', formPengiriman.statePengiriman); + updateFormPengiriman('cityInvoice', formPengiriman.cityPengiriman); + } else { + updateFormPengiriman('streetInvoice', ''); + updateFormPengiriman('stateInvoice', ''); + updateFormPengiriman('cityInvoice', ''); + setValue('streetInvoice', ''); + setValue('stateInvoice', ''); + setValue('cityInvoice', ''); + } + updateFormPengiriman('isSameAddrees', `${sameAddress}`); + validatePengiriman(); + }, [sameAddress]); + + const getFromLocalStorage = (key) => { + const itemStr = localStorage.getItem(key); + if (!itemStr) return null; + + const item = JSON.parse(itemStr); + return item; + }; + + const cachedData = getFromLocalStorage('Pengiriman'); + useEffect(() => { + if (cachedData) { + setValue('cityPengiriman', parseInt(cachedData?.cityPengiriman)); + updateFormPengiriman('cityPengiriman', `${cachedData?.cityPengiriman}`); + } + if (cachedData?.statePengiriman) { + setValue('statePengiriman', parseInt(cachedData?.statePengiriman)); + } + if (cachedData?.stateInvoice) { + setValue('stateInvoice', parseInt(cachedData?.stateInvoice)); + } + if (cachedData?.cityInvoice) { + setValue('cityInvoice', parseInt(cachedData?.cityInvoice)); + } + if (cachedData?.isSameAddrees) { + updateFormPengiriman('isSameAddrees', `${cachedData?.isSameAddrees}`); + } + validatePengiriman(); + }, [cachedData?.cityPengiriman]); + useEffect(() => { + if (cachedData?.everyWeek) { + updateFormPengiriman('everyWeek', cachedData?.everyWeek); + setEveryWeek(cachedData?.everyWeek); + } + if (cachedData?.everyWeekday) { + updateFormPengiriman('everyWeekday', cachedData?.everyWeekday); + setEveryWeekday(cachedData?.everyWeekday); + } + if (cachedData?.tukarInvoice) { + updateFormPengiriman('tukarInvoice', cachedData?.tukarInvoice); + setTukarInvoice(cachedData?.tukarInvoice); + } + if (cachedData?.everyWeekPembayaran) { + updateFormPengiriman( + 'everyWeekPembayaran', + cachedData?.everyWeekPembayaran + ); + setEveryWeekPembayaran(cachedData?.everyWeekPembayaran); + } + if (cachedData?.everyWeekdayPembayaran) { + updateFormPengiriman( + 'everyWeekdayPembayaran', + cachedData?.everyWeekdayPembayaran + ); + setEveryWeekdayPembayaran(cachedData?.everyWeekdayPembayaran); + } + if (cachedData?.tukarInvoicePembayaran) { + updateFormPengiriman( + 'tukarInvoicePembayaran', + cachedData?.tukarInvoicePembayaran + ); + setTukarInvoicePembayaran(cachedData?.tukarInvoicePembayaran); + } + validatePengiriman(); + }, [ + cachedData?.everyWeek, + cachedData?.everyWeekday, + cachedData?.tukarInvoice, + cachedData?.everyWeekdayPembayaran, + cachedData?.everyWeekPembayaran, + cachedData?.tukarInvoicePembayaran, + ]); + const handleChangeSameAddress = () => { + setSameAddress(!sameAddress); + }; + return ( + <> + {isDesktop && ( + <div> + <h1 className={`font-bold ${isKonfirmasi ? 'text-xl' : ''}`}> + Pengiriman + </h1> + <form className='flex flex-col w-full '> + <div className='w-full grid grid-row-2 gap-5'> + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama PIC Penerimaan Barang + </label> + </div> + <div className='w-3/5'> + <input + value={formPengiriman.PICName} + id='PICName' + name='PICName' + placeholder='Masukkan nama pic pengiriman disini' + type='text' + className='form-input' + aria-invalid={errorsPengiriman.PICName} + ref={PICNameRef} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.PICName} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Alamat Pengiriman Barang + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + pastikan alamat yang anda isi sesuai dengan alamat kirim + barang + </span> + )} + </div> + <div className='w-3/5 flex gap-3 flex-col'> + <div> + <input + id='streetPengiriman' + name='streetPengiriman' + ref={streetPengirimanRef} + placeholder='Masukkan alamat lengkap pengiriman barang' + type='text' + value={formPengiriman.streetPengiriman} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.streetPengiriman} + </div> + )} + </div> + <div className='sub-alamat flex flex-row w-full gap-3'> + <div className='w-2/5' ref={statePengirimanRef}> + <Controller + name='statePengiriman' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={states} + placeholder='Provinsi' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.statePengiriman} + </div> + )} + </div> + <div className='w-1/3' ref={cityPengirimanRef}> + <Controller + name='cityPengiriman' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={cities} + disabled={!watchState} + placeholder='Kota' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.cityPengiriman} + </div> + )} + </div> + <div className='w-1/3'> + <input + id='zipPengiriman' + name='zipPengiriman' + ref={zipRef} + placeholder='Kode Pos' + type='number' + value={formPengiriman.zipPengiriman} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.zipPengiriman} + </div> + )} + </div> + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama PIC Penerimaan Invoice + </label> + </div> + <div className='w-3/5'> + <input + value={formPengiriman.invoicePic} + id='invoicePic' + name='invoicePic' + placeholder='Masukkan nama pic invoice disini' + type='text' + className='form-input' + aria-invalid={errorsPengiriman.invoicePic} + ref={invoicePicRef} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.invoicePic} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Alamat Pengiriman Invoice + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pastikan alamat yang anda isi sesuai dengan alamat kirim + invoice + </span> + )} + </div> + <div className='w-3/5 flex gap-3 flex-col'> + <div> + <Checkbox + colorScheme='red' + isChecked={sameAddress} + onChange={handleChangeSameAddress} + > + Alamat invoice sama dengan alamat pengiriman + </Checkbox> + </div> + {!sameAddress && ( + <> + <div> + <input + id='streetInvoice' + name='streetInvoice' + ref={streetInvoiceRef} + placeholder='Masukkan alamat lengkap pengiriman invoice' + type='text' + value={formPengiriman.streetInvoice} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.streetInvoice} + </div> + )} + </div> + <div className='sub-alamat flex flex-row w-full gap-3'> + <div className='w-3/5' ref={stateInvoiceRef}> + <Controller + name='stateInvoice' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={states} + placeholder='Provinsi' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.stateInvoice} + </div> + )} + </div> + <div className='w-2/5' ref={cityInvoiceRef}> + <Controller + name='cityInvoice' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={cities} + disabled={!watchState} + placeholder='Kota' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.cityInvoice} + </div> + )} + </div> + </div> + </> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-wrap'> + Jadwal Penukaran Invoice{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih jika bisnis anda memiliki jadwal penukaran invoice + </span> + )} + </div> + <div className='w-3/5 flex gap-3 flex-col'> + <div className='flex gap-3 flex-col'> + <Checkbox + colorScheme='red' + isChecked={everyWeekday} + onChange={handleEveryWeekday} + > + Setiap Minggu dihari + </Checkbox> + <input + id='everyWeekdayInput' + name='everyWeekdayInput' + ref={everyWeekdayInputRef} + placeholder='Format: Senin, Selasa, Rabu, Kamis, Jumat, Sabtu, Minggu' + type='text' + value={formPengiriman.everyWeekdayInput} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div className='flex gap-3 flex-col'> + <Checkbox + colorScheme='red' + isChecked={everyWeek} + onChange={handleEveryWeek} + > + Setiap Bulan di minggu ke + </Checkbox> + <input + id='everyWeekInput' + name='everyWeekInput' + ref={everyWeekInputRef} + placeholder='Format: Minggu 1 & Minggu 2' + type='text' + value={formPengiriman.everyWeekInput} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div className='flex gap-3 flex-col'> + <Checkbox + colorScheme='red' + isChecked={tukarInvoice} + onChange={handleTukarInvoice} + > + Lainnya + </Checkbox> + <textarea + id='tukarInvoiceInput' + name='tukarInvoiceInput' + placeholder='isi manual dokumen yang anda mau' + type='textarea' + value={formPengiriman.tukarInvoiceInput} + className='form-input' + rows={4} + cols={40} + onChange={handleInputChange} + /> + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Jadwal Pembayaran{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih jika bisnis anda memiliki jadwal pembayaran + </span> + )} + </div> + <div className='w-3/5 flex gap-3 flex-col'> + <div className='flex gap-3 flex-col'> + <Checkbox + colorScheme='red' + isChecked={everyWeekdayPembayaran} + onChange={handleEveryWeekdayPembayaran} + > + Setiap Minggu dihari + </Checkbox> + <input + id='everyWeekdayInputPembayaran' + name='everyWeekdayInputPembayaran' + placeholder='Format: Senin, Selasa, Rabu, Kamis, Jumat, Sabtu, Minggu' + type='text' + value={formPengiriman.everyWeekdayInputPembayaran} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div className='flex gap-3 flex-col'> + <Checkbox + colorScheme='red' + isChecked={everyWeekPembayaran} + onChange={handleEveryWeekPembayaran} + > + Setiap Bulan di minggu ke + </Checkbox> + <input + id='everyWeekInputPembayaran' + name='everyWeekInputPembayaran' + placeholder='Format: Minggu 1 & Minggu 2' + type='text' + value={formPengiriman.everyWeekInputPembayaran} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div className='flex gap-3 flex-col'> + <Checkbox + colorScheme='red' + isChecked={tukarInvoicePembayaran} + onChange={handleTukarInvoicePembayaran} + > + Lainnya + </Checkbox> + <textarea + id='tukarInvoiceInputPembayaran' + name='tukarInvoiceInputPembayaran' + placeholder='isi manual dokumen yang anda mau' + type='textarea' + value={formPengiriman.tukarInvoiceInputPembayaran} + className='form-input' + rows={4} + cols={40} + onChange={handleInputChange} + /> + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-wrap'> + Dokumen saat Pengiriman Barang + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih dokumen lampiran saat pengiriman barang + </span> + )} + </div> + <div + className='w-3/5 flex gap-3 flex-col' + ref={dokumenPengirimanRef} + > + <Checkbox + colorScheme='red' + key='0' + isChecked={isChecked(0)} + onChange={() => handleCheckboxChange(0)} + > + Surat Tanda Terima Barang (STTB) + </Checkbox> + <Checkbox + colorScheme='red' + key='1' + isChecked={isChecked(1)} + onChange={() => handleCheckboxChange(1)} + > + Good Receipt (GR) + </Checkbox> + <Checkbox + colorScheme='red' + key='2' + isChecked={isChecked(2)} + onChange={() => handleCheckboxChange(2)} + > + Surat Terima Barang (STB) + </Checkbox> + <Checkbox + colorScheme='red' + key='3' + isChecked={isChecked(3)} + onChange={() => handleCheckboxChange(3)} + > + Lembar Penerimaan Barang (LPB) + </Checkbox> + + <div className='flex gap-3 flex-col'> + <Checkbox + colorScheme='red' + key='4' + isChecked={isChecked(4)} + onChange={() => handleCheckboxChange(4)} + > + Lainnya + </Checkbox> + <textarea + id='dokumenPengirimanInput' + name='dokumenPengirimanInput' + placeholder='isi manual dokumen yang anda mau' + type='textarea' + ref={dokumenPengirimanInputRef} + value={formPengiriman.dokumenPengirimanInput} + className='form-input' + rows={4} + cols={40} + onChange={handleInputChange} + /> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.dokumenPengiriman} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-wrap'> + Dokumen yang dilampirkan saat Pengiriman Invoice + </label> + <span className='text-xs opacity-60'> + Dokumen akan dikirimkan sesuai dengan yang anda pilih + </span> + </div> + <div + className='w-3/5 flex gap-3 flex-col' + ref={dokumenPengirimanInvoiceRef} + > + <Checkbox + colorScheme='red' + key='0' + isChecked={isCheckedInvoice(0)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(0) + } + > + Invoice Pembelian + </Checkbox> + <Checkbox + colorScheme='red' + key='1' + isChecked={isCheckedInvoice(1)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(1) + } + > + Surat Jalan + </Checkbox> + <Checkbox + colorScheme='red' + key='2' + isChecked={isCheckedInvoice(2)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(2) + } + > + Berita Acara Serah Terima (BAST) + </Checkbox> + <Checkbox + colorScheme='red' + key='3' + isChecked={isCheckedInvoice(3)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(3) + } + > + Faktur Pajak + </Checkbox> + <Checkbox + colorScheme='red' + key='4' + isChecked={isCheckedInvoice(4)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(4) + } + > + Good Receipt (GR) + </Checkbox> + + <div className='flex gap-3 flex-col'> + <Checkbox + colorScheme='red' + key='5' + isChecked={isCheckedInvoice(5)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(5) + } + > + Lainnya + </Checkbox> + <textarea + id='dokumenPengirimanInvoiceInput' + name='dokumenPengirimanInvoiceInput' + placeholder='isi manual dokumen yang anda mau' + type='textarea' + ref={dokumenPengirimanInvoiceInputRef} + value={formPengiriman.dokumenPengirimanInvoiceInput} + className='form-input' + rows={4} + cols={40} + onChange={handleInputChange} + /> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.dokumenInvoicePengiriman} + </div> + )} + </div> + </div> + </div> + </form> + </div> + )} + {isMobile && ( + <div className='text-sm'> + <h1 + className={`font-bold py-4 mt-8 ${ + isKonfirmasi ? 'hidden' : 'text-xl' + }`} + > + Pengiriman + </h1> + <form className='flex flex-col w-full '> + <div className='w-full grid grid-row-2 gap-2'> + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Nama PIC Penerimaan Barang + </label> + <input + value={formPengiriman.PICName} + id='PICName' + name='PICName' + placeholder='Masukkan nama pic pengiriman disini' + type='text' + className='form-input' + aria-invalid={errorsPengiriman.PICName} + ref={PICNameRef} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.PICName} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Alamat Pengiriman Barang + </label> + <div className='w-full'> + <input + id='streetPengiriman' + name='streetPengiriman' + ref={streetPengirimanRef} + placeholder='Masukkan alamat lengkap pengiriman barang' + type='text' + value={formPengiriman.streetPengiriman} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.streetPengiriman} + </div> + )} + </div> + <div className='sub-alamat flex flex-row w-full gap-2'> + <div className='w-2/5' ref={statePengirimanRef}> + <Controller + name='statePengiriman' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={states} + placeholder='Provinsi' + /> + )} + /> + </div> + <div className='w-1/3' ref={cityPengirimanRef}> + <Controller + name='cityPengiriman' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={cities} + disabled={!watchState} + placeholder='Kota' + /> + )} + /> + </div> + <div className='w-1/3'> + <input + id='zipPengiriman' + name='zipPengiriman' + ref={zipRef} + placeholder='Kode Pos' + type='number' + value={formPengiriman.zipPengiriman} + className='form-input' + onChange={handleInputChange} + /> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.statePengiriman} + </div> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.cityPengiriman} + </div> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.zipPengiriman} + </div> + )} + </div> + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Nama PIC Penerimaan Invoice + </label> + <input + value={formPengiriman.invoicePic} + id='invoicePic' + name='invoicePic' + placeholder='Masukkan nama pic invoice disini' + type='text' + className='form-input' + aria-invalid={errorsPengiriman.invoicePic} + ref={invoicePicRef} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.invoicePic} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Alamat Pengiriman Invoice + </label> + <div> + <Checkbox + colorScheme='red' + isChecked={sameAddress} + onChange={handleChangeSameAddress} + size='sm' + > + Alamat invoice sama dengan alamat pengiriman + </Checkbox> + </div> + {!sameAddress && ( + <> + <div className='w-full'> + <input + id='streetInvoice' + name='streetInvoice' + ref={streetInvoiceRef} + placeholder='Masukkan alamat lengkap pengiriman invoice' + type='text' + value={formPengiriman.streetInvoice} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.streetInvoice} + </div> + )} + </div> + <div className='sub-alamat flex flex-row w-full gap-3'> + <div className='w-3/5' ref={stateInvoiceRef}> + <Controller + name='stateInvoice' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={states} + placeholder='Provinsi' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.stateInvoice} + </div> + )} + </div> + <div className='w-2/5' ref={cityInvoiceRef}> + <Controller + name='cityInvoice' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={cities} + disabled={!watchState} + placeholder='Kota' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.cityInvoice} + </div> + )} + </div> + </div> + </> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-wrap'> + Jadwal Penukaran Invoice + <span className=' opacity-60'>(Opsional)</span> + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih jika bisnis anda memiliki jadwal penukaran invoice + </span> + )} + <div className='w-full flex gap-2 flex-col'> + <div className='flex gap-2 flex-col'> + <Checkbox + size='sm' + colorScheme='red' + isChecked={everyWeekday} + onChange={handleEveryWeekday} + > + Setiap Minggu dihari + </Checkbox> + <input + id='everyWeekdayInput' + name='everyWeekdayInput' + ref={everyWeekdayInputRef} + placeholder='Format: Senin, Selasa, Rabu, Kamis, Jumat, Sabtu, Minggu' + type='text' + value={formPengiriman.everyWeekdayInput} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div className='flex gap-2 w-full flex-col'> + <Checkbox + size='sm' + colorScheme='red' + isChecked={everyWeek} + onChange={handleEveryWeek} + > + Setiap Bulan di minggu ke + </Checkbox> + <input + id='everyWeekInput' + name='everyWeekInput' + ref={everyWeekInputRef} + placeholder='Format: Minggu 1 & Minggu 2' + type='text' + value={formPengiriman.everyWeekInput} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div className='flex gap-2 flex-col'> + <Checkbox + size='sm' + colorScheme='red' + isChecked={tukarInvoice} + onChange={handleTukarInvoice} + > + Lainnya + </Checkbox> + <textarea + id='tukarInvoiceInput' + name='tukarInvoiceInput' + placeholder='isi manual dokumen yang anda mau' + type='textarea' + value={formPengiriman.tukarInvoiceInput} + className='form-input' + rows={4} + cols={40} + onChange={handleInputChange} + /> + </div> + </div> + <div className='w-2/5'></div> + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Jadwal Pembayaran + <span className=' opacity-60'>(Opsional)</span> + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih jika bisnis anda memiliki jadwal pembayaran + </span> + )} + <div className='w-full flex gap-2 flex-col'> + <div className='flex gap-2 flex-col'> + <Checkbox + size='sm' + colorScheme='red' + isChecked={everyWeekdayPembayaran} + onChange={handleEveryWeekdayPembayaran} + > + Setiap Minggu dihari + </Checkbox> + <input + id='everyWeekdayInputPembayaran' + name='everyWeekdayInputPembayaran' + placeholder='Format: Senin, Selasa, Rabu, Kamis, Jumat, Sabtu, Minggu' + type='text' + value={formPengiriman.everyWeekdayInputPembayaran} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div className='flex gap-2 flex-col'> + <Checkbox + size='sm' + colorScheme='red' + isChecked={everyWeekPembayaran} + onChange={handleEveryWeekPembayaran} + > + Setiap Bulan di minggu ke + </Checkbox> + <input + id='everyWeekInputPembayaran' + name='everyWeekInputPembayaran' + placeholder='Format: Minggu 1 & Minggu 2' + type='text' + value={formPengiriman.everyWeekInputPembayaran} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div className='flex gap-2 flex-col'> + <Checkbox + size='sm' + colorScheme='red' + isChecked={tukarInvoicePembayaran} + onChange={handleTukarInvoicePembayaran} + > + Lainnya + </Checkbox> + <textarea + id='tukarInvoiceInputPembayaran' + name='tukarInvoiceInputPembayaran' + placeholder='isi manual dokumen yang anda mau' + type='textarea' + value={formPengiriman.tukarInvoiceInputPembayaran} + className='form-input' + rows={4} + cols={40} + onChange={handleInputChange} + /> + </div> + </div> + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-wrap'> + Dokumen saat Pengiriman Barang + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih dokumen lampiran saat pengiriman barang + </span> + )} + <div + className='w-full flex gap-2 flex-col' + ref={dokumenPengirimanRef} + > + <Checkbox + size='sm' + colorScheme='red' + key='0' + isChecked={isChecked(0)} + onChange={() => handleCheckboxChange(0)} + > + Surat Tanda Terima Barang (STTB) + </Checkbox> + <Checkbox + size='sm' + colorScheme='red' + key='1' + isChecked={isChecked(1)} + onChange={() => handleCheckboxChange(1)} + > + Good Receipt (GR) + </Checkbox> + <Checkbox + size='sm' + colorScheme='red' + key='2' + isChecked={isChecked(2)} + onChange={() => handleCheckboxChange(2)} + > + Surat Terima Barang (STB) + </Checkbox> + <Checkbox + size='sm' + colorScheme='red' + key='3' + isChecked={isChecked(3)} + onChange={() => handleCheckboxChange(3)} + > + Lembar Penerimaan Barang (LPB) + </Checkbox> + + <div className='flex gap-3 flex-col'> + <Checkbox + size='sm' + colorScheme='red' + key='4' + isChecked={isChecked(4)} + onChange={() => handleCheckboxChange(4)} + > + Lainnya + </Checkbox> + <textarea + id='dokumenPengirimanInput' + name='dokumenPengirimanInput' + placeholder='isi manual dokumen yang anda mau' + type='textarea' + ref={dokumenPengirimanInputRef} + value={formPengiriman.dokumenPengirimanInput} + className='form-input' + rows={4} + cols={40} + onChange={handleInputChange} + /> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.dokumenPengiriman} + </div> + )} + </div> + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-wrap'> + Dokumen yang dilampirkan saat Pengiriman Invoice + </label> + <span className='text-xs opacity-60'> + Pilih dokumen lampiran saat pengiriman invoice + </span> + <div + className='w-full flex gap-2 flex-col' + ref={dokumenPengirimanInvoiceRef} + > + <Checkbox + size='sm' + colorScheme='red' + key='0' + isChecked={isCheckedInvoice(0)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(0) + } + > + Invoice Pembelian + </Checkbox> + <Checkbox + size='sm' + colorScheme='red' + key='1' + isChecked={isCheckedInvoice(1)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(1) + } + > + Surat Jalan + </Checkbox> + <Checkbox + size='sm' + colorScheme='red' + key='2' + isChecked={isCheckedInvoice(2)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(2) + } + > + Berita Acara Serah Terima (BAST) + </Checkbox> + <Checkbox + size='sm' + colorScheme='red' + key='3' + isChecked={isCheckedInvoice(3)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(3) + } + > + Faktur Pajak + </Checkbox> + <Checkbox + size='sm' + colorScheme='red' + key='4' + isChecked={isCheckedInvoice(4)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(4) + } + > + Good Receipt (GR) + </Checkbox> + + <div className='flex gap-3 flex-col'> + <Checkbox + size='sm' + colorScheme='red' + key='5' + isChecked={isCheckedInvoice(5)} + onChange={() => + handleCheckboxChangeDokumenPengirimanInvoice(5) + } + > + Lainnya + </Checkbox> + <textarea + id='dokumenPengirimanInvoiceInput' + name='dokumenPengirimanInvoiceInput' + placeholder='isi manual dokumen yang anda mau' + type='textarea' + ref={dokumenPengirimanInvoiceInputRef} + value={formPengiriman.dokumenPengirimanInvoiceInput} + className='form-input' + rows={4} + cols={40} + onChange={handleInputChange} + /> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errorsPengiriman.dokumenInvoicePengiriman} + </div> + )} + </div> + <div className='w-2/5'></div> + </div> + </div> + </form> + </div> + )} + </> + ); +}; + +export default Pengiriman; diff --git a/src/lib/pengajuan-tempo/component/Referensi.jsx b/src/lib/pengajuan-tempo/component/Referensi.jsx new file mode 100644 index 00000000..8cb3b0c3 --- /dev/null +++ b/src/lib/pengajuan-tempo/component/Referensi.jsx @@ -0,0 +1,548 @@ +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { useForm } from 'react-hook-form'; +import { usePengajuanTempoStoreSupplier } from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import * as Yup from 'yup'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { PlusCircleIcon } from '@heroicons/react/24/outline'; +import useDevice from '@/core/hooks/useDevice'; +import { Trash2Icon } from 'lucide-react'; +import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline'; +const initialData = []; +const Referensi = ({ chekValid, buttonSubmitClick }) => { + const { isDesktop, isMobile } = useDevice(); + const [openIndexes, setOpenIndexes] = useState([]); + + const { + register, + formState: { errors }, + handleSubmit, + watch, + setValue, + control, + } = useForm({ + resolver: yupResolver(validationSchema), + defaultValues, + }); + const { formSupplier, updateFormSupplier, updateHasSave } = + usePengajuanTempoStoreSupplier(); + const [formData, setFormData] = useState([ + { + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', + }, + ]); + + const [buttonSubmit, setButtonSubmit] = useState(false); + const [supplierData, setSupplierData] = useState(initialData); + const [newSupplier, setNewSupplier] = useState({ + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', + }); + const onChangeInput = (e, index) => { + const { name, value } = e.target; + + let formattedValue = value; + + if (name === 'durasiTempo') { + formattedValue = value.replace(/\s*Hari\s*/g, ''); + } else if (name === 'creditLimit') { + formattedValue = value.replace(/^Rp\s*/, ''); + } + + const editData = supplierData.map((item, i) => + i === index ? { ...item, [name]: formattedValue } : item + ); + + setSupplierData(editData); + updateHasSave(false); + }; + + const handleNewSupplierChange = (e) => { + const { name, value } = e.target; + + let formattedValue = value; + + if (name === 'durasiTempo') { + formattedValue = value.replace(/\s*Hari\s*/g, ''); + } else if (name === 'creditLimit') { + formattedValue = value.replace(/^Rp\s*/, ''); + } + + const updatedSupplier = { ...newSupplier, [name]: formattedValue }; + setNewSupplier(updatedSupplier); + updateHasSave(false); + }; + + const handleAddNewSupplier = () => { + if (Object.values(newSupplier).every((val) => val.trim() !== '')) { + setSupplierData((prevData) => { + const newData = [...prevData, newSupplier]; + return newData; + }); + + setNewSupplier({ + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', + }); + } + updateHasSave(false); + }; + + useEffect(() => { + handleAddNewSupplier(); + updateFormSupplier(supplierData); + setButtonSubmit(!buttonSubmit); + }, [buttonSubmitClick]); + const simpanData = () => { + setButtonSubmit(!buttonSubmit); + if (Object.values(newSupplier).every((val) => val.trim() !== '')) { + setSupplierData((prevData) => { + const newData = [...prevData, newSupplier]; + return newData; + }); + + setNewSupplier({ + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', + }); + } + updateHasSave(true); + }; + const formatRupiah = (value) => { + if (!value) return ''; + const numberString = value.replace(/[^0-9]/g, ''); + return numberString + ? 'Rp ' + new Intl.NumberFormat('id-ID').format(numberString) + : ''; + }; + const formatHari = (value) => { + if (!value) return ''; + + const numberString = value.replace(/[^0-9]/g, ''); + + return numberString ? numberString.replace(/Hari/g, '') + ' Hari' : ''; + }; + + useEffect(() => { + updateFormSupplier(supplierData); + }, [buttonSubmit]); + const getFromLocalStorage = (key) => { + const itemStr = localStorage.getItem(key); + if (!itemStr) return null; + + const item = JSON.parse(itemStr); + return item; + }; + useEffect(() => { + const cachedData = getFromLocalStorage('Referensi'); + if (cachedData) { + setSupplierData(cachedData); + updateFormSupplier(cachedData); + } + }, [buttonSubmitClick]); + + useEffect(() => { + setOpenIndexes(supplierData.map((_, index) => index)); + }, [supplierData]); + + const toggleOpen = (index) => { + setOpenIndexes((prev) => + prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index] + ); + }; + return ( + <> + {isDesktop && ( + <div className='py-4'> + <div className='flex flex-col justify-start'> + <h1 className='font-bold text-2xl'> + Referensi Supplier / Rekanan Bisnis Perusahaan{' '} + <span className=' opacity-60 text-xl'>(Opsional)</span> + </h1> + <p className='opacity-60'> + Data yang anda berikan hanya untuk bahan referensi internal kami + untuk memberikan anda credit limit dan durasi tempo + </p> + </div> + <form className='flex mt-4 flex-col w-full '> + <table className='border' border='1' cellPadding='10'> + <thead> + <tr className='border '> + <th className='text-left px-5 py-2'> + Nama Supplier / Rekanan + </th> + <th className='text-left px-5 py-2'>PIC</th> + <th className='text-left px-5 py-2'>Telepon</th> + <th className='text-left px-5 py-2'>Durasi Tempo</th> + <th className='text-left px-5 py-2'>Credit Limit</th> + </tr> + </thead> + <tbody> + {supplierData.map((supplier, index) => ( + <tr key={index}> + <td> + <input + name='supplier' + value={supplier.supplier} + type='text' + onChange={(e) => onChangeInput(e, index)} + className='form-input border px-4 py-2' + placeholder='Type Supplier' + /> + </td> + <td> + <input + name='pic' + value={supplier.pic} + type='text' + className='form-input border px-4 py-2' + onChange={(e) => onChangeInput(e, index)} + placeholder='Type PIC' + /> + </td> + <td> + <input + name='telepon' + type='text' + className='form-input border px-4 py-2' + value={supplier.telepon} + onChange={(e) => onChangeInput(e, index)} + placeholder='Type Telepon' + /> + </td> + <td> + <input + name='durasiTempo' + type='text' + className='form-input border px-4 py-2' + value={formatHari(supplier.durasiTempo)} + onChange={(e) => onChangeInput(e, index)} + placeholder='Type Durasi Tempo' + /> + </td> + <td> + <input + name='creditLimit' + type='text' + value={formatRupiah(supplier.creditLimit)} + className='form-input border px-4 py-2' + onChange={(e) => onChangeInput(e, index)} + placeholder='Type Credit Limit' + /> + </td> + </tr> + ))} + <tr> + <td> + <input + name='supplier' + value={newSupplier.supplier} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='Isi nama supplier anda' + /> + </td> + <td> + <input + name='pic' + value={newSupplier.pic} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='Isi PIC supplier anda' + /> + </td> + <td> + <input + name='telepon' + value={newSupplier.telepon} + type='text' + onChange={handleNewSupplierChange} + placeholder='Isi telepon supplier anda' + className='form-input border px-4 py-2' + /> + </td> + <td> + <input + name='durasiTempo' + value={formatHari(newSupplier.durasiTempo)} + type='text' + onChange={handleNewSupplierChange} + className='form-input border px-4 py-2' + placeholder='Durasi jatuh tempo' + /> + </td> + <td> + <input + name='creditLimit' + value={formatRupiah(newSupplier.creditLimit)} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='limit kredit' + /> + </td> + </tr> + </tbody> + </table> + </form> + <div className='flex items-center gap-4 mt-8'> + <button + onClick={handleAddNewSupplier} + className='bg-gray-200 border border-gray-500 rounded-md text-sm text-gray-500 p-2 h-11 mb-1 content-center flex flex-row justify-center items-center' + > + {<PlusCircleIcon className='w-5 mr-2' />} + {''} Tambah data baru + </button> + <button + onClick={simpanData} + className='bg-gray-200 border border-gray-500 rounded-md text-sm text-gray-500 p-2 h-11 mb-1 content-center flex flex-row justify-center items-center' + > + simpan data + </button> + <span className='text-sm opacity-60 text-red-500'> + *Klik simpan sebelum lanjut ke tahap selanjutnya + </span> + </div> + </div> + )} + {isMobile && ( + <div className='text-sm'> + <div className='flex flex-col py-4 mt-8 justify-start'> + <h1 className='font-bold text-xl'> + Referensi Supplier / Rekanan Bisnis Perusahaan{' '} + <span className=' opacity-60 text-xl'>(Opsional)</span> + </h1> + <p className='opacity-60'> + Data yang anda berikan hanya untuk bahan referensi internal kami + untuk memberikan anda credit limit dan durasi tempo + </p> + </div> + <div className='flex gap-4 flex-col'> + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + <h2 className='py-2 font-semibold text-base'> + Daftar Nama Supplier + </h2> + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + <div className=''> + {supplierData.map((supplier, index) => ( + <div key={index}> + <div + className='flex flex-row justify-center items-center py-4' + onClick={() => toggleOpen(index)} + > + <p className='font-semibold text-base w-4/5'> + {supplier.supplier} + </p> + <div className='w-1/5 flex justify-end items-center gap-2'> + <Trash2Icon size={16} color='red' /> + {openIndexes.includes(index) ? ( + <ChevronUpIcon className='w-4' /> + ) : ( + <ChevronDownIcon className='w-4' /> + )} + </div> + </div> + {openIndexes.includes(index) && ( + <form className='flex flex-col w-full'> + <div className='w-full grid grid-row-2 gap-4'> + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Supplier + </label> + </div> + <div className='w-3/5 opacity-70'> + {supplier.supplier} + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + PIC + </label> + </div> + <div className='w-3/5 opacity-70'>{supplier.pic}</div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Telepon + </label> + </div> + <div className='w-3/5 opacity-70'> + {supplier.telepon} + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Durasi Tempo + </label> + </div> + <div className='w-3/5 opacity-70'> + {formatHari(supplier.durasiTempo)} + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Kredit Limit + </label> + </div> + <div className='w-3/5 opacity-70'> + {formatRupiah(supplier.creditLimit)} + </div> + </div> + </div> + </form> + )} + </div> + ))} + </div> + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + <h2 className='py-2 font-semibold text-base text-red-500 flex flex-row'> + <PlusCircleIcon className='w-5 mr-2' /> + Tambah Data Baru + </h2> + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + <form className='flex flex-col w-full'> + <div className='w-full grid grid-row-2 gap-2'> + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Supplier + </label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='supplier' + value={newSupplier.supplier} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='Format: PT. ABC TESTING INDONESIA' + /> + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>PIC</label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='pic' + value={newSupplier.pic} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='John Doe' + /> + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>Telepon</label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='telepon' + value={newSupplier.telepon} + type='text' + onChange={handleNewSupplierChange} + placeholder='Format: 08123456789' + className='form-input border px-4 py-2' + /> + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Durasi Tempo + </label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='durasiTempo' + value={formatHari(newSupplier.durasiTempo)} + type='text' + onChange={handleNewSupplierChange} + className='form-input border px-4 py-2' + placeholder='Isi durasi tempo supplier anda (hari)' + /> + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Kredit Limit + </label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='creditLimit' + value={formatRupiah(newSupplier.creditLimit)} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='Rp 999.999.999' + /> + </div> + </div> + </div> + </form> + </div> + <div className='flex flex-col justify-start items-start gap-4 mt-8'> + <span className='text-xs opacity-60 text-red-500'> + *Klik simpan sebelum lanjut ke tahap selanjutnya + </span> + <button + onClick={simpanData} + className='bg-gray-200 border border-gray-500 rounded-md w-full text-sm text-gray-500 p-2 h-11 mb-1 content-center flex flex-row justify-center items-center' + > + simpan data + </button> + </div> + </div> + )} + </> + ); +}; + +const validationSchema = Yup.object().shape({ + supplier: Yup.string().required('Harus di-isi'), + pic: Yup.string().required('Harus di-isi'), + telepon: Yup.string().required('Harus di-isi'), + durasiTempo: Yup.string().required('Harus di-isi'), + creditLimit: Yup.string().required('Harus di-isi'), +}); + +const defaultValues = { + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', +}; +export default Referensi; diff --git a/src/lib/pengajuan-tempo/component/Stepper.jsx b/src/lib/pengajuan-tempo/component/Stepper.jsx new file mode 100644 index 00000000..539fe3f3 --- /dev/null +++ b/src/lib/pengajuan-tempo/component/Stepper.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import useDevice from '@/core/hooks/useDevice'; +const Stepper = ({ currentStep, numberOfSteps }) => { + const { isDesktop, isMobile } = useDevice(); + const stepLabels = [ + 'Informasi Perusahaan', + 'Kontak Person', + 'Pengiriman', + 'Referensi', + 'Dokumen', + 'Konfirmasi', + ]; + const activeColor = (index) => + currentStep >= index ? 'bg-red-500' : 'bg-gray-300'; + const activeColorBullet = (index) => + currentStep >= index ? 'bg-red-500 ' : 'bg-white border-gray-300 border'; + const isFinalStep = (index) => index === numberOfSteps - 1; + const isFirstStep = (index) => index === 0; + return ( + <div className='flex items-center'> + {Array.from({ length: numberOfSteps }).map((_, index) => ( + <React.Fragment key={index}> + {isFirstStep(index) ? null : ( + <div + className={`${isMobile ? 'w-12' : 'w-48'} h-[0.8px] ${activeColor( + index + )}`} + ></div> + )} + <div + className={`w-6 h-6 ${ + currentStep == index + ? 'border-red-500 border' + : `${activeColorBullet(index)} ` + } rounded-full flex justify-center items-center text-nowrap`} + > + <div className='relative text-xs'> + <div + className={`absolute z-10 ${ + isMobile + ? `w-12 h-full top-4 ${ + isFinalStep(index) ? '-left-16' : '-left-4' + }` + : 'w-48 h-full -top-14 -left-24' + } `} + > + <div + className={`relative w-full max-w-md p-2 text-center ${ + currentStep == index + ? 'text-red-500' + : `${isMobile ? 'hidden' : ''}` + } text-nowrap`} + > + {stepLabels[index]} + </div> + </div> + </div> + </div> + </React.Fragment> + ))} + </div> + ); +}; + +export default Stepper; diff --git a/src/lib/pengajuan-tempo/component/informasiPerusahaan.jsx b/src/lib/pengajuan-tempo/component/informasiPerusahaan.jsx new file mode 100644 index 00000000..8a1b3508 --- /dev/null +++ b/src/lib/pengajuan-tempo/component/informasiPerusahaan.jsx @@ -0,0 +1,1401 @@ +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { Controller, set, useForm } from 'react-hook-form'; +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'; +import odooApi from '~/libs/odooApi'; +import stateApi from '@/lib/address/api/stateApi.js'; +import cityApi from '@/lib/address/api/cityApi'; +import { Radio, RadioGroup, Stack, Checkbox } from '@chakra-ui/react'; +import { usePengajuanTempoStore } from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import useDevice from '@/core/hooks/useDevice'; +import Divider from '@/core/components/elements/Divider/Divider'; +const InformasiPerusahaan = ({ + chekValid, + buttonSubmitClick, + isKonfirmasi, +}) => { + const { isDesktop, isMobile } = useDevice(); + const { control, watch, setValue, getValues } = useForm(); + const { form, errors, validate, updateForm } = usePengajuanTempoStore(); + const [industries, setIndustries] = useState([]); + const [selectedCategory, setSelectedCategory] = useState(''); + const [states, setState] = useState([]); + const [cities, setCities] = useState([]); + const [bersedia, setBersedia] = useState(null); + const category_produk = [ + { id: 2040, name: 'Pengaman, Kesehatan & Keamanan' }, + { id: 2097, name: 'Perkakas Tangan, Listrik & Pneumatic' }, + { id: 2161, name: 'Mesin Industrial' }, + { id: 2222, name: 'Mesin Pertanian & Perkebunan' }, + { id: 2246, name: 'Mesin Pembersih & Janitorial' }, + { id: 2273, name: 'Cairan Berbahan Kimia' }, + { id: 2315, name: 'Perlengkapan Pengukuran & Pengujian' }, + { id: 2354, name: 'Peralatan Listrik & Elektronik' }, + { id: 2394, name: 'Perlengkapan Logistik & Gudang' }, + { id: 2420, name: 'Peralatan Kantor & Stationery' }, + { id: 2445, name: 'Komponen & Aksesoris' }, + { id: 2477, name: 'Peralatan Horeca & Food Service' }, + ]; + const radioOptions = [ + { label: '5.000.000', value: '5000000' }, + { label: '10.000.000', value: '10000000' }, + { label: '15.000.000', value: '15000000' }, + { label: '20.000.000', value: '20000000' }, + { label: '25.000.000', value: '25000000' }, + { label: '30.000.000', value: '30000000' }, + { label: '35.000.000', value: '35000000' }, + ]; + + useEffect(() => { + const loadState = async () => { + let dataState = await stateApi(); + dataState = dataState.map((state) => ({ + value: state.id, + label: state.name, + })); + setState(dataState); + }; + loadState(); + }, []); + + const watchState = watch('state'); + useEffect(() => { + updateForm('city', ''); + if (watchState) { + updateForm('state', `${watchState}`); + validate(); + const loadCities = async () => { + let dataCities = await cityApi({ stateId: watchState }); + dataCities = dataCities.map((city) => ({ + value: city.id, + label: city.name, + })); + setCities(dataCities); + }; + loadCities(); + } + }, [watchState]); + + const watchCity = watch('city'); + useEffect(() => { + if (watchCity) { + updateForm('city', `${watchCity}`); + validate(); + } + }, [watchCity]); + + useEffect(() => { + const loadIndustries = async () => { + const dataIndustries = await odooApi('GET', '/api/v1/partner/industry'); + setIndustries( + dataIndustries?.map((o) => ({ + value: o.id, + label: o.name, + category: o.category, + })) + ); + }; + loadIndustries(); + }, []); + + useEffect(() => { + const selectedIndustryType = industries.find( + (industry) => industry.value === watch('industry_id') + ); + if (selectedIndustryType) { + updateForm('industry_id', `${selectedIndustryType?.value}`); + validate(); + setSelectedCategory(selectedIndustryType.category); + } + }, [watch('industry_id'), industries]); + + const estimasiValue = watch('estimasi'); + const tempoLimitValue = watch('tempoLimit'); + + // Memformat angka menjadi format rupiah + const formatRupiah = (value) => { + if (!value) return ''; + const numberString = value.replace(/[^0-9]/g, ''); // Menghapus karakter non-digit + return numberString + ? 'Rp ' + new Intl.NumberFormat('id-ID').format(numberString) + : ''; + }; + + const handleChange = (e) => { + const value = e.target.value; + const formattedValue = formatRupiah(value); + updateForm('estimasi', formattedValue.replace(/^Rp\s*/, '')); + validate(); + }; + const onChangeTempoDuration = (e) => { + updateForm('tempoDuration', `${e}`); + validate(); + }; + + const onChangeTempoLimit = (e) => { + updateForm('tempoLimit', `${e}`); + validate(); + }; + const [isCustom, setIsCustom] = React.useState(false); + const [tempoLimitValueEx, setTempoLimitValueEx] = React.useState(''); + const handleCheckboxBersediaChange = (value) => { + // if (value === 'bersedia') { + // setBersedia(true); + // } else if (value === 'tidakBersedia') { + // setBersedia(false); + // } + // updateForm('bersedia', `${value === 'bersedia'}`); + updateForm('bersedia', `${value}`); + validate(); + }; + const [selectedIds, setSelectedIds] = useState( + form.categoryProduk ? form.categoryProduk.split(',').map(Number) : [] // Parse string menjadi array angka + ); + + const handleCheckboxChange = (id) => { + const updatedSelected = selectedIds.includes(id) + ? selectedIds.filter((selectedId) => selectedId !== id) + : [...selectedIds, id]; + + setSelectedIds(updatedSelected); + + // Mengubah array kembali menjadi string yang dipisahkan oleh koma + updateForm('categoryProduk', updatedSelected.join(',')); + validate(); + }; + + useEffect(() => { + if (form.categoryProduk) { + setSelectedIds(form.categoryProduk.split(',').map(Number)); // Parse string menjadi array angka + } + }, [form.categoryProduk]); + const isChecked = (id) => selectedIds.includes(id); + + const handleInputChange = (event) => { + const { name, value } = event.target; + updateForm(name, value); + validate(); + }; + + const midIndex = Math.ceil(category_produk.length / 2); + const firstColumn = category_produk.slice(0, midIndex); + const secondColumn = category_produk.slice(midIndex); + const isFormValid = useMemo(() => Object.keys(errors).length === 0, [errors]); + + const nameRef = useRef(null); + const industry_idRef = useRef(null); + const streetRef = useRef(null); + const stateRef = useRef(null); + const cityRef = useRef(null); + const zipRef = useRef(null); + const mobileRef = useRef(null); + const bankNameRef = useRef(null); + const accountNameRef = useRef(null); + const accountNumberRef = useRef(null); + const estimasiRef = useRef(null); + const tempoDurationRef = useRef(null); + const bersediaRef = useRef(null); + const categoryProdukRef = useRef(null); + const tempoLimitRef = useRef(null); + useEffect(() => { + const loadIndustries = async () => { + if (!isFormValid) { + const options = { + behavior: 'smooth', + block: 'center', + }; + if (errors.name && nameRef.current) { + nameRef.current.scrollIntoView(options); + return; + } + if (errors.industry_id && industry_idRef.current) { + industry_idRef.current.scrollIntoView(options); + return; + } + if (errors.street && streetRef.current) { + streetRef.current.scrollIntoView(options); + return; + } + if (errors.state && stateRef.current) { + stateRef.current.scrollIntoView(options); + return; + } + if (errors.city && cityRef.current) { + cityRef.current.scrollIntoView(options); + return; + } + if (errors.zip && zipRef.current) { + zipRef.current.scrollIntoView(options); + return; + } + if (errors.mobile && mobileRef.current) { + mobileRef.current.scrollIntoView(options); + return; + } + if (errors.bankName && bankNameRef.current) { + bankNameRef.current.scrollIntoView(options); + return; + } + if (errors.accountName && accountNameRef.current) { + accountNameRef.current.scrollIntoView(options); + return; + } + if (errors.accountNumber && accountNumberRef.current) { + accountNumberRef.current.scrollIntoView(options); + return; + } + if (errors.estimasi && estimasiRef.current) { + estimasiRef.current.scrollIntoView(options); + return; + } + if (errors.tempoDuration && tempoDurationRef.current) { + tempoDurationRef.current.scrollIntoView(options); + return; + } + if (errors.bersedia && bersediaRef.current) { + bersediaRef.current.scrollIntoView(options); + return; + } + if (errors.categoryProduk && categoryProdukRef.current) { + categoryProdukRef.current.scrollIntoView(options); + return; + } + if (errors.tempoLimit && tempoLimitRef.current) { + tempoLimitRef.current.scrollIntoView(options); + return; + } + } + }; + loadIndustries(); + }, [buttonSubmitClick, chekValid]); + useEffect(() => { + if (form.industry_id) { + setValue('industry_id', parseInt(form.industry_id)); + } + if (form.state) { + setValue('state', parseInt(form.state)); + } + if (form.city) { + setValue('city', parseInt(form.city)); + } + if (form.tempoDuration) { + setValue('tempoDuration', form.tempoDuration); + } + if (form.tempoLimit) { + setValue('tempoLimit', form.tempoLimit); + } + if (form.tempoLimit) { + const isValueInOptions = radioOptions.some( + (option) => option.value === form.tempoLimit + ); + + if (isValueInOptions) { + setValue('tempoLimit', form.tempoLimit); // Set value dari radio options + setIsCustom(false); // Pastikan custom tidak aktif + } else { + setValue('tempoLimit', 'custom'); // Set value ke custom jika tidak termasuk dalam options + setIsCustom(true); // Aktifkan custom input + setTempoLimitValueEx(form.tempoLimit); // Set nilai input custom ke form.tempoLimit + } + } + }, [form]); + return ( + <> + {isDesktop && ( + <div className=''> + <h1 className={`font-bold ${isKonfirmasi ? 'text-xl' : ''}`}> + Informasi Perusahaan + </h1> + <form className='flex flex-col w-full '> + <div className='w-full grid grid-row-2 gap-5'> + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Perusahaan + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi detail perusahaan sesuai dengan nama yang terdaftar{' '} + </span> + )} + </div> + <div className='w-3/5'> + <input + id='name' + name='name' + placeholder='Masukkan nama perusahaan' + type='text' + className='form-input' + aria-invalid={errors.name} + value={form.name} + ref={nameRef} + onChange={handleInputChange} + /> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Format: PT. INDOTEKNIK DOTCOM GEMILANG + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.name} + </div> + )} + </div> + </div> + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5' ref={industry_idRef}> + <label className='form-label text-nowrap'>Industri</label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi detail perusahaan sesuai dengan nama yang terdaftar + </span> + )} + </div> + <div className='w-3/5'> + <Controller + name='industry_id' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={industries} + placeholder={'Pilih industri bisnis anda'} + /> + )} + /> + {!isKonfirmasi && selectedCategory && ( + <span className='text-gray_r-11 text-xs opacity-60'> + Kategori : {selectedCategory} + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.industry_id} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5 text-nowrap'> + <label className='form-label '>Alamat Perusahaan</label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + alamat sesuai dengan alamat kantor pusat + </span> + )} + </div> + <div className='w-3/5 flex gap-3 flex-col'> + <div> + <input + id='street' + name='street' + ref={streetRef} + placeholder='Masukkan alamat lengkap perusahaan' + type='text' + value={form.street} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.street} + </div> + )} + </div> + <div className='sub-alamat flex flex-row w-full gap-3'> + <div className='w-2/5' ref={stateRef}> + <Controller + name='state' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={states} + placeholder='Provinsi' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.state} + </div> + )} + </div> + <div className='w-1/3' ref={cityRef}> + <Controller + name='city' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={cities} + disabled={!watchState} + placeholder='Kota' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.city} + </div> + )} + </div> + <div className='w-1/3'> + <input + id='zip' + name='zip' + ref={zipRef} + placeholder='Kode Pos' + type='number' + value={form.zip} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.zip} + </div> + )} + </div> + </div> + </div> + </div> + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5 text-nowrap'> + <label className='form-label '>No. Telfon Perusahaan</label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi no telfon perusahaan yang sesuai + </span> + )} + </div> + <div className='w-3/5'> + <input + id='mobile' + name='mobile' + ref={mobileRef} + placeholder='Masukkan nomor telfon perusahaan' + type='tel' + value={form.mobile} + className='form-input' + aria-invalid={errors.mobile} + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.mobile} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className=' w-2/5 text-nowrap'> + <label className='form-label'>Data Bank</label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Isi detail data bank perusahaan anda + </span> + )} + </div> + <div className='w-3/5 flex gap-3 flex-row'> + <div> + <input + id='bankName' + name='bankName' + ref={bankNameRef} + placeholder='Nama bank' + type='text' + value={form.bankName} + className='form-input' + onChange={handleInputChange} + /> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Format: BCA, Mandiri, CIMB, BNI dll + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.bankName} + </div> + )} + </div> + <div> + <input + id='accountName' + name='accountName' + ref={accountNameRef} + placeholder='Nama Rekening' + type='text' + value={form.accountName} + className='form-input' + onChange={handleInputChange} + /> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Format: John Doe + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.accountName} + </div> + )} + </div> + <div> + <input + id='accountNumber' + name='accountNumber' + ref={accountNumberRef} + placeholder='Nomor Rekening Bank' + type='text' + value={form.accountNumber} + className='form-input' + onChange={handleInputChange} + /> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Format: 01234567896 + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.accountNumber} + </div> + )} + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5 text-nowrap'> + <label className='form-label '> + Website <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <input + id='website' + name='website' + placeholder='www.indoteknik.com' + type='text' + value={form.website} + className='form-input' + onChange={handleInputChange} + /> + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5 text-nowrap'> + <label className='form-label '> + Estimasi Pembelian pertahun + </label> + </div> + <div className='w-3/5'> + <div className='relative'> + <input + id='estimasi' + name='estimasi' + ref={estimasiRef} + // {...register('estimasi', { + // setValueAs: (value) => value.replace(/^Rp\s*/, ''), // Menyimpan hanya angka + // })} + placeholder='Isi estimasi pembelian produk pertahun' + type='text' + className='form-input' // padding untuk memberi ruang untuk "RP" + value={formatRupiah(form.estimasi)} + onChange={handleChange} // Mengatur perubahan input + /> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.estimasi} + </div> + )} + </div> + </div> + + <div className='flex flex-row justify-between items-center'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>Durasi Tempo</label> + <span className='text-xs opacity-60'> + Pilih durasi tempo yang anda inginkan + </span> + </div> + <div className='w-3/5 flex flex-row items-center'> + <div className='w-1/5' ref={tempoDurationRef}> + <RadioGroup + onChange={onChangeTempoDuration} + value={form.tempoDuration} + > + <Stack direction='column' className=''> + <Radio colorScheme='red' value='7'> + 7 Hari + </Radio> + <Radio colorScheme='red' value='14' className=''> + 14 Hari + </Radio> + <Radio colorScheme='red' value='30' className=''> + 30 Hari + </Radio> + </Stack> + </RadioGroup> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoDuration} + </div> + )} + </div> + {!isKonfirmasi && ( + <div className='w-4/5 flex flex-row justify-between items-center'> + <div className='w-2/5 text-nowrap'> + <label className='form-label '>Limit Tempo</label> + <span className='text-xs opacity-60'> + Ajukan nilai limit yang anda mau + </span> + </div> + <div + className='flex flex-col justify-start items-start' + ref={tempoLimitRef} + > + <RadioGroup + onChange={(value) => { + if (value === 'custom') { + setIsCustom(true); + updateForm('tempoLimit', tempoLimitValue); // Update dengan nilai input custom jika dipilih + } else { + setIsCustom(false); + onChangeTempoLimit(value); // Update dengan nilai radio button yang dipilih + } + }} + className='flex items-center justify-between' + value={isCustom ? 'custom' : form.tempoLimit} + > + <Stack direction='row'> + {/* Kolom 1 */} + <Stack + direction='column' + spacing={2} + className='mr-4' + > + {radioOptions.slice(0, 4).map((option) => ( + <Radio + key={option.value} + colorScheme='red' + value={option.value} + > + {option.label} + </Radio> + ))} + </Stack> + + {/* Kolom 2 */} + <Stack + direction='column' + className='ml-8' + spacing={2} + > + {radioOptions.slice(4).map((option) => ( + <Radio + key={option.value} + colorScheme='red' + value={option.value} + > + {option.label} + </Radio> + ))} + <div className='flex flex-row items-center'> + <Radio colorScheme='red' value='custom'></Radio> + + <input + placeholder='Isi limit yang anda inginkan' + type='text' + className='border ml-2 p-1' // padding untuk memberi ruang untuk "RP" + value={formatRupiah(tempoLimitValueEx)} // Menampilkan nilai terformat + onChange={(e) => { + const value = e.target.value; + const formattedValue = formatRupiah(value); + setTempoLimitValueEx(formattedValue); + updateForm( + 'tempoLimit', + formattedValue.replace(/^Rp\s*/, '') + ); // Mengupdate nilai di react-hook-form + }} + /> + </div> + </Stack> + </Stack> + </RadioGroup> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoLimit} + </div> + )} + </div> + </div> + )} + </div> + </div> + {isKonfirmasi && ( + <div className='flex flex-row justify-between items-center'> + <div className='w-2/5'> + <label className='form-label w-2/5 text-nowrap'> + Limit Tempo + </label> + <span className='text-xs opacity-60'> + Ajukan nilai limit yang anda mau + </span> + </div> + <div + className='w-3/5 flex flex-col justify-start items-start' + ref={tempoLimitRef} + > + <RadioGroup + onChange={(value) => { + if (value === 'custom') { + setIsCustom(true); + updateForm('tempoLimit', tempoLimitValue); // Update dengan nilai input custom jika dipilih + } else { + setIsCustom(false); + onChangeTempoLimit(value); // Update dengan nilai radio button yang dipilih + } + }} + className='flex items-center justify-between' + value={isCustom ? 'custom' : form.tempoLimit} + > + <Stack direction='row'> + {/* Kolom 1 */} + <Stack direction='column' spacing={2} className='mr-4'> + {radioOptions.slice(0, 4).map((option) => ( + <Radio + key={option.value} + colorScheme='red' + value={option.value} + > + {option.label} + </Radio> + ))} + </Stack> + + {/* Kolom 2 */} + <Stack direction='column' className='ml-8' spacing={2}> + {radioOptions.slice(4).map((option) => ( + <Radio + key={option.value} + colorScheme='red' + value={option.value} + > + {option.label} + </Radio> + ))} + <div className='flex flex-row items-center'> + <Radio colorScheme='red' value='custom'></Radio> + + <input + placeholder='Isi limit yang anda inginkan' + type='text' + className='border ml-2 p-1' // padding untuk memberi ruang untuk "RP" + value={formatRupiah(tempoLimitValueEx)} // Menampilkan nilai terformat + onChange={(e) => { + const value = e.target.value; + const formattedValue = formatRupiah(value); + setTempoLimitValueEx(formattedValue); + updateForm( + 'tempoLimit', + formattedValue.replace(/^Rp\s*/, '') + ); // Mengupdate nilai di react-hook-form + }} + /> + </div> + </Stack> + </Stack> + </RadioGroup> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoLimit} + </div> + )} + </div> + </div> + )} + + <div className='text-red-500'> + *Durasi dan limit dapat berbeda sesuai dengan verifikasi oleh + tim Indoteknik.com + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-wrap '> + Apakah bersedia transaksi via website? + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih produk bisa lebih dari 1 + </span> + )} + </div> + <div className='w-3/5 flex flex-col justify-start'> + <div className='flex gap-x-4' ref={bersediaRef}> + <RadioGroup + onChange={handleCheckboxBersediaChange} + value={form.bersedia} + > + <Stack direction='row'> + <Radio colorScheme='red' value='bersedia'> + Saya bersedia + </Radio> + <Radio colorScheme='red' value='tidakBersedia'> + Tidak bersedia + </Radio> + </Stack> + </RadioGroup> + {/* <Checkbox + name='bersedia' + borderColor='gray.600' + colorScheme='red' + isChecked={bersedia === true} // Checked when bersedia is true + onChange={() => handleCheckboxBersediaChange('bersedia')} + value={true} + size='md' + > + Saya bersedia + </Checkbox> + <Checkbox + name='bersedia' + borderColor='gray.600' + colorScheme='red' + isChecked={bersedia === false} // Checked when bersedia is false + onChange={() => handleCheckboxBersediaChange('tidakBersedia')} + value={false} + size='md' + > + Tidak bersedia + </Checkbox> */} + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.estimasi} + </div> + )} + </div> + </div> + + <div + className={`flex flex-row justify-between ${ + isKonfirmasi ? 'items-center' : 'items-start' + }`} + > + <div className='w-2/5 text-nowrap'> + <label className='form-label '> + Kategori Produk yang Digunakan + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih produk bisa lebih dari 1 + </span> + )} + </div> + <div className='w-3/5 flex flex-col'> + <div className='flex flex-row justify-between'> + <div + className='flex flex-col gap-2' + ref={categoryProdukRef} + > + {firstColumn.map((item) => ( + <Checkbox + colorScheme='red' + key={item.id} + onChange={() => handleCheckboxChange(item.id)} + isChecked={isChecked(item.id)} + > + {item.name} + </Checkbox> + ))} + </div> + <div className='flex flex-col gap-2'> + {secondColumn.map((item) => ( + <Checkbox + colorScheme='red' + key={item.id} + isChecked={isChecked(item.id)} + onChange={() => handleCheckboxChange(item.id)} + > + {item.name} + </Checkbox> + ))} + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.categoryProduk} + </div> + )} + </div> + </div> + </div> + </form> + </div> + )} + {isMobile && ( + <div className='text-sm'> + <h1 + className={`font-bold py-4 mt-8 ${ + isKonfirmasi ? 'hidden' : 'text-xl' + }`} + > + Informasi Perusahaan + </h1> + <form className='flex flex-col w-full '> + <div className='w-full grid grid-row-2 gap-4'> + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'> + Nama Perusahaan + </label> + <input + id='name' + name='name' + placeholder='Format: PT. INDOTEKNIK DOTCOM GEMILANG' + type='text' + className='form-input' + aria-invalid={errors.name} + value={form.name} + ref={nameRef} + onChange={handleInputChange} + /> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + isi detail perusahaan sesuai dengan nama yang terdaftar{' '} + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.name} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label text-nowrap'>Industri</label> + <div className='w-full' ref={industry_idRef}> + <Controller + name='industry_id' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={industries} + placeholder={ + 'Pilih Industri yang sesuai dengan perusahaan' + } + /> + )} + /> + </div> + {!isKonfirmasi && selectedCategory && ( + <span className='text-gray_r-11 text-xs opacity-60'> + Kategori : {selectedCategory} + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.industry_id} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label '>Alamat Perusahaan</label> + <input + id='street' + name='street' + ref={streetRef} + placeholder='Masukkan alamat lengkap perusahaan' + type='text' + value={form.street} + className='form-input' + onChange={handleInputChange} + /> + <div className='w-full text-nowrap'> + <div className='sub-alamat flex flex-row w-full gap-3'> + <div className='w-2/5' ref={stateRef}> + <Controller + name='state' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={states} + placeholder='Provinsi' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.state} + </div> + )} + </div> + <div className='w-1/3' ref={cityRef}> + <Controller + name='city' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={cities} + disabled={!watchState} + placeholder='Kota' + /> + )} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.city} + </div> + )} + </div> + <div className='w-1/3'> + <input + id='zip' + name='zip' + ref={zipRef} + placeholder='Kode Pos' + type='number' + value={form.zip} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.zip} + </div> + )} + </div> + </div> + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Isi detail alamat sesuai dengan yang terdaftar + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.street} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label '>No. Telfon Perusahaan</label> + <input + id='mobile' + name='mobile' + ref={mobileRef} + placeholder='Format: 08123456789 / (021) 123 4567' + type='tel' + value={form.mobile} + className='form-input' + aria-invalid={errors.mobile} + onChange={handleInputChange} + /> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Isi detail perusahaan sesuai dengan nama yang terdaftar + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.mobile} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label'>Data Bank</label> + <div className='flex gap-3 flex-row'> + <div> + <input + id='bankName' + name='bankName' + ref={bankNameRef} + placeholder='Nama bank' + type='text' + value={form.bankName} + className='form-input' + onChange={handleInputChange} + /> + </div> + <div> + <input + id='accountName' + name='accountName' + ref={accountNameRef} + placeholder='Nama Rekening' + type='text' + value={form.accountName} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.accountName} + </div> + )} + </div> + <div> + <input + id='accountNumber' + name='accountNumber' + ref={accountNumberRef} + placeholder='Nomor Rekening' + type='text' + value={form.accountNumber} + className='form-input' + onChange={handleInputChange} + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.accountNumber} + </div> + )} + </div> + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Isi data bank perusahaan sesuai dengan yang terdaftar + </span> + )} + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.bankName} + </div> + )} + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label '> + Website <span className=' opacity-60'>(Opsional)</span> + </label> + <input + id='website' + name='website' + placeholder='Format: www.indoteknik.com' + type='text' + value={form.website} + className='form-input' + onChange={handleInputChange} + /> + </div> + + <div className='flex flex-col gap-2 justify-between items-start'> + <label className='form-label '> + Estimasi Pembelian pertahun + </label> + <input + id='estimasi' + name='estimasi' + ref={estimasiRef} + // {...register('estimasi', { + // setValueAs: (value) => value.replace(/^Rp\s*/, ''), // Menyimpan hanya angka + // })} + placeholder='Isi estimasi pembelian produk pertahun' + type='text' + className='form-input' // padding untuk memberi ruang untuk "RP" + value={formatRupiah(form.estimasi)} + onChange={handleChange} // Mengatur perubahan input + /> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.estimasi} + </div> + )} + </div> + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + <div className='flex flex-col gap-2 justify-start items-start'> + <label className='form-label text-nowrap'>Durasi Tempo</label> + <div className='' ref={tempoDurationRef}> + <RadioGroup + size='sm' + onChange={onChangeTempoDuration} + value={form.tempoDuration} + > + <Stack direction='row' className=''> + <Radio colorScheme='red' value='7'> + 7 Hari + </Radio> + <Radio colorScheme='red' value='14' className=''> + 14 Hari + </Radio> + <Radio colorScheme='red' value='30' className=''> + 30 Hari + </Radio> + </Stack> + </RadioGroup> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoDuration} + </div> + )} + </div> + </div> + <div className='flex flex-col gap-2 justify-start items-start'> + <label className='form-label '>Limit Tempo</label> + <div + className='flex justify-between items-center ' + ref={tempoLimitRef} + > + <RadioGroup + size='sm' + onChange={(value) => { + if (value === 'custom') { + setIsCustom(true); + updateForm('tempoLimit', tempoLimitValue); // Update dengan nilai input custom jika dipilih + } else { + setIsCustom(false); + onChangeTempoLimit(value); // Update dengan nilai radio button yang dipilih + } + }} + className='flex items-center justify-between' + value={isCustom ? 'custom' : form.tempoLimit} + > + <Stack direction='row'> + {/* Kolom 1 */} + <Stack direction='row' spacing={2} className='mr-4'> + {radioOptions.slice(0, 3).map((option) => ( + <Radio + key={option.value} + colorScheme='red' + value={option.value} + > + {option.label} + </Radio> + ))} + <Radio colorScheme='red' value='custom'></Radio> + + <input + placeholder='Isi limit' + type='text' + className='border ml-1 p-1 w-full ' // padding untuk memberi ruang untuk "RP" + value={formatRupiah(tempoLimitValueEx)} // Menampilkan nilai terformat + onChange={(e) => { + const value = e.target.value; + const formattedValue = formatRupiah(value); + setTempoLimitValueEx(formattedValue); + updateForm( + 'tempoLimit', + formattedValue.replace(/^Rp\s*/, '') + ); // Mengupdate nilai di react-hook-form + }} + /> + </Stack> + + {/* Kolom 2 */} + {/* <Stack direction='column' className='ml-8' spacing={2}> + {radioOptions.slice(4).map((option) => ( + <Radio + key={option.value} + colorScheme='red' + value={option.value} + > + {option.label} + </Radio> + ))} + <div className='flex flex-row items-center'></div> + </Stack> */} + </Stack> + </RadioGroup> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoLimit} + </div> + )} + </div> + </div> + <div className='text-red-500 text-xs'> + **Durasi & Limit dapat berbeda dengan verifikasi oleh tim + indoteknik.com + </div> + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + <div className='flex flex-col gap justify-between items-start'> + <label className='form-label text-wrap '> + Apakah bersedia transaksi via website? + </label> + <div className='flex gap-x-4' ref={bersediaRef}> + <RadioGroup + size='sm' + onChange={handleCheckboxBersediaChange} + value={form.bersedia} + > + <Stack direction='col'> + <Radio colorScheme='red' value='bersedia'> + Saya bersedia + </Radio> + <Radio colorScheme='red' value='tidakBersedia'> + Tidak bersedia + </Radio> + </Stack> + </RadioGroup> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.estimasi} + </div> + )} + </div> + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + + <div + className={`flex flex-col gap-2 justify-between ${ + isKonfirmasi ? 'items-start' : 'items-start' + }`} + > + <label className='form-label '> + Kategori Produk yang Digunakan + </label> + <div className='flex flex-col justify-between gap-2 '> + <div className='flex flex-col gap-2' ref={categoryProdukRef}> + {firstColumn.map((item) => ( + <Checkbox + size='sm' + colorScheme='red' + key={item.id} + onChange={() => handleCheckboxChange(item.id)} + isChecked={isChecked(item.id)} + > + {item.name} + </Checkbox> + ))} + </div> + <div className='flex flex-col gap-2'> + {secondColumn.map((item) => ( + <Checkbox + size='sm' + colorScheme='red' + key={item.id} + isChecked={isChecked(item.id)} + onChange={() => handleCheckboxChange(item.id)} + > + {item.name} + </Checkbox> + ))} + </div> + </div> + {chekValid && ( + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.categoryProduk} + </div> + )} + </div> + </div> + </form> + </div> + )} + </> + ); +}; + +export default InformasiPerusahaan; |
