diff options
Diffstat (limited to 'src/lib/pengajuan-tempo/component/Referensi.jsx')
| -rw-r--r-- | src/lib/pengajuan-tempo/component/Referensi.jsx | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/src/lib/pengajuan-tempo/component/Referensi.jsx b/src/lib/pengajuan-tempo/component/Referensi.jsx new file mode 100644 index 00000000..8db321d1 --- /dev/null +++ b/src/lib/pengajuan-tempo/component/Referensi.jsx @@ -0,0 +1,636 @@ +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { useForm } from 'react-hook-form'; +import { + usePengajuanTempoStoreSupplier, + usePengajuanTempoStore, +} from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore'; +import * as Yup from 'yup'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { PlusCircleIcon } from '@heroicons/react/24/outline'; +import useDevice from '@/core/hooks/useDevice'; +import { Trash2Icon } from 'lucide-react'; +import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +const initialData = []; +const Referensi = ({ chekValid, buttonSubmitClick, data }) => { + const [changeConfirmation, setChangeConfirmation] = useState(false); + const [selectedIndex, setSelectedIndex] = useState(null); + + const { isDesktop, isMobile } = useDevice(); + const [openIndexes, setOpenIndexes] = useState([]); + + const { + register, + formState: { errors }, + handleSubmit, + watch, + setValue, + control, + } = useForm({ + resolver: yupResolver(validationSchema), + defaultValues, + }); + const { formSupplier, updateFormSupplier, updateHasSave, hasSavedata } = + usePengajuanTempoStoreSupplier(); + const { form } = usePengajuanTempoStore(); + const [formData, setFormData] = useState([ + { + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', + }, + ]); + + const [buttonSubmit, setButtonSubmit] = useState(false); + const [supplierData, setSupplierData] = useState(initialData); + const [newSupplier, setNewSupplier] = useState({ + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', + }); + const onChangeInput = (e, index) => { + updateHasSave(false); + const { name, value } = e.target; + + let formattedValue = value; + + if (name === 'durasiTempo') { + formattedValue = value.replace(/\s*Hari\s*/g, ''); + } else if (name === 'creditLimit') { + formattedValue = value.replace(/^Rp\s*/, ''); + } + + const editData = supplierData.map((item, i) => + i === index ? { ...item, [name]: formattedValue } : item + ); + setSupplierData(editData); + if (value == '' && supplierData.supplier) { + updateHasSave(true); + } + }; + + const handleNewSupplierChange = (e) => { + updateHasSave(false); + const { name, value } = e.target; + + let formattedValue = value; + + if (name === 'durasiTempo') { + formattedValue = value.replace(/\s*Hari\s*/g, ''); + } else if (name === 'creditLimit') { + formattedValue = value.replace(/^Rp\s*/, ''); + } + + const updatedSupplier = { ...newSupplier, [name]: formattedValue }; + setNewSupplier(updatedSupplier); + if (value == '') { + updateHasSave(true); + } + }; + + useEffect(() => { + const isAllFieldsEmpty = Object.values(newSupplier).every( + (value) => value === '' + ); + if (isAllFieldsEmpty) { + updateHasSave(true); + } else { + updateHasSave(false); + } + }, [newSupplier]); + + const handleDeleteSupplier = () => { + if (selectedIndex !== null) { + // Logika untuk menghapus supplier + const updatedSuppliers = supplierData.filter( + (_, idx) => idx !== selectedIndex + ); + setSupplierData(updatedSuppliers); + setChangeConfirmation(false); + updateHasSave(false); + } + }; + + const handleAddNewSupplier = () => { + // updateHasSave(false); + if (Object.values(newSupplier).every((val) => val.trim() !== '')) { + setSupplierData((prevData) => { + const newData = [...prevData, newSupplier]; + return newData; + }); + + setNewSupplier({ + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', + }); + } + }; + + useEffect(() => { + handleAddNewSupplier(); + updateFormSupplier(supplierData); + setButtonSubmit(!buttonSubmit); + }, [buttonSubmitClick]); + const simpanData = () => { + setButtonSubmit(!buttonSubmit); + if (Object.values(newSupplier).every((val) => val.trim() !== '')) { + setSupplierData((prevData) => { + const newData = [...prevData, newSupplier]; + return newData; + }); + + setNewSupplier({ + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', + }); + } + updateHasSave(true); + }; + const formatRupiah = (value) => { + if (!value) return ''; + const numberString = value.replace(/[^0-9]/g, ''); + return numberString + ? 'Rp ' + new Intl.NumberFormat('id-ID').format(numberString) + : ''; + }; + const formatHari = (value) => { + if (!value) return ''; + + const numberString = value.replace(/[^0-9]/g, ''); + + return numberString ? numberString.replace(/Hari/g, '') + ' Hari' : ''; + }; + + useEffect(() => { + updateFormSupplier(supplierData); + }, [buttonSubmit]); + const getFromLocalStorage = (key) => { + const itemStr = localStorage.getItem(key); + if (!itemStr) return null; + + const item = JSON.parse(itemStr); + return item; + }; + useEffect(() => { + // const cachedData = getFromLocalStorage('Referensi'); + if (data) { + setSupplierData(data); + updateFormSupplier(data); + } + }, [buttonSubmitClick]); + + useEffect(() => { + setOpenIndexes(supplierData.map((_, index) => index)); + }, [supplierData]); + + const toggleOpen = (index) => { + setOpenIndexes((prev) => + prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index] + ); + }; + + const handleOpenConfirmation = (index) => { + setSelectedIndex(index); + setChangeConfirmation(true); + }; + return ( + <> + <BottomPopup + active={changeConfirmation} + close={() => setChangeConfirmation(false)} + title='Konfirmasi Hapus Data' + > + <div className='leading-7 text-gray_r-12/80'> + Apakah anda yakin menghapus data? + </div> + <div className='flex mt-6 gap-x-4 md:justify-end'> + <button + className='btn-solid-red flex-1 md:flex-none' + type='button' + onClick={handleDeleteSupplier} + > + Ya, Hapus + </button> + <button + className='btn-light flex-1 md:flex-none' + type='button' + onClick={() => setChangeConfirmation(false)} + > + Batal + </button> + </div> + </BottomPopup> + {isDesktop && ( + <div className='py-4'> + <div className='flex flex-col justify-start'> + <h1 className='font-bold text-2xl'> + Referensi Supplier / Rekanan Bisnis Perusahaan{' '} + <span className=' opacity-60 text-xl'>(Opsional)</span> + </h1> + <p className='opacity-60'> + Data yang anda berikan hanya untuk bahan referensi internal kami + untuk memberikan anda credit limit dan durasi tempo + </p> + </div> + <form className='flex mt-4 flex-col w-full '> + <table className='border' border='1' cellPadding='10'> + <thead> + <tr className='border '> + <th className='text-left px-5 py-2'> + Nama Supplier / Rekanan + </th> + <th className='text-left px-5 py-2'>PIC</th> + <th className='text-left px-5 py-2'>Telepon</th> + <th className='text-left px-5 py-2'>Durasi Tempo</th> + <th className='text-left px-5 py-2'>Credit Limit</th> + </tr> + </thead> + <tbody> + {supplierData.map((supplier, index) => ( + <tr key={index}> + <td> + <input + name='supplier' + value={supplier.supplier} + type='text' + onChange={(e) => onChangeInput(e, index)} + className='form-input border px-4 py-2' + placeholder='Type Supplier' + /> + </td> + <td> + <input + name='pic' + value={supplier.pic} + type='text' + className='form-input border px-4 py-2' + onChange={(e) => onChangeInput(e, index)} + placeholder='Type PIC' + /> + </td> + <td> + <input + name='telepon' + type='text' + className='form-input border px-4 py-2' + value={supplier.telepon} + onChange={(e) => onChangeInput(e, index)} + placeholder='Type Telepon' + /> + </td> + <td> + <input + name='durasiTempo' + type='text' + className='form-input border px-4 py-2' + value={formatHari(supplier.durasiTempo)} + onChange={(e) => onChangeInput(e, index)} + placeholder='Type Durasi Tempo' + /> + </td> + <td className='flex flex-row gap-2 justify-center items-center'> + <input + name='creditLimit' + type='text' + value={formatRupiah(supplier.creditLimit)} + className='form-input border px-4 py-2' + onChange={(e) => onChangeInput(e, index)} + placeholder='Type Credit Limit' + /> + <Trash2Icon + size={18} + onClick={() => handleOpenConfirmation(index)} + className='cursor-pointer' + /> + </td> + </tr> + ))} + <tr> + <td> + <input + name='supplier' + value={newSupplier.supplier} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='Isi nama supplier anda' + /> + </td> + <td> + <input + name='pic' + value={newSupplier.pic} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='Isi PIC supplier anda' + /> + </td> + <td> + <input + name='telepon' + value={newSupplier.telepon} + type='text' + onChange={handleNewSupplierChange} + placeholder='Isi telepon supplier anda' + className='form-input border px-4 py-2' + /> + </td> + <td> + <input + name='durasiTempo' + value={formatHari(newSupplier.durasiTempo)} + type='text' + onChange={handleNewSupplierChange} + className='form-input border px-4 py-2' + placeholder='Durasi jatuh tempo' + /> + </td> + <td className='flex flex-row items-center gap-2 '> + <input + name='creditLimit' + value={formatRupiah(newSupplier.creditLimit)} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='limit kredit' + /> + {/* <Trash2Icon + size={18} + onClick={() => handleDeleteSupplier(index)} + /> */} + </td> + </tr> + </tbody> + </table> + </form> + <div className='flex items-center gap-4 mt-8'> + {/* <button + onClick={handleAddNewSupplier} + className='bg-gray-200 border border-gray-500 rounded-md text-sm text-gray-500 p-2 h-11 mb-1 content-center flex flex-row justify-center items-center' + > + {<PlusCircleIcon className='w-5 mr-2' />} + {''} Tambah Data Baru + </button> */} + {!hasSavedata && ( + <> + <button + onClick={simpanData} + className={`bg-red-500 border border-red-500 rounded-md text-sm text-white p-2 h-11 mb-1 content-center flex flex-row justify-center items-center `} + > + Simpan Data + </button> + <span className='text-sm opacity-60 text-red-500'> + *Klik simpan sebelum lanjut ke tahap selanjutnya + </span> + </> + )} + </div> + </div> + )} + {isMobile && ( + <div className='text-sm'> + <div className='flex flex-col py-4 mt-8 justify-start'> + <h1 className='font-bold text-xl'> + Referensi Supplier / Rekanan Bisnis Perusahaan{' '} + <span className=' opacity-60 text-xl'>(Opsional)</span> + </h1> + <p className='opacity-60'> + Data yang anda berikan hanya untuk bahan referensi internal kami + untuk memberikan anda credit limit dan durasi tempo + </p> + </div> + <div className='flex gap-4 flex-col'> + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + <h2 className='py-2 font-semibold text-base'> + Daftar Nama Supplier + </h2> + {/* <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> */} + <div className=''> + {supplierData.map((supplier, index) => ( + <div key={index}> + <div + className='flex flex-row justify-center items-center py-4' + onClick={() => toggleOpen(index)} + > + <p className='font-semibold text-base w-4/5'> + {supplier.supplier} + </p> + <div className='w-1/5 flex justify-end items-center gap-2'> + <Trash2Icon + size={16} + color='red' + onClick={() => handleOpenConfirmation(index)} + className='cursor-pointer' + /> + {openIndexes.includes(index) ? ( + <ChevronUpIcon className='w-4' /> + ) : ( + <ChevronDownIcon className='w-4' /> + )} + </div> + </div> + {openIndexes.includes(index) && ( + <form className='flex flex-col w-full'> + <div className='w-full grid grid-row-2 gap-4'> + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Supplier + </label> + </div> + <div className='w-3/5 opacity-70'> + {supplier.supplier} + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + PIC + </label> + </div> + <div className='w-3/5 opacity-70'>{supplier.pic}</div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Telepon + </label> + </div> + <div className='w-3/5 opacity-70'> + {supplier.telepon} + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Durasi Tempo + </label> + </div> + <div className='w-3/5 opacity-70'> + {formatHari(supplier.durasiTempo)} + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Kredit Limit + </label> + </div> + <div className='w-3/5 opacity-70'> + {formatRupiah(supplier.creditLimit)} + </div> + </div> + </div> + </form> + )} + </div> + ))} + </div> + {/* <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> */} + {/* <h2 className='py-2 font-semibold text-base text-red-500 flex flex-row'> + <PlusCircleIcon className='w-5 mr-2' /> + Tambah Data Baru + </h2> */} + <div className='h-[2px] bg-gray-300 w-[120%] inset-0 relative transform -translate-x-5'></div> + <form className='flex flex-col w-full'> + <div className='w-full grid grid-row-2 gap-2'> + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Nama Supplier + </label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='supplier' + value={newSupplier.supplier} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='Format: PT. ABC TESTING INDONESIA' + /> + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>PIC</label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='pic' + value={newSupplier.pic} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='John Doe' + /> + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'>Telepon</label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='telepon' + value={newSupplier.telepon} + type='text' + onChange={handleNewSupplierChange} + placeholder='Format: 08123456789' + className='form-input border px-4 py-2' + /> + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Durasi Tempo + </label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='durasiTempo' + value={formatHari(newSupplier.durasiTempo)} + type='text' + onChange={handleNewSupplierChange} + className='form-input border px-4 py-2' + placeholder='Isi durasi tempo supplier anda (hari)' + /> + </div> + </div> + + <div className='flex flex-row justify-start items-start'> + <div className='w-2/5'> + <label className='form-label text-nowrap'> + Kredit Limit + </label> + </div> + <div className='w-3/5 opacity-70'> + <input + name='creditLimit' + value={formatRupiah(newSupplier.creditLimit)} + type='text' + className='form-input border px-4 py-2' + onChange={handleNewSupplierChange} + placeholder='Rp 999.999.999' + /> + </div> + </div> + </div> + </form> + </div> + <div className='flex flex-col justify-start items-start gap-4 mt-8'> + {!hasSavedata && ( + <> + <span className='text-xs opacity-60 text-red-500'> + *Klik simpan sebelum lanjut ke tahap selanjutnya + </span> + <button + onClick={simpanData} + className={`bg-red-500 border border-red-500 rounded-md w-full text-sm text-white p-2 h-11 mb-1 content-center flex flex-row justify-center items-center`} + > + Simpan Data + </button> + </> + )} + </div> + </div> + )} + </> + ); +}; + +const validationSchema = Yup.object().shape({ + supplier: Yup.string().required('Harus di-isi'), + pic: Yup.string().required('Harus di-isi'), + telepon: Yup.string().required('Harus di-isi'), + durasiTempo: Yup.string().required('Harus di-isi'), + creditLimit: Yup.string().required('Harus di-isi'), +}); + +const defaultValues = { + supplier: '', + pic: '', + telepon: '', + durasiTempo: '', + creditLimit: '', +}; +export default Referensi; |
