diff options
Diffstat (limited to 'src/lib/merchant/components')
| -rw-r--r-- | src/lib/merchant/components/AccountSwitch.jsx | 60 | ||||
| -rw-r--r-- | src/lib/merchant/components/Dokumen.jsx | 1252 | ||||
| -rw-r--r-- | src/lib/merchant/components/InformasiPerusahaan.jsx | 1399 | ||||
| -rw-r--r-- | src/lib/merchant/components/InformasiVendor.jsx | 748 | ||||
| -rw-r--r-- | src/lib/merchant/components/Konfirmasi.jsx | 224 | ||||
| -rw-r--r-- | src/lib/merchant/components/Merchant.jsx | 147 | ||||
| -rw-r--r-- | src/lib/merchant/components/SyaratDagang.jsx | 822 |
7 files changed, 4652 insertions, 0 deletions
diff --git a/src/lib/merchant/components/AccountSwitch.jsx b/src/lib/merchant/components/AccountSwitch.jsx new file mode 100644 index 00000000..b9bf34b1 --- /dev/null +++ b/src/lib/merchant/components/AccountSwitch.jsx @@ -0,0 +1,60 @@ +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(); + + return ( + <div className='container flex flex-col items-center gap-4'> + <div + className={`flex ${ + isMobile ? 'w-full' : 'w-2/3' + } justify-center items-center`} + > + <h1 + className={`text-red-500 text-center py-4 font-semibold ${ + isMobile ? 'text-lg' : 'text-3xl' + }`} + > + Form Merchant Kamu Gagal Dilakukan + </h1> + </div> + <Image + src='/images/ICON_TEMPO.png' + alt='Registrasi Tempo' + width={isMobile ? 300 : 550} + height={isMobile ? 300 : 550} + /> + + <div + className={`mt-2 text-center opacity-75 leading-6 p-4 md:p-0 ${ + isMobile ? 'w-full text-sm' : 'w-4/5 text-base' + }`} + > + Terima kasih atas minat anda untuk mendaftar merchant, namun sayangnya + akun anda bukan merupakan akun bisnis. Segera ubah akun anda menjadi + Bisnis untuk menggunakan fitur ini + </div> + <Link + href={'/my/profile'} + className='btn-solid-red rounded-md text-base flex flex-row items-center justify-center' + > + Ubah Akun + <ChevronRightIcon className='w-5' /> + </Link> + </div> + ); +}; + +export default FinishTempo; diff --git a/src/lib/merchant/components/Dokumen.jsx b/src/lib/merchant/components/Dokumen.jsx new file mode 100644 index 00000000..c13353e5 --- /dev/null +++ b/src/lib/merchant/components/Dokumen.jsx @@ -0,0 +1,1252 @@ +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'; +import cityApi from '@/lib/address/api/cityApi'; +import stateApi from '@/lib/address/api/stateApi.js'; +import districtApi from '@/lib/address/api/districtApi'; +import subDistrictApi from '@/lib/address/api/subDistrictApi'; +import { yupResolver } from '@hookform/resolvers/yup'; +import React, { + useEffect, + useRef, + useState, + forwardRef, + useImperativeHandle, +} from 'react'; +import ReCAPTCHA from 'react-google-recaptcha'; +import { Controller, useForm } from 'react-hook-form'; +import { toast } from 'react-hot-toast'; +import * as Yup from 'yup'; +import createMerchantApi from '../api/createMerchantApi'; +import getMerchantApi from '../api/getMerchantApi'; +import addressApi from '@/lib/address/api/addressApi'; +import PageContent from '@/lib/content/components/PageContent'; +import { useRouter } from 'next/router'; +import useAuth from '@/core/hooks/useAuth'; +import { Radio, RadioGroup, Stack, Divider, Button } from '@chakra-ui/react'; +import { EyeIcon } from '@heroicons/react/24/outline'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import Image from 'next/image'; +import ImageBanner from '~/components/ui/image'; +import { ChevronRightIcon } from '@heroicons/react/24/outline'; +import MobileView from '@/core/components/views/MobileView'; +import DesktopView from '@/core/components/views/DesktopView'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import odooApi from '~/libs/odooApi'; +const Dokumen = forwardRef( + ({ handleIsError, isKonfirmasi, buttonSubmitClick }, ref) => { + const isError = (value) => { + // Logika menentukan error + const result = value ? true : false; + handleIsError(result); // Panggil handleIsError dari Merchant + return result; + }; + const { + register, + handleSubmit, + formState: { errors }, + control, + reset, + watch, + setValue, + getValues, + } = useForm({ + resolver: yupResolver(validationSchema), + defaultValues, + }); + + const list_unit = [ + { + value: 'Manufacturing', + label: 'Manufacturing', + }, + { + value: 'Hospitality', + label: 'Hospitality', + }, + { + value: 'Automotive', + label: 'Automotive', + }, + { + value: 'Retail', + label: 'Retail', + }, + { + value: 'Maining', + label: 'Maining', + }, + { + value: 'Lain - Lain', + label: 'Lain - Lain', + }, + ]; + const [fileNames, setFileNames] = useState({}); + const [DeatailFile, setDetailFile] = useState({}); + const [isExample, setIsExample] = useState(false); + const [isPkp, setIsPkp] = useState(false); + + const npwpRef = useRef(null); + const sppkpRef = useRef(null); + const ktpDirutRef = useRef(null); + const kartuNamaRef = useRef(null); + const suratPernyataanRef = useRef(null); + const fotoKantorRef = useRef(null); + const dataProdukRef = useRef(null); + const pricelistRef = useRef(null); + const router = useRouter(); + + const auth = useAuth(); + if (auth == false) { + router.push(`/login?next=${encodeURIComponent('/daftar-merchant')}`); + } + useEffect(() => { + const loadData = async () => { + try { + const data = await getMerchantApi(); + if (data) { + setFileNames((prev) => ({ + ...prev, + ['npwp']: data.fileNpwp ? data.fileNpwp.name : '', + ['sppkp']: data.fileSppkp ? data.fileSppkp.name : '', + ['dokumenKtpDirut']: data.fileDokumenKtpDirut + ? data.fileDokumenKtpDirut.name + : '', + ['kartuNama']: data.fileKartuNama ? data.fileKartuNama.name : '', + ['suratPernyataan']: data.fileSuratPernyataan + ? data.fileSuratPernyataan.name + : '', + ['fotoKantor']: data.fileFotoKantor + ? data.fileFotoKantor.name + : '', + ['dataProduk']: data.fileDataProduk + ? data.fileDataProduk.name + : '', + ['pricelist']: data.filePricelist ? data.filePricelist.name : '', + })); + } + } catch (error) { + console.error('Error loading profile:', error); + handleIsError(true); // Jika ada error, panggil fungsi error handler + } + }; + + loadData(); + }, [reset, handleIsError]); + + useEffect(() => { + if (!isKonfirmasi) { + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + } + }, []); + useImperativeHandle(ref, () => () => { + handleSubmit(onSubmitHandler)(); + }); + useEffect(() => { + const loadProfile = async () => { + try { + const dataProfile = await addressApi({ + id: auth.parentId ? auth.parentId : auth.partnerId, + }); + if (dataProfile.companyType == 'pkp') { + setIsPkp(true); + } + setValue('company', dataProfile?.name); + setValue('address', dataProfile?.alamatBisnis); + setValue('state', parseInt(dataProfile.stateId.id)); + setValue('city', parseInt(dataProfile.city.id)); + setValue('district', parseInt(dataProfile.district.id)); + setValue('subDistrict', parseInt(dataProfile.subDistrict.id)); + setValue('zip', parseInt(dataProfile.zip)); + } catch (error) { + console.error('Error loading profile:', error); + } + }; + + loadProfile(); + }, [auth?.parentId]); + + const onSubmitHandler = async (values) => { + const options = { + behavior: 'smooth', + block: 'center', + }; + const npwp = { name: fileNames.npwp, format: DeatailFile.npwp }; + const sppkp = { name: fileNames.sppkp, format: DeatailFile.sppkp }; + const dokumenKtpDirut = { + name: fileNames.dokumenKtpDirut, + format: DeatailFile.dokumenKtpDirut, + }; + const kartuNama = { + name: fileNames.kartuNama, + format: DeatailFile.kartuNama, + }; + const suratPernyataan = { + name: fileNames.suratPernyataan, + format: DeatailFile.suratPernyataan, + }; + const fotoKantor = { + name: fileNames.fotoKantor, + format: DeatailFile.fotoKantor, + }; + const dataProduk = { + name: fileNames.dataProduk, + format: DeatailFile.dataProduk, + }; + const pricelist = { + name: fileNames.pricelist, + format: DeatailFile.pricelist, + }; + + if (!npwp.name && isPkp) { + if (npwpRef?.current) { + npwpRef.current.scrollIntoView(options); + } + toast.error('NPWP wajib di tambahkan'); + return; + } + if (!sppkp.name && isPkp) { + toast.error('SPPKP wajib di tambahkan'); + if (sppkpRef?.current) { + sppkpRef.current.scrollIntoView(options); + } + return; + } + if (!dokumenKtpDirut.name && !isPkp) { + toast.error('KTP Dirut/Direktur wajib di tambahkan'); + if (ktpDirutRef?.current) { + ktpDirutRef.current.scrollIntoView(options); + } + return; + } + if (!fotoKantor.name) { + toast.error('Foto Gudang / Kantor Bagian Depan wajib di tambahkan'); + if (fotoKantorRef?.current) { + fotoKantorRef.current.scrollIntoView(options); + } + return; + } + if (!pricelist.name) { + toast.error('Pricelist wajib di tambahkan'); + if (pricelistRef?.current) { + pricelistRef.current.scrollIntoView(options); + } + return; + } + const toastId = toast.loading('Mengirimkan formulir merchant...'); + const dokumen = { + file_npwp: { details: npwp.format ? npwp : '' }, + file_sppkp: { details: sppkp.format ? sppkp : '' }, + file_dokumenKtpDirut: { + details: dokumenKtpDirut.format ? dokumenKtpDirut : '', + }, + file_kartuNama: { details: kartuNama.format ? kartuNama : '' }, + file_suratPernyataan: { + details: suratPernyataan.format ? suratPernyataan : '', + }, + file_fotoKantor: { details: fotoKantor.format ? fotoKantor : '' }, + file_dataProduk: { details: dataProduk.format ? dataProduk : '' }, + file_pricelist: { details: pricelist.format ? pricelist : '' }, + }; + let data = { + file_dokumen: JSON.stringify(dokumen), + }; + const create_leads = await createMerchantApi({ data }); + if (create_leads) { + toast.dismiss(toastId); + toast.success('Berhasil menambahkan data'); + isError(false); + reset(); + } else { + toast.dismiss(toastId); + toast.error('Gagal menambahkan data'); + } + }; + + if (!auth) { + return; + } + + const handleFileChange = async (event) => { + let fileBase64 = ''; + const file = event.target.files[0]; + + if (file.size > 2000000) { + // try { + // const toastId = toast.loading('mencoba mengompresi file...'); + // // Compress image file + // const options = { + // maxSizeMB: 0.5, // Target size in MB + // maxWidthOrHeight: 1920, // Adjust as needed + // useWebWorker: true, + // }; + // const compressedFile = await imageCompression(file, options); + // toast.success('berhasil mengompresi file', { duration: 4000 }); + // // Convert compressed file to Base64 + // fileBase64 = await getFileBase64(compressedFile); + // } catch (error) { + // toast.error('Gagal mengompresi file', { duration: 4000 }); + // } + toast.error('Maks file size 2MB', { duration: 4000 }); + } else { + // Convert file to Base64 + fileBase64 = await getFileBase64(file); + } + const fieldName = event.target.name; // Nama input file + setDetailFile((prev) => ({ + ...prev, + [fieldName]: file ? fileBase64 : '', // Tambahkan atau perbarui file di state + })); + setFileNames((prev) => ({ + ...prev, + [fieldName]: file ? file.name : '', // Tambahkan atau perbarui file di state + })); + }; + return ( + <> + <BottomPopup + className='' + title='Contoh SPPKP' + active={isExample} + close={() => setIsExample(false)} + > + <div className='flex p-2'> + <Image + src='/images/NO-SPPKP-FORMAT-TEMPLATE.jpg' + alt='Contoh SPPKP' + className='w-full h-full ' + width={800} + height={800} + quality={85} + /> + </div> + </BottomPopup> + <DesktopView> + <div className='container flex flex-col items-star py-4 '> + <h2 className='text-xs md:text-title-sm font-semibold mb-6'> + Dokumen + </h2> + + <div className='w-full mt-4'> + <form + onSubmit={handleSubmit(onSubmitHandler)} + className='flex flex-col gap-4' + > + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + NPWP{' '} + {!isPkp && ( + <span className=' opacity-60'>(Opsional)</span> + )} + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Pastikan dokumen yang anda upload sudah benar + </span> + )} + </div> + <div + className={`w-3/5 flex flex-col justify-between ${ + isKonfirmasi ? 'items-end' : 'items-start' + }`} + ref={npwpRef} + > + <div + className={`flex flex-row items-start gap-2 w-full ${ + isKonfirmasi ? 'justify-end' : 'justify-start' + }`} + > + {isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.npwp} + </span> + )} + <label + htmlFor='npwp' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.npwp ? 'Ubah Dokumen' : 'Upload Dokumen'} + </label> + <input + {...register('npwp')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='npwp' + onChange={(e) => { + handleFileChange(e); // Untuk update UI (opsional) + }} + aria-invalid={errors.npwp?.message} + /> + {!isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.npwp} + </span> + )} + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + )} + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.npwp?.message} + </div> + </div> + </div> + <div + className={`w-full flex flex-row items-start ${ + isKonfirmasi && 'gap-2' + } `} + > + <div className='w-2/5 flex flex-row justify-between items-center '> + <div> + <label className='form-label text-nowrap' ref={sppkpRef}> + SPPKP{' '} + {!isPkp && ( + <span className=' opacity-60'>(Opsional)</span> + )} + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Pastikan dokumen yang anda upload sudah benar + </span> + )} + </div> + <div + onClick={() => setIsExample(!isExample)} + className={`h-fit ${ + !isKonfirmasi && 'mr-8' + } rounded text-white p-2 flex flex-row items-center bg-red-500 hover:cursor-pointer hover:bg-red-400`} + > + <EyeIcon + className={`${isKonfirmasi ? 'w-4' : 'w-4 mr-2'} `} + /> + {!isKonfirmasi && ( + <p className='font-light text-xs '>Lihat Contoh</p> + )} + </div> + </div> + <div + className={`w-3/5 flex flex-col justify-between ${ + isKonfirmasi ? 'items-end' : 'items-start' + }`} + > + <div className='flex flex-row items-start justify-start gap-2'> + {isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2 '> + {fileNames.sppkp} + </span> + )} + <label + htmlFor='sppkp' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.sppkp ? 'Ubah Dokumen' : 'Upload Dokumen'} + </label> + <input + {...register('sppkp')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='sppkp' + onChange={handleFileChange} + aria-invalid={errors.sppkp?.message} + /> + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + )} + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.sppkp?.message} + </div> + </div> + </div> + + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + KTP Dirut/Direktur{' '} + {isPkp && <span className=' opacity-60'>(Opsional)</span>} + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Pastikan dokumen yang anda upload sudah benar + </span> + )} + </div> + <div + className={`w-3/5 flex flex-col justify-between ${ + isKonfirmasi ? 'items-end' : 'items-start' + }`} + ref={ktpDirutRef} + > + <div + className={`flex flex-row items-start ${ + isKonfirmasi ? 'justify-end' : 'justify-start' + } gap-2 w-full`} + > + {isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.dokumenKtpDirut} + </span> + )} + <label + htmlFor='dokumenKtpDirut' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.dokumenKtpDirut + ? 'Ubah Dokumen' + : 'Upload Dokumen'} + </label> + <input + {...register('dokumenKtpDirut')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='dokumenKtpDirut' + onChange={handleFileChange} + aria-invalid={errors.dokumenKtpDirut?.message} + /> + {!isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.dokumenKtpDirut} + </span> + )} + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + )} + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.dokumenKtpDirut?.message} + </div> + </div> + </div> + + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label + className='form-label text-nowrap' + ref={kartuNamaRef} + > + Kartu Nama <span className=' opacity-60'>(Opsional)</span>{' '} + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Pastikan dokumen yang anda upload sudah benar + </span> + )} + </div> + <div + className={`w-3/5 flex flex-col justify-between ${ + isKonfirmasi ? 'items-end' : 'items-start' + }`} + > + <div className='flex flex-row items-start justify-start gap-2'> + {isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.kartuNama} + </span> + )} + <label + htmlFor='kartuNama' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.kartuNama + ? 'Ubah Dokumen' + : 'Upload Dokumen'} + </label> + <input + {...register('kartuNama')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='kartuNama' + onChange={handleFileChange} + aria-invalid={errors.kartuNama?.message} + /> + {!isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.kartuNama} + </span> + )} + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + )} + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.kartuNama?.message} + </div> + </div> + </div> + + <div className='w-full flex flex-row items-start '> + <div className='w-2/5 flex flex-row justify-between items-center '> + <div> + <label + className={`form-label ${ + isKonfirmasi ? 'text-wrap' : ' text-nowrap' + }`} + ref={suratPernyataanRef} + > + Surat Pernyataan Nomor Rekening{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Wajib diisi jika nomor rekening berbeda dengan nama + perusahaan + </span> + )} + </div> + <a + href='/file/Surat Pernyataan Nomor Rekening.docx' + download='Surat Pernyataan Nomor Rekening.docx' + className='h-fit mr-8 rounded text-white p-2 flex flex-row items-center bg-red-500 hover:cursor-pointer hover:bg-red-400' + > + <p className='font-light text-xs'>Download Template</p> + </a> + </div> + <div + className={`w-3/5 flex flex-col justify-between ${ + isKonfirmasi ? 'items-end' : 'items-start' + }`} + > + <div className='flex flex-row items-start justify-start gap-2'> + {isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.suratPernyataan} + </span> + )} + <label + htmlFor='suratPernyataan' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.suratPernyataan + ? 'Ubah Dokumen' + : 'Upload Dokumen'} + </label> + <input + {...register('suratPernyataan')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='suratPernyataan' + onChange={handleFileChange} + aria-invalid={errors.suratPernyataan?.message} + /> + {!isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.suratPernyataan} + </span> + )} + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + )} + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.suratPernyataan?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row items-start '> + <div className='w-2/5 flex flex-col justify-start items-start '> + <label + className={`form-label ${ + isKonfirmasi ? 'text-wrap' : 'text-nowrap' + }`} + ref={fotoKantorRef} + > + Foto Gudang / Kantor Bagian Depan + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Pastikan dokumen yang anda upload sudah benar + </span> + )} + </div> + <div + className={`w-3/5 flex flex-col justify-between ${ + isKonfirmasi ? 'items-end' : 'items-start' + }`} + > + <div className='flex flex-row items-start justify-start gap-2'> + {isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.fotoKantor} + </span> + )} + <label + htmlFor='fotoKantor' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.fotoKantor + ? 'Ubah Dokumen' + : 'Upload Dokumen'} + </label> + <input + {...register('fotoKantor')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='fotoKantor' + onChange={handleFileChange} + aria-invalid={errors.fotoKantor?.message} + /> + {!isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.fotoKantor} + </span> + )} + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + )} + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.fotoKantor?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row items-start '> + <div className='w-2/5 flex flex-col justify-start items-start '> + <label + className={`form-label ${ + isKonfirmasi ? 'text-wrap' : 'text-nowrap' + }`} + ref={dataProdukRef} + > + Data Produk (Item Name, Gambar, Deskripsi){' '} + <span className=' opacity-60'>(Opsional)</span>{' '} + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Pastikan dokumen yang anda upload sudah benar + </span> + )} + </div> + <div + className={`w-3/5 flex flex-col justify-between ${ + isKonfirmasi ? 'items-end' : 'items-start' + }`} + > + <div className='flex flex-row items-start justify-start gap-2'> + {isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.dataProduk} + </span> + )} + <label + htmlFor='dataProduk' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.dataProduk + ? 'Ubah Dokumen' + : 'Upload Dokumen'} + </label> + <input + {...register('dataProduk')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='dataProduk' + onChange={handleFileChange} + aria-invalid={errors.dataProduk?.message} + /> + {!isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.dataProduk} + </span> + )} + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + )} + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.dataProduk?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row items-start '> + <div className='w-2/5 flex flex-col justify-start items-start '> + <label + className='form-label text-nowrap' + ref={pricelistRef} + > + Pricelist + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Pastikan dokumen yang anda upload sudah benar + </span> + )} + </div> + <div + className={`w-3/5 flex flex-col justify-between ${ + isKonfirmasi ? 'items-end' : 'items-start' + }`} + > + <div className='flex flex-row items-start justify-start gap-2'> + {isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.pricelist} + </span> + )} + <label + htmlFor='pricelist' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.pricelist + ? 'Ubah Dokumen' + : 'Upload Dokumen'} + </label> + <input + {...register('pricelist')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='pricelist' + onChange={handleFileChange} + aria-invalid={errors.pricelist?.message} + /> + {!isKonfirmasi && ( + <span className='mt-2 text-gray-600 line-clamp-2'> + {fileNames.pricelist} + </span> + )} + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + )} + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.pricelist?.message} + </div> + </div> + </div> + <div className=''> + {/* <div> + <ReCAPTCHA + ref={recaptchaRef} + sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_GOOGLE} + /> + </div> */} + </div> + <div className='flex justify-end'> + {/* <Button + colorScheme='red' + className='w-full md:w-fit' + type='submit' + > + Daftar Merchant{' '} + {<ChevronRightIcon className='w-5' color='white' />} + </Button> */} + {!isKonfirmasi && ( + <div> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <button + type='submit' + className='btn-light bg-red-500 rounded-lg text-white w-fit py-2 px-4 md:w-fit mt-2 ml-0 md:ml-auto flex justify-between hover:bg-red-400' + > + <span className={` `}>Langkah Selanjutnya</span> + {<ChevronRightIcon className='w-5' />} + </button> + </div> + )} + </div> + </form> + <PageContent path='/daftar-merchant' /> + </div> + </div> + </DesktopView> + <MobileView> + <div className='container flex flex-col items-star py-4'> + {!isKonfirmasi && ( + <h2 className='font-semibold mb-6 text-xl'>Dokumen</h2> + )} + + <div className='w-full mt-4'> + <form + onSubmit={handleSubmit(onSubmitHandler)} + className='flex flex-col gap-4' + > + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + NPWP{' '} + {!isPkp && <span className=' opacity-60'>(Opsional)</span>} + </label> + <div className='flex flex-row items-center justify-start gap-2'> + <label + htmlFor='npwp' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.npwp ? 'Ubah Dokumen' : 'Upload Dokumen'} + </label> + <input + {...register('npwp')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='npwp' + onChange={(e) => { + handleFileChange(e); // Untuk update UI (opsional) + }} + aria-invalid={errors.npwp?.message} + /> + <span className=' text-gray-600 line-clamp-2'> + {fileNames.npwp} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.npwp?.message} + </div> + </div> + <div className='w-full flex flex-col gap-2 items-start '> + <div className='flex flex-row w-full justify-between items-center '> + <label className='form-label text-nowrap'> + SPPKP{' '} + {!isPkp && ( + <span className=' opacity-60'>(Opsional)</span> + )} + </label> + <div + onClick={() => setIsExample(!isExample)} + className='h-fit rounded text-white p-2 flex flex-row items-center bg-red-500 hover:cursor-pointer hover:bg-red-400' + > + <EyeIcon className={`w-4 mr-2 `} /> + + <p className='font-light text-xs '>Lihat Contoh</p> + </div> + </div> + <div className='flex flex-row items-center justify-start gap-2'> + <label + htmlFor='sppkp' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.sppkp ? 'Ubah Dokumen' : 'Upload Dokumen'} + </label> + <input + {...register('sppkp')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='sppkp' + onChange={handleFileChange} + aria-invalid={errors.sppkp?.message} + /> + <span className=' text-gray-600 line-clamp-2'> + {fileNames.sppkp} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.sppkp?.message} + </div> + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + KTP Dirut/Direktur{' '} + {isPkp && <span className=' opacity-60'>(Opsional)</span>} + </label> + <div className='flex flex-row items-center justify-start gap-2 '> + <label + htmlFor='dokumenKtpDirut' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.dokumenKtpDirut + ? 'Ubah Dokumen' + : 'Upload Dokumen'} + </label> + <input + {...register('dokumenKtpDirut')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='dokumenKtpDirut' + onChange={handleFileChange} + aria-invalid={errors.dokumenKtpDirut?.message} + /> + <span className=' text-gray-600 line-clamp-2'> + {fileNames.dokumenKtpDirut} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.dokumenKtpDirut?.message} + </div> + </div> + + <div className='w-full flex flex-col gap-2'> + <label className='form-label text-nowrap'> + Kartu Nama <span className=' opacity-60'>(Opsional)</span>{' '} + </label> + <div className='flex flex-row items-center justify-start gap-2'> + <label + htmlFor='kartuNama' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.kartuNama ? 'Ubah Dokumen' : 'Upload Dokumen'} + </label> + <input + {...register('kartuNama')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='kartuNama' + onChange={handleFileChange} + aria-invalid={errors.kartuNama?.message} + /> + <span className=' text-gray-600 line-clamp-2'> + {fileNames.kartuNama} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.kartuNama?.message} + </div> + </div> + + <div className='w-full flex flex-col gap-2 items-start '> + <div className='flex flex-row w-full justify-between items-center'> + <label className='form-label text-wrap'> + Surat Pernyataan Nomor Rekening{' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + <a + href='/file/Surat Pernyataan Nomor Rekening.docx' + download='Surat Pernyataan Nomor Rekening.docx' + className='h-fit rounded text-white p-2 flex flex-row items-center bg-red-500 hover:cursor-pointer hover:bg-red-400' + > + <p className='font-light text-xs text-nowrap'> + Download Template + </p> + </a> + </div> + <div className='flex flex-row items-center justify-start gap-2'> + <label + htmlFor='suratPernyataan' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.suratPernyataan + ? 'Ubah Dokumen' + : 'Upload Dokumen'} + </label> + <input + {...register('suratPernyataan')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='suratPernyataan' + onChange={handleFileChange} + aria-invalid={errors.suratPernyataan?.message} + /> + <span className=' text-gray-600 line-clamp-2'> + {fileNames.suratPernyataan} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.suratPernyataan?.message} + </div> + </div> + <div className='w-full flex flex-col gap-2 items-start '> + <label className='form-label text-nowrap'> + Foto Gudang / Kantor Bagian Depan + </label> + <div className='flex flex-row items-center justify-start gap-2 '> + <label + htmlFor='fotoKantor' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.fotoKantor ? 'Ubah Dokumen' : 'Upload Dokumen'} + </label> + <input + {...register('fotoKantor')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='fotoKantor' + onChange={handleFileChange} + aria-invalid={errors.fotoKantor?.message} + /> + <span className=' text-gray-600 line-clamp-2'> + {fileNames.fotoKantor} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.fotoKantor?.message} + </div> + </div> + <div className='w-full flex flex-col gap-2 items-start '> + <label className='form-label text-wrap'> + Data Produk (Item Name, Gambar, Deskripsi){' '} + <span className=' opacity-60'>(Opsional)</span>{' '} + </label> + <div className='flex flex-row items-center justify-start gap-2'> + <label + htmlFor='dataProduk' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.dataProduk ? 'Ubah Dokumen' : 'Upload Dokumen'} + </label> + <input + {...register('dataProduk')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='dataProduk' + onChange={handleFileChange} + aria-invalid={errors.dataProduk?.message} + /> + <span className=' text-gray-600 line-clamp-2'> + {fileNames.dataProduk} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.fotoKantor?.message} + </div> + </div> + <div className='w-full flex flex-col gap-2 items-start '> + <label className='form-label text-nowrap'>Pricelist</label> + <div className='flex flex-row items-center justify-start gap-2'> + <label + htmlFor='pricelist' + className='cursor-pointer min-w-40 text-center bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded' + > + {fileNames.pricelist ? 'Ubah Dokumen' : 'Upload Dokumen'} + </label> + <input + {...register('pricelist')} + type='file' + className='form-input hidden' + accept='.pdf,.png,.jpg,.jpeg' + id='pricelist' + onChange={handleFileChange} + aria-invalid={errors.pricelist?.message} + /> + <span className=' text-gray-600 line-clamp-2'> + {fileNames.pricelist} + </span> + </div> + <span className='text-xs opacity-60 text-red-500'> + Format: pdf, jpeg, jpg, png. max file size 2MB + </span> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.pricelist?.message} + </div> + </div> + <div className=''> + {/* <div> + <ReCAPTCHA + ref={recaptchaRef} + sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_GOOGLE} + /> + </div> */} + </div> + <div className='flex justify-center w-full '> + {/* <Button + colorScheme='red' + className='w-full md:w-fit' + type='submit' + > + Daftar Merchant{' '} + {<ChevronRightIcon className='w-5' color='white' />} + </Button> */} + {!isKonfirmasi && ( + <div className='w-full'> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <button + type='submit' + className='btn-light bg-red-500 rounded-lg text-white w-full py-2 px-4 md:w-fit mt-2 ml-0 md:ml-auto flex justify-center hover:bg-red-400' + > + <span className={` `}>Langkah Selanjutnya</span> + {<ChevronRightIcon className='w-5' />} + </button> + </div> + )} + </div> + </form> + <PageContent path='/daftar-merchant' /> + </div> + </div> + </MobileView> + </> + ); + } +); +const validationSchema = Yup.object().shape({ + npwp: Yup.mixed().required('File is required'), + pricelist: Yup.mixed().required('File is required'), +}); +const defaultValues = { + company: '', + pejabatName: '', + PICName: '', + PICPosition: '', + email: '', + emailSales: '', + emailFinance: '', + phone: '', + state: '', + city: '', + district: '', + subDistrict: '', + zip: '', + bank: '', + rekening: '', + accountNumber: '', + address: '', + mobile: '', +}; + +export default Dokumen; diff --git a/src/lib/merchant/components/InformasiPerusahaan.jsx b/src/lib/merchant/components/InformasiPerusahaan.jsx new file mode 100644 index 00000000..ee5560a9 --- /dev/null +++ b/src/lib/merchant/components/InformasiPerusahaan.jsx @@ -0,0 +1,1399 @@ +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'; +import cityApi from '@/lib/address/api/cityApi'; +import stateApi from '@/lib/address/api/stateApi.js'; +import districtApi from '@/lib/address/api/districtApi'; +import subDistrictApi from '@/lib/address/api/subDistrictApi'; +import { yupResolver } from '@hookform/resolvers/yup'; +import React, { + useEffect, + useRef, + useState, + forwardRef, + useImperativeHandle, +} from 'react'; +import ReCAPTCHA from 'react-google-recaptcha'; +import { Controller, useForm } from 'react-hook-form'; +import { toast } from 'react-hot-toast'; +import * as Yup from 'yup'; +import createMerchantApi from '../api/createMerchantApi'; +import getMerchantApi from '../api/getMerchantApi'; +import addressApi from '@/lib/address/api/addressApi'; +import PageContent from '@/lib/content/components/PageContent'; +import { useRouter } from 'next/router'; +import useAuth from '@/core/hooks/useAuth'; +import { Radio, RadioGroup, Stack, Divider, Button } from '@chakra-ui/react'; +import { EyeIcon } from '@heroicons/react/24/outline'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import Image from 'next/image'; +import ImageBanner from '~/components/ui/image'; +import { ChevronRightIcon, ChevronLeftIcon } from '@heroicons/react/24/outline'; +import MobileView from '@/core/components/views/MobileView'; +import DesktopView from '@/core/components/views/DesktopView'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import odooApi from '~/libs/odooApi'; + +const CreateMerchant = forwardRef( + ({ handleIsError, isKonfirmasi, buttonSubmitClick }, ref) => { + const isError = (value) => { + // Logika menentukan error + const result = value ? true : false; + handleIsError(result); // Panggil handleIsError dari Merchant + return result; + }; + // React.useEffect(() => { + // handleIsError(isError()); + // }, [handleIsError]); + const { + register, + handleSubmit, + formState: { errors }, + control, + reset, + watch, + setValue, + getValues, + } = useForm({ + resolver: yupResolver(validationSchema), + defaultValues, + }); + const [state, setState] = useState([]); + const [cities, setCities] = useState([]); + const [districts, setDistricts] = useState([]); + const [subDistricts, setSubDistricts] = useState([]); + const [zips, setZips] = useState([]); + const [isExample, setIsExample] = useState(false); + const [isPkp, setIsPkp] = useState(false); + + useEffect(() => { + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + }, []); + + + useImperativeHandle(ref, () => () => { + handleSubmit(onSubmitHandler)(); + }); + + const recaptchaRef = useRef(null); + const router = useRouter(); + + const auth = useAuth(); + if (auth == false) { + router.push(`/login?next=${encodeURIComponent('/daftar-merchant')}`); + } + const dataBisnisType = [ + { value: 1, label: 'PT' }, + { value: 2, label: 'CV' }, + { value: 3, label: 'Perorangan' }, + ]; + const dataCategoryPerusahaan = [ + { value: 1, label: 'Principal (Pemegang merk/Produsen)' }, + { value: 2, label: 'Sole Distributor (Distributor Tunggal)' }, + { value: 3, label: 'Authorized Distributor (Distributor Resmi)' }, + { value: 4, label: 'Importer (Pengimpor Barang)' }, + { value: 5, label: 'Wholesaler (Pedagang Besar)' }, + ]; + + useEffect(() => { + const loadData = async () => { + try { + const data = await getMerchantApi(); + if (data) { + reset({ + pejabatName: data.pejabatName ? data.pejabatName : '', + PICName: data.picMerchant || '', + PICPosition: data.picPosition || '', + address: data.address ? data.address : '', + state: data.state ? data.state : '', + city: data.city || '', + district: data.district || '', + subDistrict: data.subDistrict || '', + zip: parseInt(data.zip) || '', + email: data.emailCompany || '', + emailSales: data.emailSales || '', + emailFinance: data.emailFinance || '', + bank: data.bankName || '', + rekening: data.rekeningName || '', + accountNumber: data.accountNumber || '', + phone: data.phone || '', + mobile: data.mobile || '', + bisnisType: data.bisnisType ? parseInt(data.bisnisType) : null, + categoryPerusahaan: data.categoryPerusahaan + ? parseInt(data.categoryPerusahaan) + : null, + website: data.website || '', + }); + } + } catch (error) { + console.error('Error loading profile:', error); + handleIsError(true); // Jika ada error, panggil fungsi error handler + } + }; + + loadData(); + }, [reset, handleIsError]); + + useEffect(() => { + const loadProfile = async () => { + try { + const dataProfile = await addressApi({ + id: auth.parentId ? auth.parentId : auth.partnerId, + }); + if (dataProfile.companyType == 'pkp') { + setIsPkp(true); + } + setValue('company', dataProfile?.name); + setValue('address', dataProfile?.alamatBisnis); + setValue('state', parseInt(dataProfile.stateId.id)); + setValue('city', parseInt(dataProfile.city.id)); + setValue('district', parseInt(dataProfile.district.id)); + setValue('subDistrict', parseInt(dataProfile.subDistrict.id)); + setValue('zip', parseInt(dataProfile.zip)); + } catch (error) { + console.error('Error loading profile:', error); + } + }; + + loadProfile(); + }, [auth?.parentId]); + + useEffect(() => { + const loadState = async () => { + let dataState = await stateApi({ tempo: false }); + dataState = dataState.map((state) => ({ + value: state.id, + label: state.name, + })); + setState(dataState); + }; + loadState(); + }, []); + + const watchState = watch('state'); + useEffect(() => { + if (auth == false) { + return; + } + if (watchState) { + // setValue('city', ''); + const loadCities = async () => { + let dataCities = await cityApi({ stateId: watchState }); + dataCities = dataCities?.map((city) => ({ + value: city.id, + label: city.name, + })); + setCities(dataCities); + }; + loadCities(); + } + }, [auth, watchState]); + + const watchCity = watch('city'); + useEffect(() => { + if (watchCity) { + // setValue('district', ''); + const loadDistricts = async () => { + let dataDistricts = await districtApi({ cityId: watchCity }); + dataDistricts = dataDistricts.map((district) => ({ + value: district.id, + label: district.name, + })); + setDistricts(dataDistricts); + }; + loadDistricts(); + } + }, [watchCity]); + + const watchDistrict = watch('district'); + useEffect(() => { + if (watchDistrict) { + // setValue('subDistrict', ''); + const loadSubDistricts = async () => { + let dataSubDistricts = await subDistrictApi({ + districtId: watchDistrict, + }); + dataSubDistricts = dataSubDistricts.map((district) => ({ + value: district.id, + label: district.name, + })); + setSubDistricts(dataSubDistricts); + }; + loadSubDistricts(); + } + }, [watchDistrict]); + + const watchsubDistrict = watch('subDistrict'); + + useEffect(() => { + let kelurahan = ''; + let kecamatan = ''; + + if (watchDistrict) { + // setValue('zip', ''); + for (const data in districts) { + if (districts[data].value == watchDistrict) { + kecamatan = districts[data].label.toLowerCase(); + } + } + } + + if (watchsubDistrict) { + for (const data in subDistricts) { + if (subDistricts[data].value == watchsubDistrict) { + kelurahan = subDistricts[data].label.toLowerCase(); + } + } + const loadZip = async () => { + const response = await fetch( + `https://alamat.thecloudalert.com/api/cari/index/?keyword=${kelurahan}` + ); + + let dataMasuk = []; // Array untuk menyimpan kode pos yang sudah diproses + + const result = await response.json(); + + // Filter dan map data + const dataZips = result.result + .filter((zip) => zip.kecamatan.toLowerCase() === kecamatan) // Filter berdasarkan kecamatan + .filter((zip) => { + // Pastikan zip.kodepos belum ada di dataMasuk + if (dataMasuk.includes(zip.kodepos)) { + return false; // Jika sudah ada, maka skip (tidak akan ditambahkan) + } else { + dataMasuk.push(zip.kodepos); // Tambahkan ke dataMasuk + return true; // Tambahkan zip ke hasil + } + }) + .map((zip) => ({ + value: parseInt(zip.kodepos), + label: zip.kodepos, + })); + + setZips(dataZips); // Set hasil ke state + }; + + loadZip(); + } + }, [watchsubDistrict, subDistricts]); + const onSubmitHandler = async (values) => { + const toastId = toast.loading('Mengirimkan formulir merchant...'); + const data = { + name_merchant: 'Form Merchant - ' + values.company, + pejabat_name: values.pejabatName, + pic_merchant: values.PICName, + pic_position: values.PICPosition, + address: values.address, + state: parseInt(values.state), + city: parseInt(values.city), + district: parseInt(values.district), + subDistrict: parseInt(values.subDistrict), + zip: values.zip, + bank_name: values.bank, + rekening_name: values.rekening, + account_number: values.accountNumber, + email_company: values.email, + email_sales: values.emailSales, + email_finance: values.emailFinance, + phone: values.phone, + mobile: values.mobile, + bisnis_type: values.bisnisType, + category_perusahaan: values.categoryPerusahaan, + website: values.website, + description: + 'Nama Perusahaan : ' + + values.company + + ' \r\n Alamat : ' + + values.address + + ' \r\n Kota : ' + + values.city + + ' \r\n Telepon: ' + + values.phone + + ' \r\n Email : ' + + values.email + + ' \r\n No Hp : ' + + values.mobile, + }; + const create_leads = await createMerchantApi({ data }); + if (create_leads) { + toast.dismiss(toastId); + toast.success('Berhasil menambahkan data'); + isError(false); + reset(); + // router.push('/'); + } else { + toast.dismiss(toastId); + toast.error('Gagal menambahkan data'); + } + }; + + // const DownLoadSurat = () => { + // download surat dari /public/file/Surat Pernyataan Nomor Rekening.docx + // }; + + if (!auth) { + return; + } + // Tetap di bagian atas, tidak boleh ada kondisi sebelum hook + + + + return ( + <> + <BottomPopup + className='' + title='Contoh SPPKP' + active={isExample} + close={() => setIsExample(false)} + > + <div className='flex p-2'> + <Image + src='/images/NO-SPPKP-FORMAT-TEMPLATE.jpg' + alt='Contoh SPPKP' + className='w-full h-full ' + width={800} + height={800} + quality={85} + /> + </div> + </BottomPopup> + <DesktopView> + <div className='container flex flex-col items-star py-4 '> + <h2 className='text-xs md:text-title-sm font-semibold mb-6'> + Informasi Perusahaan + </h2> + + <div className='w-full mt-4'> + <form + onSubmit={handleSubmit(onSubmitHandler)} + className='flex flex-col gap-4' + > + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Perusahaan + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Isi detail perusahaan sesuai dengan nama yang terdaftar{' '} + </span> + )} + </div> + <div className='w-3/5'> + <input + {...register('company')} + placeholder='Masukkan nama perusahaan' + type='text' + className='form-input' + /> + <span className='opacity-65 text-xs'> + Format: PT. INDOTEKNIK DOTCOM GEMILANG + </span> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.company?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Pejabat Berwenang + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan nama pejabat yang berwewenang di perusahaan + anda + </span> + )} + </div> + <div className='w-3/5'> + <input + {...register('pejabatName')} + placeholder='Masukkan nama pejabat berwenang' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.pejabatName?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>Nama PIC</label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan nama sales / penanggung jawab + </span> + )} + </div> + <div className='w-3/5'> + <input + {...register('PICName')} + placeholder='Masukkan nama PIC' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.PICName?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Jabatan PIC + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan jabatan sales / penanggung jawab + </span> + )} + </div> + <div className='w-3/5'> + <input + {...register('PICPosition')} + placeholder='Masukkan jabatan PIC' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.PICPosition?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Alamat Perusahaan + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Alamat sesuai dengan alamat perusahaan + </span> + )} + </div> + <div className='w-3/5 flex flex-col'> + <div> + <input + {...register('address')} + placeholder='Masukkan alamat lengkap perusahaan' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.address?.message} + </div> + </div> + <div + className={` sub-alamat flex ${ + isKonfirmasi ? 'flex-col' : 'flex-row' + } w-full gap-3`} + > + <div + className={`flex ${ + isKonfirmasi + ? ' flex-row gap-3 w-full' + : 'flex-row gap-3 w-2/5' + }`} + > + <div className='provinsi w-full'> + <Controller + name='state' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={state} + placeholder='Provinsi' + /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.state?.message} + </div> + </div> + <div className='kab w-full'> + <Controller + name='city' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={cities} + disabled={!watchState} + placeholder='Kab/Kota' + /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.city?.message} + </div> + </div> + </div> + <div + className={`flex-row flex gap-2 justify-between ${ + isKonfirmasi ? 'w-full' : 'w-3/5' + }`} + > + <div className='kec w-full'> + <Controller + name='district' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={districts} + disabled={!watchState || !watchCity} + placeholder='Kecamatan' + /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.district?.message} + </div> + </div> + <div className='kel w-full'> + <Controller + name='subDistrict' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={subDistricts} + disabled={!watchDistrict} + placeholder='Kelurahan' + /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.subDistrict?.message} + </div> + </div> + <div className='zip w-full'> + <Controller + name='zip' + control={control} + render={(props) => ( + <> + {/* Jika zips tidak kosong, tampilkan dropdown */} + {zips.length < 0 ? ( + // Jika zips kosong, tampilkan input manual + <input + {...register('zip')} + placeholder='Kode Pos' + type='number' + className='form-input' + disabled={!watchsubDistrict} + /> + ) : ( + <HookFormSelect + {...props} + options={zips} + disabled={!watchsubDistrict} + placeholder='Zip' + /> + )} + </> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.zip?.message} + </div> + </div> + </div> + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>Data Bank</label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Isi detail data bank perusahaan anda + </span> + )} + </div> + <div className='w-3/5 flex flex-row gap-2'> + <div> + <input + {...register('bank')} + placeholder='Nama bank' + type='text' + className='form-input' + /> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Format: BCA, Mandiri, CIMB, BNI dll + </span> + )} + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.bank?.message} + </div> + </div> + <div> + <input + {...register('rekening')} + placeholder='Nama Rekening' + type='text' + className='form-input' + /> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Format: John Doe + </span> + )} + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.rekening?.message} + </div> + </div> + <div> + <input + {...register('accountNumber')} + placeholder='Nomor Rekening Bank' + type='number' + className='form-input' + /> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Format: 01234567896 + </span> + )} + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.accountNumber?.message} + </div> + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Email Perusahaan + </label> + </div> + <div className='w-3/5'> + <input + {...register('email')} + placeholder='contoh@email.com' + type='email' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.email?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Email Sales + </label> + </div> + <div className='w-3/5'> + <input + {...register('emailSales')} + placeholder='contoh@email.com' + type='email' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.emailSales?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Email Finance + </label> + </div> + <div className='w-3/5'> + <input + {...register('emailFinance')} + placeholder='contoh@email.com' + type='email' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.emailFinance?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + No. Telepon Perusahaan + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Isi no telepon perusahaan yang sesuai + </span> + )} + </div> + <div className='w-3/5'> + <input + {...register('phone', { + required: 'Nomor telepon wajib diisi.', + pattern: { + value: /^\+?[0-9]{10,15}$/, + message: 'Nomor telepon tidak valid.', + }, + })} + placeholder='Masukkan nomor telepon perusahaan' + type='tel' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.phone?.message} + </div> + </div> + </div> + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + No. Handphone + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + Isi no handphone perusahaan yang sesuai + </span> + )} + </div> + <div className='w-3/5'> + <input + {...register('mobile')} + placeholder='Masukkan nomor handphone' + type='tel' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.mobile?.message} + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-center'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Tipe Bisnis + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih tipe bisnis yang sesuai + </span> + )} + </div> + <div className='w-3/5 flex flex-col '> + <div className='flex flex-row items-center gap-3'> + <div + // className={`${isKonfirmasi ? 'w-[75%]' : 'w-[25%]'}`} + // ref={tempoDurationRef} + > + <Controller + name='bisnisType' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataBisnisType} + placeholder={'Pilih tipe bisnis'} + /> + )} + /> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.bisnisType?.message} + </div> + </div> + </div> + </div> + </div> + <div className='flex flex-row justify-between items-center'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Kategori Perusahaan + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih kategori perusahaan yang sesuai + </span> + )} + </div> + <div className='w-3/5 flex flex-col '> + <div className='flex flex-row items-center gap-3'> + <div + // className={`${isKonfirmasi ? 'w-[75%]' : 'w-[25%]'}`} + className='w-[55%]' + // ref={tempoDurationRef} + > + <Controller + name='categoryPerusahaan' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataCategoryPerusahaan} + placeholder={'Pilih category perusahaan'} + /> + )} + /> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.categoryPerusahaan?.message} + </div> + </div> + </div> + </div> + </div> + + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>Website</label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan website perusahaan anda + </span> + )} + </div> + <div className='w-3/5'> + <input + {...register('website')} + placeholder='Masukkan website' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.website?.message} + </div> + </div> + </div> + + <div className=''> + {/* <div> + <ReCAPTCHA + ref={recaptchaRef} + sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_GOOGLE} + /> + </div> */} + </div> + <div className='flex justify-end'> + {/* <Button + colorScheme='red' + className='w-full md:w-fit' + type='submit' + > + Daftar Merchant{' '} + {<ChevronRightIcon className='w-5' color='white' />} + </Button> */} + {!isKonfirmasi && ( + <div> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <button + type='submit' + className='btn-light bg-red-500 rounded-lg text-white w-fit py-2 px-4 md:w-fit mt-2 ml-0 md:ml-auto flex justify-between hover:bg-red-400' + > + <span className={` `}>Langkah Selanjutnya</span> + {<ChevronRightIcon className='w-5' />} + </button> + </div> + )} + </div> + </form> + <PageContent path='/daftar-merchant' /> + </div> + </div> + </DesktopView> + <MobileView> + <div className='container flex flex-col items-star py-4'> + {!isKonfirmasi && ( + <h2 className='font-semibold mb-6 text-xl'> + Informasi Perusahaan + </h2> + )} + + <div className='w-full mt-4'> + <form + onSubmit={handleSubmit(onSubmitHandler)} + className='flex flex-col gap-4' + > + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'> + Nama Perusahaan + </label> + <input + {...register('company')} + placeholder='Format: PT. INDOTEKNIK DOTCOM GEMILANG' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.company?.message} + </div> + <span className='opacity-65 text-xs'> + Isi detail perusahaan sesuai dengan nama yang terdaftar{' '} + </span> + </div> + </div> + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'> + Pejabat Berwenang + </label> + <input + {...register('pejabatName')} + placeholder='Masukkan nama pejabat berwenang' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.pejabatName?.message} + </div> + <span className='opacity-65 text-xs'> + isi dengan nama pejabat yang berwewenang di perusahaan + anda{' '} + </span> + </div> + </div> + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'>Nama PIC</label> + <input + {...register('PICName')} + placeholder='Masukkan Nama PIC ' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.PICName?.message} + </div> + <span className='opacity-65 text-xs'> + Isi dengan nama sales / penanggung jawab + </span> + </div> + </div> + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'> + Jabatan PIC + </label> + <input + {...register('PICPosition')} + placeholder='Masukkan jabatan PIC ' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.PICPosition?.message} + </div> + <span className='opacity-65 text-xs'> + isi dengan jabatan sales / penanggung jawab + </span> + </div> + </div> + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'> + Alamat Perusahaan + </label> + <input + {...register('address')} + placeholder='Masukkan alamat lengkap perusahaan' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.address?.message} + </div> + <div className='flex flex-row w-full justify-between gap-2'> + <div className='provinsi w-full'> + <Controller + name='state' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={state} + placeholder='Provinsi' + /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.state?.message} + </div> + </div> + <div className='kab w-full'> + <Controller + name='city' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={cities} + disabled={!watchState} + placeholder='Kab/Kota' + /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.city?.message} + </div> + </div> + </div> + <div className='flex flex-row w-full justify-between gap-2'> + <div className='kec w-full'> + <Controller + name='district' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={districts} + disabled={!watchState || !watchCity} + placeholder='Kecamatan' + /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.district?.message} + </div> + </div> + <div className='kel w-full'> + <Controller + name='subDistrict' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={subDistricts} + disabled={!watchDistrict} + placeholder='Kelurahan' + /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.subDistrict?.message} + </div> + </div> + <div className='zip w-full'> + <Controller + name='zip' + control={control} + render={(props) => ( + <> + {zips.length > 0 ? ( + <HookFormSelect + {...props} + options={zips} + disabled={!watchsubDistrict} + placeholder='Zip' + /> + ) : ( + <input + {...register('zip')} + placeholder='Kode Pos' + type='number' + className='form-input' + disabled={!watchsubDistrict} + /> + )} + </> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.zip?.message} + </div> + </div> + </div> + </div> + <span className='opacity-65 text-xs'> + Alamat sesuai dengan alamat perusahaan + </span> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'>Data Bank</label> + <div className='w-full flex flex-row gap-2'> + <div> + <input + {...register('bank')} + placeholder='Nama bank' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.bank?.message} + </div> + </div> + <div> + <input + {...register('rekening')} + placeholder='Nama Rekening' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.rekening?.message} + </div> + </div> + <div> + <input + {...register('accountNumber')} + placeholder='Nomor Rekening Bank' + type='number' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.accountNumber?.message} + </div> + </div> + </div> + <span className='opacity-65 text-xs'> + Isi detail data bank perusahaan anda + </span> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + Email Perusahaan + </label> + <input + {...register('email')} + placeholder='contoh@email.com' + type='email' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.email?.message} + </div> + <span className='opacity-65 text-xs'> + Isi detail perusahaan sesuai dengan data yang terdaftar + </span> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'>Email Sales</label> + <input + {...register('emailSales')} + placeholder='contoh@email.com' + type='email' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.emailSales?.message} + </div> + <span className='opacity-65 text-xs'> + Isi detail perusahaan sesuai dengan data yang terdaftar + </span> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + Email Finance + </label> + <input + {...register('emailFinance')} + placeholder='contoh@email.com' + type='email' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.emailFinance?.message} + </div> + <span className='opacity-65 text-xs'> + Isi detail perusahaan sesuai dengan data yang terdaftar + </span> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + No. Telepon Perusahaan + </label> + <input + {...register('phone')} + placeholder='Format: 08123456789 / (021) 123 4567' + type='tel' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.phone?.message} + </div> + <span className='opacity-65 text-xs'> + Isi detail perusahaan sesuai dengan data yang terdaftar + </span> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + No. Handphone + </label> + <input + {...register('mobile')} + placeholder='Masukkan nomor handphone' + type='tel' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.mobile?.message} + </div> + <span className='opacity-65 text-xs'> + Isi detail perusahaan sesuai dengan data yang terdaftar + </span> + </div> + <div className='flex flex-col'> + <label className='form-label text-nowrap'>Tipe Bisnis</label> + <div className='flex flex-col '> + <Controller + name='bisnisType' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataBisnisType} + placeholder={'Pilih tipe bisnis'} + /> + )} + /> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih tipe bisnis yang sesuai + </span> + )} + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.bisnisType?.message} + </div> + </div> + </div> + <div className='flex flex-col'> + <label className='form-label text-nowrap'> + Kategori Perusahaan + </label> + <div className='flex flex-col '> + <Controller + name='categoryPerusahaan' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataCategoryPerusahaan} + placeholder={'Pilih category perusahaan'} + /> + )} + /> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih kategori perusahaan yang sesuai + </span> + )} + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.categoryPerusahaan?.message} + </div> + </div> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'>Website</label> + <input + {...register('website')} + placeholder='Masukkan website' + type='text' + className='form-input' + /> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan website perusahaan anda + </span> + )} + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.website?.message} + </div> + </div> + + <div className=''> + {/* <div> + <ReCAPTCHA + ref={recaptchaRef} + sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_GOOGLE} + /> + </div> */} + </div> + <div className='flex justify-center w-full '> + {/* <Button + colorScheme='red' + className='w-full md:w-fit' + type='submit' + > + Daftar Merchant{' '} + {<ChevronRightIcon className='w-5' color='white' />} + </Button> */} + {!isKonfirmasi && ( + <div className='w-full'> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <button + type='submit' + className='btn-light bg-red-500 rounded-lg text-white w-full py-2 px-4 md:w-fit mt-2 ml-0 md:ml-auto flex justify-center hover:bg-red-400' + > + <span className={` `}>Langkah Selanjutnya</span> + {<ChevronRightIcon className='w-5' />} + </button> + </div> + )} + </div> + </form> + <PageContent path='/daftar-merchant' /> + </div> + </div> + </MobileView> + </> + ); + } +); + +const validationSchema = Yup.object().shape({ + company: Yup.string().required('Harus di-isi'), + pejabatName: Yup.string().required('Harus di-isi'), + PICName: Yup.string().required('Harus di-isi'), + PICPosition: Yup.string().required('Harus di-isi'), + address: Yup.string().required('Harus di-isi'), + state: Yup.string().required('Harus dipilih'), + city: Yup.string().required('Harus dipilih'), + district: Yup.string().required('Harus dipilih'), + subDistrict: Yup.string().required('Harus dipilih'), + zip: Yup.string().required('Harus di-isi'), + bank: Yup.string().required('Harus di-isi'), + rekening: Yup.string().required('Harus di-isi'), + accountNumber: Yup.string().required('Harus di-isi'), + email: Yup.string() + .email('Format harus seperti contoh@email.com') + .required('Harus di-isi'), + emailSales: Yup.string() + .email('Format harus seperti contoh@email.com') + .required('Harus di-isi'), + emailFinance: Yup.string() + .email('Format harus seperti contoh@email.com') + .required('Harus di-isi'), + phone: Yup.string().required('Harus di-isi'), + mobile: Yup.string().required('Harus di-isi'), + bisnisType: Yup.string().required('Harus dipilih'), + categoryPerusahaan: Yup.string().required('Harus dipilih'), +}); +const defaultValues = { + company: '', + pejabatName: '', + PICName: '', + PICPosition: '', + address: '', + state: '', + city: '', + district: '', + subDistrict: '', + zip: '', + email: '', + emailSales: '', + emailFinance: '', + bank: '', + rekening: '', + accountNumber: '', + phone: '', + mobile: '', +}; + +export default CreateMerchant; diff --git a/src/lib/merchant/components/InformasiVendor.jsx b/src/lib/merchant/components/InformasiVendor.jsx new file mode 100644 index 00000000..d00f27ed --- /dev/null +++ b/src/lib/merchant/components/InformasiVendor.jsx @@ -0,0 +1,748 @@ +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'; +import cityApi from '@/lib/address/api/cityApi'; +import stateApi from '@/lib/address/api/stateApi.js'; +import districtApi from '@/lib/address/api/districtApi'; +import subDistrictApi from '@/lib/address/api/subDistrictApi'; +import { yupResolver } from '@hookform/resolvers/yup'; +import React, { + useEffect, + useRef, + useState, + forwardRef, + useImperativeHandle, +} from 'react'; +import ReCAPTCHA from 'react-google-recaptcha'; +import { Controller, useForm } from 'react-hook-form'; +import { toast } from 'react-hot-toast'; +import * as Yup from 'yup'; +import createMerchantApi from '../api/createMerchantApi'; +import getMerchantApi from '../api/getMerchantApi'; +import addressApi from '@/lib/address/api/addressApi'; +import PageContent from '@/lib/content/components/PageContent'; +import { useRouter } from 'next/router'; +import useAuth from '@/core/hooks/useAuth'; +import { Radio, RadioGroup, Stack, Checkbox, Button } from '@chakra-ui/react'; +import { EyeIcon } from '@heroicons/react/24/outline'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import Image from 'next/image'; +import ImageBanner from '~/components/ui/image'; +import { ChevronRightIcon } from '@heroicons/react/24/outline'; +import MobileView from '@/core/components/views/MobileView'; +import DesktopView from '@/core/components/views/DesktopView'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import odooApi from '~/libs/odooApi'; +import { formatValue } from 'react-currency-input-field'; +const InformasiVendor = forwardRef(({ handleIsError, isKonfirmasi }, ref) => { + const isError = (value) => { + // Logika menentukan error + const result = value ? true : false; + handleIsError(result); // Panggil handleIsError dari Merchant + return result; + }; + const { + register, + handleSubmit, + formState: { errors }, + control, + reset, + watch, + setValue, + getValues, + } = useForm({ + resolver: yupResolver(validationSchema), + defaultValues, + }); + const [categoryProduk, setCategoryProduk] = useState([]); + const [isExample, setIsExample] = useState(false); + + const router = useRouter(); + + const auth = useAuth(); + if (auth == false) { + router.push(`/login?next=${encodeURIComponent('/daftar-merchant')}`); + } + const dataTerhitungSejak = [ + { value: 1, label: 'Terima PO' }, + { value: 2, label: 'Barang Dikirimkan' }, + { value: 3, label: 'Tukar Faktur' }, + ]; + + const dataTempo = [ + { value: 24, label: 'Tempo 14 Hari' }, + { value: 25, label: 'Tempo 30 Hari' }, + { value: 28, label: 'Tempo 60 Hari' }, + { value: 31, label: 'Tempo 90 Hari' }, + ]; + + const midIndex = Math.ceil(categoryProduk.length / 2); + const firstColumn = categoryProduk.slice(0, midIndex); + const secondColumn = categoryProduk.slice(midIndex); + const [kreditLimitFormat, setKreditLimitFormat] = useState(); + + useEffect(() => { + const loadData = async () => { + const data = await getMerchantApi(); + if (data) { + reset({ + hargaTayang: data.hargaTayang || '', + categoryProduk: data.categoryProduk || '', + merkDagang: data.merkDagang || '', + isPengajuanTempo: data.isPengajuanTempo || '', + tempoDuration: parseInt(data.tempoDuration) || '', + // kreditLimit: parseInt(data.kreditLimit) || '', + waktuPengiriman: data.waktuPengiriman || '', + terhitungSejak: parseInt(data.terhitungSejak) || '', + }); + handleKreditLimitChange(data.kreditLimit || ''); + setSelectedIds(watch('categoryProduk').split(',').map(Number)); + } + }; + + loadData(); + }, []); + + useImperativeHandle(ref, () => () => { + handleSubmit(onSubmitHandler)(); + }); + + const handleKreditLimitChange = (e) => { + let value = e.target?.value ? e.target.value : e; + + // Hapus semua karakter non-numeric + value = value.replace(/[^\d]/g, ''); + + // Format angka sebagai Rupiah tanpa mengubah nilai sebenarnya + const formattedValue1 = formatValue({ + value: value, + groupSeparator: '.', + decimalSeparator: ',', + prefix: 'Rp ', + }); + + setKreditLimitFormat(formattedValue1); + setValue('kreditLimit', formattedValue1); + }; + + const [selectedIds, setSelectedIds] = useState( + watch('categoryProduk') + ? watch('categoryProduk').split(',').map(Number) + : [] + // form.categoryProduk ? form.categoryProduk.split(',').map(Number) : [] // Parse string menjadi array angka + // [] // 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 + setValue('categoryProduk', updatedSelected.join(',')); + }; + + const isChecked = (id) => selectedIds.includes(id); + + const handleCheckboxPortalChange = (value) => { + setValue('isPengajuanTempo', `${value}`); + }; + + useEffect(() => { + if (!isKonfirmasi) { + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + } + }, []); + + useEffect(() => { + const loadCategories = async () => { + let dataCategories = await odooApi('GET', '/api/v1/category/tree'); + const formattedCategories = dataCategories.map((category) => ({ + id: category.id, + name: category.name, + })); + // Simpan hasil ke state + setCategoryProduk(formattedCategories); + }; + loadCategories(); + }, []); + + const onSubmitHandler = async (values) => { + const toastId = toast.loading('Mengirimkan formulir merchant...'); + const data = { + harga_tayang: values.hargaTayang, + categoryProduk: values.categoryProduk, + merk_dagang: values.merkDagang, + is_pengajuan_tempo: values.isPengajuanTempo, + tempo_duration: values.tempoDuration, + kredit_limit: values.kreditLimit, + waktu_pengiriman: values.waktuPengiriman, + terhitung_sejak: values.terhitungSejak, + }; + const create_leads = await createMerchantApi({ data }); + if (create_leads) { + toast.dismiss(toastId); + isError(false); + toast.success('Berhasil menambahkan data'); + reset(); + // router.push('/+'); + } else { + toast.dismiss(toastId); + toast.error('Gagal menambahkan data'); + } + }; + + // const DownLoadSurat = () => { + // download surat dari /public/file/Surat Pernyataan Nomor Rekening.docx + // }; + + if (!auth) { + return; + } + + return ( + <> + <BottomPopup + className='' + title='Contoh SPPKP' + active={isExample} + close={() => setIsExample(false)} + > + <div className='flex p-2'> + <Image + src='/images/NO-SPPKP-FORMAT-TEMPLATE.jpg' + alt='Contoh SPPKP' + className='w-full h-full ' + width={800} + height={800} + quality={85} + /> + </div> + </BottomPopup> + <DesktopView> + <div className='container flex flex-col items-star py-4 '> + <h2 className='text-xs md:text-title-sm font-semibold mb-6'> + Informasi Vendor + </h2> + + <div className='w-full mt-4'> + <form + onSubmit={handleSubmit(onSubmitHandler)} + className='flex flex-col gap-4' + > + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Harga Tayang (HET){' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + </div> + <div className='w-3/5'> + <textarea + {...register('hargaTayang')} + placeholder='Jelaskan detail HET yang anda miliki' + type='textarea' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.hargaTayang?.message} + </div> + </div> + </div> + + <div className={`flex flex-row justify-between items-start`}> + <div className='w-2/5 text-nowrap'> + <label + className={`form-label ${isKonfirmasi && 'text-wrap'}`} + > + Tipe Kategori Produk yang Digunakan + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih kategori produk bisa lebih dari 1 + </span> + )} + </div> + <div className='w-3/5 flex flex-col'> + <div className='flex flex-row justify-between gap-2'> + <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> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.categoryProduk?.message} + </div> + </div> + </div> + + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>Merk Dagang</label> + </div> + <div className='w-3/5'> + <input + {...register('merkDagang')} + placeholder='Merk 1, Merk 2, Merk 3' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.merkDagang?.message} + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-wrap '> + Apakah anda memiliki Form Pengajuan Tempo? + </label> + </div> + <div className='w-3/5 flex flex-col justify-start'> + <div className='flex gap-x-4'> + <RadioGroup + onChange={handleCheckboxPortalChange} + value={watch('isPengajuanTempo')} + > + <Stack direction='row'> + <Radio colorScheme='red' value='ada'> + Ya, ada + </Radio> + <Radio colorScheme='red' value='tidak'> + Tidak ada + </Radio> + </Stack> + </RadioGroup> + </div> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.isPengajuanTempo?.message} + </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> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih durasi tempo yang anda inginkan + </span> + )} + </div> + <div className='w-3/5 flex flex-col '> + <div className='flex flex-row items-center gap-3'> + <div className={`${!isKonfirmasi && 'w-[25%]'}`}> + <Controller + name='tempoDuration' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataTempo} + placeholder={'Pilih Durasi Tempo'} + /> + )} + /> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoDuration?.message} + </div> + </div> + </div> + </div> + </div> + + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Jumlah Kredit Limit + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan kredit limit perusahaan anda + </span> + )} + </div> + <div className='w-3/5'> + <input + value={kreditLimitFormat} + onChange={handleKreditLimitChange} + placeholder='Masukkan jumlah kredit limit' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.kreditLimit?.message} + </div> + </div> + </div> + + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Waktu Pengiriman + </label> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan waktu pengiriman anda + </span> + )} + </div> + <div className='w-3/5 flex flex-row gap-2'> + <div className='w-1/3'> + <input + {...register('waktuPengiriman')} + placeholder='Masukkan waktu pengiriman' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.waktuPengiriman?.message} + </div> + </div> + <div className='w-2/3 '> + <div className='flex flex-row items-center gap-2'> + <label className=' text-nowrap text-sm opacity-70 italic'> + terhitung sejak + </label> + + <Controller + name='terhitungSejak' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataTerhitungSejak} + placeholder={'waktu pengiriman'} + /> + )} + /> + </div> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.terhitungSejak?.message} + </div> + </div> + </div> + </div> + + <div className=''> + {/* <div> + <ReCAPTCHA + ref={recaptchaRef} + sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_GOOGLE} + /> + </div> */} + </div> + <div className='flex justify-end'> + {/* <Button + colorScheme='red' + className='w-full md:w-fit' + type='submit' + > + Daftar Merchant{' '} + {<ChevronRightIcon className='w-5' color='white' />} + </Button> */} + {!isKonfirmasi && ( + <div> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <button + type='submit' + className='btn-light bg-red-500 rounded-lg text-white w-fit py-2 px-4 md:w-fit mt-2 ml-0 md:ml-auto flex justify-between hover:bg-red-400' + > + <span className={` `}>Langkah Selanjutnya</span> + {<ChevronRightIcon className='w-5' />} + </button> + </div> + )} + </div> + </form> + <PageContent path='/daftar-merchant' /> + </div> + </div> + </DesktopView> + <MobileView> + <div className='container flex flex-col items-star py-4'> + {!isKonfirmasi && ( + <h2 className='font-semibold mb-6 text-xl'>Informasi Vendor</h2> + )} + + <div className='w-full mt-4'> + <form + onSubmit={handleSubmit(onSubmitHandler)} + className='flex flex-col gap-4' + > + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'> + Harga Tayang (HET){' '} + <span className=' opacity-60'>(Opsional)</span> + </label> + <input + {...register('hargaTayang')} + placeholder='Jelaskan detail HET yang anda miliki' + type='textarea' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.hargaTayang?.message} + </div> + </div> + </div> + <div + className={`flex flex-col gap-2 justify-between ${ + isKonfirmasi ? 'items-start' : 'items-start' + }`} + > + <label className='form-label '> + Tipe Kategori Produk yang Digunakan + </label> + <div className='flex flex-col justify-between gap-2 '> + <div className='flex flex-col gap-2'> + {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> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.categoryProduk?.message} + </div> + </div> + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'>Merk Dagang</label> + <input + {...register('merkDagang')} + placeholder='Merk 1, Merk 2, Merk 3' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.merkDagang?.message} + </div> + </div> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + Apakah anda memiliki Form Pengajuan Tempo? + </label> + <div className='flex gap-x-4'> + <RadioGroup + onChange={handleCheckboxPortalChange} + value={watch('isPengajuanTempo')} + > + <Stack direction='row'> + <Radio colorScheme='red' value='ada'> + Ya, ada + </Radio> + <Radio colorScheme='red' value='tidak'> + Tidak ada + </Radio> + </Stack> + </RadioGroup> + </div> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.isPengajuanTempo?.message} + </div> + </div> + + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'>Durasi Tempo</label> + <Controller + name='tempoDuration' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataTempo} + placeholder={'Pilih Durasi Tempo'} + /> + )} + /> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoDuration?.message} + </div> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih durasi tempo yang anda inginkan + </span> + )} + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + Jumlah Kredit Limit + </label> + <input + value={kreditLimitFormat} + onChange={handleKreditLimitChange} + placeholder='Masukkan jumlah kredit limit' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.kreditLimit?.message} + </div> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan kredit limit perusahaan anda + </span> + )} + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + {' '} + Waktu Pengiriman + </label> + <div className='w-full flex flex-row gap-2'> + <div className='w-1/3'> + <input + {...register('waktuPengiriman')} + placeholder='Masukkan waktu pengiriman' + type='text' + className='form-input' + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.waktuPengiriman?.message} + </div> + </div> + <div className='w-2/3 '> + <div className='flex flex-row items-center gap-2'> + <label className=' text-nowrap text-sm opacity-70 italic'> + terhitung sejak + </label> + + <Controller + name='terhitungSejak' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataTerhitungSejak} + placeholder={'waktu pengiriman'} + /> + )} + /> + </div> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.terhitungSejak?.message} + </div> + </div> + </div> + {!isKonfirmasi && ( + <span className='opacity-65 text-xs'> + isi dengan waktu pengiriman anda + </span> + )} + </div> + + <div className=''> + {/* <div> + <ReCAPTCHA + ref={recaptchaRef} + sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_GOOGLE} + /> + </div> */} + </div> + <div className='flex justify-center w-full '> + {/* <Button + colorScheme='red' + className='w-full md:w-fit' + type='submit' + > + Daftar Merchant{' '} + {<ChevronRightIcon className='w-5' color='white' />} + </Button> */} + {!isKonfirmasi && ( + <div className='w-full'> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <button + type='submit' + className='btn-light bg-red-500 rounded-lg text-white w-full py-2 px-4 md:w-fit mt-2 ml-0 md:ml-auto flex justify-center hover:bg-red-400' + > + <span className={` `}>Langkah Selanjutnya</span> + {<ChevronRightIcon className='w-5' />} + </button> + </div> + )} + </div> + </form> + <PageContent path='/daftar-merchant' /> + </div> + </div> + </MobileView> + </> + ); +}); +const validationSchema = Yup.object().shape({ + categoryProduk: Yup.string().required('Harus di-pilih'), + merkDagang: Yup.string().required('Harus di-isi'), + isPengajuanTempo: Yup.string().required('Harus di-pilih'), + tempoDuration: Yup.string().required('Harus di-pilih'), + kreditLimit: Yup.string().required('Harus di-isi'), + waktuPengiriman: Yup.string().required('Harus di-isi'), + terhitungSejak: Yup.string().required('Harus di-pilih'), +}); +const defaultValues = { + categoryProduk: '', + merkDagang: '', + isPengajuanTempo: '', + tempoDuration: '', + kreditLimit: '', + waktuPengiriman: '', + terhitungSejak: '', +}; + +export default InformasiVendor; diff --git a/src/lib/merchant/components/Konfirmasi.jsx b/src/lib/merchant/components/Konfirmasi.jsx new file mode 100644 index 00000000..9556c88a --- /dev/null +++ b/src/lib/merchant/components/Konfirmasi.jsx @@ -0,0 +1,224 @@ +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 ProgressBar from '@ramonak/react-progress-bar'; +import { + Button, + Checkbox, + Spinner, + Tooltip, + 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 InformasiVendor from './InformasiVendor'; +import SyaratDagang from './SyaratDagang'; +import Dokumen from './Dokumen'; +import createMerchantApi from '../api/createMerchantApi'; +import useDevice from '@/core/hooks/useDevice'; +import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline'; +import { useRouter } from 'next/router'; +const Konfirmasi = ({ chekValid, buttonSubmitClick }) => { + const { control, watch, setValue, getValues, reset } = useForm(); + const { isDesktop, isMobile } = useDevice(); + const [isOpenInformasi, setIsOpenInformasi] = useState(true); + const [isOpenKontak, setIsOpenKontak] = useState(false); + const [isOpenPengiriman, setIsOpenPengiriman] = useState(false); + const [isOpenKonfirmasi, setIsOpenKonfirmasi] = useState(false); + const formRef = useRef(null); + const router = useRouter(); + const handleDaftarMerchant = () => { + if (formRef.current) { + formRef.current(); // Memicu submit form di InformasiPerusahaan + } + }; + const handleIsError = async (value) => { + if (!value) { + // goToNextStep(); + const toastId = toast.loading('Mengirimkan formulir merchant...'); + const data = { + merchant_request: true, + }; + const create_leads = await createMerchantApi({ data }); + if (create_leads) { + toast.dismiss(toastId); + toast.success('Berhasil medaftarkan merchant'); + reset(); + // router.push('/+'); + } else { + toast.dismiss(toastId); + toast.error('Gagal menambahkan data'); + } + } + reset(); + router.push('/'); + }; + + 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} + ref={formRef} + handleIsError={handleIsError} + /> + </div> + <div className='h-px bg-gray-300'></div> + <div className=''> + <SyaratDagang + isKonfirmasi={true} + ref={formRef} + handleIsError={handleIsError} + /> + </div> + </div> + + <div className='w-px bg-gray-300'></div> + <div className='w-full grid grid-rows-[1fc_auto_1fc] gap-5'> + <div className=''> + <InformasiVendor + isKonfirmasi={true} + ref={formRef} + handleIsError={handleIsError} + /> + </div> + <div className='h-px bg-gray-300'></div> + <div> + <Dokumen + isKonfirmasi={true} + ref={formRef} + handleIsError={handleIsError} + /> + </div> + </div> + </div> + </form> + + <div className='flex flex-col items-end justify-end gap-2'> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <Button + colorScheme='red' + w='36' + onClick={handleDaftarMerchant} // Memicu form submit + > + Daftar Merchant + </Button> + </div> + </> + )} + {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 items-center'> + <div className='flex flex-col justify-center items-start'> + <p className='font-semibold text-lg'>Informasi Perusahaan</p> + {/* <span className='text-xs opacity-70'> + Pastikan informasi usaha yang anda masukkan sudah sesuai + dengan data perusahaan anda + </span> */} + </div> + <div className='p-2 bg-gray-200'> + {isOpenInformasi ? ( + <ChevronUpIcon + className='w-4' + onClick={() => setIsOpenInformasi(!isOpenInformasi)} + /> + ) : ( + <ChevronDownIcon + className='w-4' + onClick={() => setIsOpenInformasi(!isOpenInformasi)} + /> + )} + </div> + </div> + {isOpenInformasi && <InformasiPerusahaan isKonfirmasi={true} />} + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 mt-4 mb-4 relative transform -translate-x-5'></div> + </div> + <div className='flex flex-col gap-4'> + <div className='flex flex-row justify-between'> + <p className='font-semibold text-lg'>Informasi Vendor</p> + <div className='p-2 bg-gray-200'> + {isOpenKontak ? ( + <ChevronUpIcon + className='w-4' + onClick={() => setIsOpenKontak(!isOpenKontak)} + /> + ) : ( + <ChevronDownIcon + className='w-4' + onClick={() => setIsOpenKontak(!isOpenKontak)} + /> + )} + </div> + </div> + {isOpenKontak && <InformasiVendor isKonfirmasi={true} />} + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 mt-4 mb-4 relative transform -translate-x-5'></div> + </div> + <div className='flex flex-col gap-4'> + <div className='flex flex-row justify-between'> + <p className='font-semibold text-lg'>Syarat Perdagangan</p> + <div className='p-2 bg-gray-200'> + {isOpenPengiriman ? ( + <ChevronUpIcon + className='w-4' + onClick={() => setIsOpenPengiriman(!isOpenPengiriman)} + /> + ) : ( + <ChevronDownIcon + className='w-4' + onClick={() => setIsOpenPengiriman(!isOpenPengiriman)} + /> + )} + </div> + </div> + {isOpenPengiriman && <SyaratDagang isKonfirmasi={true} />} + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 mt-4 mb-4 relative transform -translate-x-5'></div> + </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'> + {isOpenKonfirmasi ? ( + <ChevronUpIcon + className='w-4' + onClick={() => setIsOpenKonfirmasi(!isOpenKonfirmasi)} + /> + ) : ( + <ChevronDownIcon + className='w-4' + onClick={() => setIsOpenKonfirmasi(!isOpenKonfirmasi)} + /> + )} + </div> + </div> + {isOpenKonfirmasi && <Dokumen isKonfirmasi={true} />} + </div> + <div className='flex flex-col items-end justify-end gap-2'> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <Button + colorScheme='red' + w='full' + onClick={handleDaftarMerchant} // Memicu form submit + > + Daftar Merchant + </Button> + </div> + </form> + )} + </> + ); +}; + +export default Konfirmasi; diff --git a/src/lib/merchant/components/Merchant.jsx b/src/lib/merchant/components/Merchant.jsx new file mode 100644 index 00000000..3c16e3ba --- /dev/null +++ b/src/lib/merchant/components/Merchant.jsx @@ -0,0 +1,147 @@ +import React from 'react'; +import { useMemo, useState, useEffect, useRef } from 'react'; +import Image from '~/components/ui/image'; +import InformasiPerusahaan from './InformasiPerusahaan'; +import InformasiVendor from './InformasiVendor'; +import SyaratDagang from './SyaratDagang'; +import Dokumen from './Dokumen'; +import Konfirmasi from './Konfirmasi'; +import { getAuth } from '~/libs/auth'; +import { setAuth } from '@/core/utils/auth'; +import useAuth from '@/core/hooks/useAuth'; +import { useRouter } from 'next/router'; +import { Controller, useForm } from 'react-hook-form'; +import { ChevronRightIcon, ChevronLeftIcon } from '@heroicons/react/24/outline'; +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'; +import odooApi from '~/libs/odooApi'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import PageContent from '@/lib/content/components/PageContent'; +const Merchant = () => { + const { isDesktop, isMobile } = useDevice(); + const [currentStep, setCurrentStep] = React.useState(0); + const NUMBER_OF_STEPS = 5; + const [isLoading, setIsLoading] = useState(false); + const [bigData, setBigData] = useState(); + const [idTempo, setIdTempo] = useState(0); + const { control, watch, setValue } = useForm(); + const auth = useAuth(); + const router = useRouter(); + const [BannerTempo, setBannerTempo] = useState(); + const [notValid, setNotValid] = useState(false); + const [buttonSubmitClick, setButtonSubmitClick] = useState(false); + + const [error, setError] = useState(false); + + const handleIsError = (value) => { + if (!value) { + goToNextStep(); + } + setError(value); // Memperbarui state berdasarkan isError + }; + const stepDivs = [ + <InformasiPerusahaan + handleIsError={handleIsError} + buttonSubmitClick={buttonSubmitClick} + />, + <InformasiVendor + handleIsError={handleIsError} + buttonSubmitClick={buttonSubmitClick} + />, + <SyaratDagang + handleIsError={handleIsError} + buttonSubmitClick={buttonSubmitClick} + />, + <Dokumen + handleIsError={handleIsError} + buttonSubmitClick={buttonSubmitClick} + />, + <Konfirmasi handleIsError={handleIsError} />, + ]; + + const stepLabels = [ + 'informasi_perusahaan', + 'kontak_person', + 'Pengiriman', + 'Referensi', + 'Dokumen', + 'Konfirmasi', + ]; + + useEffect(() => { + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + }, [currentStep]); + + useEffect(() => { + <InformasiPerusahaan buttonSubmitClick={buttonSubmitClick} />; + }, [buttonSubmitClick]); + + const goToNextStep = () => { + setCurrentStep((prev) => (prev === NUMBER_OF_STEPS - 1 ? prev : prev + 1)); + }; + + const goPrevStep = () => { + setCurrentStep((prev) => (prev === NUMBER_OF_STEPS - 1 ? prev : prev - 1)); + }; + + useEffect(() => { + const getBanner = async () => { + const get = await odooApi('GET', '/api/v1/banner?type=banner-form-tempo'); + // setBannerTempo(get[0].image); + setBannerTempo( + 'https://erp.indoteknik.com/api/image/x_banner.banner/x_banner_image/431' + ); + }; + getBanner(); + }, []); + return ( + <> + <div className='container flex flex-col items-center '> + {BannerTempo && ( + <Image + src={BannerTempo} + alt='FORM Tempo' + width={500} + height={160} + className='w-full mt-6' + /> + )} + <h1 className=' font-semibold text-center mb-6'>Form Merchant</h1> + <p + className={`text-center ${ + isMobile ? 'w-full text-sm' : 'w-3/4 mb-4' + }`} + > + Pembayaran tempo adalah layanan pembayaran berjangka yang difasilitasi + indoteknik.com untuk konsumen akun bisnis yang terdaftar dengan waktu + pembayaran mulai dari 7, 14, 21 hingga 30 Hari. + </p> + </div> + <div + className={`h-[2px] w-full ${isMobile ? 'mt-4' : 'mb-4'} bg-gray_r-3`} + /> + + <div className={`container ${isMobile ? 'mt-4' : ''} flex flex-col`}> + <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-col justify-end items-end' + } mb-8 gap-2`} + ></div> + </div> + </> + ); +}; + +export default Merchant; diff --git a/src/lib/merchant/components/SyaratDagang.jsx b/src/lib/merchant/components/SyaratDagang.jsx new file mode 100644 index 00000000..96681064 --- /dev/null +++ b/src/lib/merchant/components/SyaratDagang.jsx @@ -0,0 +1,822 @@ +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'; +import cityApi from '@/lib/address/api/cityApi'; +import stateApi from '@/lib/address/api/stateApi.js'; +import districtApi from '@/lib/address/api/districtApi'; +import subDistrictApi from '@/lib/address/api/subDistrictApi'; +import { yupResolver } from '@hookform/resolvers/yup'; +import React, { + useEffect, + useRef, + useState, + forwardRef, + useImperativeHandle, +} from 'react'; +import ReCAPTCHA from 'react-google-recaptcha'; +import { Controller, useForm } from 'react-hook-form'; +import { toast } from 'react-hot-toast'; +import * as Yup from 'yup'; +import createMerchantApi from '../api/createMerchantApi'; +import getMerchantApi from '../api/getMerchantApi'; +import addressApi from '@/lib/address/api/addressApi'; +import PageContent from '@/lib/content/components/PageContent'; +import { useRouter } from 'next/router'; +import useAuth from '@/core/hooks/useAuth'; +import { Radio, RadioGroup, Stack, Checkbox, Button } from '@chakra-ui/react'; +import { EyeIcon } from '@heroicons/react/24/outline'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import Image from 'next/image'; +import ImageBanner from '~/components/ui/image'; +import { ChevronRightIcon } from '@heroicons/react/24/outline'; +import MobileView from '@/core/components/views/MobileView'; +import DesktopView from '@/core/components/views/DesktopView'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import odooApi from '~/libs/odooApi'; +const SyaratDagang = forwardRef(({ handleIsError, isKonfirmasi }, ref) => { + const isError = (value) => { + // Logika menentukan error + const result = value ? true : false; + handleIsError(result); // Panggil handleIsError dari Merchant + return result; + }; + const { + register, + handleSubmit, + formState: { errors }, + control, + reset, + watch, + setValue, + getValues, + } = useForm({ + resolver: yupResolver(validationSchema), + defaultValues, + }); + const [bigData, setbigData] = useState([]); + const [isExample, setIsExample] = useState(false); + + const recaptchaRef = useRef(null); + const router = useRouter(); + + useEffect(() => { + const loadData = async () => { + const data = await getMerchantApi(); + setbigData(data); + if (data) { + reset({ + isKembaliBarang: data.isKembaliBarang || '', + textReturn: data.textReturn || '', + tenggatWaktu: (() => { + const waktu = data.tenggatWaktu + ? data.tenggatWaktu.split(' ')[0] + : ''; + if (waktu === '14') return '14'; + if (waktu === '30') return '30'; + return 'custom'; + })(), + customTenggatWaktu: (() => { + if (watch('tenggatWaktu') === 'custom') + return data.tenggatWaktu ? data.tenggatWaktu : ''; + return ''; + })(), + sertifikatProduk: data.sertifikatProduk || '', + customSertifikatProduk: data.customSertifikatProduk || '', + tempoGaransi: parseInt(data.tempoGaransi) || '', + explainGaransi: data.explainGaransi || '', + minimumPembelian: + data.isOrderQuantity == 'tidak' ? '' : data.minimumPembelian || '', + isOrderQuantity: data.isOrderQuantity || '', + }); + // handleKreditLimitChange(data.kreditLimit); + if (watch('sertifikatProduk') != false) { + setSelectedIds(watch('sertifikatProduk').split(',').map(Number)); + } + if (watch('customSertifikatProduk')) { + // setSelectedIds([...selectedIds, 4]); + } + } + }; + + loadData(); + }, []); + useEffect(() => { + if (!isKonfirmasi) { + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + } + }, []); + useImperativeHandle(ref, () => () => { + handleSubmit(onSubmitHandler)(); + }); + const auth = useAuth(); + if (auth == false) { + router.push(`/login?next=${encodeURIComponent('/daftar-merchant')}`); + } + + const dataGaransi = [ + { value: 1, label: '6 Bulan Garansi' }, + { value: 2, label: '1 Tahun Garansi' }, + { value: 3, label: '2 Tahun Garansi' }, + ]; + const dataMinimumOrderQuantity = [ + { value: 'dus', label: 'Dus' }, + { value: 'lusin', label: 'Lusin' }, + { value: 'minimum pembelian', label: 'Minimum pembelian' }, + ]; + + const category_produk = [ + { id: 0, name: 'TKDN' }, + { id: 1, name: 'SNI' }, + { id: 2, name: 'K3L' }, + { id: 3, name: '' }, + ]; + + const [selectedIds, setSelectedIds] = useState( + watch('sertifikatProduk') + ? watch('sertifikatProduk').split(',').map(Number) + : [] + // form.sertifikatProduk ? form.sertifikatProduk.split(',').map(Number) : [] // Parse string menjadi array angka + // [] // 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 + setValue('sertifikatProduk', updatedSelected.join(',')); + }; + const custom_sertifikat_produk_handle = () => { + const updatedSelected = [...selectedIds, 3]; + + setSelectedIds(updatedSelected); + + // Mengubah array kembali menjadi string yang dipisahkan oleh koma + setValue('sertifikatProduk', updatedSelected.join(',')); + }; + + const isChecked = (id) => selectedIds.includes(id); + + const handleCheckboxReturChange = (value) => { + setValue('isKembaliBarang', `${value}`); + }; + const handleCheckboxOrderQuantityChange = (value) => { + setValue('isOrderQuantity', `${value}`); + }; + + const handleCheckboxTenggatWaktuChange = (value) => { + setValue('tenggatWaktu', `${value}`); + }; + + const onSubmitHandler = async (values) => { + const toastId = toast.loading('Mengirimkan formulir merchant...'); + const data = { + is_kembali_barang: values.isKembaliBarang, + text_return: values.textReturn, + tenggat_waktu: values.tenggatWaktu, + custom_tenggat_waktu: values.customTenggatWaktu, + sertifikat_produk: values.sertifikatProduk, + custom_sertifikat_produk: + values.customSertifikatProduk == '' + ? false + : values.customSertifikatProduk, + tempo_garansi: values.tempoGaransi, + explain_garansi: values.explainGaransi, + is_order_quantity: values.isOrderQuantity, + minimum_pembelian: values.minimumPembelian, + }; + const create_leads = await createMerchantApi({ data }); + if (create_leads) { + toast.dismiss(toastId); + toast.success('Berhasil menambahkan data'); + isError(false); + reset(); + // router.push('/'); + } else { + toast.dismiss(toastId); + toast.error('Gagal menambahkan data'); + } + }; + + // const DownLoadSurat = () => { + // download surat dari /public/file/Surat Pernyataan Nomor Rekening.docx + // }; + + if (!auth) { + return; + } + // Tetap di bagian atas, tidak boleh ada kondisi sebelum hook + + return ( + <> + <BottomPopup + className='' + title='Contoh SPPKP' + active={isExample} + close={() => setIsExample(false)} + > + <div className='flex p-2'> + <Image + src='/images/NO-SPPKP-FORMAT-TEMPLATE.jpg' + alt='Contoh SPPKP' + className='w-full h-full ' + width={800} + height={800} + quality={85} + /> + </div> + </BottomPopup> + <DesktopView> + <div + className={`container flex flex-col h-fit items-start ${ + !isKonfirmasi && 'py-4' + }`} + > + <h2 className='text-xs md:text-title-sm font-semibold mb-6'> + Syarat Perdagangan + </h2> + + <div className='w-full mt-4 '> + <form + onSubmit={handleSubmit(onSubmitHandler)} + className='flex flex-col gap-4' + > + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-wrap '> + Syarat Pengembalian Barang + </label> + </div> + <div className='w-3/5 flex flex-row justify-start'> + <div className='flex gap-x-4 flex-col w-full'> + <RadioGroup + onChange={handleCheckboxReturChange} + value={watch('isKembaliBarang')} + > + <Stack direction='column'> + <div className='flex flex-row text-nowrap gap-2'> + <Radio colorScheme='red' value='ya'> + Ya, dapat diretur + </Radio> + {watch('isKembaliBarang') == 'ya' && ( + <textarea + {...register('textReturn')} + placeholder='jelaskan syarat pengembalian' + type='textarea' + className='form-input w-full' + /> + )} + </div> + <Radio colorScheme='red' value='tidak'> + Tidak dapat diretur + </Radio> + </Stack> + </RadioGroup> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.isKembaliBarang?.message} + </div> + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-wrap '> + Tenggat Waktu Perubahan Harga + </label> + </div> + <div className='w-3/5 flex flex-row justify-start'> + <div className='flex gap-x-4 flex-col w-full'> + <RadioGroup + onChange={handleCheckboxTenggatWaktuChange} + value={watch('tenggatWaktu')} + > + <Stack direction='column'> + <Radio + colorScheme='red' + value='14' + onChange={() => setValue('customTenggatWaktu', ' ')} + > + 14 hari sejak data dikirimkan + </Radio> + <Radio + colorScheme='red' + value='30' + onChange={() => setValue('customTenggatWaktu', ' ')} + > + 30 hari sejak data dikirimkan + </Radio> + <div className='flex flex-row gap-2'> + <Radio colorScheme='red' value='custom'></Radio> + <input + {...register('customTenggatWaktu')} + placeholder='Masukkan jumlah hari untuk tenggat waktu' + type='text' + onFocus={() => setValue('tenggatWaktu', 'custom')} + className='form-input mt-2' + /> + </div> + </Stack> + </RadioGroup> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tenggatWaktu?.message} + </div> + </div> + </div> + </div> + + <div className={`flex flex-row justify-between items-start`}> + <div className='w-2/5 text-nowrap'> + <label + className={`form-label ${isKonfirmasi && 'text-wrap'}`} + > + Dokumen/Sertifikat yang Dimiliki Oleh Brand + </label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih dokumen/sertifikat bisa lebih dari 1 + </span> + )} + </div> + <div className='w-3/5 flex flex-col'> + <div className='flex flex-row justify-between w-full'> + <div + className='flex flex-col gap-2 w-full' + // ref={categoryProdukRef} + > + <Checkbox + colorScheme='red' + key={0} + onChange={() => handleCheckboxChange(0)} + isChecked={isChecked(0)} + > + TKDN + </Checkbox> + <Checkbox + colorScheme='red' + key={1} + onChange={() => handleCheckboxChange(1)} + isChecked={isChecked(1)} + > + SNI + </Checkbox> + <Checkbox + colorScheme='red' + key={2} + onChange={() => handleCheckboxChange(2)} + isChecked={isChecked(2)} + > + K3L + </Checkbox> + <div className='flex flex-row gap-2 w-full'> + <Checkbox + colorScheme='red' + key={3} + onChange={() => handleCheckboxChange(3)} + isChecked={isChecked(3)} + ></Checkbox> + <input + {...register('customSertifikatProduk')} + placeholder='Masukkan Dokumen/Sertifikat yang dimiliki oleh brand' + type='text' + onFocus={() => { + custom_sertifikat_produk_handle(); + }} + // onFocus={() => handleCheckboxChange(4)} + className='form-input mt-2' + /> + </div> + </div> + </div> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.sertifikatProduk?.message} + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-center'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>Garansi</label> + {!isKonfirmasi && ( + <span className='text-xs opacity-60'> + Pilih waktu garansi yang diberikan + </span> + )} + </div> + <div className='w-3/5 flex flex-col '> + <div className='flex flex-row items-center gap-3'> + <div className={`${!isKonfirmasi && 'w-[25%]'}`}> + <Controller + name='tempoGaransi' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataGaransi} + placeholder={'Pilih durasi garansi'} + /> + )} + /> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoGaransi?.message} + </div> + </div> + </div> + </div> + </div> + + <div className='w-full flex flex-row'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Jelaskan Garansi yang dimaksud! + </label> + </div> + <div className='w-3/5'> + <textarea + {...register('explainGaransi')} + placeholder='Jelaskan bagian apa yang termasuk garansi' + type='textarea' + className='form-input' + rows={4} + cols={40} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.explainGaransi?.message} + </div> + </div> + </div> + + <div className='flex flex-row justify-between items-start'> + <div className='w-2/5'> + <label className='form-label text-wrap '> + Apakah Memiliki Minimum Order Quantity (MOQ) + </label> + </div> + <div className='w-3/5 flex flex-row justify-start'> + <div className='flex gap-x-4 flex-col w-full'> + <RadioGroup + onChange={handleCheckboxOrderQuantityChange} + value={ + watch('minimumPembelian') + ? 'ya' + : watch('isOrderQuantity') + } + > + <Stack direction='column'> + <div className='flex flex-row text-nowrap gap-2'> + <Radio + colorScheme='red' + value='ya' + onChange={() => setValue('isOrderQuantity', 'ya')} + > + Ya + </Radio> + + <Controller + name='minimumPembelian' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataMinimumOrderQuantity} + placeholder={ + 'Pilih jenis minimum order quantity' + } + onFocus={() => + setValue('isOrderQuantity', 'ya') + } + /> + )} + /> + </div> + <Radio + colorScheme='red' + value='tidak' + onChange={() => setValue('minimumPembelian', '')} + > + Tidak Ada + </Radio> + </Stack> + </RadioGroup> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.isOrderQuantity?.message} + </div> + </div> + </div> + </div> + + {!isKonfirmasi && ( + <div className='flex justify-end'> + <div> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <button + type='submit' + className='btn-light bg-red-500 rounded-lg text-white w-fit py-2 px-4 md:w-fit mt-2 ml-0 md:ml-auto flex justify-between hover:bg-red-400' + > + <span className={` `}>Langkah Selanjutnya</span> + {<ChevronRightIcon className='w-5' />} + </button> + </div> + </div> + )} + </form> + </div> + </div> + </DesktopView> + <MobileView> + <div className='container flex flex-col items-star py-4'> + {!isKonfirmasi && ( + <h2 className='font-semibold mb-6 text-xl'>Syarat Perdagangan</h2> + )} + + <div className='w-full mt-4'> + <form + onSubmit={handleSubmit(onSubmitHandler)} + className='flex flex-col gap-4' + > + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'> + Syarat Pengembalian Barang + </label> + <div className='flex gap-x-4 flex-col w-full'> + <RadioGroup + onChange={handleCheckboxReturChange} + value={watch('isKembaliBarang')} + > + <Stack direction='column'> + <div className='flex flex-row text-nowrap gap-2'> + <Radio colorScheme='red' value='ya'> + Ya, dapat diretur + </Radio> + {watch('isKembaliBarang') == 'ya' && ( + <textarea + {...register('textReturn')} + placeholder='jelaskan syarat pengembalian' + type='textarea' + className='form-input w-full' + /> + )} + </div> + <Radio colorScheme='red' value='tidak'> + Tidak dapat diretur + </Radio> + </Stack> + </RadioGroup> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.isKembaliBarang?.message} + </div> + </div> + </div> + </div> + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'> + Tenggat Waktu Perubahan Harga + </label> + <div className='flex gap-x-4 flex-col w-full'> + <RadioGroup + onChange={handleCheckboxTenggatWaktuChange} + value={watch('tenggatWaktu')} + > + <Stack direction='column'> + <Radio + colorScheme='red' + value='14' + onChange={() => setValue('customTenggatWaktu', ' ')} + > + 14 hari sejak data dikirimkan + </Radio> + <Radio + colorScheme='red' + value='30' + onChange={() => setValue('customTenggatWaktu', ' ')} + > + 30 hari sejak data dikirimkan + </Radio> + <div className='flex flex-row gap-2'> + <Radio colorScheme='red' value='custom'></Radio> + <input + {...register('customTenggatWaktu')} + placeholder='Masukkan jumlah hari untuk tenggat waktu' + type='text' + onFocus={() => setValue('tenggatWaktu', 'custom')} + className='form-input mt-2' + /> + </div> + </Stack> + </RadioGroup> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tenggatWaktu?.message} + </div> + </div> + </div> + </div> + <div className='w-full flex flex-col'> + <div className='w-full'> + <label className='form-label text-nowrap'> + Dokumen/Sertifikat yang Dimiliki Oleh Brand + </label> + <div + className='flex flex-col gap-2 w-full' + // ref={categoryProdukRef} + > + <Checkbox + colorScheme='red' + key={0} + onChange={() => handleCheckboxChange(0)} + isChecked={isChecked(0)} + > + TKDN + </Checkbox> + <Checkbox + colorScheme='red' + key={1} + onChange={() => handleCheckboxChange(1)} + isChecked={isChecked(1)} + > + SNI + </Checkbox> + <Checkbox + colorScheme='red' + key={2} + onChange={() => handleCheckboxChange(2)} + isChecked={isChecked(2)} + > + K3L + </Checkbox> + <div className='flex flex-row gap-2 w-full'> + <Checkbox + colorScheme='red' + key={3} + onChange={() => handleCheckboxChange(3)} + isChecked={isChecked(3)} + ></Checkbox> + <input + {...register('customSertifikatProduk')} + placeholder='Masukkan Dokumen/Sertifikat yang dimiliki oleh brand' + type='text' + onFocus={() => { + custom_sertifikat_produk_handle(); + }} + // onFocus={() => handleCheckboxChange(4)} + className='form-input mt-2' + /> + </div> + </div> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.sertifikatProduk?.message} + </div> + </div> + </div> + + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'>Garansi</label> + <div className='w-full flex flex-row gap-2'> + <Controller + name='tempoGaransi' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataGaransi} + placeholder={'Pilih durasi garansi'} + /> + )} + /> + + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.tempoGaransi?.message} + </div> + </div> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + Jelaskan Garansi yang dimaksud! + </label> + <textarea + {...register('explainGaransi')} + placeholder='Jelaskan bagian apa yang termasuk garansi' + type='textarea' + className='form-input' + rows={4} + cols={40} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.explainGaransi?.message} + </div> + </div> + <div className='w-full flex flex-col'> + <label className='form-label text-nowrap'> + Apakah Memiliki Minimum Order Quantity (MOQ) + </label> + <div className='flex gap-x-4 flex-col w-full'> + <RadioGroup + onChange={handleCheckboxOrderQuantityChange} + value={ + watch('minimumPembelian') + ? 'ya' + : watch('isOrderQuantity') + } + > + <Stack direction='column'> + <div className='flex flex-row text-nowrap gap-2'> + <Radio + colorScheme='red' + value='ya' + onChange={() => setValue('isOrderQuantity', 'ya')} + > + Ya + </Radio> + + <Controller + name='minimumPembelian' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={dataMinimumOrderQuantity} + placeholder={'Pilih jenis minimum order quantity'} + onFocus={() => setValue('isOrderQuantity', 'ya')} + /> + )} + /> + </div> + <Radio + colorScheme='red' + value='tidak' + onChange={() => setValue('minimumPembelian', '')} + > + Tidak Ada + </Radio> + </Stack> + </RadioGroup> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.isOrderQuantity?.message} + </div> + </div> + </div> + + <div className=''> + {/* <div> + <ReCAPTCHA + ref={recaptchaRef} + sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_GOOGLE} + /> + </div> */} + </div> + <div className='flex justify-center w-full '> + {/* <Button + colorScheme='red' + className='w-full md:w-fit' + type='submit' + > + Daftar Merchant{' '} + {<ChevronRightIcon className='w-5' color='white' />} + </Button> */} + {!isKonfirmasi && ( + <div className='w-full'> + <span className='text-xs opacity-60'> + *Pastikan data yang anda masukan sudah benar dan sesuai + </span> + <button + type='submit' + className='btn-light bg-red-500 rounded-lg text-white w-full py-2 px-4 md:w-fit mt-2 ml-0 md:ml-auto flex justify-center hover:bg-red-400' + > + <span className={` `}>Langkah Selanjutnya</span> + {<ChevronRightIcon className='w-5' />} + </button> + </div> + )} + </div> + </form> + <PageContent path='/daftar-merchant' /> + </div> + </div> + </MobileView> + </> + ); +}); +const validationSchema = Yup.object().shape({ + isKembaliBarang: Yup.string().required('Harus di-pilih'), + tenggatWaktu: Yup.string().required('Harus di-pilih'), + sertifikatProduk: Yup.string().required('Harus di-pilih'), + tempoGaransi: Yup.string().required('Harus di-pilih'), + explainGaransi: Yup.string().required('Harus di-isi'), + isOrderQuantity: Yup.string().required('Harus di-isi'), +}); +const defaultValues = { + isKembaliBarang: '', + tenggatWaktu: '', + sertifikatProduk: '', + explainGaransi: '', + isOrderQuantity: '', +}; + +export default SyaratDagang; |
