diff options
| author | IT Fixcomart <it@fixcomart.co.id> | 2025-08-15 10:23:38 +0000 |
|---|---|---|
| committer | IT Fixcomart <it@fixcomart.co.id> | 2025-08-15 10:23:38 +0000 |
| commit | 5ef267f76486ed590c00d3c37cccde5c713491cd (patch) | |
| tree | 4a3cf919743ac45d4ecb8d01fdf7ef51685ca16a | |
| parent | 4d7e2f7b6e92cbe700e5b8fcea006b3d70ed81f9 (diff) | |
| parent | b1bdfbb9f780a1a1305e02c4b9c338b98c7a4556 (diff) | |
Merged in tempo-v2 (pull request #442)
Tempo v2
| -rw-r--r-- | src/lib/auth/api/checkParentStatusApi.js | 13 | ||||
| -rw-r--r-- | src/lib/auth/api/editPersonalProfileApi.js | 2 | ||||
| -rw-r--r-- | src/lib/auth/api/switchAccountApi.js | 2 | ||||
| -rw-r--r-- | src/lib/auth/components/SwitchAccount.jsx | 71 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js | 2 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/FinishTempo.jsx | 130 | ||||
| -rw-r--r-- | src/lib/pengajuan-tempo/component/PengajuanTempo.jsx | 1 | ||||
| -rw-r--r-- | src/pages/my/profile.jsx | 91 |
8 files changed, 232 insertions, 80 deletions
diff --git a/src/lib/auth/api/checkParentStatusApi.js b/src/lib/auth/api/checkParentStatusApi.js new file mode 100644 index 00000000..aa2eb1b6 --- /dev/null +++ b/src/lib/auth/api/checkParentStatusApi.js @@ -0,0 +1,13 @@ +import odooApi from '@/core/api/odooApi'; +import { getAuth } from '@/core/utils/auth'; + +const checkParentStatusApi = async () => { + const auth = getAuth(); + const checkParentStatus = await odooApi( + 'GET', + `/api/v1/user/${auth.partnerId}/parent_status` + ); + return checkParentStatus; +}; + +export default checkParentStatusApi;
\ No newline at end of file diff --git a/src/lib/auth/api/editPersonalProfileApi.js b/src/lib/auth/api/editPersonalProfileApi.js index 39cd44c1..90bda114 100644 --- a/src/lib/auth/api/editPersonalProfileApi.js +++ b/src/lib/auth/api/editPersonalProfileApi.js @@ -3,7 +3,7 @@ import { getAuth } from '@/core/utils/auth' const editPersonalProfileApi = async ({ data }) => { const auth = getAuth() - const dataProfile = await odooApi('PUT', `/api/v1/user/${auth.id}`, data) + const dataProfile = await odooApi('POST', `/api/v1/user/${auth.id}`, data) return dataProfile } diff --git a/src/lib/auth/api/switchAccountApi.js b/src/lib/auth/api/switchAccountApi.js index 79ca2553..f62693f6 100644 --- a/src/lib/auth/api/switchAccountApi.js +++ b/src/lib/auth/api/switchAccountApi.js @@ -4,7 +4,7 @@ import { getAuth } from '@/core/utils/auth'; const switchAccountApi = async ({ data }) => { const auth = getAuth(); const switchAccount = await odooApi( - 'PUT', + 'POST', `/api/v1/user/${auth.partnerId}/switch`, data ); diff --git a/src/lib/auth/components/SwitchAccount.jsx b/src/lib/auth/components/SwitchAccount.jsx index 46e57348..840758c9 100644 --- a/src/lib/auth/components/SwitchAccount.jsx +++ b/src/lib/auth/components/SwitchAccount.jsx @@ -13,9 +13,10 @@ import { useRegisterStore } from '~/modules/register/stores/useRegisterStore.ts' import { registerUser } from '~/services/auth'; import { useMutation } from 'react-query'; import { isValid } from 'zod'; +import Spinner from "@/core/components/elements/Spinner/LogoSpinner"; import useDevice from '@/core/hooks/useDevice'; import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; -const SwitchAccount = ({ company_type }) => { +const SwitchAccount = ({ company_type, setIsAprove, setUbahAkun }) => { const { isDesktop, isMobile } = useDevice(); const auth = useAuth(); const [isOpen, setIsOpen] = useState(true); @@ -27,6 +28,8 @@ const SwitchAccount = ({ company_type }) => { const [selectedValue, setSelectedValue] = useState('PKP'); const [buttonSubmitClick, setButtonSubmitClick] = useState(false); const [changeConfirmation, setChangeConfirmation] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [isLoadingPopup, setIsLoadingPopup] = useState(false); const { register, setValue, handleSubmit } = useForm({ defaultValues: { email: '', @@ -131,35 +134,46 @@ const SwitchAccount = ({ company_type }) => { setIsPKP(false); } }; - const onSubmitHandler = async (values) => { - toast.loading('Mengubah status akun...'); + const onSubmitHandler = async () => { + setChangeConfirmation(false); // Tutup popup konfirmasi + setIsLoadingPopup(true); // Munculkan popup loading + updateForm('parent_id', `${auth.parentId}`); - setChangeConfirmation(false); - // let data = { ...form, id: `${auth.partnerId}` }; + const data = form; if (!isFormValid) { setNotValid(true); setButtonSubmitClick(!buttonSubmitClick); + toast.error('Form belum valid. Mohon periksa kembali input Anda.'); + setIsLoadingPopup(false); return; - } else { - setButtonSubmitClick(!buttonSubmitClick); - setNotValid(false); } - // if (!values.password) delete data.password; - const isUpdated = await switchAccountApi({ data }); - if (isUpdated?.switch === 'Pending') { - // setAuth(isUpdated.user); - // setValue('password', ''); - toast.success('Berhasil mengubah akun', { duration: 1500 }); - setTimeout(() => { - window.location.reload(); - }, 1500); - return; + try { + const isUpdated = await switchAccountApi({ data }); + + if (isUpdated?.switch === 'pending') { + toast.success('Berhasil mengajukan ubah akun', { duration: 1500 }); + if (typeof window !== 'undefined') { + localStorage.setItem('autoCheckProfile', 'true'); + } + setTimeout(() => { + setIsAprove('pending'); + setUbahAkun('pending'); + window.location.reload(); + }, 1500); + } else { + toast.error('Gagal mengubah akun. Silakan coba lagi nanti atau hubungi admin jika masalah tetap terjadi.'); + setIsLoadingPopup(false); + } + } catch (error) { + console.error(error); + toast.error('Terjadi kesalahan saat menghubungi server, silahkan cek internet Anda atau hubungi admin Indoteknik.'); + setIsLoadingPopup(false); } - toast.error('Terjadi kesalahan internal'); }; + const onSubmitHandlerCancel = async (values) => { window.location.reload(); }; @@ -172,26 +186,37 @@ const SwitchAccount = ({ company_type }) => { title='Ubah profil Bisnis' > <div className='leading-7 text-gray_r-12/80'> - Anda yakin akan merubah profil bisnis anda dari INDIVIDU menjadi{' '} - {selectedValue}? + Anda yakin akan merubah profil bisnis anda dari INDIVIDU menjadi {selectedValue}? </div> <div className='flex mt-6 gap-x-4 md:justify-end'> <button - className='btn-solid-red flex-1 md:flex-none' + className='btn-solid-red flex-1 md:flex-none flex items-center justify-center' type='button' onClick={onSubmitHandler} + disabled={isLoading} > - Ya, Ubah + {isLoading && <Spinner className="w-4 h-4 mr-2 text-white" />} + {isLoading ? 'Menyimpan...' : 'Ya, Ubah'} </button> <button className='btn-light flex-1 md:flex-none' type='button' onClick={() => setChangeConfirmation(false)} + disabled={isLoading} > Batal </button> </div> </BottomPopup> + <BottomPopup active={isLoadingPopup} close=""> + <div className="leading-7 text-gray_r-12/80 flex justify-center"> + Mengubah status akun... + </div> + <div className="container flex justify-center my-4"> + <Spinner width={48} height={48} /> + </div> + </BottomPopup> + {/* <div type='button' className='ml-4 flex items-center text-left w-full'> <div className={`flex ${ diff --git a/src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js b/src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js index af1d6c3a..173287de 100644 --- a/src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js +++ b/src/lib/pengajuan-tempo/api/createPengajuanTempoApi.js @@ -11,4 +11,4 @@ const createPengajuanTempoApi = async (data) => { return dataPengajuanTempo; }; -export default createPengajuanTempoApi; +export default createPengajuanTempoApi;
\ No newline at end of file diff --git a/src/lib/pengajuan-tempo/component/FinishTempo.jsx b/src/lib/pengajuan-tempo/component/FinishTempo.jsx index aacb9ef3..abf218d9 100644 --- a/src/lib/pengajuan-tempo/component/FinishTempo.jsx +++ b/src/lib/pengajuan-tempo/component/FinishTempo.jsx @@ -8,13 +8,19 @@ import useAuth from '@/core/hooks/useAuth'; import axios from 'axios'; import { toast } from 'react-hot-toast'; import { ChevronRightIcon, ChevronLeftIcon } from '@heroicons/react/24/outline'; +import { useRouter } from 'next/router'; +import switchAccountProgresApi from '@/lib/auth/api/switchAccountProgresApi.js'; const FinishTempo = ({ query }) => { const [data, setData] = useState(); + const [switchStatus, setSwitchStatus] = useState(null); + const [loadingStatus, setLoadingStatus] = useState(true); const [transactionData, setTransactionData] = useState(); const { isDesktop, isMobile } = useDevice(); const auth = useAuth(); const so_order = query?.order_id?.replaceAll('-', '/'); + const router = useRouter(); + useEffect(() => { const fetchData = async () => { const fetchedData = await odooApi( @@ -26,8 +32,46 @@ const FinishTempo = ({ query }) => { fetchData(); }, [query]); + useEffect(() => { + const fetchSwitchStatus = async () => { + try { + const progres = await switchAccountProgresApi(); + setSwitchStatus(progres?.status); + } catch (err) { + console.error('Gagal cek progres switch account:', err); + } finally { + setLoadingStatus(false); + } + }; + fetchSwitchStatus(); + }, []); + + // Handler khusus untuk tombol Ubah Akun + const handleSwitchAccountClick = () => { + if (switchStatus === 'pending') { + toast.info('Akun sedang menunggu verifikasi. Tidak dapat mengubah akun saat ini.', { duration: 2500 }); + return; + } + localStorage.setItem('autoCheckProfile', 'true'); + router.push('/my/profile'); + }; + + if (loadingStatus) { + return ( + <div className="container flex flex-col items-center gap-4"> + <div className="py-20 text-gray-500">Memuat data...</div> + </div> + ); + } + return ( - <div className='container flex flex-col items-center gap-4'> + <div + className={`container flex flex-col items-center gap-4 pb-20 ${ + switchStatus === 'pending' + ? 'min-h-[calc(100vh-80px)] md:min-h-[calc(100vh-100px)] lg:min-h-[calc(100vh-120px)]' + : 'min-h-screen' + }`} + > <div className={`flex ${ isMobile ? 'w-full' : 'w-2/3' @@ -40,8 +84,11 @@ const FinishTempo = ({ query }) => { > {query?.status == 'finish' && 'Form Pengajuan Tempo kamu Telah Berhasil Didaftarkan Mohon menunggu hingga Proses Verifikasi Selesai Dilakukan'} - {query?.status == 'switch-account' && - 'Form Pengajuan Tempo Kamu Gagal Dilakukan'} + {switchStatus === 'pending' + ? 'Form Pengajuan Tempo Kamu Belum Dapat Dilakukan' + : query?.status == 'switch-account' && + 'Form Pengajuan Tempo Kamu Gagal Dilakukan' + } {query?.status == 'review' && 'Pengajuan Tempo dalam Proses Verifikasi'} {query?.status == 'approve' && 'Pengajuan Tempo Berhasil'} @@ -85,8 +132,11 @@ const FinishTempo = ({ query }) => { isMobile ? 'w-full text-sm' : 'w-4/5 text-base' }`} > - {query?.status == 'switch-account' && - 'Terima kasih atas minat anda untuk mendaftar Tempo, namun sayangnya akun anda bukan merupakan akun bisnis. Segera ubah akun anda menjadi Bisnis untuk menggunakan fitur ini'} + {switchStatus === 'pending' + ? 'Proses perubahan ke akun bisnis sedang kami review, mohon menunggu hingga 2x24 jam' + : query?.status == 'switch-account' && + 'Terima kasih atas minat anda untuk mendaftar Tempo, namun sayangnya akun anda bukan merupakan akun bisnis. Segera ubah akun anda menjadi Bisnis untuk menggunakan fitur ini' + } {query?.status == 'finish' && 'Mohon menunggu untuk verifikasi dokumen dan kelengkapan data yang telah anda berikan. Proses approval pembayaran tempo kamu berhasil atau tidak akan diinfokan melalui email perusahaan / email yang mendaftar'} {query?.status == 'review' && @@ -94,23 +144,59 @@ const FinishTempo = ({ query }) => { {query?.status == 'approve' && 'Proses pengajuan tempo anda sudah berhasil terdaftar di indoteknik.com. Nikmati pembelian anda di website indoteknik dengan menggunakan pembayaran tempo'} </div> - <Link - href={ - query?.status === 'switch-account' - ? '/my/profile' - : query?.status === 'approve' - ? '/my/tempo/' - : '/' - } - className='btn-solid-red rounded-md text-base flex flex-row items-center justify-center' - > - {query?.status === 'switch-account' - ? 'Ubah Akun' - : query?.status === 'approve' - ? 'Lihat Detail Tempo' - : 'Kembali Ke Beranda'} - <ChevronRightIcon className='w-5' /> - </Link> + + {switchStatus !== 'pending' && ( + <hr className="border-gray-300 w-full" /> + )} + + {/* Video panduan khusus tampil saat status switch-account */} + {query?.status === 'switch-account' && switchStatus !== 'pending' && ( + <div className="w-full max-w-3xl mx-auto px-4 text-center text-gray-700 mb-6"> + <div className="mb-3 font-medium"> + <h1 + className={`text-red-500 text-center font-semibold ${ + isMobile ? 'text-lg' : 'text-3xl' + }`} + // Mengganti py-4 dengan my-6 supaya jarak vertikalnya sama dengan hr + style={{ marginTop: 24, marginBottom: 24 }} + > + Video Panduan Pengajuan Tempo + </h1> + </div> + <div className="relative" style={{ paddingTop: '56.25%' /* 16:9 aspect ratio */ }}> + <iframe + src="https://www.youtube.com/embed/m15f8-eLqUc?si=frNbGnJu1zjINnDT" + title="YouTube video player" + frameBorder="0" + allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" + allowFullScreen + referrerPolicy="strict-origin-when-cross-origin" + className="absolute top-0 left-0 w-full h-full rounded-md shadow-lg" + ></iframe> + </div> + </div> + )} + + {/* Tombol dengan behavior berbeda jika status switch-account */} + {query?.status === 'switch-account' && switchStatus !== 'pending' ? ( + <button + onClick={handleSwitchAccountClick} + className="btn-solid-red rounded-md text-base flex flex-row items-center justify-center mb-10" + > + Ubah Akun + <ChevronRightIcon className="w-5" /> + </button> + ) : query?.status !== 'switch-account' && ( + <Link + href={query?.status === 'approve' ? '/my/tempo/' : '/'} + className="btn-solid-red rounded-md text-base flex flex-row items-center justify-center mb-10" + > + {query?.status === 'approve' + ? 'Lihat Detail Tempo' + : 'Kembali Ke Beranda'} + <ChevronRightIcon className="w-5" /> + </Link> + )} </div> ); }; diff --git a/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx b/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx index ae3d97fd..096fe1ed 100644 --- a/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx +++ b/src/lib/pengajuan-tempo/component/PengajuanTempo.jsx @@ -40,6 +40,7 @@ const PengajuanTempo = () => { const { form, errors, validate, updateForm } = usePengajuanTempoStore(); const { control, watch, setValue, setError } = useForm(); const auth = useAuth(); + console.log('auth', auth); const router = useRouter(); const [BannerTempo, setBannerTempo] = useState(); const { formDokumen, errorsDokumen, validateDokumen, updateFormDokumen } = diff --git a/src/pages/my/profile.jsx b/src/pages/my/profile.jsx index 859b6960..b65a5e4d 100644 --- a/src/pages/my/profile.jsx +++ b/src/pages/my/profile.jsx @@ -14,19 +14,27 @@ import { Checkbox } from '@chakra-ui/react'; import { useState, useEffect } from 'react'; import switchAccountProgresApi from '@/lib/auth/api/switchAccountProgresApi.js'; import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import { useRouter } from 'next/router'; + export default function Profile() { const auth = useAuth(); + console.log('auth', auth); const [isChecked, setIsChecked] = useState(false); const [ubahAkun, setUbahAkun] = useState(false); const [isAprove, setIsAprove] = useState(); const [changeConfirmation, setChangeConfirmation] = useState(false); - const handleChange = async () => { + const router = useRouter(); + + // Handle checkbox toggle + const handleChange = () => { if (isChecked) { - setIsChecked(!isChecked); + setIsChecked(false); } else { setChangeConfirmation(true); } }; + + // Load status dan cek localStorage "autoCheckProfile" useEffect(() => { const loadPromo = async () => { const progresSwitchAccount = await switchAccountProgresApi(); @@ -36,7 +44,28 @@ export default function Profile() { } }; loadPromo(); - }, []); + + if (typeof window !== 'undefined') { + const autoCheck = localStorage.getItem('autoCheckProfile'); + if (autoCheck === 'true') { + setIsChecked(true); + localStorage.removeItem('autoCheckProfile'); + + // Hapus query param supaya URL bersih + if (router.query.autoCheck) { + const cleanQuery = { ...router.query }; + delete cleanQuery.autoCheck; + router.replace( + { pathname: router.pathname, query: cleanQuery }, + undefined, + { shallow: true } + ); + } + } + } + }, [router]); + + // Confirm checkbox change from popup const handleConfirmSubmit = () => { setChangeConfirmation(false); setIsChecked(true); @@ -46,22 +75,22 @@ export default function Profile() { <BottomPopup active={changeConfirmation} close={() => setChangeConfirmation(false)} // Menutup popup - title='Ubah type akun' + title="Ubah type akun" > - <div className='leading-7 text-gray_r-12/80'> + <div className="leading-7 text-gray_r-12/80"> Anda akan mengubah type akun anda? </div> - <div className='flex mt-6 gap-x-4 md:justify-end'> + <div className="flex mt-6 gap-x-4 md:justify-end"> <button - className='btn-solid-red flex-1 md:flex-none' - type='button' + className="btn-solid-red flex-1 md:flex-none" + type="button" onClick={handleConfirmSubmit} > Yakin </button> <button - className='btn-light flex-1 md:flex-none' - type='button' + className="btn-light flex-1 md:flex-none" + type="button" onClick={() => setChangeConfirmation(false)} > Batal @@ -70,23 +99,22 @@ export default function Profile() { </BottomPopup> <IsAuth> <MobileView> - <AppLayout title='Akun Saya'> - {auth?.company || - (!ubahAkun && ( - <div className='text-sm p-4 flex items-center'> + <AppLayout title="Akun Saya"> + {auth?.company || ((isChecked || (!ubahAkun && ubahAkun !== 'pending')) && ( + <div className="text-sm p-4 flex items-center"> <Checkbox - borderColor='gray.600' - colorScheme='red' - size='lg' + borderColor="gray.600" + colorScheme="red" + size="lg" isChecked={isChecked} onChange={handleChange} /> - <p className='ml-2'>Ubah ke akun bisnis</p> + <p className="ml-2">Ubah ke akun bisnis</p> </div> ))} - {isChecked && ( + {isChecked && ubahAkun !== 'pending' && ( <div> - <SwitchAccount company_type='nonpkp' /> + <SwitchAccount company_type="nonpkp" setIsAprove={setIsAprove} setUbahAkun={setUbahAkun}/> <Divider /> </div> )} @@ -104,27 +132,26 @@ export default function Profile() { <DesktopView> <BasicLayout> - <div className='container mx-auto flex py-10'> - <div className='w-3/12 pr-4'> + <div className="container mx-auto flex py-10"> + <div className="w-3/12 pr-4"> <Menu /> </div> - <div className='w-9/12 bg-white border border-gray_r-6 rounded'> - {auth?.company || - (!ubahAkun && ( - <div className='text-sm p-4 flex items-center'> + <div className="w-9/12 bg-white border border-gray_r-6 rounded"> + {auth?.company || ((isChecked || (!ubahAkun && ubahAkun !== 'pending')) && ( + <div className="text-sm p-4 flex items-center"> <Checkbox - borderColor='gray.600' - colorScheme='red' - size='lg' + borderColor="gray.600" + colorScheme="red" + size="lg" isChecked={isChecked} onChange={handleChange} /> - <p className='ml-2'>Ubah ke akun bisnis</p> + <p className="ml-2">Ubah ke akun bisnis</p> </div> ))} - {isChecked && ( + {isChecked && ubahAkun !== 'pending' && ( <div> - <SwitchAccount company_type='nonpkp' /> + <SwitchAccount company_type="nonpkp" setIsAprove={setIsAprove} setUbahAkun={setUbahAkun}/> <Divider /> </div> )} |
