summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorIT Fixcomart <it@fixcomart.co.id>2024-09-24 01:36:05 +0000
committerIT Fixcomart <it@fixcomart.co.id>2024-09-24 01:36:05 +0000
commitcf42512eb11b1a96c99ced8d1f867aeb8c2dcbc1 (patch)
tree802eb86425e40b8bacda6067aa797c36598a7221 /src/lib
parentb7e7696d675d0c2e36364f7cbedb0483a343048d (diff)
parent4bd29979c34c1ec3b31dd384829b008eb726769c (diff)
Merged in Feature/new-register (pull request #326)
Feature/new register
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/address/components/Addresses.jsx140
-rw-r--r--src/lib/address/components/CreateAddress.jsx205
-rw-r--r--src/lib/address/components/EditAddress.jsx420
-rw-r--r--src/lib/auth/components/CompanyProfile.jsx260
-rw-r--r--src/lib/checkout/components/Checkout.jsx3
5 files changed, 687 insertions, 341 deletions
diff --git a/src/lib/address/components/Addresses.jsx b/src/lib/address/components/Addresses.jsx
index a610d371..9ca617ae 100644
--- a/src/lib/address/components/Addresses.jsx
+++ b/src/lib/address/components/Addresses.jsx
@@ -1,34 +1,72 @@
-import Link from '@/core/components/elements/Link/Link'
-import Spinner from '@/core/components/elements/Spinner/Spinner'
-import useAuth from '@/core/hooks/useAuth'
-import { getItemAddress, updateItemAddress } from '@/core/utils/address'
-import { useRouter } from 'next/router'
-import useAddresses from '../hooks/useAddresses'
-import MobileView from '@/core/components/views/MobileView'
-import DesktopView from '@/core/components/views/DesktopView'
-import Menu from '@/lib/auth/components/Menu'
+import { useState } from 'react';
+import Link from '@/core/components/elements/Link/Link';
+import Spinner from '@/core/components/elements/Spinner/Spinner';
+import useAuth from '@/core/hooks/useAuth';
+import { getItemAddress, updateItemAddress } from '@/core/utils/address';
+import { useRouter } from 'next/router';
+import useAddresses from '../hooks/useAddresses';
+import MobileView from '@/core/components/views/MobileView';
+import DesktopView from '@/core/components/views/DesktopView';
+import Menu from '@/lib/auth/components/Menu';
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
const Addresses = () => {
- const router = useRouter()
- const { select = null } = router.query
- const { addresses } = useAddresses()
- const selectedAddress = getItemAddress(select || '')
+ const router = useRouter();
+ const { select = null } = router.query;
+ const { addresses } = useAddresses();
+ const selectedAddress = getItemAddress(select || '');
+ const [changeConfirmation, setChangeConfirmation] = useState(false);
+ const [selectedForChange, setSelectedForChange] = useState(null); // State baru untuk simpan alamat yang akan diubah
+
const changeSelectedAddress = (id) => {
- if (!select) return
- updateItemAddress(select, id)
- router.back()
- }
+ if (!select) return;
+ updateItemAddress(select, id);
+ router.back();
+ };
+
+ const handleConfirmSubmit = () => {
+ setChangeConfirmation(false);
+ if (selectedForChange) {
+ router.push(`/my/address/${selectedForChange}/edit`);
+ }
+ };
if (addresses.isLoading) {
return (
<div className='flex justify-center my-6'>
<Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' />
</div>
- )
+ );
}
return (
<>
+ <BottomPopup
+ active={changeConfirmation}
+ close={() => setChangeConfirmation(false)} // Menutup popup
+ title='Ubah alamat Bisnis'
+ >
+ <div className='leading-7 text-gray_r-12/80'>
+ Anda akan mengubah alamat utama bisnis?
+ </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={handleConfirmSubmit}
+ >
+ Yakin
+ </button>
+ <button
+ className='btn-light flex-1 md:flex-none'
+ type='button'
+ onClick={() => setChangeConfirmation(false)}
+ >
+ Batal
+ </button>
+ </div>
+ </BottomPopup>
+
<MobileView>
<div className='p-4'>
<div className='text-right'>
@@ -37,7 +75,10 @@ const Addresses = () => {
<div className='grid gap-y-4 mt-4'>
{addresses.data?.map((address, index) => {
- const type = address.type.charAt(0).toUpperCase() + address.type.slice(1) + ' Address'
+ const type =
+ address.type.charAt(0).toUpperCase() +
+ address.type.slice(1) +
+ ' Address';
return (
<AddressCard
key={index}
@@ -45,9 +86,11 @@ const Addresses = () => {
type={type}
changeSelectedAddress={changeSelectedAddress}
selectedAddress={selectedAddress}
+ setChangeConfirmation={setChangeConfirmation} // Memanggil popup
+ setSelectedForChange={setSelectedForChange} // Simpan id address yang akan diubah
select={select}
/>
- )
+ );
})}
</div>
</div>
@@ -72,7 +115,9 @@ const Addresses = () => {
<div className='grid grid-cols-2 gap-4'>
{addresses.data?.map((address, index) => {
const type =
- address.type.charAt(0).toUpperCase() + address.type.slice(1) + ' Address'
+ address.type.charAt(0).toUpperCase() +
+ address.type.slice(1) +
+ ' Address';
return (
<AddressCard
key={index}
@@ -80,20 +125,31 @@ const Addresses = () => {
type={type}
changeSelectedAddress={changeSelectedAddress}
selectedAddress={selectedAddress}
+ setChangeConfirmation={setChangeConfirmation}
+ setSelectedForChange={setSelectedForChange}
select={select}
/>
- )
+ );
})}
</div>
</div>
</div>
</DesktopView>
</>
- )
-}
+ );
+};
-const AddressCard = ({ address, selectedAddress, changeSelectedAddress, type, select }) => {
- const auth = useAuth()
+const AddressCard = ({
+ address,
+ selectedAddress,
+ changeSelectedAddress,
+ type,
+ select,
+ setChangeConfirmation,
+ setSelectedForChange,
+}) => {
+ const auth = useAuth();
+ const router = useRouter();
return (
<div
@@ -106,23 +162,37 @@ const AddressCard = ({ address, selectedAddress, changeSelectedAddress, type, se
(select && 'cursor-pointer hover:bg-gray_r-4 transition')
}`}
>
- <div onClick={() => changeSelectedAddress(address.id)} className={select && 'cursor-pointer'}>
+ <div
+ onClick={() => changeSelectedAddress(address.id)}
+ className={select && 'cursor-pointer'}
+ >
<div className='flex gap-x-2'>
<div className='badge-red'>{type}</div>
- {auth?.partnerId == address.id && <div className='badge-green'>Utama</div>}
+ {auth?.partnerId == address.id && (
+ <div className='badge-green'>Utama</div>
+ )}
</div>
<p className='font-medium mt-2'>{address.name}</p>
- {address.mobile && <p className='mt-2 text-gray_r-11'>{address.mobile}</p>}
+ {address.mobile && (
+ <p className='mt-2 text-gray_r-11'>{address.mobile}</p>
+ )}
<p className='mt-1 leading-6 text-gray_r-11'>{address.street}</p>
</div>
- <Link
- href={`/my/address/${address.id}/edit`}
+ <button
+ onClick={() => {
+ if (type == 'Contact Address' && auth.parentId) {
+ setSelectedForChange(address.id); // Set alamat yang dipilih
+ setChangeConfirmation(true); // Tampilkan popup konfirmasi
+ } else {
+ router.push(`/my/address/${address.id}/edit`);
+ }
+ }}
className='btn-light bg-white mt-3 w-full !text-gray_r-11'
>
Ubah Alamat
- </Link>
+ </button>
</div>
- )
-}
+ );
+};
-export default Addresses
+export default Addresses;
diff --git a/src/lib/address/components/CreateAddress.jsx b/src/lib/address/components/CreateAddress.jsx
index 86519147..e315affe 100644
--- a/src/lib/address/components/CreateAddress.jsx
+++ b/src/lib/address/components/CreateAddress.jsx
@@ -1,76 +1,101 @@
-import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'
-import useAuth from '@/core/hooks/useAuth'
-import { useRouter } from 'next/router'
-import { Controller, useForm } from 'react-hook-form'
-import * as Yup from 'yup'
-import cityApi from '../api/cityApi'
-import districtApi from '../api/districtApi'
-import subDistrictApi from '../api/subDistrictApi'
-import { useEffect, useState } from 'react'
-import createAddressApi from '../api/createAddressApi'
-import { toast } from 'react-hot-toast'
-import { yupResolver } from '@hookform/resolvers/yup'
-import Menu from '@/lib/auth/components/Menu'
+import HookFormSelect from '@/core/components/elements/Select/HookFormSelect';
+import useAuth from '@/core/hooks/useAuth';
+import { useRouter } from 'next/router';
+import { Controller, useForm } from 'react-hook-form';
+import * as Yup from 'yup';
+import cityApi from '../api/cityApi';
+import districtApi from '../api/districtApi';
+import subDistrictApi from '../api/subDistrictApi';
+import { useEffect, useState } from 'react';
+import createAddressApi from '../api/createAddressApi';
+import { toast } from 'react-hot-toast';
+import { yupResolver } from '@hookform/resolvers/yup';
+import Menu from '@/lib/auth/components/Menu';
+import useAddresses from '../hooks/useAddresses';
const CreateAddress = () => {
- const auth = useAuth()
- const router = useRouter()
+ const auth = useAuth();
+ const router = useRouter();
const {
register,
formState: { errors },
handleSubmit,
watch,
setValue,
- control
+ control,
} = useForm({
resolver: yupResolver(validationSchema),
- defaultValues
- })
-
- const [cities, setCities] = useState([])
- const [districts, setDistricts] = useState([])
- const [subDistricts, setSubDistricts] = useState([])
+ defaultValues,
+ });
+ const { addresses = [] } = useAddresses(); // Ensure addresses is an array
+ const [cities, setCities] = useState([]);
+ const [districts, setDistricts] = useState([]);
+ const [subDistricts, setSubDistricts] = useState([]);
+ const [filteredTypes, setFilteredTypes] = useState(types); // State to manage filtered types
useEffect(() => {
const loadCities = async () => {
- let dataCities = await cityApi()
- dataCities = dataCities.map((city) => ({ value: city.id, label: city.name }))
- setCities(dataCities)
+ let dataCities = await cityApi();
+ dataCities = dataCities.map((city) => ({
+ value: city.id,
+ label: city.name,
+ }));
+ setCities(dataCities);
+ };
+ loadCities();
+ }, []);
+
+ useEffect(() => {
+ if (addresses) {
+ let hasContactAddress = false;
+
+ for (let i = 0; i < addresses?.data?.length; i++) {
+ if (addresses.data[i].type === 'contact') {
+ hasContactAddress = true;
+ break;
+ }
+ }
+ if (hasContactAddress) {
+ setFilteredTypes(types.filter((type) => type.value !== 'contact'));
+ } else {
+ setFilteredTypes(types);
+ }
}
- loadCities()
- }, [])
+ }, [auth]);
- const watchCity = watch('city')
+ const watchCity = watch('city');
useEffect(() => {
- setValue('district', '')
+ setValue('district', '');
if (watchCity) {
const loadDistricts = async () => {
- let dataDistricts = await districtApi({ cityId: watchCity })
+ let dataDistricts = await districtApi({ cityId: watchCity });
dataDistricts = dataDistricts.map((district) => ({
value: district.id,
- label: district.name
- }))
- setDistricts(dataDistricts)
- }
- loadDistricts()
+ label: district.name,
+ }));
+ setDistricts(dataDistricts);
+ };
+ loadDistricts();
}
- }, [watchCity, setValue])
+ }, [watchCity, setValue]);
- const watchDistrict = watch('district')
+ const watchDistrict = watch('district');
useEffect(() => {
- setValue('subDistrict', '')
+ setValue('subDistrict', '');
if (watchDistrict) {
const loadSubDistricts = async () => {
- let dataSubDistricts = await subDistrictApi({ districtId: watchDistrict })
+ let dataSubDistricts = await subDistrictApi({
+ districtId: watchDistrict,
+ });
dataSubDistricts = dataSubDistricts.map((district) => ({
value: district.id,
- label: district.name
- }))
- setSubDistricts(dataSubDistricts)
- }
- loadSubDistricts()
+ label: district.name,
+ }));
+ setSubDistricts(dataSubDistricts);
+ };
+ loadSubDistricts();
}
- }, [watchDistrict, setValue])
+ }, [watchDistrict, setValue]);
const onSubmitHandler = async (values) => {
const data = {
@@ -78,15 +103,15 @@ const CreateAddress = () => {
city_id: values.city,
district_id: values.district,
sub_district_id: values.subDistrict,
- parent_id: auth.partnerId
- }
+ parent_id: auth.partnerId,
+ };
- const address = await createAddressApi({ data })
+ const address = await createAddressApi({ data });
if (address?.id) {
- toast.success('Berhasil menambahkan alamat')
- router.back()
+ toast.success('Berhasil menambahkan alamat');
+ router.back();
}
- }
+ };
return (
<div className='max-w-none md:container mx-auto flex p-0 md:py-10'>
@@ -102,10 +127,16 @@ const CreateAddress = () => {
name='type'
control={control}
render={(props) => (
- <HookFormSelect {...props} isSearchable={false} options={types} />
+ <HookFormSelect
+ {...props}
+ isSearchable={false}
+ options={filteredTypes}
+ />
)}
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.type?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.type?.message}
+ </div>
</div>
<div>
@@ -116,7 +147,9 @@ const CreateAddress = () => {
type='text'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.name?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.name?.message}
+ </div>
</div>
<div>
@@ -127,7 +160,9 @@ const CreateAddress = () => {
type='email'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.email?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.email?.message}
+ </div>
</div>
<div>
@@ -138,7 +173,9 @@ const CreateAddress = () => {
type='tel'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.mobile?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.mobile?.message}
+ </div>
</div>
<div>
@@ -149,7 +186,9 @@ const CreateAddress = () => {
type='text'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.street?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.street?.message}
+ </div>
</div>
<div>
@@ -160,7 +199,9 @@ const CreateAddress = () => {
type='number'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.zip?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.zip?.message}
+ </div>
</div>
<div>
@@ -168,9 +209,13 @@ const CreateAddress = () => {
<Controller
name='city'
control={control}
- render={(props) => <HookFormSelect {...props} options={cities} />}
+ render={(props) => (
+ <HookFormSelect {...props} options={cities} />
+ )}
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.city?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.city?.message}
+ </div>
</div>
<div>
@@ -179,10 +224,16 @@ const CreateAddress = () => {
name='district'
control={control}
render={(props) => (
- <HookFormSelect {...props} options={districts} disabled={!watchCity} />
+ <HookFormSelect
+ {...props}
+ options={districts}
+ disabled={!watchCity}
+ />
)}
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.district?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.district?.message}
+ </div>
</div>
<div>
@@ -191,31 +242,37 @@ const CreateAddress = () => {
name='subDistrict'
control={control}
render={(props) => (
- <HookFormSelect {...props} options={subDistricts} disabled={!watchDistrict} />
+ <HookFormSelect
+ {...props}
+ options={subDistricts}
+ disabled={!watchDistrict}
+ />
)}
/>
</div>
</div>
- <button type='submit' className='btn-yellow w-full md:w-fit mt-6 ml-0 md:ml-auto'>
+ <button
+ type='submit'
+ className='btn-yellow w-full md:w-fit mt-6 ml-0 md:ml-auto'
+ >
Simpan
</button>
</form>
</div>
</div>
- )
-}
+ );
+};
const validationSchema = Yup.object().shape({
type: Yup.string().required('Harus di-pilih'),
name: Yup.string().min(3, 'Minimal 3 karakter').required('Harus di-isi'),
- // email: Yup.string().email('Format harus seperti contoh@email.com').required('Harus di-isi'),
mobile: Yup.string().required('Harus di-isi'),
street: Yup.string().required('Harus di-isi'),
zip: Yup.string().required('Harus di-isi'),
city: Yup.string().required('Harus di-pilih'),
- district: Yup.string().required('Harus di-pilih')
-})
+ district: Yup.string().required('Harus di-pilih'),
+});
const defaultValues = {
type: '',
@@ -226,14 +283,14 @@ const defaultValues = {
city: '',
district: '',
subDistrict: '',
- zip: ''
-}
+ zip: '',
+};
const types = [
{ value: 'contact', label: 'Contact Address' },
{ value: 'invoice', label: 'Invoice Address' },
{ value: 'delivery', label: 'Delivery Address' },
- { value: 'other', label: 'Other Address' }
-]
+ { value: 'other', label: 'Other Address' },
+];
-export default CreateAddress
+export default CreateAddress;
diff --git a/src/lib/address/components/EditAddress.jsx b/src/lib/address/components/EditAddress.jsx
index 520bba51..ff6b1f12 100644
--- a/src/lib/address/components/EditAddress.jsx
+++ b/src/lib/address/components/EditAddress.jsx
@@ -1,18 +1,22 @@
-import { yupResolver } from '@hookform/resolvers/yup'
-import { useRouter } from 'next/router'
-import { useEffect, useState } from 'react'
-import * as Yup from 'yup'
-import cityApi from '../api/cityApi'
-import { Controller, useForm } from 'react-hook-form'
-import districtApi from '../api/districtApi'
-import subDistrictApi from '../api/subDistrictApi'
-import editAddressApi from '../api/editAddressApi'
-import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'
-import { toast } from 'react-hot-toast'
-import Menu from '@/lib/auth/components/Menu'
+import { yupResolver } from '@hookform/resolvers/yup';
+import { useRouter } from 'next/router';
+import { useEffect, useState } from 'react';
+import * as Yup from 'yup';
+import cityApi from '../api/cityApi';
+import { Controller, useForm } from 'react-hook-form';
+import districtApi from '../api/districtApi';
+import subDistrictApi from '../api/subDistrictApi';
+import addressApi from '@/lib/address/api/addressApi';
+import editAddressApi from '../api/editAddressApi';
+import HookFormSelect from '@/core/components/elements/Select/HookFormSelect';
+import { toast } from 'react-hot-toast';
+import Menu from '@/lib/auth/components/Menu';
+import useAuth from '@/core/hooks/useAuth';
+import odooApi from '@/core/api/odooApi';
const EditAddress = ({ id, defaultValues }) => {
- const router = useRouter()
+ const auth = useAuth();
+ const router = useRouter();
const {
register,
formState: { errors },
@@ -20,205 +24,283 @@ const EditAddress = ({ id, defaultValues }) => {
watch,
setValue,
getValues,
- control
+ control,
} = useForm({
resolver: yupResolver(validationSchema),
- defaultValues
- })
+ defaultValues,
+ });
+ const [cities, setCities] = useState([]);
+ const [districts, setDistricts] = useState([]);
+ const [subDistricts, setSubDistricts] = useState([]);
- const [cities, setCities] = useState([])
- const [districts, setDistricts] = useState([])
- const [subDistricts, setSubDistricts] = useState([])
+ useEffect(() => {
+ const loadProfile = async () => {
+ const dataProfile = await addressApi({ id: auth.parentId });
+ setValue('industry', dataProfile.industryId);
+ setValue('companyType', dataProfile.companyTypeId);
+ setValue('taxName', dataProfile.taxName);
+ setValue('npwp', dataProfile.npwp);
+ setValue('alamat_wajib_pajak', dataProfile.alamatWajibPajak);
+ setValue('alamat_bisnis', dataProfile.alamatBisnis);
+ setValue('business_name', dataProfile.name);
+ };
+ if (auth) loadProfile();
+ }, [auth, setValue]);
useEffect(() => {
const loadCities = async () => {
- let dataCities = await cityApi()
+ let dataCities = await cityApi();
dataCities = dataCities.map((city) => ({
value: city.id,
- label: city.name
- }))
- setCities(dataCities)
- }
- loadCities()
- }, [])
+ label: city.name,
+ }));
+ setCities(dataCities);
+ };
+ loadCities();
+ }, []);
- const watchCity = watch('city')
+ const watchCity = watch('city');
useEffect(() => {
- setValue('district', '')
+ setValue('district', '');
if (watchCity) {
const loadDistricts = async () => {
- let dataDistricts = await districtApi({ cityId: watchCity })
+ let dataDistricts = await districtApi({ cityId: watchCity });
dataDistricts = dataDistricts.map((district) => ({
value: district.id,
- label: district.name
- }))
- setDistricts(dataDistricts)
- let oldDistrict = getValues('oldDistrict')
+ label: district.name,
+ }));
+ setDistricts(dataDistricts);
+ let oldDistrict = getValues('oldDistrict');
if (oldDistrict) {
- setValue('district', oldDistrict)
- setValue('oldDistrict', '')
+ setValue('district', oldDistrict);
+ setValue('oldDistrict', '');
}
- }
- loadDistricts()
+ };
+ loadDistricts();
}
- }, [watchCity, setValue, getValues])
+ }, [watchCity, setValue, getValues]);
- const watchDistrict = watch('district')
+ const watchDistrict = watch('district');
useEffect(() => {
- setValue('subDistrict', '')
+ setValue('subDistrict', '');
if (watchDistrict) {
const loadSubDistricts = async () => {
let dataSubDistricts = await subDistrictApi({
- districtId: watchDistrict
- })
+ districtId: watchDistrict,
+ });
dataSubDistricts = dataSubDistricts.map((district) => ({
value: district.id,
- label: district.name
- }))
- setSubDistricts(dataSubDistricts)
- let oldSubDistrict = getValues('oldSubDistrict')
+ label: district.name,
+ }));
+ setSubDistricts(dataSubDistricts);
+ let oldSubDistrict = getValues('oldSubDistrict');
if (oldSubDistrict) {
- setValue('subDistrict', oldSubDistrict)
- setValue('oldSubDistrict', '')
+ setValue('subDistrict', oldSubDistrict);
+ setValue('oldSubDistrict', '');
}
- }
- loadSubDistricts()
+ };
+ loadSubDistricts();
}
- }, [watchDistrict, setValue, getValues])
-
+ }, [watchDistrict, setValue, getValues]);
const onSubmitHandler = async (values) => {
const data = {
...values,
+ phone: values.mobile,
city_id: values.city,
district_id: values.district,
- sub_district_id: values.subDistrict
+ sub_district_id: values.subDistrict,
+ };
+ const address = await editAddressApi({ id, data });
+ let dataAlamat;
+ let isUpdated = true;
+ if (auth?.partnerId == id) {
+ dataAlamat = {
+ id_user: auth.partnerId,
+ company_type_id: values.companyType,
+ industry_id: values.industry,
+ tax_name: values.taxName,
+ alamat_lengkap_text: values.alamat_wajib_pajak,
+ street: values.street,
+ business_name: values.business_name,
+ name: values.business_name,
+ npwp: values.npwp,
+ };
+ isUpdated = await odooApi(
+ 'PUT',
+ `/api/v1/partner/${auth.parentId}`,
+ dataAlamat
+ );
}
- const address = await editAddressApi({ id, data })
- if (address?.id) {
- toast.success('Berhasil mengubah alamat')
- router.back()
+ // if (isUpdated?.id) {
+ if (address?.id && isUpdated?.id) {
+ toast.success('Berhasil mengubah alamat');
+ router.back();
+ } else {
+ toast.error('Terjadi kesalahan internal');
+ router.back();
}
- }
+ };
return (
- <div className='max-w-none md:container mx-auto flex p-0 md:py-10'>
- <div className='hidden md:block w-3/12 pr-4'>
- <Menu />
- </div>
- <div className='w-full md:w-9/12 p-4 bg-white border border-gray_r-6 rounded'>
- <h1 className='text-title-sm font-semibold mb-6 hidden md:block'>Ubah Alamat</h1>
- <form onSubmit={handleSubmit(onSubmitHandler)}>
- <div className='grid grid-cols-1 md:grid-cols-2 gap-4'>
- <div>
- <label className='form-label mb-2'>Label Alamat</label>
- <Controller
- name='type'
- control={control}
- render={(props) => (
- <HookFormSelect {...props} isSearchable={false} options={types} />
- )}
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.type?.message}</div>
- </div>
+ <>
+ <div className='max-w-none md:container mx-auto flex p-0 md:py-10'>
+ <div className='hidden md:block w-3/12 pr-4'>
+ <Menu />
+ </div>
+ <div className='w-full md:w-9/12 p-4 bg-white border border-gray_r-6 rounded'>
+ <div className='flex justify-start items-center mb-6'>
+ <h1 className='text-title-sm font-semibold hidden md:block mr-2'>
+ Ubah Alamat
+ </h1>
+ {auth?.partnerId == id && <div className='badge-green'>Utama</div>}
+ </div>
+ <form onSubmit={handleSubmit(onSubmitHandler)}>
+ <div className='grid grid-cols-1 md:grid-cols-2 gap-4'>
+ <div>
+ <label className='form-label mb-2'>Label Alamat</label>
+ <Controller
+ name='type'
+ control={control}
+ render={(props) => (
+ <HookFormSelect
+ {...props}
+ isSearchable={false}
+ options={types}
+ />
+ )}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.type?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Nama</label>
- <input
- {...register('name')}
- placeholder='John Doe'
- type='text'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.name?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Nama</label>
+ <input
+ {...register('name')}
+ placeholder='John Doe'
+ type='text'
+ className='form-input'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.name?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Email</label>
- <input
- {...register('email')}
- placeholder='johndoe@example.com'
- type='email'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.email?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Email</label>
+ <input
+ {...register('email')}
+ placeholder='johndoe@example.com'
+ type='email'
+ className='form-input'
+ disabled={auth?.partnerId == id && true}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.email?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Mobile</label>
- <input
- {...register('mobile')}
- placeholder='08xxxxxxxx'
- type='tel'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.mobile?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Mobile</label>
+ <input
+ {...register('mobile')}
+ placeholder='08xxxxxxxx'
+ type='tel'
+ className='form-input'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.mobile?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Alamat</label>
- <input
- {...register('street')}
- placeholder='Jl. Bandengan Utara 85A'
- type='text'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.street?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Alamat</label>
+ <input
+ {...register('street')}
+ placeholder='Jl. Bandengan Utara 85A'
+ type='text'
+ className='form-input'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.street?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Kode Pos</label>
- <input
- {...register('zip')}
- placeholder='10100'
- type='number'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.zip?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Kode Pos</label>
+ <input
+ {...register('zip')}
+ placeholder='10100'
+ type='number'
+ className='form-input'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.zip?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Kota</label>
- <Controller
- name='city'
- control={control}
- render={(props) => <HookFormSelect {...props} options={cities} />}
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.city?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Kota</label>
+ <Controller
+ name='city'
+ control={control}
+ render={(props) => (
+ <HookFormSelect {...props} options={cities} />
+ )}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.city?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Kecamatan</label>
- <Controller
- name='district'
- control={control}
- render={(props) => (
- <HookFormSelect {...props} options={districts} disabled={!watchCity} />
- )}
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.district?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Kecamatan</label>
+ <Controller
+ name='district'
+ control={control}
+ render={(props) => (
+ <HookFormSelect
+ {...props}
+ options={districts}
+ disabled={!watchCity}
+ />
+ )}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.district?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Kelurahan</label>
- <Controller
- name='subDistrict'
- control={control}
- render={(props) => (
- <HookFormSelect {...props} options={subDistricts} disabled={!watchDistrict} />
- )}
- />
+ <div>
+ <label className='form-label mb-2'>Kelurahan</label>
+ <Controller
+ name='subDistrict'
+ control={control}
+ render={(props) => (
+ <HookFormSelect
+ {...props}
+ options={subDistricts}
+ disabled={!watchDistrict}
+ />
+ )}
+ />
+ </div>
</div>
- </div>
- <button type='submit' className='btn-yellow w-full md:w-fit mt-6 ml-0 md:ml-auto'>
- Simpan
- </button>
- </form>
+ <button
+ type='submit'
+ className='btn-yellow w-full md:w-fit mt-6 ml-0 md:ml-auto'
+ >
+ Simpan
+ </button>
+ </form>
+ </div>
</div>
- </div>
- )
-}
+ </>
+ );
+};
const validationSchema = Yup.object().shape({
type: Yup.string().required('Harus di-pilih'),
@@ -228,14 +310,14 @@ const validationSchema = Yup.object().shape({
street: Yup.string().required('Harus di-isi'),
zip: Yup.string().required('Harus di-isi'),
city: Yup.string().required('Harus di-pilih'),
- district: Yup.string().required('Harus di-pilih')
-})
+ district: Yup.string().required('Harus di-pilih'),
+});
const types = [
{ value: 'contact', label: 'Contact Address' },
{ value: 'invoice', label: 'Invoice Address' },
{ value: 'delivery', label: 'Delivery Address' },
- { value: 'other', label: 'Other Address' }
-]
+ { value: 'other', label: 'Other Address' },
+];
-export default EditAddress
+export default EditAddress;
diff --git a/src/lib/auth/components/CompanyProfile.jsx b/src/lib/auth/components/CompanyProfile.jsx
index 2faede9b..7bda992f 100644
--- a/src/lib/auth/components/CompanyProfile.jsx
+++ b/src/lib/auth/components/CompanyProfile.jsx
@@ -1,78 +1,136 @@
-import odooApi from '@/core/api/odooApi'
-import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'
-import useAuth from '@/core/hooks/useAuth'
-import addressApi from '@/lib/address/api/addressApi'
-import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline'
-import { useEffect, useState } from 'react'
-import { Controller, useForm } from 'react-hook-form'
-import { toast } from 'react-hot-toast'
+import odooApi from '@/core/api/odooApi';
+import HookFormSelect from '@/core/components/elements/Select/HookFormSelect';
+import useAuth from '@/core/hooks/useAuth';
+import addressApi from '@/lib/address/api/addressApi';
+import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline';
+import { useEffect, useState } from 'react';
+import { Controller, useForm } from 'react-hook-form';
+import { toast } from 'react-hot-toast';
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
+import { yupResolver } from '@hookform/resolvers/yup';
+import * as Yup from 'yup';
const CompanyProfile = () => {
- const auth = useAuth()
- const [isOpen, setIsOpen] = useState(false)
- const toggle = () => setIsOpen(!isOpen)
- const { register, setValue, control, handleSubmit } = useForm({
- defaultValues: {
- industry: '',
- companyType: '',
- name: '',
- taxName: '',
- npwp: ''
- }
- })
+ const [changeConfirmation, setChangeConfirmation] = useState(false);
+ const auth = useAuth();
+ const [isOpen, setIsOpen] = useState(false);
+ const toggle = () => setIsOpen(!isOpen);
+ const {
+ register,
+ formState: { errors },
+ setValue,
+ control,
+ handleSubmit,
+ } = useForm({
+ resolver: yupResolver(validationSchema),
+ defaultValues,
+ });
- const [industries, setIndustries] = useState([])
+ const [industries, setIndustries] = useState([]);
useEffect(() => {
const loadIndustries = async () => {
- const dataIndustries = await odooApi('GET', '/api/v1/partner/industry')
- setIndustries(dataIndustries?.map((o) => ({ value: o.id, label: o.name })))
- }
- loadIndustries()
- }, [])
+ const dataIndustries = await odooApi('GET', '/api/v1/partner/industry');
+ setIndustries(
+ dataIndustries?.map((o) => ({ value: o.id, label: o.name }))
+ );
+ };
+ loadIndustries();
+ }, []);
- const [companyTypes, setCompanyTypes] = useState([])
+ const [companyTypes, setCompanyTypes] = useState([]);
useEffect(() => {
const loadCompanyTypes = async () => {
- const dataCompanyTypes = await odooApi('GET', '/api/v1/partner/company_type')
- setCompanyTypes(dataCompanyTypes?.map((o) => ({ value: o.id, label: o.name })))
- }
- loadCompanyTypes()
- }, [])
+ const dataCompanyTypes = await odooApi(
+ 'GET',
+ '/api/v1/partner/company_type'
+ );
+ setCompanyTypes(
+ dataCompanyTypes?.map((o) => ({ value: o.id, label: o.name }))
+ );
+ };
+ loadCompanyTypes();
+ }, []);
useEffect(() => {
const loadProfile = async () => {
- const dataProfile = await addressApi({ id: auth.parentId })
- setValue('name', dataProfile.name)
- setValue('industry', dataProfile.industryId)
- setValue('companyType', dataProfile.companyTypeId)
- setValue('taxName', dataProfile.taxName)
- setValue('npwp', dataProfile.npwp)
- }
- if (auth) loadProfile()
- }, [auth, setValue])
+ const dataProfile = await addressApi({ id: auth.parentId });
+ setValue('name', dataProfile.name);
+ setValue('industry', dataProfile.industryId);
+ setValue('companyType', dataProfile.companyTypeId);
+ setValue('taxName', dataProfile.taxName);
+ setValue('npwp', dataProfile.npwp);
+ setValue('alamat_wajib_pajak', dataProfile.alamatWajibPajak);
+ setValue('alamat_bisnis', dataProfile.alamatBisnis);
+ };
+ if (auth) loadProfile();
+ }, [auth, setValue]);
const onSubmitHandler = async (values) => {
- const data = {
- ...values,
- company_type_id: values.companyType,
- industry_id: values.industry,
- tax_name: values.taxName
+ if (changeConfirmation) {
+ const data = {
+ ...values,
+ id_user: auth.partnerId,
+ company_type_id: values.companyType,
+ industry_id: values.industry,
+ tax_name: values.taxName,
+ alamat_lengkap_text: values.alamat_wajib_pajak,
+ street: values.alamat_bisnis,
+ };
+ const isUpdated = await odooApi(
+ 'PUT',
+ `/api/v1/partner/${auth.parentId}`,
+ data
+ );
+ if (isUpdated?.id) {
+ toast.success('Berhasil mengubah profil', { duration: 1500 });
+ return;
+ }
+ toast.error('Terjadi kesalahan internal');
}
- const isUpdated = await odooApi('PUT', `/api/v1/partner/${auth.parentId}`, data)
- if (isUpdated?.id) {
- toast.success('Berhasil mengubah profil', { duration: 1500 })
- return
- }
- toast.error('Terjadi kesalahan internal')
- }
+ };
+
+ const handleConfirmSubmit = () => {
+ setChangeConfirmation(false);
+ handleSubmit(onSubmitHandler)();
+ };
return (
<>
- <button type='button' onClick={toggle} className='p-4 flex items-center text-left w-full'>
+ <BottomPopup
+ active={changeConfirmation}
+ close={() => setChangeConfirmation(true)}
+ title='Ubah profil Bisnis'
+ >
+ <div className='leading-7 text-gray_r-12/80'>
+ Apakah anda yakin mengubah data bisnis?
+ </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={handleConfirmSubmit}
+ >
+ Ya, Ubah
+ </button>
+ <button
+ className='btn-light flex-1 md:flex-none'
+ type='button'
+ onClick={() => setChangeConfirmation(false)}
+ >
+ Batal
+ </button>
+ </div>
+ </BottomPopup>
+ <button
+ type='button'
+ onClick={toggle}
+ className='p-4 flex items-center text-left w-full'
+ >
<div>
<div className='font-semibold mb-2'>Informasi Usaha</div>
<div className='text-gray_r-11'>
- Dibawah ini adalah data usaha yang anda masukkan, periksa kembali data usaha anda.
+ Dibawah ini adalah data usaha yang anda masukkan, periksa kembali
+ data usaha anda.
</div>
</div>
<div className='ml-auto p-2 bg-gray_r-3 rounded'>
@@ -82,15 +140,26 @@ const CompanyProfile = () => {
</button>
{isOpen && (
- <form className='p-4 border-t border-gray_r-6' onSubmit={handleSubmit(onSubmitHandler)}>
+ <form
+ className='p-4 border-t border-gray_r-6'
+ onSubmit={(e) => {
+ e.preventDefault();
+ setChangeConfirmation(true);
+ }}
+ >
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
<div>
<label className='block mb-3'>Klasifikasi Jenis Usaha</label>
<Controller
name='industry'
control={control}
- render={(props) => <HookFormSelect {...props} options={industries} />}
+ render={(props) => (
+ <HookFormSelect {...props} options={industries} />
+ )}
/>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.industry?.message}
+ </div>
</div>
<div className='flex flex-wrap'>
<div className='w-full mb-3'>Badan Usaha</div>
@@ -98,8 +167,13 @@ const CompanyProfile = () => {
<Controller
name='companyType'
control={control}
- render={(props) => <HookFormSelect {...props} options={companyTypes} />}
+ render={(props) => (
+ <HookFormSelect {...props} options={companyTypes} />
+ )}
/>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.companyType?.message}
+ </div>
</div>
<div className='w-9/12 pl-1'>
<input
@@ -108,15 +182,55 @@ const CompanyProfile = () => {
className='form-input'
placeholder='Cth: Indoteknik Dotcom Gemilang'
/>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.name?.message}
+ </div>
</div>
</div>
<div>
<label>Nama Wajib Pajak</label>
- <input {...register('taxName')} type='text' className='form-input mt-3' />
+ <input
+ {...register('taxName')}
+ type='text'
+ className='form-input mt-3'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.taxName?.message}
+ </div>
+ </div>
+ <div>
+ <label>Alamat Wajib Pajak</label>
+ <input
+ {...register('alamat_wajib_pajak')}
+ type='text'
+ className='form-input mt-3'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.alamat_wajib_pajak?.message}
+ </div>
+ </div>
+ <div>
+ <label>Alamat Bisnis</label>
+ <input
+ {...register('alamat_bisnis')}
+ type='text'
+ className='form-input mt-3'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.alamat_bisnis?.message}
+ </div>
</div>
<div>
<label>Nomor NPWP</label>
- <input {...register('npwp')} type='text' className='form-input mt-3' />
+ <input
+ {...register('npwp')}
+ type='text'
+ className='form-input mt-3'
+ maxLength={16}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.npwp?.message}
+ </div>
</div>
</div>
<button type='submit' className='btn-yellow w-full mt-6'>
@@ -125,7 +239,27 @@ const CompanyProfile = () => {
</form>
)}
</>
- )
-}
+ );
+};
+
+export default CompanyProfile;
+
+const validationSchema = Yup.object().shape({
+ alamat_bisnis: Yup.string().required('Harus di-isi'),
+ alamat_wajib_pajak: Yup.string().required('Harus di-isi'),
+ taxName: Yup.string().required('Harus di-isi'),
+ npwp: Yup.string().required('Harus di-isi'),
+ name: Yup.string().required('Harus di-isi'),
+ industry: Yup.string().required('Harus di-pilih'),
+ companyType: Yup.string().required('Harus di-pilih'),
+});
-export default CompanyProfile
+const defaultValues = {
+ industry: '',
+ companyType: '',
+ name: '',
+ taxName: '',
+ npwp: '',
+ alamat_wajib_pajak: '',
+ alamat_bisnis: '',
+};
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index f63ef457..4c7e852f 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -77,6 +77,9 @@ const Checkout = () => {
if (!addresses) return;
const matchAddress = (key) => {
+ if (key === 'invoicing') {
+ key = 'invoice';
+ }
const addressToMatch = getItemAddress(key);
const foundAddress = addresses.filter(
(address) => address.id == addressToMatch