summaryrefslogtreecommitdiff
path: root/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/pengajuan-tempo/component/PengajuanTempo.jsx')
-rw-r--r--src/lib/pengajuan-tempo/component/PengajuanTempo.jsx716
1 files changed, 716 insertions, 0 deletions
diff --git a/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx b/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx
new file mode 100644
index 00000000..5bef5134
--- /dev/null
+++ b/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx
@@ -0,0 +1,716 @@
+import React from 'react';
+import { useMemo, useState, useEffect, useRef } from 'react';
+import Image from '~/components/ui/image';
+import Stepper from './Stepper';
+import InformasiPerusahaan from './informasiPerusahaan';
+import KontakPerusahaan from './KontakPerusahaan';
+import Pengiriman from './Pengiriman';
+import Referensi from './Referensi';
+import Dokumen from './Dokumen';
+import Konfirmasi from './Konfirmasi';
+import { 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 {
+ usePengajuanTempoStore,
+ usePengajuanTempoStoreKontakPerson,
+ usePengajuanTempoStorePengiriman,
+ usePengajuanTempoStoreSupplier,
+ usePengajuanTempoStoreDokumen,
+} from '../../../../src-migrate/modules/register/stores/usePengajuanTempoStore';
+import { ChevronRightIcon, ChevronLeftIcon } from '@heroicons/react/24/outline';
+import createPengajuanTempoApi from '../api/createPengajuanTempoApi';
+import { Button, Checkbox, Spinner, Tooltip } from '@chakra-ui/react';
+import clsxm from '~/libs/clsxm';
+import { toast } from 'react-hot-toast';
+import useDevice from '@/core/hooks/useDevice';
+import odooApi from '~/libs/odooApi';
+import editAuthTempo from '../api/editAuthTempo';
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
+import PageContent from '@/lib/content/components/PageContent';
+const PengajuanTempo = () => {
+ const { isDesktop, isMobile } = useDevice();
+ const [currentStep, setCurrentStep] = React.useState(0);
+ const NUMBER_OF_STEPS = 6;
+ const [isLoading, setIsLoading] = useState(false);
+ const [bigData, setBigData] = useState();
+ const [idTempo, setIdTempo] = useState(0);
+ const { form, errors, validate, updateForm } = usePengajuanTempoStore();
+ const { control, watch, setValue } = useForm();
+ const auth = useAuth();
+ const router = useRouter();
+ const [BannerTempo, setBannerTempo] = useState();
+ const { formDokumen, errorsDokumen, validateDokumen, updateFormDokumen } =
+ usePengajuanTempoStoreDokumen();
+ const {
+ formKontakPerson,
+ errorsKontakPerson,
+ validateKontakPerson,
+ updateFormKontakPerson,
+ } = usePengajuanTempoStoreKontakPerson();
+ const {
+ formSupplier,
+ errorsSupplier,
+ validateSupplier,
+ updateFormSupplier,
+ hasSavedata,
+ updateHasSave,
+ } = usePengajuanTempoStoreSupplier();
+ const {
+ formPengiriman,
+ errorsPengiriman,
+ validatePengiriman,
+ updateFormPengiriman,
+ } = usePengajuanTempoStorePengiriman();
+ const [notValid, setNotValid] = useState(false);
+ const [buttonSubmitClick, setButtonSubmitClick] = useState(false);
+ const stepDivs = [
+ <InformasiPerusahaan
+ key='informasi-perusahaan'
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />,
+ <KontakPerusahaan
+ key='kontak-perusahaan'
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />,
+ <Pengiriman
+ key='pengiriman'
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />,
+ <Referensi
+ key='referensi'
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ data={bigData?.supplierIds}
+ />,
+ <Dokumen
+ key='dokumen'
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />,
+ <Konfirmasi
+ key='konfirmasi'
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />,
+ ];
+
+ const stepDivsError = [
+ errors,
+ errorsKontakPerson,
+ errorsPengiriman,
+ errorsSupplier,
+ errorsDokumen,
+ <div key='konfirmasi'>Konfirmasi</div>,
+ ];
+ const stepDivsForm = [
+ form,
+ formKontakPerson,
+ formPengiriman,
+ formSupplier,
+ formDokumen,
+ '',
+ ];
+ const stepDivsUpdateForm = [
+ updateForm,
+ updateFormKontakPerson,
+ updateFormPengiriman,
+ updateFormSupplier,
+ updateFormDokumen,
+ <div key='konfirmasi'>Konfirmasi</div>,
+ ];
+ const stepLabels = [
+ 'informasi_perusahaan',
+ 'kontak_person',
+ 'Pengiriman',
+ 'Referensi',
+ 'Dokumen',
+ 'Konfirmasi',
+ ];
+ const isFormValid = useMemo(
+ () => Object.keys(stepDivsError[currentStep]).length === 0,
+ [stepDivsError[currentStep]]
+ );
+ useEffect(() => {
+ validate();
+ validateKontakPerson();
+ validatePengiriman();
+ validateDokumen();
+ updateHasSave(true);
+ if (isFormValid) {
+ window.scrollTo({
+ top: 0,
+ behavior: 'smooth',
+ });
+ }
+ }, [currentStep, buttonSubmitClick]);
+ useEffect(() => {
+ window.scrollTo({
+ top: 0,
+ behavior: 'smooth',
+ });
+ }, [currentStep]);
+
+ useEffect(() => {
+ const loadBigData = async () => {
+ const toCamelCase = (str) =>
+ str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
+
+ const transformKeysToCamelCase = (data) => {
+ if (Array.isArray(data)) {
+ return data.map((item) => transformKeysToCamelCase(item));
+ } else if (data && typeof data === 'object') {
+ return Object.keys(data).reduce((acc, key) => {
+ const camelKey = toCamelCase(key); // Ubah kunci menjadi camelCase
+ acc[camelKey] = transformKeysToCamelCase(data[key]); // Rekursif untuk nested object atau array
+ return acc;
+ }, {});
+ }
+ return data; // Jika bukan object atau array, kembalikan nilai aslinya
+ };
+
+ try {
+ const dataPaymentTerm = await odooApi(
+ 'GET',
+ `/api/v1/partner/detail-tempo/${auth.parentId}`
+ );
+ const transformedData = transformKeysToCamelCase(dataPaymentTerm);
+ setBigData(transformedData);
+ } catch (error) {
+ console.error('Error loading dataPaymentTerm:', error);
+ }
+ };
+
+ loadBigData();
+ }, [auth]);
+
+ useEffect(() => {
+ const cachedData = bigData;
+
+ const loadBigData = async () => {
+ if (cachedData) {
+ // Ambil kunci-kunci yang relevan berdasarkan currentStep dari stepDivsForm
+ const formKeys = stepDivsForm[currentStep]
+ ? Object.keys(stepDivsForm[currentStep])
+ : [];
+ if (currentStep === 3) {
+ stepDivsUpdateForm[currentStep](cachedData.supplierIds);
+ } else if (currentStep === 4) {
+ formKeys.forEach((key) => {
+ if (cachedData[key]) {
+ // Proses hanya kunci yang ada di cachedData
+ const { name, format, base64 } = cachedData[key];
+ stepDivsUpdateForm[currentStep](key, name, format, base64);
+ }
+ });
+ } else {
+ formKeys.forEach((key) => {
+ if (bigData[key]) {
+ // Ubah data menjadi string
+ const stringData =
+ typeof bigData[key] === 'object'
+ ? JSON.stringify(bigData[key]) // Untuk objek atau array
+ : String(bigData[key]); // Untuk tipe primitif
+ // Kirim data yang sudah diubah ke string ke stepDivsUpdateForm
+ stepDivsUpdateForm[currentStep](key, stringData);
+ }
+ });
+ }
+ }
+ };
+ loadBigData();
+ validate();
+ validateKontakPerson();
+ validatePengiriman();
+ validateDokumen();
+ validateSupplier();
+ updateHasSave(true);
+ }, [currentStep, bigData, auth]);
+
+ const goToNextStep = () => {
+ if (!isFormValid) {
+ setNotValid(true);
+ setButtonSubmitClick(!buttonSubmitClick);
+ return;
+ } else {
+ // saveToLocalStorage(stepLabels[currentStep], stepDivsForm[currentStep]);
+ if (currentStep == 3) {
+ handleDaftarTempoSupplier();
+ } else if (currentStep == 4) {
+ handleDaftarTempoDokumen();
+ } else {
+ handleDaftarTempoPerPage(
+ stepLabels[currentStep],
+ stepDivsForm[currentStep]
+ );
+ }
+ setButtonSubmitClick(!buttonSubmitClick);
+ setNotValid(false);
+ }
+ setCurrentStep((prev) => (prev === NUMBER_OF_STEPS - 1 ? prev : prev + 1));
+ };
+
+ const goPrevStep = () => {
+ // if (!isFormValid) {
+ // setNotValid(true);
+ // setButtonSubmitClick(!buttonSubmitClick);
+ // return;
+ // } else {
+ // // saveToLocalStorage(stepLabels[currentStep], stepDivsForm[currentStep]);
+ // if (currentStep == 3) {
+ // handleDaftarTempoSupplier();
+ // } else if (currentStep == 4) {
+ // handleDaftarTempoDokumen();
+ // } else {
+ // handleDaftarTempoPerPage(
+ // stepLabels[currentStep],
+ // stepDivsForm[currentStep]
+ // );
+ // }
+ // setButtonSubmitClick(!buttonSubmitClick);
+ // setNotValid(false);
+ // }
+ setCurrentStep((prev) => (prev === NUMBER_OF_STEPS - 1 ? prev : prev - 1));
+ };
+
+ const handleDaftarTempoPerPage = async (
+ label,
+ formData,
+ tempoRequest = false
+ ) => {
+ for (const error of stepDivsError) {
+ if (error.length > 0) {
+ return;
+ }
+ }
+ const toastId = toast.loading('Mengirimkan formulir pengajuan tempo...');
+ setIsLoading(true);
+ try {
+ const address = await createPengajuanTempoApi({
+ id: idTempo,
+ user_id: auth.parentId,
+ partner_id: auth.partnerId,
+ section: label,
+ tempo_request: tempoRequest,
+ ...formData,
+ });
+ if (address.id) {
+ setIdTempo(address.id);
+ }
+ toast.dismiss(toastId);
+ setIsLoading(false);
+ } catch (error) {
+ toast.dismiss(toastId);
+ setIsLoading(false);
+
+ toast.error('Terjadi kesalahan dalam pengiriman formulir');
+ console.error(error);
+ }
+ };
+ const handleDaftarTempoDokumen = async () => {
+ for (const error of stepDivsError) {
+ if (error.length > 0) {
+ return;
+ }
+ }
+
+ // Filter hanya dokumen dengan `format` yang tidak undefined
+ const formattedDokumen = Object.entries(formDokumen)
+ .filter(([_, doc]) => doc.format !== undefined) // Hanya dokumen dengan `format` tidak undefined
+ .map(([key, doc]) => ({
+ documentName: key,
+ details: {
+ name: doc.name,
+ format: doc.format,
+ base64: doc.base64,
+ },
+ }));
+
+ const toastId = toast.loading('Mengirimkan formulir pengajuan tempo...');
+ if (formattedDokumen.length === 0) {
+ // toast.error('Tidak ada dokumen valid untuk dikirim.');
+ return;
+ }
+
+ setIsLoading(true);
+ try {
+ const address = await createPengajuanTempoApi({
+ id: idTempo,
+ user_id: auth.parentId,
+ partner_id: auth.partnerId,
+ formDocs: JSON.stringify(formattedDokumen),
+ });
+ if (address.id) {
+ setIdTempo(address.id);
+ }
+ toast.dismiss(toastId);
+ setIsLoading(false);
+ } catch (error) {
+ toast.dismiss(toastId);
+ setIsLoading(false);
+
+ toast.error('Terjadi kesalahan dalam pengiriman formulir');
+ console.error(error);
+ }
+ };
+
+ const isSupplierDataChanged = (formSupplier, supplierIds) => {
+ if (formSupplier.length !== supplierIds.length) {
+ return true;
+ }
+ return formSupplier.some((supplier, index) => {
+ const original = supplierIds[index];
+ return (
+ supplier.supplier !== original.supplier ||
+ supplier.pic !== original.pic ||
+ supplier.telepon !== original.telepon ||
+ supplier.durasiTempo !== original.durasiTempo ||
+ supplier.creditLimit !== original.creditLimit
+ );
+ });
+ };
+
+ const handleDaftarTempoSupplier = async () => {
+ for (const error of stepDivsError) {
+ if (error.length > 0) {
+ return;
+ }
+ }
+
+ const productOrder = formSupplier.map((product) => ({
+ supplier: product.supplier,
+ pic: product.pic,
+ telepon: product.telepon,
+ durasiTempo: product.durasiTempo,
+ creditLimit: product.creditLimit,
+ }));
+
+ // Periksa perubahan
+ const toastId = toast.loading('Mengirimkan formulir pengajuan tempo...');
+ if (bigData?.supplierIds) {
+ if (!isSupplierDataChanged(productOrder, bigData.supplierIds)) {
+ return;
+ }
+ }
+
+ setIsLoading(true);
+ try {
+ const address = await createPengajuanTempoApi({
+ id: idTempo,
+ user_id: auth.parentId,
+ partner_id: auth.partnerId,
+ formSupplier: JSON.stringify(productOrder),
+ });
+ if (address.id) {
+ setIdTempo(address.id);
+ }
+ toast.dismiss(toastId);
+ setIsLoading(false);
+ } catch (error) {
+ toast.dismiss(toastId);
+ setIsLoading(false);
+
+ toast.error('Terjadi kesalahan dalam pengiriman formulir');
+ console.error(error);
+ }
+ };
+
+ const handleDaftarTempo = async () => {
+ for (const error of stepDivsError) {
+ if (error.length > 0) {
+ return;
+ }
+ }
+
+ // Filter hanya dokumen dengan `format` yang tidak undefined
+ const formattedDokumen = Object.entries(formDokumen)
+ .filter(([_, doc]) => doc.format !== undefined) // Hanya dokumen dengan `format` tidak undefined
+ .map(([key, doc]) => ({
+ documentName: key,
+ details: {
+ name: doc.name,
+ format: doc.format,
+ base64: doc.base64,
+ },
+ }));
+
+ const toastId = toast.loading('Mengirimkan formulir pengajuan tempo...');
+ setIsLoading(true);
+ try {
+ let address4;
+ let address3;
+ const address = await createPengajuanTempoApi({
+ id: 0,
+ partner_id: auth.partnerId,
+ user_id: auth.parentId,
+ tempo_request: false,
+ ...form,
+ });
+ if (address.id) {
+ const address2 = await createPengajuanTempoApi({
+ id: address.id,
+ partner_id: auth.partnerId,
+ user_id: address.userId,
+ tempo_request: false,
+ ...formKontakPerson,
+ });
+ if (address2.id) {
+ address3 = await createPengajuanTempoApi({
+ id: address2.id,
+ partner_id: auth.partnerId,
+ user_id: address2.userId,
+ tempo_request: false,
+ ...formPengiriman,
+ });
+ if (address3.id && formattedDokumen.length > 0) {
+ // Kirim dokumen yang sudah difilter
+ address4 = await createPengajuanTempoApi({
+ id: address3.id,
+ partner_id: auth.partnerId,
+ user_id: address3.userId,
+ tempo_request: true,
+ formDocs: JSON.stringify(formattedDokumen),
+ });
+ } else {
+ address4 = await createPengajuanTempoApi({
+ id: address3.id,
+ partner_id: auth.partnerId,
+ user_id: address3.userId,
+ tempo_request: true,
+ });
+ }
+ }
+ }
+
+ if (address4?.id) {
+ toast.success('Pengajuan tempo berhasil dilakukan');
+ const toastId = toast.loading('Mengubah status akun...');
+ const isUpdated = await editAuthTempo();
+ if (isUpdated?.user) {
+ const update = await setAuth(isUpdated.user);
+ if (update) {
+ toast.dismiss(toastId);
+ setIsLoading(false);
+ toast.success('Berhasil mengubah status akun', { duration: 1000 });
+ router.push('/pengajuan-tempo/finish');
+ } else {
+ toast.dismiss(toastId);
+ setIsLoading(false);
+ toast.success('Pengajuan tempo berhasil dilakukan');
+ toast.error('Gagal mengubah status akun', { duration: 1000 });
+ router.push('/pengajuan-tempo');
+ }
+ removeFromLocalStorage();
+ return;
+ }
+ } else {
+ toast.dismiss(toastId);
+ setIsLoading(false);
+
+ toast.error('Terjadi kesalahan dalam pengiriman formulir');
+ }
+ } catch (error) {
+ toast.dismiss(toastId);
+ setIsLoading(false);
+
+ toast.error('Terjadi kesalahan dalam pengiriman formulir');
+ console.error(error);
+ }
+ };
+
+ const removeFromLocalStorage = () => {
+ for (const key of stepLabels) {
+ localStorage.removeItem(key);
+ }
+ };
+
+ const [isCheckedTNC, setIsCheckedTNC] = useState(false);
+
+ const handleCheckChange = (checked) => {
+ setIsCheckedTNC(checked);
+ };
+
+ 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 Pengajuan Tempo
+ </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-20'} bg-gray_r-3`}
+ />
+
+ <div className={`container ${isMobile ? 'mt-4' : 'mt-10'} flex flex-col`}>
+ <div className='flex items-center justify-center'>
+ <Stepper currentStep={currentStep} numberOfSteps={NUMBER_OF_STEPS} />
+ </div>
+ <div>{stepDivs[currentStep]}</div>
+ {isDesktop && <section className='flex gap-10 mt-10'></section>}
+ {isMobile && (
+ <div className='h-[2px] bg-gray-300 w-[120%] inset-0 mt-4 mb-4 relative transform -translate-x-5'></div>
+ )}
+ <div
+ className={`flex ${
+ isMobile
+ ? 'flex-col justify-start items-start'
+ : 'flex-col justify-end items-end'
+ } mb-8 gap-2`}
+ >
+ <span className='text-xs opacity-60'>
+ *Pastikan data yang anda masukan sudah benar dan sesuai
+ </span>
+ <div
+ className={` flex flex-row ${
+ currentStep > 0 && currentStep < 5
+ ? 'justify-between'
+ : 'justify-end'
+ } items-center w-full ${isMobile ? 'gap-x-4 ' : ''}`}
+ >
+ {currentStep < 5 && currentStep > 0 && (
+ <Button
+ colorScheme='yellow'
+ w={`${isMobile ? 'full' : 'fit'}`}
+ onClick={goPrevStep}
+ >
+ {<ChevronLeftIcon className='w-5' />}
+ <span className={`font-medium ${isMobile ? 'text-xs' : ''} `}>
+ Langkah Sebelumnya
+ </span>
+ </Button>
+ )}
+ {currentStep < 5 && (
+ <>
+ <Tooltip
+ label={clsxm({
+ 'Klik simpan data terlebih dahulu':
+ currentStep === 3 && !hasSavedata,
+ })}
+ >
+ <Button
+ colorScheme='red'
+ w={`${isMobile ? 'full' : 'fit'}`}
+ isDisabled={
+ (currentStep === 3 && !hasSavedata) ||
+ currentStep === NUMBER_OF_STEPS - 1
+ }
+ onClick={goToNextStep}
+ >
+ <span className={`${isMobile ? 'text-xs' : ''} `}>
+ Langkah Selanjutnya
+ </span>
+ {<ChevronRightIcon className='w-5' />}
+ </Button>
+ </Tooltip>
+ </>
+ )}
+ </div>
+ {currentStep == 5 && (
+ <div
+ className={`flex flex-col ${
+ isMobile ? 'items-start' : 'items-end'
+ } w-full justify-start gap-4`}
+ >
+ <TempoTermCondition onCheckChange={handleCheckChange} />
+ <Button
+ colorScheme='red'
+ w={`${isMobile ? 'full' : '36'}`}
+ isDisabled={!isCheckedTNC}
+ onClick={handleDaftarTempo}
+ >
+ Daftar Tempo {<ChevronRightIcon className='w-5' />}
+ </Button>
+ </div>
+ )}
+ </div>
+ </div>
+ </>
+ );
+};
+const TempoTermCondition = ({ onCheckChange }) => {
+ const [isCheckedTNC, SetIsCheckedTNC] = useState(false);
+ const [openTNC, SetOpenTNC] = useState(false);
+ const { isDesktop, isMobile } = useDevice();
+
+ const openTNCHandle = () => {
+ SetOpenTNC(!openTNC);
+ };
+
+ const toggleCheckTNC = () => {
+ const newValue = !isCheckedTNC;
+ SetIsCheckedTNC(newValue);
+ if (onCheckChange) {
+ onCheckChange(newValue);
+ }
+ };
+ return (
+ <>
+ <div className='flex items-center gap-x-2'>
+ <Checkbox
+ id='tnc'
+ name='tnc'
+ colorScheme='red'
+ isChecked={isCheckedTNC}
+ onChange={toggleCheckTNC}
+ />
+ <div className={`${isMobile ? 'text-xs' : ''}`}>
+ <label htmlFor='tnc' className='cursor-pointer'>
+ Dengan ini saya menyetujui
+ </label>{' '}
+ <span
+ className='font-medium text-danger-500 cursor-pointer'
+ onClick={openTNCHandle}
+ >
+ syarat dan ketentuan
+ </span>
+ <label htmlFor='tnc' className='ml-2 cursor-pointer'>
+ yang berlaku
+ </label>
+ </div>
+ </div>
+
+ <BottomPopup
+ active={openTNC}
+ close={() => SetOpenTNC(false)}
+ title='Syarat & Ketentuan Pendaftaran Tempo'
+ >
+ <PageContent path='/tempoTnd' />
+ </BottomPopup>
+ </>
+ );
+};
+
+export default PengajuanTempo;