summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
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.jsx419
-rw-r--r--src/lib/auth/components/CompanyProfile.jsx260
-rw-r--r--src/lib/brand/components/BrandCard.jsx28
-rw-r--r--src/lib/checkout/components/Checkout.jsx3
-rw-r--r--src/lib/home/api/categoryManagementApi.js78
-rw-r--r--src/lib/home/components/BannerSection.jsx20
-rw-r--r--src/lib/home/components/CategoryDynamic.jsx137
-rw-r--r--src/lib/home/components/CategoryDynamicMobile.jsx174
-rw-r--r--src/lib/home/components/CategoryHomeId.jsx18
-rw-r--r--src/lib/home/components/CategoryPilihan.jsx265
-rw-r--r--src/lib/home/components/PreferredBrand.jsx8
-rw-r--r--src/lib/home/components/PromotionProgram.jsx118
-rw-r--r--src/lib/home/components/ServiceList.jsx34
-rw-r--r--src/lib/product/components/ProductCard.jsx59
-rw-r--r--src/lib/product/components/ProductSearch.jsx121
-rw-r--r--src/lib/quotation/components/Quotation.jsx107
-rw-r--r--src/lib/quotation/components/Quotationheader.jsx125
-rw-r--r--src/lib/review/components/CustomerReviews.jsx37
-rw-r--r--src/lib/tracking-order/component/TrackingOrder.jsx272
-rw-r--r--src/lib/transaction/api/transactionsApi.js3
22 files changed, 1606 insertions, 1025 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..182c8a31 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,282 @@ 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?.parentId]);
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,
+ };
+ if (!auth.company) {
+ data.alamat_lengkap_text = values.street;
+ }
+ const address = await editAddressApi({ id, data });
+ let dataAlamat;
+ let isUpdated = true;
+ if (auth.company) {
+ if (auth?.partnerId == id) {
+ dataAlamat = {
+ id_user: auth.partnerId,
+ alamat_lengkap_text: values.alamat_wajib_pajak,
+ street: values.street,
+ };
+ 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 && auth.company ? isUpdated?.id : true) {
+ 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 +309,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/brand/components/BrandCard.jsx b/src/lib/brand/components/BrandCard.jsx
index 2d78d956..ebd41a67 100644
--- a/src/lib/brand/components/BrandCard.jsx
+++ b/src/lib/brand/components/BrandCard.jsx
@@ -1,10 +1,10 @@
-import Image from '~/components/ui/image'
-import Link from '@/core/components/elements/Link/Link'
-import useDevice from '@/core/hooks/useDevice'
-import { createSlug } from '@/core/utils/slug'
+import NextImage from 'next/image';
+import Link from '@/core/components/elements/Link/Link';
+import useDevice from '@/core/hooks/useDevice';
+import { createSlug } from '@/core/utils/slug';
const BrandCard = ({ brand }) => {
- const { isMobile } = useDevice()
+ const { isMobile } = useDevice();
return (
<Link
href={createSlug('/shop/brands/', brand.name, brand.id)}
@@ -13,21 +13,25 @@ const BrandCard = ({ brand }) => {
}`}
>
{brand.logo && (
- <Image
+ <NextImage
src={brand.logo}
alt={brand.name}
- width={50}
- height={50}
+ width={500}
+ height={500}
+ quality={85}
className='h-full w-[122px] object-contain object-center'
/>
)}
{!brand.logo && (
- <span className='text-center' style={{ fontSize: `${16 - brand.name.length * 0.5}px` }}>
+ <span
+ className='text-center'
+ style={{ fontSize: `${16 - brand.name.length * 0.5}px` }}
+ >
{brand.name}
</span>
)}
</Link>
- )
-}
+ );
+};
-export default BrandCard
+export default BrandCard;
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
diff --git a/src/lib/home/api/categoryManagementApi.js b/src/lib/home/api/categoryManagementApi.js
index 0aeb2aac..2ff4fdfc 100644
--- a/src/lib/home/api/categoryManagementApi.js
+++ b/src/lib/home/api/categoryManagementApi.js
@@ -1,40 +1,44 @@
export const fetchCategoryManagementSolr = async () => {
- let sort ='sort=sequence_i asc';
- try {
- const response = await fetch(`/solr/category_management/query?q=*:*&q.op=OR&indent=true&${sort}&&rows=20`);
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- const data = await response.json();
- const promotions = await map(data.response.docs);
- return promotions;
- } catch (error) {
- console.error("Error fetching promotion data:", error);
- return [];
+ let sort = 'sort=sequence_i asc';
+ try {
+ const response = await fetch(
+ `/solr/category_management/query?q=*:*&q.op=OR&indent=true&${sort}&&rows=20`
+ );
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const data = await response.json();
+ const promotions = await map(data.response.docs);
+ return promotions;
+ } catch (error) {
+ console.error('Error fetching promotion data:', error);
+ return [];
+ }
+};
+
+const map = async (promotions) => {
+ return promotions.map((promotion) => {
+ let parsedCategories = promotion.categories.map((category) => {
+ // Parse string JSON utama
+ let parsedCategory = JSON.parse(category);
+
+ // Parse setiap elemen di child_frontend_id_i jika ada
+ if (parsedCategory.child_frontend_id_i) {
+ parsedCategory.child_frontend_id_i =
+ parsedCategory.child_frontend_id_i.map((child) => JSON.parse(child));
}
+
+ return parsedCategory;
+ });
+ let productMapped = {
+ id: promotion.id,
+ name: promotion.name_s,
+ image: promotion.image_s,
+ sequence: promotion.sequence_i,
+ numFound: promotion.numFound_i,
+ categories: parsedCategories,
+ category_id: promotion.category_id_i,
};
-
- const map = async (promotions) => {
- return promotions.map((promotion) =>{
- let parsedCategories = promotion.categories.map(category => {
- // Parse string JSON utama
- let parsedCategory = JSON.parse(category);
-
- // Parse setiap elemen di child_frontend_id_i jika ada
- if (parsedCategory.child_frontend_id_i) {
- parsedCategory.child_frontend_id_i = parsedCategory.child_frontend_id_i.map(child => JSON.parse(child));
- }
-
- return parsedCategory;
- });
- let productMapped = {
- id: promotion.id,
- name: promotion.name_s,
- image: promotion.image_s,
- sequence: promotion.sequence_i,
- numFound: promotion.numFound_i,
- categories: parsedCategories
- };
- return productMapped;
- })
- }; \ No newline at end of file
+ return productMapped;
+ });
+};
diff --git a/src/lib/home/components/BannerSection.jsx b/src/lib/home/components/BannerSection.jsx
index 2010503d..f83c36fc 100644
--- a/src/lib/home/components/BannerSection.jsx
+++ b/src/lib/home/components/BannerSection.jsx
@@ -1,12 +1,12 @@
-import Link from '@/core/components/elements/Link/Link'
-import Image from 'next/image'
+import Link from '@/core/components/elements/Link/Link';
+import Image from 'next/image';
-const { useQuery } = require('react-query')
-const { default: bannerSectionApi } = require('../api/bannerSectionApi')
+const { useQuery } = require('react-query');
+const { default: bannerSectionApi } = require('../api/bannerSectionApi');
const BannerSection = () => {
- const fetchBannerSection = async () => await bannerSectionApi()
- const bannerSection = useQuery('bannerSection', fetchBannerSection)
+ const fetchBannerSection = async () => await bannerSectionApi();
+ const bannerSection = useQuery('bannerSection', fetchBannerSection);
return (
bannerSection.data &&
@@ -17,7 +17,7 @@ const BannerSection = () => {
<Image
width={1024}
height={512}
- quality={100}
+ quality={85}
src={banner.image}
alt={banner.name}
className='h-auto w-full rounded'
@@ -26,7 +26,7 @@ const BannerSection = () => {
))}
</div>
)
- )
-}
+ );
+};
-export default BannerSection
+export default BannerSection;
diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx
index ca104ada..49a9a93f 100644
--- a/src/lib/home/components/CategoryDynamic.jsx
+++ b/src/lib/home/components/CategoryDynamic.jsx
@@ -1,46 +1,44 @@
import React, { useEffect, useState, useCallback } from 'react';
-import {fetchCategoryManagementSolr} from '../api/categoryManagementApi'
+import { fetchCategoryManagementSolr } from '../api/categoryManagementApi';
import NextImage from 'next/image';
-import Link from "next/link";
+import Link from 'next/link';
import { createSlug } from '@/core/utils/slug';
-import odooApi from '@/core/api/odooApi';
import { Skeleton } from '@chakra-ui/react';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
-import { Navigation, Pagination, Autoplay } from 'swiper';
+import { Pagination } from 'swiper';
const CategoryDynamic = () => {
-
- const [categoryManagement, setCategoryManagement] = useState([])
- const [isLoading, setIsLoading] = useState(false)
+ const [categoryManagement, setCategoryManagement] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
const loadBrand = useCallback(async () => {
- setIsLoading(true)
+ setIsLoading(true);
const items = await fetchCategoryManagementSolr();
-
- setIsLoading(false)
- setCategoryManagement(items)
- }, [])
+
+ setIsLoading(false);
+ setCategoryManagement(items);
+ }, []);
useEffect(() => {
- loadBrand()
- }, [loadBrand])
-
+ loadBrand();
+ }, [loadBrand]);
+
// const [categoryData, setCategoryData] = useState({});
// const [subCategoryData, setSubCategoryData] = useState({});
-
+
// useEffect(() => {
// const fetchCategoryData = async () => {
// if (categoryManagement && categoryManagement.data) {
// const updatedCategoryData = {};
// const updatedSubCategoryData = {};
-
+
// for (const category of categoryManagement.data) {
// const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`);
-
+
// updatedCategoryData[category.categoryIdI] = countLevel1?.numFound;
-
+
// for (const subCategory of countLevel1?.children) {
// updatedSubCategoryData[subCategory.id] = subCategory?.numFound;
// }
@@ -55,34 +53,45 @@ const CategoryDynamic = () => {
// }, [categoryManagement.isLoading]);
const swiperBanner = {
- modules: [Pagination, ],
- classNames:'mySwiper',
+ modules: [Pagination],
+ classNames: 'mySwiper',
slidesPerView: 3,
- spaceBetween:10,
+ spaceBetween: 10,
pagination: {
dynamicBullets: true,
clickable: true,
- }
+ },
};
-
+
return (
<div>
- {categoryManagement && categoryManagement?.map((category) => {
+ {categoryManagement &&
+ categoryManagement?.map((category) => {
// const countLevel1 = categoryData[category.categoryIdI] || 0;
return (
<Skeleton key={category.id} isLoaded={!isLoading}>
<div key={category.id}>
<div className='bagian-judul flex flex-row justify-start items-center gap-3 mb-4 mt-4'>
- <div className='font-semibold sm:text-h-lg mr-2'>{category.name}</div>
+ <h1 className='font-semibold text-[14px] sm:text-h-lg mr-2'>
+ {category.name}
+ </h1>
{/* <Skeleton isLoaded={countLevel1 != 0}>
<p className={`text-gray_r-10 text-sm`}>{countLevel1} Produk tersedia</p>
</Skeleton> */}
- <Link href={createSlug('/shop/category/', category?.name, category?.id)} className="!text-red-500 font-semibold">Lihat Semua</Link>
+ <Link
+ href={createSlug(
+ '/shop/category/',
+ category?.name,
+ category?.category_id
+ )}
+ className='!text-red-500 font-semibold'
+ >
+ Lihat Semua
+ </Link>
</div>
-
+
{/* Swiper for SubCategories */}
- <Swiper {...swiperBanner}
- >
+ <Swiper {...swiperBanner}>
{category.categories.map((subCategory) => {
// const countLevel2 = subCategoryData[subCategory.idLevel2] || 0;
@@ -92,39 +101,69 @@ const CategoryDynamic = () => {
<div className='p-3'>
<div className='flex flex-row border rounded mb-2 justify-start items-center'>
<NextImage
- src={subCategory.image ? subCategory.image : "/images/noimage.jpeg"}
+ src={
+ subCategory.image
+ ? subCategory.image
+ : '/images/noimage.jpeg'
+ }
alt={subCategory.name}
width={90}
height={30}
className='object-fit p-4'
/>
<div className='bagian-judul flex flex-col justify-center items-start gap-2 ml-2'>
- <div className='font-semibold text-lg mr-2'>{subCategory?.name}</div>
+ <h2 className='font-semibold text-lg mr-2'>
+ {subCategory?.name}
+ </h2>
{/* <Skeleton isLoaded={countLevel2 != 0}>
<p className={`text-gray_r-10 text-sm`}>
{countLevel2} Produk tersedia
</p>
</Skeleton> */}
- <Link href={createSlug('/shop/category/', subCategory?.name, subCategory?.id_level_2)} className="!text-red-500 font-semibold">Lihat Semua</Link>
+ <Link
+ href={createSlug(
+ '/shop/category/',
+ subCategory?.name,
+ subCategory?.id_level_2
+ )}
+ className='!text-red-500 font-semibold'
+ >
+ Lihat Semua
+ </Link>
</div>
</div>
<div className='grid grid-cols-2 gap-2 overflow-y-auto max-h-[240px] min-h-[240px] content-start'>
- {subCategory.child_frontend_id_i.map((childCategory) => (
- <div key={childCategory.id} className=''>
- <Link href={createSlug('/shop/category/', childCategory?.name, childCategory?.id_level_3)} className="flex flex-row gap-2 border rounded group hover:border-red-500">
- <NextImage
- src={childCategory.image ? childCategory.image : "/images/noimage.jpeg"}
- alt={childCategory.name}
- className='p-2 ml-1'
- width={40}
- height={40}
- />
- <div className='bagian-judul flex flex-col justify-center items-center gap-2 break-words line-clamp-2 group-hover:text-red-500'>
- <div className='font-semibold line-clamp-2 group-hover:text-red-500 text-sm mr-2'>{childCategory.name}</div>
- </div>
- </Link>
- </div>
- ))}
+ {subCategory.child_frontend_id_i.map(
+ (childCategory) => (
+ <div key={childCategory.id} className=''>
+ <Link
+ href={createSlug(
+ '/shop/category/',
+ childCategory?.name,
+ childCategory?.id_level_3
+ )}
+ className='flex flex-row gap-2 border rounded group hover:border-red-500'
+ >
+ <NextImage
+ src={
+ childCategory.image
+ ? childCategory.image
+ : '/images/noimage.jpeg'
+ }
+ alt={childCategory.name}
+ className='p-2 ml-1'
+ width={40}
+ height={40}
+ />
+ <div className='bagian-judul flex flex-col justify-center items-center gap-2 break-words line-clamp-2 group-hover:text-red-500'>
+ <h3 className='font-semibold line-clamp-2 group-hover:text-red-500 text-sm mr-2'>
+ {childCategory.name}
+ </h3>
+ </div>
+ </Link>
+ </div>
+ )
+ )}
</div>
</div>
</div>
diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx
index 1061f3e4..4a8f13cf 100644
--- a/src/lib/home/components/CategoryDynamicMobile.jsx
+++ b/src/lib/home/components/CategoryDynamicMobile.jsx
@@ -1,38 +1,41 @@
import React, { useEffect, useState, useCallback } from 'react';
import NextImage from 'next/image';
-import Link from "next/link";
+import Link from 'next/link';
import { createSlug } from '@/core/utils/slug';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
-import {fetchCategoryManagementSolr} from '../api/categoryManagementApi'
+import { fetchCategoryManagementSolr } from '../api/categoryManagementApi';
const CategoryDynamicMobile = () => {
const [selectedCategory, setSelectedCategory] = useState({});
- const [categoryManagement, setCategoryManagement] = useState([])
- const [isLoading, setIsLoading] = useState(false)
+ const [categoryManagement, setCategoryManagement] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
const loadBrand = useCallback(async () => {
- setIsLoading(true)
+ setIsLoading(true);
const items = await fetchCategoryManagementSolr();
-
- setIsLoading(false)
- setCategoryManagement(items)
- }, [])
+
+ setIsLoading(false);
+ setCategoryManagement(items);
+ }, []);
useEffect(() => {
- loadBrand()
- }, [loadBrand])
+ loadBrand();
+ }, [loadBrand]);
useEffect(() => {
const loadPromo = async () => {
try {
if (categoryManagement?.length > 0) {
- const initialSelections = categoryManagement.reduce((acc, category) => {
- if (category.categories.length > 0) {
- acc[category.id] = category.categories[0].id_level_2;
- }
- return acc;
- }, {});
+ const initialSelections = categoryManagement.reduce(
+ (acc, category) => {
+ if (category.categories.length > 0) {
+ acc[category.id] = category.categories[0].id_level_2;
+ }
+ return acc;
+ },
+ {}
+ );
setSelectedCategory(initialSelections);
}
} catch (loadError) {
@@ -44,69 +47,102 @@ const CategoryDynamicMobile = () => {
}, [categoryManagement]);
const handleCategoryLevel2Click = (categoryIdI, idLevel2) => {
- setSelectedCategory(prev => ({
+ setSelectedCategory((prev) => ({
...prev,
- [categoryIdI]: idLevel2
+ [categoryIdI]: idLevel2,
}));
};
-
+
return (
<div className='p-4'>
- {categoryManagement && categoryManagement?.map((category) => (
- <div key={category.id}>
- <div className='bagian-judul flex flex-row justify-between items-center gap-3 mb-4 mt-4'>
- <div className='font-semibold sm:text-h-sm mr-2'>{category?.name}</div>
- <Link href={createSlug('/shop/category/', category?.name, category?.id)} className="!text-red-500 font-semibold text-sm">Lihat Semua</Link>
- </div>
- <Swiper slidesPerView={2.3} spaceBetween={10}>
- {category.categories.map((index) => (
- <SwiperSlide key={index.id}>
- <div
- onClick={() => handleCategoryLevel2Click(category.id, index?.id_level_2)}
- className={`border flex justify-start items-center max-w-48 max-h-16 rounded ${selectedCategory[category.id] === index?.id_level_2 ? 'bg-red-50 border-red-500 text-red-500' : 'border-gray-200 text-gray-900'}`}
- >
- <div className='p-1 flex justify-start items-center'>
- <div className='flex flex-row justify-center items-center'>
- <NextImage
- src={index.image ? index.image : "/images/noimage.jpeg"}
- alt={index.name}
- width={30}
- height={30}
- className=''
- />
- <div className='bagian-judul flex flex-col justify-center items-start gap-1 ml-2'>
- <div className='font-semibold text-[10px] line-clamp-1'>{index?.name}</div>
- </div>
- </div>
- </div>
- </div>
- </SwiperSlide>
- ))}
- </Swiper>
- <div className='p-3 mt-2 border'>
- <div className='grid grid-cols-2 gap-2 overflow-y-auto max-h-[240px]'>
+ {categoryManagement &&
+ categoryManagement?.map((category) => (
+ <div key={category.id}>
+ <div className='bagian-judul flex flex-row justify-between items-center gap-3 mb-4 mt-4'>
+ <h1 className='font-semibold text-[14px] sm:text-h-lg mr-2'>
+ {category.name}
+ </h1>
+ <Link
+ href={createSlug(
+ '/shop/category/',
+ category?.name,
+ category?.category_id
+ )}
+ className='!text-red-500 font-semibold text-sm'
+ >
+ Lihat Semua
+ </Link>
+ </div>
+ <Swiper slidesPerView={2.3} spaceBetween={10}>
{category.categories.map((index) => (
- selectedCategory[category.id] === index?.id_level_2 && index?.child_frontend_id_i.map((x) => (
- <div key={x.id}>
- <Link href={createSlug('/shop/category/', x?.name, x?.id_level_3)} className="flex flex-row gap-1 border rounded group hover:border-red-500">
- <NextImage
- src={x.image ? x.image : "/images/noimage.jpeg"}
- alt={x.name}
- width={40}
- height={40}
- className='p-2'
- />
- <div className='bagian-judul flex flex-col justify-center items-start gap-1 break-words line-clamp-2 group-hover:text-red-500'>
- <div className='font-semibold line-clamp-2 group-hover:text-red-500 text-[10px]'>{x?.name}</div>
+ <SwiperSlide key={index.id}>
+ <div
+ onClick={() =>
+ handleCategoryLevel2Click(category.id, index?.id_level_2)
+ }
+ className={`border flex justify-start items-center max-w-48 max-h-16 rounded ${
+ selectedCategory[category.id] === index?.id_level_2
+ ? 'bg-red-50 border-red-500 text-red-500'
+ : 'border-gray-200 text-gray-900'
+ }`}
+ >
+ <div className='p-1 flex justify-start items-center'>
+ <div className='flex flex-row justify-center items-center'>
+ <NextImage
+ src={
+ index.image ? index.image : '/images/noimage.jpeg'
+ }
+ alt={index.name}
+ width={30}
+ height={30}
+ className=''
+ />
+ <div className='bagian-judul flex flex-col justify-center items-start gap-1 ml-2'>
+ <h2 className='font-semibold text-[10px] line-clamp-1'>
+ {index?.name}
+ </h2>
+ </div>
</div>
- </Link>
+ </div>
</div>
- ))
+ </SwiperSlide>
))}
+ </Swiper>
+ <div className='p-3 mt-2 border'>
+ <div className='grid grid-cols-2 gap-2 overflow-y-auto max-h-[240px]'>
+ {category.categories.map(
+ (index) =>
+ selectedCategory[category.id] === index?.id_level_2 &&
+ index?.child_frontend_id_i.map((x) => (
+ <div key={x.id}>
+ <Link
+ href={createSlug(
+ '/shop/category/',
+ x?.name,
+ x?.id_level_3
+ )}
+ className='flex flex-row gap-1 border rounded group hover:border-red-500'
+ >
+ <NextImage
+ src={x.image ? x.image : '/images/noimage.jpeg'}
+ alt={x.name}
+ width={40}
+ height={40}
+ className='p-2'
+ />
+ <div className='bagian-judul flex flex-col justify-center items-start gap-1 break-words line-clamp-2 group-hover:text-red-500'>
+ <h3 className='font-semibold line-clamp-2 group-hover:text-red-500 text-[10px]'>
+ {x?.name}
+ </h3>
+ </div>
+ </Link>
+ </div>
+ ))
+ )}
+ </div>
</div>
</div>
- </div>
- ))}
+ ))}
</div>
);
};
diff --git a/src/lib/home/components/CategoryHomeId.jsx b/src/lib/home/components/CategoryHomeId.jsx
index 71428e27..9f436dac 100644
--- a/src/lib/home/components/CategoryHomeId.jsx
+++ b/src/lib/home/components/CategoryHomeId.jsx
@@ -1,13 +1,15 @@
-import { LazyLoadComponent } from 'react-lazy-load-image-component'
-import useCategoryHomeId from '../hooks/useCategoryHomeId'
-import CategoryHome from './CategoryHome'
+import { LazyLoadComponent } from 'react-lazy-load-image-component';
+import useCategoryHomeId from '../hooks/useCategoryHomeId';
+import CategoryHome from './CategoryHome';
const CategoryHomeId = () => {
- const { categoryHomeIds } = useCategoryHomeId()
+ const { categoryHomeIds } = useCategoryHomeId();
return (
<div>
- <div className='font-semibold sm:text-h-lg mb-6 px-4 sm:px-0'>Kategori Pilihan</div>
+ <h1 className='font-semibold text-[14px] sm:text-h-lg mb-6 px-4 sm:px-0'>
+ Kategori Pilihan
+ </h1>
<div className='flex flex-col gap-y-10'>
{categoryHomeIds.data?.map((id) => (
<LazyLoadComponent key={id}>
@@ -16,7 +18,7 @@ const CategoryHomeId = () => {
))}
</div>
</div>
- )
-}
+ );
+};
-export default CategoryHomeId
+export default CategoryHomeId;
diff --git a/src/lib/home/components/CategoryPilihan.jsx b/src/lib/home/components/CategoryPilihan.jsx
index 6dbf771e..2e5ca721 100644
--- a/src/lib/home/components/CategoryPilihan.jsx
+++ b/src/lib/home/components/CategoryPilihan.jsx
@@ -1,123 +1,168 @@
-import Image from 'next/image'
-import useCategoryHome from '../hooks/useCategoryHome'
-import Link from '@/core/components/elements/Link/Link'
-import { createSlug } from '@/core/utils/slug'
+import Image from 'next/image';
+import useCategoryHome from '../hooks/useCategoryHome';
+import Link from '@/core/components/elements/Link/Link';
+import { createSlug } from '@/core/utils/slug';
import { useEffect, useState } from 'react';
import { bannerApi } from '../../../api/bannerApi';
-const { useQuery } = require('react-query')
+const { useQuery } = require('react-query');
import { HeroBannerSkeleton } from '../../../components/skeleton/BannerSkeleton';
import useCategoryPilihan from '../hooks/useCategoryPilihan';
-import useDevice from '@/core/hooks/useDevice'
+import useDevice from '@/core/hooks/useDevice';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
const CategoryPilihan = ({ id, categories }) => {
- const { isDesktop, isMobile } = useDevice()
- const { categoryPilihan } = useCategoryPilihan();
- const heroBanner = useQuery('categoryPilihan', bannerApi({ type: 'banner-category-list' }));
- return (
- categoryPilihan.length > 0 && (
- <section>
- {isDesktop && (
- <div>
- <div className='flex flex-row items-center mb-4'>
- <div className='font-semibold sm:text-h-lg mr-2'>LOB Kategori Pilihan</div>
- <p className='text-gray_r-10 text-sm'>200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia!</p>
- </div>
- {heroBanner.data &&
- heroBanner.data?.length > 0 && (
- <div className='flex w-full h-full justify-center mb-4 bg-cover bg-center'>
- <Link key={heroBanner.data[0].id} href={heroBanner.data[0].url}>
- <Image
- width={1260}
- height={170}
- quality={100}
- src={heroBanner.data[0].image}
- alt={heroBanner.data[0].name}
- className='h-full object-cover w-full'
- />
- </Link>
- </div>
- )}
- <div className="group/item grid grid-cols-6 gap-y-2 w-full h-full col-span-2 ">
- {categoryPilihan?.data?.map((category) => (
- <div key={category.id} className="KartuInti h-48 w-60 max-w-sm lg:max-w-full flex flex-col border-[1px] border-gray-200 relative group">
- <div className='KartuB absolute h-48 w-60 inset-0 flex items-center justify-center '>
- <div className="group/edit flex items-center justify-end h-48 w-60 flex-col group-hover/item:visible">
- <div className=' h-36 flex justify-end items-end'>
- <Image className='group-hover:scale-105 transition-transform duration-300 ' src={category?.image? category?.image : '/images/noimage.jpeg'} width={120} height={120} alt={category?.name} />
- </div>
- <h2 className="text-gray-700 content-center h-12 border-t-[1px] px-1 w-60 border-gray-200 font-normal text-sm text-center">{category?.industries}</h2>
- </div>
- </div>
- <div className='KartuA relative inset-0 flex h-36 w-60 items-center justify-center opacity-0 group-hover:opacity-75 group-hover:bg-[#E20613] transition-opacity '>
- <Link
- href={createSlug('/shop/lob/', category?.industries, category?.id)}
- className='category-mega-box__parent text-white rounded-lg'
- >
- Lihat semua
- </Link>
- </div>
- </div>
- ))}
+ const { isDesktop, isMobile } = useDevice();
+ const { categoryPilihan } = useCategoryPilihan();
+ const heroBanner = useQuery(
+ 'categoryPilihan',
+ bannerApi({ type: 'banner-category-list' })
+ );
+ return (
+ categoryPilihan.length > 0 && (
+ <section>
+ {isDesktop && (
+ <div>
+ <div className='flex flex-row items-center mb-4'>
+ <div className='font-semibold sm:text-h-lg mr-2'>
+ LOB Kategori Pilihan
+ </div>
+ <p className='text-gray_r-10 text-sm'>
+ 200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia!
+ </p>
+ </div>
+ {heroBanner.data && heroBanner.data?.length > 0 && (
+ <div className='flex w-full h-full justify-center mb-4 bg-cover bg-center'>
+ <Link key={heroBanner.data[0].id} href={heroBanner.data[0].url}>
+ <Image
+ width={1260}
+ height={170}
+ quality={85}
+ src={heroBanner.data[0].image}
+ alt={heroBanner.data[0].name}
+ className='h-full object-cover w-full'
+ />
+ </Link>
+ </div>
+ )}
+ <div className='group/item grid grid-cols-6 gap-y-2 w-full h-full col-span-2 '>
+ {categoryPilihan?.data?.map((category) => (
+ <div
+ key={category.id}
+ className='KartuInti h-48 w-60 max-w-sm lg:max-w-full flex flex-col border-[1px] border-gray-200 relative group'
+ >
+ <div className='KartuB absolute h-48 w-60 inset-0 flex items-center justify-center '>
+ <div className='group/edit flex items-center justify-end h-48 w-60 flex-col group-hover/item:visible'>
+ <div className=' h-36 flex justify-end items-end'>
+ <Image
+ className='group-hover:scale-105 transition-transform duration-300 '
+ src={
+ category?.image
+ ? category?.image
+ : '/images/noimage.jpeg'
+ }
+ width={120}
+ height={120}
+ alt={category?.name}
+ />
+ </div>
+ <h2 className='text-gray-700 content-center h-12 border-t-[1px] px-1 w-60 border-gray-200 font-normal text-sm text-center'>
+ {category?.industries}
+ </h2>
</div>
+ </div>
+ <div className='KartuA relative inset-0 flex h-36 w-60 items-center justify-center opacity-0 group-hover:opacity-75 group-hover:bg-[#E20613] transition-opacity '>
+ <Link
+ href={createSlug(
+ '/shop/lob/',
+ category?.industries,
+ category?.id
+ )}
+ className='category-mega-box__parent text-white rounded-lg'
+ >
+ Lihat semua
+ </Link>
+ </div>
</div>
- )}
- {isMobile && (
- <div className='p-4'>
- <div className='flex flex-row items-center mb-4'>
- <div className='font-semibold sm:text-h-md mr-2'>LOB Kategori Pilihan</div>
- {/* <p className='text-gray_r-10 text-sm'>200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia!</p> */}
+ ))}
+ </div>
+ </div>
+ )}
+ {isMobile && (
+ <div className='p-4'>
+ <div className='flex flex-row items-center mb-4'>
+ <div className='font-semibold sm:text-h-md mr-2'>
+ LOB Kategori Pilihan
+ </div>
+ {/* <p className='text-gray_r-10 text-sm'>200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia!</p> */}
+ </div>
+ <div className='flex'>
+ {heroBanner.data && heroBanner.data?.length > 0 && (
+ <div className=' object-fill '>
+ <Link
+ key={heroBanner.data[0].id}
+ href={heroBanner.data[0].url}
+ >
+ <Image
+ width={439}
+ height={150}
+ quality={85}
+ src={heroBanner.data[0].image}
+ alt={heroBanner.data[0].name}
+ className='object-cover'
+ />
+ </Link>
+ </div>
+ )}
+ </div>
+ <Swiper slidesPerView={2.1} spaceBetween={10}>
+ {categoryPilihan?.data?.map((category) => (
+ <SwiperSlide key={category.id}>
+ <div
+ key={category.id}
+ className='KartuInti mt-2 h-48 w-48 max-w-sm lg:max-w-full flex flex-col border-[1px] border-gray-200 relative group'
+ >
+ <div className='KartuB absolute h-48 w-48 inset-0 flex items-center justify-center '>
+ <div className='group/edit flex items-center justify-end h-48 w-48 flex-col group-hover/item:visible'>
+ <div className=' h-36 flex justify-end items-end'>
+ <Image
+ className='group-hover:scale-105 transition-transform duration-300 '
+ src={
+ category?.image
+ ? category?.image
+ : '/images/noimage.jpeg'
+ }
+ width={120}
+ height={120}
+ alt={category?.name}
+ />
+ </div>
+ <h2 className='text-gray-700 content-center h-12 border-t-[1px] px-1 w-48 border-gray-200 font-normal text-sm text-center'>
+ {category?.industries}
+ </h2>
+ </div>
</div>
- <div className='flex'>
- {heroBanner.data &&
- heroBanner.data?.length > 0 && (
- <div className=' object-fill '>
- <Link key={heroBanner.data[0].id} href={heroBanner.data[0].url}>
- <Image
- width={439}
- height={150}
- quality={100}
- src={heroBanner.data[0].image}
- alt={heroBanner.data[0].name}
- className='object-cover'
- />
- </Link>
- </div>
- )}
+ <div className='KartuA relative inset-0 flex h-36 w-48 items-center justify-center opacity-0 group-hover:opacity-75 group-hover:bg-[#E20613] transition-opacity '>
+ <Link
+ href={createSlug(
+ '/shop/lob/',
+ category?.industries,
+ category?.id
+ )}
+ className='category-mega-box__parent text-white rounded-lg'
+ >
+ Lihat semua
+ </Link>
</div>
- <Swiper slidesPerView={2.1} spaceBetween={10}>
- {categoryPilihan?.data?.map((category) => (
- <SwiperSlide key={category.id}>
- <div key={category.id} className="KartuInti mt-2 h-48 w-48 max-w-sm lg:max-w-full flex flex-col border-[1px] border-gray-200 relative group">
- <div className='KartuB absolute h-48 w-48 inset-0 flex items-center justify-center '>
- <div className="group/edit flex items-center justify-end h-48 w-48 flex-col group-hover/item:visible">
- <div className=' h-36 flex justify-end items-end'>
- <Image className='group-hover:scale-105 transition-transform duration-300 ' src={category?.image? category?.image : '/images/noimage.jpeg'} width={120} height={120} alt={category?.name} />
- </div>
- <h2 className="text-gray-700 content-center h-12 border-t-[1px] px-1 w-48 border-gray-200 font-normal text-sm text-center">{category?.industries}</h2>
- </div>
- </div>
- <div className='KartuA relative inset-0 flex h-36 w-48 items-center justify-center opacity-0 group-hover:opacity-75 group-hover:bg-[#E20613] transition-opacity '>
- <Link
- href={createSlug('/shop/lob/', category?.industries, category?.id)}
- className='category-mega-box__parent text-white rounded-lg'
- >
- Lihat semua
- </Link>
- </div>
- </div>
- </SwiperSlide>
- ))}
-
- </Swiper>
-
- </div>
- )}
- </section>
-
- )
- )
-}
+ </div>
+ </SwiperSlide>
+ ))}
+ </Swiper>
+ </div>
+ )}
+ </section>
+ )
+ );
+};
-export default CategoryPilihan
+export default CategoryPilihan;
diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx
index 4d53272b..eefced60 100644
--- a/src/lib/home/components/PreferredBrand.jsx
+++ b/src/lib/home/components/PreferredBrand.jsx
@@ -9,7 +9,7 @@ import Link from '@/core/components/elements/Link/Link'
import axios from 'axios'
const PreferredBrand = () => {
- let query = 'level_s'
+ let query = ''
let params = 'prioritas'
const [isLoading, setIsLoading] = useState(true)
const [startWith, setStartWith] = useState(null)
@@ -18,7 +18,7 @@ const PreferredBrand = () => {
const loadBrand = useCallback(async () => {
setIsLoading(true)
const name = startWith ? `${startWith}*` : ''
- const result = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?params=${name}`)
+ const result = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?rows=20`)
setIsLoading(false)
setManufactures((manufactures) => [...result.data])
@@ -35,9 +35,9 @@ const PreferredBrand = () => {
useEffect(() => {
loadBrand()
- }, [loadBrand])
+ }, [])
- const { preferredBrands } = usePreferredBrand(query)
+ // const { preferredBrands } = usePreferredBrand(query)
const { isMobile, isDesktop } = useDevice()
const swiperBanner = {
modules:[Navigation, Pagination, Autoplay],
diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx
index ae8d5d6f..ae06bd4d 100644
--- a/src/lib/home/components/PromotionProgram.jsx
+++ b/src/lib/home/components/PromotionProgram.jsx
@@ -1,13 +1,16 @@
-import Link from '@/core/components/elements/Link/Link'
-import Image from 'next/image'
+import Link from '@/core/components/elements/Link/Link';
+import Image from 'next/image';
import { bannerApi } from '@/api/bannerApi';
-import useDevice from '@/core/hooks/useDevice'
+import useDevice from '@/core/hooks/useDevice';
import { Swiper, SwiperSlide } from 'swiper/react';
-import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton';
-const { useQuery } = require('react-query')
+import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton';
+const { useQuery } = require('react-query');
const BannerSection = () => {
- const promotionProgram = useQuery('promotionProgram', bannerApi({ type: 'banner-promotion' }));
- const { isMobile, isDesktop } = useDevice()
+ const promotionProgram = useQuery(
+ 'promotionProgram',
+ bannerApi({ type: 'banner-promotion' })
+ );
+ const { isMobile, isDesktop } = useDevice();
if (promotionProgram.isLoading) {
return <BannerPromoSkeleton />;
@@ -16,60 +19,65 @@ const BannerSection = () => {
return (
<div className='px-4 sm:px-0'>
<div className='flex justify-between items-center mb-4 '>
- <h1 className='font-semibold text-[14px] sm:text-h-lg'> <Link href='/shop/promo' className='!text-black font-semibold' >Promo Tersedia</Link></h1>
+ <h1 className='font-semibold text-[14px] sm:text-h-lg'>
+ {' '}
+ <Link href='/shop/promo' className='!text-black font-semibold'>
+ Promo Tersedia
+ </Link>
+ </h1>
{isDesktop && (
<Link href='/shop/promo' className='!text-red-500 font-semibold'>
- Lihat Semua
- </Link>
+ Lihat Semua
+ </Link>
)}
{isMobile && (
- <Link href='/shop/promo' className='!text-red-500 font-semibold sm:text-h-sm'>
- Lihat Semua
- </Link>
- )}
- </div>
- {isDesktop && (promotionProgram.data &&
- promotionProgram.data?.length > 0 && (
- <div className='grid grid-cols-3 sm:grid-cols-3 gap-4 rounded-md'>
- {promotionProgram.data?.map((banner) => (
- <Link key={banner.id} href={banner.url}>
- <Image
- width={439}
- height={150}
- quality={100}
- src={banner.image}
- alt={banner.name}
- className='h-auto w-full rounded hover:scale-105 transition duration-500 ease-in-out'
- />
+ <Link
+ href='/shop/promo'
+ className='!text-red-500 font-semibold sm:text-h-sm'
+ >
+ Lihat Semua
</Link>
- ))}
+ )}
</div>
-
- ))}
+ {isDesktop &&
+ promotionProgram.data &&
+ promotionProgram.data?.length > 0 && (
+ <div className='grid grid-cols-3 sm:grid-cols-3 gap-4 rounded-md'>
+ {promotionProgram.data?.map((banner) => (
+ <Link key={banner.id} href={banner.url}>
+ <Image
+ width={439}
+ height={150}
+ quality={85}
+ src={banner.image}
+ alt={banner.name}
+ className='h-auto w-full rounded hover:scale-105 transition duration-500 ease-in-out'
+ />
+ </Link>
+ ))}
+ </div>
+ )}
-{isMobile && (
-
- <Swiper slidesPerView={1.1} spaceBetween={8} freeMode>
- {promotionProgram.data?.map((banner) => (
- <SwiperSlide key={banner.id}>
- <Link key={banner.id} href={banner.url}>
- <Image
- width={439}
- height={150}
- quality={100}
- src={banner.image}
- alt={banner.name}
- className='h-auto w-full rounded '
- />
- </Link>
- </SwiperSlide>
- ))}
- </Swiper>
-
- )}
+ {isMobile && (
+ <Swiper slidesPerView={1.1} spaceBetween={8} freeMode>
+ {promotionProgram.data?.map((banner) => (
+ <SwiperSlide key={banner.id}>
+ <Link key={banner.id} href={banner.url}>
+ <Image
+ width={439}
+ height={150}
+ quality={85}
+ src={banner.image}
+ alt={banner.name}
+ className='h-auto w-full rounded '
+ />
+ </Link>
+ </SwiperSlide>
+ ))}
+ </Swiper>
+ )}
</div>
-
- )
-}
+ );
+};
-export default BannerSection
+export default BannerSection;
diff --git a/src/lib/home/components/ServiceList.jsx b/src/lib/home/components/ServiceList.jsx
index b8799d7d..5b16915d 100644
--- a/src/lib/home/components/ServiceList.jsx
+++ b/src/lib/home/components/ServiceList.jsx
@@ -1,5 +1,5 @@
-import Image from 'next/image'
-import Link from '@/core/components/elements/Link/Link'
+import Image from 'next/image';
+import Link from '@/core/components/elements/Link/Link';
const ServiceList = () => {
return (
@@ -14,14 +14,16 @@ const ServiceList = () => {
<Image
width={24}
height={24}
- quality={100}
+ quality={85}
src='/images/icon_service/ONE-STOP-SOLUTIONS.svg'
alt=''
className='h-20 w-20 rounded'
/>
</div>
<div className=''>
- <h1 className='text-gray-900 font-semibold text-base'>One Stop Solution</h1>
+ <h1 className='text-gray-900 font-semibold text-base'>
+ One Stop Solution
+ </h1>
<p className='text-xs md:text-sm text-gray-500'>
Temukan Solusi Lengkap Anda dalam Satu Tempat.
</p>
@@ -37,14 +39,16 @@ const ServiceList = () => {
<Image
width={24}
height={24}
- quality={100}
+ quality={85}
src='/images/icon_service/WARRANTY.svg'
alt=''
className='h-20 w-20 rounded'
/>
</div>
<div>
- <h1 className='text-gray-900 font-semibold text-base'>Garansi Resmi</h1>
+ <h1 className='text-gray-900 font-semibold text-base'>
+ Garansi Resmi
+ </h1>
<p className='text-xs md:text-sm text-gray-500'>
Garansi Keaslian Barang dan Jaminan Purna Jual.
</p>
@@ -60,14 +64,16 @@ const ServiceList = () => {
<Image
width={24}
height={24}
- quality={100}
+ quality={85}
src='/images/icon_service/DUE-PAYMENT.svg'
alt=''
className='h-20 w-20 rounded'
/>
</div>
<div>
- <h1 className='text-gray-900 font-semibold text-base'>Pembayaran Tempo</h1>
+ <h1 className='text-gray-900 font-semibold text-base'>
+ Pembayaran Tempo
+ </h1>
<p className='text-xs md:text-sm text-gray-500'>
Lebih mudah mengatur pembelian dengan pembayaran tempo.
</p>
@@ -83,14 +89,16 @@ const ServiceList = () => {
<Image
width={24}
height={24}
- quality={100}
+ quality={85}
src='/images/icon_service/TAX.svg'
alt=''
className='h-20 w-20 rounded'
/>
</div>
<div>
- <h1 className='text-gray-900 font-semibold text-base'>Faktur Pajak</h1>
+ <h1 className='text-gray-900 font-semibold text-base'>
+ Faktur Pajak
+ </h1>
<p className='text-xs md:text-sm text-gray-500'>
Dapat Faktur pajak untuk setiap transaksi dengan indoteknik.com
</p>
@@ -99,7 +107,7 @@ const ServiceList = () => {
</div>
</div>
</div>
- )
-}
+ );
+};
-export default ServiceList
+export default ServiceList;
diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx
index 22ce0533..d3b50302 100644
--- a/src/lib/product/components/ProductCard.jsx
+++ b/src/lib/product/components/ProductCard.jsx
@@ -17,12 +17,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
const [discount, setDiscount] = useState(0);
let voucherPastiHemat = 0;
-
- if (product?.voucherPastiHemat ? product?.voucherPastiHemat.length : voucherPastiHemat > 0) {
- const stringVoucher = product?.voucherPastiHemat[0];
- const validJsonString = stringVoucher.replace(/'/g, '"');
- voucherPastiHemat = JSON.parse(validJsonString);
- }
+ voucherPastiHemat = product?.newVoucherPastiHemat[0];
const callForPriceWhatsapp = whatsappUrl('product', {
name: product.name,
@@ -48,18 +43,18 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
const hitungDiscountVoucher = () => {
let countDiscount = 0;
- if (voucherPastiHemat.discount_type === 'percentage') {
+ if (voucherPastiHemat.discountType === 'percentage') {
countDiscount =
product?.lowestPrice.priceDiscount *
- (voucherPastiHemat.discount_amount / 100);
+ (voucherPastiHemat.discountAmount / 100);
if (
- voucherPastiHemat.max_discount > 0 &&
- countDiscount > voucherPastiHemat.max_discount
+ voucherPastiHemat.maxDiscount > 0 &&
+ countDiscount > voucherPastiHemat.maxDiscount
) {
- countDiscount = voucherPastiHemat.max_discount;
+ countDiscount = voucherPastiHemat.maxDiscount;
}
} else {
- countDiscount = voucherPastiHemat.discount_amount;
+ countDiscount = voucherPastiHemat.discountAmount;
}
setDiscount(countDiscount);
@@ -147,20 +142,24 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
</Link>
<div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'>
<div className='flex justify-between '>
- {product?.manufacture?.name ? (
- <Link href={URL.manufacture} className='mb-1 mt-1'>
- {product.manufacture.name}
- </Link>
- ) : (
- <div>-</div>
- )}
- {product?.isInBu && (
- <Link href='/panduan-pick-up-service' className='group'>
- <Image src='/images/PICKUP-NOW.png' className='group-hover:scale-105 transition-transform duration-200' alt='pickup now' width={90} height={12} />
- </Link>
-
-
- )}
+ {product?.manufacture?.name ? (
+ <Link href={URL.manufacture} className='mb-1 mt-1'>
+ {product.manufacture.name}
+ </Link>
+ ) : (
+ <div>-</div>
+ )}
+ {product?.isInBu && (
+ <Link href='/panduan-pick-up-service' className='group'>
+ <Image
+ src='/images/PICKUP-NOW.png'
+ className='group-hover:scale-105 transition-transform duration-200'
+ alt='pickup now'
+ width={90}
+ height={12}
+ />
+ </Link>
+ )}
</div>
<Link
href={URL.product}
@@ -301,11 +300,11 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
</div>
)}
{product?.manufacture?.name ? (
- <div className='flex justify-between'>
+ <div className='flex justify-between'>
<Link href={URL.manufacture} className='mb-1'>
- {product.manufacture.name}
- </Link>
- {/* {product?.is_in_bu && (
+ {product.manufacture.name}
+ </Link>
+ {/* {product?.is_in_bu && (
<div className='bg-red-500 rounded'>
<span className='p-[6px] text-xs text-white'>
Click & Pickup
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index 1edc31c9..26114acf 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -28,7 +28,7 @@ import SideBanner from '~/modules/side-banner';
import FooterBanner from '~/modules/footer-banner';
import CategorySection from './CategorySection';
import LobSectionCategory from './LobSectionCategory';
-import { getIdFromSlug } from '@/core/utils/slug'
+import { getIdFromSlug } from '@/core/utils/slug';
import { data } from 'autoprefixer';
const ProductSearch = ({
@@ -45,35 +45,40 @@ const ProductSearch = ({
const [orderBy, setOrderBy] = useState(router.query?.orderBy);
const [finalQuery, setFinalQuery] = useState({});
const [queryFinal, setQueryFinal] = useState({});
- const [dataCategoriesProduct, setDataCategoriesProduct] = useState([])
- const [dataCategoriesLob, setDataCategoriesLob] = useState([])
- const categoryId = getIdFromSlug(prefixUrl)
- const [data, setData] = useState([])
+ const [dataCategoriesProduct, setDataCategoriesProduct] = useState([]);
+ const [dataCategoriesLob, setDataCategoriesLob] = useState([]);
+ const categoryId = getIdFromSlug(prefixUrl);
+ const [data, setData] = useState([]);
const [dataLob, setDataLob] = useState([]);
if (defaultBrand) query.brand = defaultBrand.toLowerCase();
- const dataIdCategories = []
+ const dataIdCategories = [];
useEffect(() => {
- if(prefixUrl.includes('category')){
+ if (prefixUrl.includes('category')) {
const loadProduct = async () => {
- const getCategoriesId = await odooApi('GET', `/api/v1/category/numFound?parent_id=${categoryId}`);
+ const getCategoriesId = await odooApi(
+ 'GET',
+ `/api/v1/category/numFound?parent_id=${categoryId}`
+ );
if (getCategoriesId) {
setDataCategoriesProduct(getCategoriesId);
}
};
loadProduct();
- }else if(prefixUrl.includes('lob')){
+ } else if (prefixUrl.includes('lob')) {
const loadProduct = async () => {
- const lobData = await odooApi('GET', `/api/v1/lob_homepage/${categoryId}/category_id`);
-
+ const lobData = await odooApi(
+ 'GET',
+ `/api/v1/lob_homepage/${categoryId}/category_id`
+ );
+
if (lobData) {
setDataLob(lobData);
}
};
loadProduct();
-
}
}, [categoryId]);
-
+
const collectIds = (category) => {
const ids = [];
function recurse(cat) {
@@ -88,45 +93,40 @@ const ProductSearch = ({
return ids;
};
useEffect(() => {
- if(prefixUrl.includes('category')){
+ if (prefixUrl.includes('category')) {
const ids = collectIds(dataCategoriesProduct);
const newQuery = {
fq: `category_id_ids:(${ids.join(' OR ')})`,
- page : router.query.page? router.query.page : 1,
- brand : router.query.brand? router.query.brand : '',
- category : router.query.category? router.query.category : '',
- priceFrom : router.query.priceFrom? router.query.priceFrom : '',
- priceTo : router.query.priceTo? router.query.priceTo : '',
- limit : router.query.limit? router.query.limit : '',
- orderBy : router.query.orderBy? router.query.orderBy : ''
+ page: router.query.page ? router.query.page : 1,
+ brand: router.query.brand ? router.query.brand : '',
+ category: router.query.category ? router.query.category : '',
+ priceFrom: router.query.priceFrom ? router.query.priceFrom : '',
+ priceTo: router.query.priceTo ? router.query.priceTo : '',
+ limit: router.query.limit ? router.query.limit : '',
+ orderBy: router.query.orderBy ? router.query.orderBy : '',
};
setFinalQuery(newQuery);
- } else if (prefixUrl.includes('lob')){
-
+ } else if (prefixUrl.includes('lob')) {
const fetchCategoryData = async () => {
if (dataLob[0]?.categoryIds) {
-
for (const cate of dataLob[0].categoryIds) {
-
- dataIdCategories.push(cate.childId)
+ dataIdCategories.push(cate.childId);
}
-
-
+
const mergedArray = dataIdCategories.flat();
-
+
const newQuery = {
fq: `category_id_ids:(${mergedArray.join(' OR ')})`,
- category : router.query.category? router.query.category : '',
- page : router.query.page? router.query.page : 1,
- brand : router.query.brand? router.query.brand : '',
- priceFrom : router.query.priceFrom? router.query.priceFrom : '',
- priceTo : router.query.priceTo? router.query.priceTo : '',
- limit : router.query.limit? router.query.limit : '',
- orderBy : router.query.orderBy? router.query.orderBy : ''
+ category: router.query.category ? router.query.category : '',
+ page: router.query.page ? router.query.page : 1,
+ brand: router.query.brand ? router.query.brand : '',
+ priceFrom: router.query.priceFrom ? router.query.priceFrom : '',
+ priceTo: router.query.priceTo ? router.query.priceTo : '',
+ limit: router.query.limit ? router.query.limit : '',
+ orderBy: router.query.orderBy ? router.query.orderBy : '',
};
-
+
setFinalQuery(newQuery);
-
}
};
fetchCategoryData();
@@ -139,7 +139,7 @@ const ProductSearch = ({
} else {
setQueryFinal({ ...query, q, limit, orderBy });
}
- }, [prefixUrl,dataCategoriesProduct, query, finalQuery]);
+ }, [prefixUrl, dataCategoriesProduct, query, finalQuery]);
const { productSearch } = useProductSearch({
query: queryFinal,
@@ -162,7 +162,7 @@ const ProductSearch = ({
const [categoryValues, setCategory] = useState(
router.query?.category?.split(',') || router.query?.category?.split(',')
);
-
+
const [priceFrom, setPriceFrom] = useState(router.query?.priceFrom || null);
const [priceTo, setPriceTo] = useState(router.query?.priceTo || null);
@@ -170,8 +170,8 @@ const ProductSearch = ({
const productStart = productSearch.data?.responseHeader.params.start;
const productRows = limit;
const productFound = productSearch.data?.response.numFound;
- const [dataCategories, setDataCategories] = useState([])
-
+ const [dataCategories, setDataCategories] = useState([]);
+
useEffect(() => {
if (productFound == 0 && query.q && !spellings) {
searchSpellApi({ query: query.q }).then((response) => {
@@ -201,7 +201,7 @@ const ProductSearch = ({
});
}
}, [productFound, query, spellings]);
- let id = []
+ let id = [];
useEffect(() => {
const checkIfBrand = async () => {
const brand = await axios(
@@ -218,21 +218,21 @@ const ProductSearch = ({
checkIfBrand();
}
}, [q]);
-
+
useEffect(() => {
- if(prefixUrl.includes('category')){
+ if (prefixUrl.includes('category')) {
const loadCategories = async () => {
- const getCategories = await odooApi('GET', `/api/v1/category/child?parent_id=${categoryId}`)
- if(getCategories){
- setDataCategories(getCategories)
- }
- }
- loadCategories()
+ const getCategories = await odooApi(
+ 'GET',
+ `/api/v1/category/child?parent_id=${categoryId}`
+ );
+ if (getCategories) {
+ setDataCategories(getCategories);
+ }
+ };
+ loadCategories();
}
- }, [])
-
-
-
+ }, []);
const brands = [];
for (
@@ -248,7 +248,6 @@ const ProductSearch = ({
brands.push({ brand, qty });
}
}
-
const categories = [];
for (
@@ -263,7 +262,6 @@ const ProductSearch = ({
categories.push({ name, qty });
}
}
-
const orderOptions = [
{ value: '', label: 'Pilih Filter' },
@@ -382,7 +380,6 @@ const ProductSearch = ({
const isNotReadyStockPage = router.asPath !== '/shop/search?orderBy=stock';
- console.log('is spelling', spellings);
return (
<>
<MobileView>
@@ -443,8 +440,8 @@ const ProductSearch = ({
SpellingComponent
)}
</div>
- <LobSectionCategory categories={dataLob}/>
- <CategorySection categories={dataCategories}/>
+ <LobSectionCategory categories={dataLob} />
+ <CategorySection categories={dataCategories} />
{productFound > 0 && (
<div className='flex items-center gap-x-2 mb-5 justify-between'>
@@ -536,8 +533,8 @@ const ProductSearch = ({
</div>
<div className='w-9/12 pl-6'>
- <LobSectionCategory categories={dataLob}/>
- <CategorySection categories={dataCategories}/>
+ <LobSectionCategory categories={dataLob} />
+ <CategorySection categories={dataCategories} />
{bannerPromotionHeader && bannerPromotionHeader?.image && (
<div className='mb-3'>
<Image
diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx
index 0ad042de..cf0ad41f 100644
--- a/src/lib/quotation/components/Quotation.jsx
+++ b/src/lib/quotation/components/Quotation.jsx
@@ -39,12 +39,12 @@ const { getProductsCheckout } = require('@/lib/checkout/api/checkoutApi');
const Quotation = () => {
const router = useRouter();
const auth = useAuth();
-
+
const { data: cartCheckout } = useQuery('cartCheckout', () =>
getProductsCheckout()
-);
+ );
-const { setRefreshCart } = useProductCartContext();
+ const { setRefreshCart } = useProductCartContext();
const SELF_PICKUP_ID = 32;
const [products, setProducts] = useState(null);
@@ -69,18 +69,18 @@ const { setRefreshCart } = useProductCartContext();
const [selectedExpedisiService, setselectedExpedisiService] = useState(null);
const [etd, setEtd] = useState(null);
const [etdFix, setEtdFix] = useState(null);
-
+
const [isApproval, setIsApproval] = useState(false);
-
+
const expedisiValidation = useRef(null);
-
+
const [selectedAddress, setSelectedAddress] = useState({
shipping: null,
invoicing: null,
});
-
+
const [addresses, setAddresses] = useState(null);
-
+
const [note_websiteText, setselectedNote_websiteText] = useState('');
useEffect(() => {
@@ -99,6 +99,9 @@ const { setRefreshCart } = useProductCartContext();
if (!addresses) return;
const matchAddress = (key) => {
+ if (key === 'invoicing') {
+ key = 'invoice';
+ }
const addressToMatch = getItemAddress(key);
const foundAddress = addresses.filter(
(address) => address.id == addressToMatch
@@ -271,7 +274,7 @@ const { setRefreshCart } = useProductCartContext();
toast.error('Maaf, Note wajib dimasukkan.');
return;
}
-
+
setIsLoading(true);
const productOrder = products.map((product) => ({
product_id: product.id,
@@ -286,11 +289,10 @@ const { setRefreshCart } = useProductCartContext();
carrier_id: selectedCarrierId,
estimated_arrival_days: splitDuration(etd),
delivery_service_type: selectedExpedisiService,
- note_website : note_websiteText,
+ note_website: note_websiteText,
};
-
+
const isSuccess = await checkoutApi({ data });
- ;
setIsLoading(false);
if (isSuccess?.id) {
for (const product of products) deleteItemCart({ productId: product.id });
@@ -298,7 +300,7 @@ const { setRefreshCart } = useProductCartContext();
setRefreshCart(true);
return;
}
-
+
toast.error('Gagal melakukan transaksi, terjadi kesalahan internal');
};
@@ -455,25 +457,26 @@ const { setRefreshCart } = useProductCartContext();
</Link>{' '}
yang berlaku
</p>
- <hr className='my-4 border-gray_r-6' />
-
- <div className='flex gap-x-2 justify-start mb-4'>
- <div className=''>Note</div>
- {isApproval && (
- <div className='text-caption-1 text-red-500 items-center flex'>*harus diisi</div>
- )}
- </div>
- <div className='text-caption-2 text-gray_r-11'>
- <textarea
- rows="4"
- cols="50"
- className={`w-full p-1 rounded border border-gray_r-6`}
- onChange={(e) => setselectedNote_websiteText(e.target.value)}
- />
- </div>
+ <hr className='my-4 border-gray_r-6' />
+
+ <div className='flex gap-x-2 justify-start mb-4'>
+ <div className=''>Note</div>
+ {isApproval && (
+ <div className='text-caption-1 text-red-500 items-center flex'>
+ *harus diisi
+ </div>
+ )}
+ </div>
+ <div className='text-caption-2 text-gray_r-11'>
+ <textarea
+ rows='4'
+ cols='50'
+ className={`w-full p-1 rounded border border-gray_r-6`}
+ onChange={(e) => setselectedNote_websiteText(e.target.value)}
+ />
+ </div>
</div>
-
-
+
<Divider />
<div className='flex gap-x-3 p-4'>
@@ -606,27 +609,31 @@ const { setRefreshCart } = useProductCartContext();
yang berlaku
</p>
- <div>
- <hr className='my-4 border-gray_r-6' />
-
- <div className='flex gap-x-1 flex-col mb-4'>
- <div className='flex flex-row gap-x-1'>
- <div className=''>Note</div>
- {isApproval && (
- <div className='text-caption-1 text-red-500 items-center flex'>*harus diisi</div>
- )}
- </div>
- <div className='text-caption-2 text-gray_r-11'>
- <textarea
- rows="4"
- cols="50"
- className={`w-full p-1 rounded border border-gray_r-6`}
- onChange={(e) => setselectedNote_websiteText(e.target.value)}
- />
- </div>
+ <div>
+ <hr className='my-4 border-gray_r-6' />
+
+ <div className='flex gap-x-1 flex-col mb-4'>
+ <div className='flex flex-row gap-x-1'>
+ <div className=''>Note</div>
+ {isApproval && (
+ <div className='text-caption-1 text-red-500 items-center flex'>
+ *harus diisi
+ </div>
+ )}
+ </div>
+ <div className='text-caption-2 text-gray_r-11'>
+ <textarea
+ rows='4'
+ cols='50'
+ className={`w-full p-1 rounded border border-gray_r-6`}
+ onChange={(e) =>
+ setselectedNote_websiteText(e.target.value)
+ }
+ />
</div>
</div>
-
+ </div>
+
<hr className='my-4 border-gray_r-6' />
<button
diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx
index 4529c977..d94a55de 100644
--- a/src/lib/quotation/components/Quotationheader.jsx
+++ b/src/lib/quotation/components/Quotationheader.jsx
@@ -19,14 +19,22 @@ const Quotationheader = (quotationCount) => {
context: 'quotation',
site: auth?.webRole === null && auth?.site ? auth.site : null,
};
-
+
const router = useRouter();
const [subTotal, setSubTotal] = useState(null);
const [buttonLoading, SetButtonTerapkan] = useState(false);
const itemLoading = [1, 2, 3];
const [countQuotation, setCountQuotation] = useState(null);
- const { productCart, setProductCart, refreshCart, setRefreshCart, isLoading, setIsloading, productQuotation, setProductQuotation } =
- useProductCartContext();
+ const {
+ productCart,
+ setProductCart,
+ refreshCart,
+ setRefreshCart,
+ isLoading,
+ setIsloading,
+ productQuotation,
+ setProductQuotation,
+ } = useProductCartContext();
const [isHovered, setIsHovered] = useState(false);
const [isTop, setIsTop] = useState(true);
@@ -53,30 +61,36 @@ const Quotationheader = (quotationCount) => {
const refreshCartf = useCallback(async () => {
setIsloading(true);
- let pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft');
+ let pendingTransactions = transactions?.data?.saleOrders.filter(
+ (transaction) => transaction.status === 'draft'
+ );
setProductQuotation(pendingTransactions);
- setCountQuotation(pendingTransactions?.length ? pendingTransactions?.length : pendingTransactions?.length);
+ setCountQuotation(
+ pendingTransactions?.length
+ ? pendingTransactions?.length
+ : pendingTransactions?.length
+ );
setIsloading(false);
}, [setProductQuotation, setIsloading]);
useEffect(() => {
- if (!qotation) return
+ if (!qotation) return;
- let calculateTotalDiscountAmount = 0
+ let calculateTotalDiscountAmount = 0;
for (const product of qotation) {
- // if (qotation.quantity == '') continue
- calculateTotalDiscountAmount += product.amountUntaxed
+ // if (qotation.quantity == '') continue
+ calculateTotalDiscountAmount += product.amountUntaxed;
}
- let subTotal = calculateTotalDiscountAmount
- setSubTotal(subTotal)
- }, [qotation])
+ let subTotal = calculateTotalDiscountAmount;
+ setSubTotal(subTotal);
+ }, [qotation]);
useEffect(() => {
if (refreshCart) {
refreshCartf();
}
setRefreshCart(false);
- }, [ refreshCartf, setRefreshCart]);
+ }, [refreshCartf, setRefreshCart]);
useEffect(() => {
setCountQuotation(quotationCount.quotationCount);
@@ -95,7 +109,10 @@ const Quotationheader = (quotationCount) => {
const handleCheckout = async () => {
SetButtonTerapkan(true);
- let checkoutAll = await odooApi('POST', `/api/v1/user/${auth.id}/cart/select-all`);
+ let checkoutAll = await odooApi(
+ 'POST',
+ `/api/v1/user/${auth.id}/cart/select-all`
+ );
router.push('/my/quotations');
};
@@ -150,7 +167,9 @@ const Quotationheader = (quotationCount) => {
className='w-full max-w-md p-2 bg-white border border-gray-200 rounded-lg shadow overflow-hidden'
>
<div className='p-2 flex justify-between items-center'>
- <h5 className='text-base font-semibold leading-none'>Daftar Quotation</h5>
+ <h5 className='text-base font-semibold leading-none'>
+ Daftar Quotation
+ </h5>
</div>
<hr className='mt-3 mb-3 border border-gray-100' />
<div className='flow-root max-h-[250px] overflow-y-auto'>
@@ -158,7 +177,10 @@ const Quotationheader = (quotationCount) => {
<div className='justify-center p-4'>
<p className='text-gray-500 text-center '>
Silahkan{' '}
- <Link href='/login' className='text-red-600 underline leading-6'>
+ <Link
+ href='/login'
+ className='text-red-600 underline leading-6'
+ >
Login
</Link>{' '}
Untuk Melihat Daftar Quotation Anda
@@ -167,7 +189,11 @@ const Quotationheader = (quotationCount) => {
)}
{isLoading &&
itemLoading.map((item) => (
- <div key={item} role='status' className='max-w-sm animate-pulse'>
+ <div
+ key={item}
+ role='status'
+ className='max-w-sm animate-pulse'
+ >
<div className='flex items-center space-x-4 mb- 2'>
<div className='flex-shrink-0'>
<PhotoIcon className='h-16 w-16 text-gray-500' />
@@ -189,43 +215,70 @@ const Quotationheader = (quotationCount) => {
)}
{auth && qotation.length > 0 && !isLoading && (
<>
- <ul role='list' className='divide-y divide-gray-200 dark:divide-gray-700'>
+ <ul
+ role='list'
+ className='divide-y divide-gray-200 dark:divide-gray-700'
+ >
{qotation &&
qotation?.map((product, index) => (
<>
<li className='py-1 sm:py-2'>
<div className='flex justify-between border p-2 flex-col gap-y-2 hover:border-red-500'>
- <Link
+ <Link
href={`/my/quotations/${product?.id}`}
- className='hover:border-red-500'
- >
+ className='hover:border-red-500'
+ >
<div className='flex justify-between mb-2'>
<div className='flex flex-row items-center'>
- <p className='tanggal text-xs opacity-80 mr-[2px]'>Sales : </p>
- <p className='tanggal text-xs text-red-500 font-semibold'>{product.sales}</p>
+ <p className='tanggal text-xs opacity-80 mr-[2px]'>
+ Sales :{' '}
+ </p>
+ <p className='tanggal text-xs text-red-500 font-semibold'>
+ {product.sales}
+ </p>
</div>
<div className='flex flex-row items-center'>
- <p className='text-xs opacity-80 mr-[2px]'>Status :</p>
- <p className='badge-red h-fit text-xs whitespace-nowrap'>Pending Quotation</p>
+ <p className='text-xs opacity-80 mr-[2px]'>
+ Status :
+ </p>
+ <p className='badge-red h-fit text-xs whitespace-nowrap'>
+ Pending Quotation
+ </p>
</div>
</div>
<div className='flex justify-between mb-2'>
<div className='flex flex-col items-start'>
- <p className=' text-xs opacity-80 mr-[2px]'>No. Transaksi</p>
- <p className=' text-sm text-red-500 font-semibold'> {product.name}</p>
+ <p className=' text-xs opacity-80 mr-[2px]'>
+ No. Transaksi
+ </p>
+ <p className=' text-sm text-red-500 font-semibold'>
+ {' '}
+ {product.name}
+ </p>
</div>
<div className='flex flex-col items-end'>
- <p className='text-xs opacity-80 mr-[2px]'>No. Purchase Order</p>
- <p className='font-semibold text-sm text-red-500'> {product.purchaseOrderName ? product.purchaseOrderName : '-'}</p>
+ <p className='text-xs opacity-80 mr-[2px]'>
+ No. Purchase Order
+ </p>
+ <p className='font-semibold text-sm text-red-500'>
+ {' '}
+ {product.purchaseOrderName
+ ? product.purchaseOrderName
+ : '-'}
+ </p>
</div>
</div>
{/* <div className='my-0.5 h-0.5 bg-gray-200'></div> */}
<hr className='mt-3 mb-3 border border-gray-100' />
<div className='bagian bawah flex justify-between mt-2'>
- <p className='font-semibold text-sm'>Total</p>
- <p className='font-semibold text-sm'>{currencyFormat(product.amountUntaxed)}</p>
+ <p className='font-semibold text-sm'>
+ Total
+ </p>
+ <p className='font-semibold text-sm'>
+ {currencyFormat(product.amountUntaxed)}
+ </p>
</div>
- </Link>
+ </Link>
</div>
</li>
</>
@@ -238,8 +291,12 @@ const Quotationheader = (quotationCount) => {
{auth && qotation.length > 0 && !isLoading && (
<>
<div className='mt-3 ml-1'>
- <span className='text-gray-400 text-caption-2'>Subtotal Sebelum PPN : </span>
- <span className='font-semibold text-red-600'>{currencyFormat(subTotal)}</span>
+ <span className='text-gray-400 text-caption-2'>
+ Subtotal Sebelum PPN :{' '}
+ </span>
+ <span className='font-semibold text-red-600'>
+ {currencyFormat(subTotal)}
+ </span>
</div>
<div className='mt-5 mb-2'>
<button
diff --git a/src/lib/review/components/CustomerReviews.jsx b/src/lib/review/components/CustomerReviews.jsx
index 7cad52fb..a6e697f0 100644
--- a/src/lib/review/components/CustomerReviews.jsx
+++ b/src/lib/review/components/CustomerReviews.jsx
@@ -1,18 +1,23 @@
-import DesktopView from '@/core/components/views/DesktopView'
-import MobileView from '@/core/components/views/MobileView'
-import Image from 'next/image'
-import { Swiper, SwiperSlide } from 'swiper/react'
-import { Autoplay } from 'swiper'
+import DesktopView from '@/core/components/views/DesktopView';
+import MobileView from '@/core/components/views/MobileView';
+import Image from 'next/image';
+import { Swiper, SwiperSlide } from 'swiper/react';
+import { Autoplay } from 'swiper';
-const { useQuery } = require('react-query')
-const { getCustomerReviews } = require('../api/customerReviewsApi')
+const { useQuery } = require('react-query');
+const { getCustomerReviews } = require('../api/customerReviewsApi');
const CustomerReviews = () => {
- const { data: customerReviews } = useQuery('customerReviews', getCustomerReviews)
+ const { data: customerReviews } = useQuery(
+ 'customerReviews',
+ getCustomerReviews
+ );
return (
<div className='px-4 sm:px-0'>
- <div className='font-semibold sm:text-h-lg mb-4'>Ulasan Konsumen Kami</div>
+ <h1 className='font-semibold text-[14px] sm:text-h-lg mb-4'>
+ Ulasan Konsumen Kami
+ </h1>
<DesktopView>
<Swiper slidesPerView={3.2} spaceBetween={16} {...swiperProps}>
@@ -36,17 +41,17 @@ const CustomerReviews = () => {
</Swiper>
</MobileView>
</div>
- )
-}
+ );
+};
const swiperProps = {
autoplay: {
delay: 6000,
- disableOnInteraction: false
+ disableOnInteraction: false,
},
loop: true,
- modules: [Autoplay]
-}
+ modules: [Autoplay],
+};
const Card = ({ customerReview }) => (
<div className='bg-gray-200 rounded-md px-5 py-6 shadow-md shadow-gray-500/20 h-full'>
@@ -67,6 +72,6 @@ const Card = ({ customerReview }) => (
dangerouslySetInnerHTML={{ __html: customerReview.ulasan }}
/>
</div>
-)
+);
-export default CustomerReviews
+export default CustomerReviews;
diff --git a/src/lib/tracking-order/component/TrackingOrder.jsx b/src/lib/tracking-order/component/TrackingOrder.jsx
index 394979c1..8a7b2579 100644
--- a/src/lib/tracking-order/component/TrackingOrder.jsx
+++ b/src/lib/tracking-order/component/TrackingOrder.jsx
@@ -1,139 +1,161 @@
-import { yupResolver } from '@hookform/resolvers/yup'
-import React, { useEffect, useState } from 'react'
-import { useForm } from 'react-hook-form'
-import * as Yup from 'yup'
-import Manifest from '@/lib/treckingAwb/component/Manifest'
-import { trackingOrder } from '../api/trackingOrder'
-import { useQuery } from 'react-query'
+import { yupResolver } from '@hookform/resolvers/yup';
+import React, { useEffect, useState } from 'react';
+import { useForm } from 'react-hook-form';
+import * as Yup from 'yup';
+import Manifest from '@/lib/treckingAwb/component/Manifest';
+import { trackingOrder } from '../api/trackingOrder';
+import { useQuery } from 'react-query';
import { Spinner } from '@chakra-ui/react';
import { Search } from 'lucide-react';
-import whatsappUrl from '@/core/utils/whatsappUrl';
-import Link from 'next/link'
+import Link from 'next/link';
const TrackingOrder = () => {
- const [idAWB, setIdAWB] = useState(null)
- const [inputQuery, setInputQuery] = useState(null)
- const [buttonClick, setButtonClick] = useState(false)
- const [apiError, setApiError] = useState(null) // State to store API error message
-
- const closePopup = () => {
- setIdAWB(null)
- setButtonClick(false)
- setInputQuery(null)
- setApiError(null) // Reset error message on close
- }
-
- const {
- register,
- handleSubmit,
- formState: { errors },
- control,
- reset
- } = useForm({
- resolver: yupResolver(validationSchema),
- defaultValues
- })
-
- const query = {
- email: inputQuery?.email,
- so: inputQuery?.id
- }
-
- const { data: tracking, isLoading, isError, error } = useQuery(
- ['tracking', query],
- () => trackingOrder({ query: query }),
- {
- enabled: !!query.email && !!query.so,
- onSuccess: (data) => {
- if (buttonClick) {
- if (data?.code === 403 || data?.code === 400 || data?.code === 404) {
- setApiError(data?.description);
- } else if (data?.pickings?.length > 0) {
- setIdAWB(data.pickings[0]?.id);
- } else {
- setApiError('No pickings data available');
- }
- setButtonClick(false);
- setInputQuery(null);
- }
- },
+ const [idAWB, setIdAWB] = useState(null);
+ const [inputQuery, setInputQuery] = useState(null);
+ const [buttonClick, setButtonClick] = useState(false);
+ const [apiError, setApiError] = useState(null); // State to store API error message
+
+ const closePopup = () => {
+ setIdAWB(null);
+ setButtonClick(false);
+ setInputQuery(null);
+ setApiError(null); // Reset error message on close
+ };
+
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ control,
+ reset,
+ } = useForm({
+ resolver: yupResolver(validationSchema),
+ defaultValues,
+ });
+
+ const query = {
+ email: inputQuery?.email,
+ so: inputQuery?.id,
+ };
+
+ const {
+ data: tracking,
+ isLoading,
+ isError,
+ error,
+ } = useQuery(['tracking', query], () => trackingOrder({ query: query }), {
+ enabled: !!query.email && !!query.so,
+ onSuccess: (data) => {
+ if (buttonClick) {
+ if (data?.code === 403 || data?.code === 400 || data?.code === 404) {
+ setApiError(data?.description);
+ } else if (data?.pickings?.length > 0) {
+ setIdAWB(data.pickings[0]?.id);
+ } else {
+ setApiError('No pickings data available');
}
- );
+ setButtonClick(false);
+ setInputQuery(null);
+ }
+ },
+ });
- const onSubmitHandler = async (values) => {
- setInputQuery(values)
- setButtonClick(true)
- }
+ const onSubmitHandler = async (values) => {
+ setInputQuery(values);
+ setButtonClick(true);
+ };
- return (
- <div className='container mx-auto flex py-10 flex-col'>
- <h1 className='text-h-sm md:text-title-sm font-semibold mb-6'>Tracking Order</h1>
- <div className='flex justify-start items-start'>
- <span className='text-base w-full'>
- {`Untuk melacak pesanan Anda, masukkan Nomor Transaksi di kotak bawah ini dan masukkan Email login anda lalu tekan tombol "Lacak". Nomor Transaksi ini dapat Anda lihat dalam menu `}
- <Link href='/my/transactions' className='text-red-500'>
- Daftar Transaksi
- </Link>
- {`. Jika mengalami kesulitan `}
- <Link href='https://wa.me/6281717181922' target='_blank' rel='noreferrer' className='text-red-500'>
- hubungi kami
- </Link>
- {`.`}
- </span>
+ return (
+ <div className='container mx-auto flex py-10 flex-col'>
+ <h1 className='text-h-sm md:text-title-sm font-semibold mb-6'>
+ Tracking Order
+ </h1>
+ <div className='flex justify-start items-start'>
+ <p className='text-base w-full'>
+ {`Untuk melacak pesanan Anda, masukkan Nomor Transaksi di kotak bawah ini dan masukkan Email login anda lalu tekan tombol "Lacak". Nomor Transaksi ini dapat Anda lihat dalam menu `}
+ <Link href='/my/transactions' className='text-red-500'>
+ Daftar Transaksi
+ </Link>
+ {`. Jika mengalami kesulitan `}
+ <Link
+ href='https://wa.me/6281717181922'
+ target='_blank'
+ rel='noreferrer'
+ className='text-red-500'
+ >
+ hubungi kami
+ </Link>
+ {`.`}
+ </p>
+ </div>
+ <div>
+ <form
+ onSubmit={handleSubmit(onSubmitHandler)}
+ className='flex mt-4 flex-row w-full '
+ >
+ <div className='w-[90%] grid grid-cols-2 gap-4'>
+ <div className='flex flex-col '>
+ <label className='form-label mb-2'>ID Pesanan*</label>
+ <input
+ {...register('id')}
+ placeholder='dapat dilihat pada email konfirmasi anda'
+ type='text'
+ className='form-input mb-2'
+ aria-invalid={errors.id?.message}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.id?.message}
+ </div>
</div>
- <div>
- <form onSubmit={handleSubmit(onSubmitHandler)} className='flex mt-4 flex-row w-full '>
- <div className='w-[90%] grid grid-cols-2 gap-4'>
- <div className='flex flex-col '>
- <label className='form-label mb-2'>ID Pesanan*</label>
- <input
- {...register('id')}
- placeholder='dapat dilihat pada email konfirmasi anda'
- type='text'
- className='form-input mb-2'
- aria-invalid={errors.id?.message}
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.id?.message}</div>
- </div>
- <div className='flex flex-col '>
- <label className='form-label mb-2'>Email Penagihan*</label>
- <input
- {...register('email')}
- placeholder='Email yang anda gunakan saat pembayaran'
- type='text'
- className='form-input'
- aria-invalid={errors.email?.message}
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.email?.message}</div>
- </div>
- </div>
- <div className={` ${errors.id?.message ? 'mt-2' : 'mt-5'} flex items-center ml-4`}>
- <button
- type='submit'
- className='bg-red-600 border border-red-600 rounded-md text-sm text-white w-24 h-11 mb-1 content-center flex flex-row justify-center items-center'
- >
- {isLoading && <Spinner size='xs' className='mr-2'/>}
- {!isLoading && <Search size={16} strokeWidth={1} className='mr-2'/>}
- <p>Lacak</p>
- </button>
- </div>
- </form>
- {/* Display the API error message */}
- {apiError && <div className='text-danger-500 mt-4'>{apiError}</div>}
- <Manifest idAWB={idAWB} closePopup={closePopup} />
+ <div className='flex flex-col '>
+ <label className='form-label mb-2'>Email Penagihan*</label>
+ <input
+ {...register('email')}
+ placeholder='Email yang anda gunakan saat pembayaran'
+ type='text'
+ className='form-input'
+ aria-invalid={errors.email?.message}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.email?.message}
+ </div>
</div>
- </div>
- )
-}
+ </div>
+ <div
+ className={` ${
+ errors.id?.message ? 'mt-2' : 'mt-5'
+ } flex items-center ml-4`}
+ >
+ <button
+ type='submit'
+ className='bg-red-600 border border-red-600 rounded-md text-sm text-white w-24 h-11 mb-1 content-center flex flex-row justify-center items-center'
+ >
+ {isLoading && <Spinner size='xs' className='mr-2' />}
+ {!isLoading && (
+ <Search size={16} strokeWidth={1} className='mr-2' />
+ )}
+ <p>Lacak</p>
+ </button>
+ </div>
+ </form>
+ {/* Display the API error message */}
+ {apiError && <div className='text-danger-500 mt-4'>{apiError}</div>}
+ <Manifest idAWB={idAWB} closePopup={closePopup} />
+ </div>
+ </div>
+ );
+};
const validationSchema = Yup.object().shape({
- email: Yup.string().email('Format harus seperti contoh@email.com').required('Harus di-isi'),
- id: Yup.string().required('Harus di-isi'),
-})
+ email: Yup.string()
+ .email('Format harus seperti contoh@email.com')
+ .required('Harus di-isi'),
+ id: Yup.string().required('Harus di-isi'),
+});
const defaultValues = {
- email: '',
- id: ''
-}
+ email: '',
+ id: '',
+};
-export default TrackingOrder
+export default TrackingOrder;
diff --git a/src/lib/transaction/api/transactionsApi.js b/src/lib/transaction/api/transactionsApi.js
index f4e36e6f..5ea2b5b0 100644
--- a/src/lib/transaction/api/transactionsApi.js
+++ b/src/lib/transaction/api/transactionsApi.js
@@ -3,6 +3,9 @@ import { getAuth } from '@/core/utils/auth'
const transactionsApi = async ({ query }) => {
const auth = getAuth()
+ if (!auth) {
+ return null
+ }
const dataTransactions = await odooApi(
'GET',
`/api/v1/partner/${auth.partnerId}/sale_order?${query}`