summaryrefslogtreecommitdiff
path: root/src/lib/checkout/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/checkout/components')
-rw-r--r--src/lib/checkout/components/Checkout.jsx107
-rw-r--r--src/lib/checkout/components/FinishCheckout.jsx19
-rw-r--r--src/lib/checkout/components/SectionExpedition.jsx152
-rw-r--r--src/lib/checkout/components/SectionQuotationExpedition.jsx19
4 files changed, 171 insertions, 126 deletions
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index d8ede118..6cda069c 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -55,7 +55,9 @@ function convertToInternational(number) {
}
const Checkout = () => {
- const PPN = process.env.NEXT_PUBLIC_PPN ? parseFloat(process.env.NEXT_PUBLIC_PPN) : 0;
+ const PPN = process.env.NEXT_PUBLIC_PPN
+ ? parseFloat(process.env.NEXT_PUBLIC_PPN)
+ : 0;
const router = useRouter();
const query = router.query.source ?? null;
const qVoucher = router.query.voucher ?? null;
@@ -172,7 +174,7 @@ const Checkout = () => {
selectedService,
listExpedisi,
setExpedisi,
- productSla
+ productSla,
} = useCheckout();
const expedisiValidation = useRef(null);
@@ -184,7 +186,7 @@ const Checkout = () => {
let dataVoucher = await getVoucher(auth?.id, {
source: query,
type: 'all,brand',
- partner_id : auth?.partnerId,
+ partner_id: auth?.partnerId,
});
SetListVoucher(dataVoucher);
@@ -210,7 +212,6 @@ const Checkout = () => {
return;
}
-
dataVoucher.forEach((addNewLine) => {
if (addNewLine.applyType !== 'shipping') {
// Mencari voucher dalam listVouchers
@@ -374,17 +375,21 @@ const Checkout = () => {
}
return;
}
- if (selectedCourierId !== SELF_PICKUP_ID) { // Menggunakan selectedCourierId karena lebih spesifik dan numerik
- if (!selectedService) { // Jika kurir bukan Self Pickup, maka harus ada layanan yang dipilih
- toast.error('Harap pilih tipe layanan pengiriman');
- return;
- }
- // Validasi biaya kirim hanya untuk kurir selain Self Pickup (dan ID kurir 1 jika itu kasus khusus)
- // Jika selectedCourierId adalah 1 (misalnya kurir internal yang bisa gratis), lewati validasi biayaKirim 0
- if (selectedCourierId !== 1 && biayaKirim === 0) {
- toast.error('Maaf, layanan tidak tersedia untuk ekspedisi ini. Mohon pilih ekspedisi lain atau layanan lain.');
- return;
- }
+ if (selectedCourierId !== SELF_PICKUP_ID) {
+ // Menggunakan selectedCourierId karena lebih spesifik dan numerik
+ if (!selectedService) {
+ // Jika kurir bukan Self Pickup, maka harus ada layanan yang dipilih
+ toast.error('Harap pilih tipe layanan pengiriman');
+ return;
+ }
+ // Validasi biaya kirim hanya untuk kurir selain Self Pickup (dan ID kurir 1 jika itu kasus khusus)
+ // Jika selectedCourierId adalah 1 (misalnya kurir internal yang bisa gratis), lewati validasi biayaKirim 0
+ if (selectedCourierId !== 1 && biayaKirim === 0) {
+ toast.error(
+ 'Maaf, layanan tidak tersedia untuk ekspedisi ini. Mohon pilih ekspedisi lain atau layanan lain.'
+ );
+ return;
+ }
}
setIsLoading(true);
const productOrder = products.map((product) => ({
@@ -415,7 +420,8 @@ const Checkout = () => {
order_line: JSON.stringify(productOrder),
delivery_amount: biayaKirim,
carrier_id: selectedCourierId,
- estimated_arrival_days_start : parseInt(eta_courier_start) + parseInt(productSla),
+ estimated_arrival_days_start:
+ parseInt(eta_courier_start) + parseInt(productSla),
estimated_arrival_days: parseInt(eta_courier) + parseInt(productSla),
delivery_service_type: selectedService?.service_type,
flash_sale: hasFlashSale, // dibuat negasi untuk ngetest kebalikan nilai false
@@ -430,8 +436,8 @@ const Checkout = () => {
if (typeof file == 'undefined') {
toast.error(
'Nomor PO ' +
- poNumber.current.value +
- ' telah dimasukkan, Harap upload file PO yang dimaksud'
+ poNumber.current.value +
+ ' telah dimasukkan, Harap upload file PO yang dimaksud'
);
setIsLoading(false);
return;
@@ -1019,10 +1025,10 @@ const Checkout = () => {
</div>
)}
- {selectedCarrierId == SELF_PICKUP_ID && (
+ {selectedCourierId == SELF_PICKUP_ID && (
<PickupAddress label='Alamat Pickup' />
)}
- {selectedCarrierId != SELF_PICKUP_ID && (
+ {selectedCourierId != SELF_PICKUP_ID && (
<Skeleton
isLoaded={!!selectedAddress.invoicing && !!selectedAddress.shipping}
minHeight={320}
@@ -1137,7 +1143,9 @@ const Checkout = () => {
<div>{currencyFormat(cartCheckout?.subtotal)}</div>
</div>
<div className='flex gap-x-2 justify-between'>
- <div className='text-gray_r-11'>PPN {((PPN - 1) * 100).toFixed(0)}%</div>
+ <div className='text-gray_r-11'>
+ PPN {((PPN - 1) * 100).toFixed(0)}%
+ </div>
<div>{currencyFormat(cartCheckout?.tax)}</div>
</div>
<div className='flex gap-x-2 justify-between'>
@@ -1269,10 +1277,7 @@ const Checkout = () => {
className='flex-1 btn-yellow'
onClick={checkout}
disabled={
- !products ||
- products?.length == 0 ||
- priceCheck ||
- hasNoPrice
+ !products || products?.length == 0 || priceCheck || hasNoPrice || isLoading
}
>
{isLoading ? 'Loading...' : 'Lanjut Pembayaran'}
@@ -1317,16 +1322,11 @@ const Checkout = () => {
<div className='flex'>
{' '}
<div className='w-3/4 border border-gray_r-6 rounded bg-white'>
- {selectedCarrierId == SELF_PICKUP_ID && (
+ {selectedCourierId == SELF_PICKUP_ID && (
<PickupAddress label='Alamat Pickup' />
)}
- {selectedCarrierId != SELF_PICKUP_ID && (
- <Skeleton
- isLoaded={
- !!selectedAddress.invoicing && !!selectedAddress.shipping
- }
- minHeight={290}
- >
+ {selectedCourierId != SELF_PICKUP_ID && (
+ <Skeleton isLoaded minHeight={290}>
<SectionAddress
address={selectedAddress.shipping}
label='Alamat Pengiriman'
@@ -1444,7 +1444,9 @@ const Checkout = () => {
<div>{currencyFormat(cartCheckout?.subtotal)}</div>
</div>
<div className='flex gap-x-2 justify-between'>
- <div className='text-gray_r-11'>PPN {((PPN - 1) * 100).toFixed(0)}%</div>
+ <div className='text-gray_r-11'>
+ PPN {((PPN - 1) * 100).toFixed(0)}%
+ </div>
<div>{currencyFormat(cartCheckout?.tax)}</div>
</div>
<div className='flex gap-x-2 justify-between'>
@@ -1577,7 +1579,8 @@ const Checkout = () => {
!products ||
products?.length == 0 ||
priceCheck ||
- hasNoPrice
+ hasNoPrice ||
+ isLoading
}
>
{isLoading ? 'Loading...' : 'Lanjut Pembayaran'}
@@ -1633,8 +1636,14 @@ const SectionAddress = ({ address, label, url }) => (
{address.addressMap ? (
<label>Sudah Pinpoint</label>
) : (
- <Link href={'/my/address/' + address.id + '/edit'} target='_blank' className='cursor-pointer'>
- <label className='text-red-500 cursor-pointer '>Belum Pinpoint</label>
+ <Link
+ href={'/my/address/' + address.id + '/edit'}
+ target='_blank'
+ className='cursor-pointer'
+ >
+ <label className='text-red-500 cursor-pointer '>
+ Belum Pinpoint
+ </label>
</Link>
)}
</div>
@@ -1644,7 +1653,7 @@ const SectionAddress = ({ address, label, url }) => (
);
const SectionValidation = ({ address }) =>
- address?.stateId == 0 && (
+ address?.stateId === 0 && (
<BottomPopup active={true} title='Update Alamat'>
<div className='leading-7 text-gray_r-12/80'>
Mohon untuk memperbarui alamat Anda dengan mengklik tombol di bawah ini.{' '}
@@ -1661,14 +1670,14 @@ const SectionValidation = ({ address }) =>
);
const SectionExpedisi = ({
- address,
- listExpedisi,
- setSelectedExpedisi,
- checkWeigth,
- checkoutValidation,
- expedisiValidation,
- loadingRajaOngkir,
- }) =>
+ address,
+ listExpedisi,
+ setSelectedExpedisi,
+ checkWeigth,
+ checkoutValidation,
+ expedisiValidation,
+ loadingRajaOngkir,
+}) =>
address?.rajaongkirCityId > 0 && (
<div className='p-4' ref={expedisiValidation}>
<div className='flex justify-between items-center'>
@@ -1720,9 +1729,9 @@ const SectionExpedisi = ({
)}
</div>
<style jsx>{`
- .shake {
- animation: shake 0.4s ease-in-out;
- }
+ .shake {
+ animation: shake 0.4s ease-in-out;
+ }
`}</style>
</div>
{checkWeigth == true && (
diff --git a/src/lib/checkout/components/FinishCheckout.jsx b/src/lib/checkout/components/FinishCheckout.jsx
index d533325e..51837a59 100644
--- a/src/lib/checkout/components/FinishCheckout.jsx
+++ b/src/lib/checkout/components/FinishCheckout.jsx
@@ -55,12 +55,21 @@ const FinishCheckout = ({ query }) => {
<div className='text-title-sm md:text-title-lg text-center font-semibold'>
Terima Kasih atas Pembelian di Indoteknik.com
</div>
- <p className='text-title-sm md:text-title-lg font-semibold my-2'>No. Transaksi: <span className='text-red-500'>{query?.order_id?.replaceAll('-', '/')}</span></p>
+ <p className='text-title-sm md:text-title-lg font-semibold my-2'>
+ No. Transaksi:{' '}
+ <span className='text-red-500'>
+ {query?.order_id?.replaceAll('-', '/')}
+ </span>
+ </p>
<div className='flex flex-col justify-center items-center text-body-2 md:text-body-1 text-center mt-3 px-24 md:px-36 py-4 border-2 gap-y-2 rounded'>
- <p className="text-title-sm md:text-title-xl text-gray-500 mt-1">Estimasi Barang Siap pada Tanggal</p>
- <p className="text-title-sm md:text-title-xl text-red-500 font-semibold my-2">{data?.expectedReadyToShip}</p>
+ <p className='text-title-sm md:text-title-xl text-gray-500 mt-1'>
+ Estimasi Barang Siap pada Tanggal
+ </p>
+ <p className='text-title-sm md:text-title-xl text-red-500 font-semibold my-2'>
+ {data?.expectedReadyToShip}
+ </p>
<Link
- href={`/my/quotations/${data?.id}`}
+ href={`/my/transactions/${data?.id}`}
className='btn-solid-red rounded-md text-base'
>
Cek Detail Transaksi
@@ -74,7 +83,7 @@ const FinishCheckout = ({ query }) => {
</a>{' '}
atau{' '}
<span onClick={sendEmail} className='text-red-500 cursor-pointer'>
- kirim rincian pesanan ulang
+ Kirim ulang rincian pesanan ke Email anda.
</span>
.
</div>
diff --git a/src/lib/checkout/components/SectionExpedition.jsx b/src/lib/checkout/components/SectionExpedition.jsx
index 2e92ffbc..66182589 100644
--- a/src/lib/checkout/components/SectionExpedition.jsx
+++ b/src/lib/checkout/components/SectionExpedition.jsx
@@ -18,7 +18,7 @@ import { getProductsSla } from '../api/checkoutApi';
function mappingItems(products) {
return products?.map((item) => ({
// name: item.parent.name || item?.name || 'Unknown Product',
- name: item?.name,
+ name: item?.name,
description: `${item.code} - ${item.name}`,
value: item.price.priceDiscount,
weight: item.weight * 1000,
@@ -27,61 +27,71 @@ function mappingItems(products) {
}
function reverseMappingCourier(couriersOdoo, couriers, includeInstant = false) {
- // Buat peta courier berdasarkan nama courier dari couriers
+ // Bangun peta dari hasil Biteship (pakai dua key: code & name)
const courierMap = couriers.reduce((acc, item) => {
- const { courier_name, courier_code, courier_service_code } = item;
- const key = courier_code.toLowerCase();
-
- if (
- !includeInstant && (['hours'].includes(item.shipment_duration_unit.toLowerCase()) || item.service_type == 'same_day')
-
- ) {
- return acc;
- }
+ const codeKey = (item.courier_code || '').toLowerCase();
+ const nameKey = (item.courier_name || '').toLowerCase();
+
+ const isInstant =
+ (item.shipment_duration_unit || '').toLowerCase() === 'hours' ||
+ (item.service_type || '').toLowerCase() === 'same_day';
+ if (!includeInstant && isInstant) return acc;
+
+ const ensureEntry = (key) => {
+ if (!key) return;
+ if (!acc[key]) {
+ acc[key] = {
+ courier_name: item.courier_name,
+ courier_code: item.courier_code,
+ service_type: {},
+ };
+ }
+ };
- if (!acc[key]) {
- acc[key] = {
- courier_name: item.courier_name,
- courier_code: courier_code,
- service_type: {},
- };
- }
+ ensureEntry(codeKey);
+ ensureEntry(nameKey);
- acc[key].service_type[courier_service_code] = {
+ const svc = {
service_name: item.courier_service_name,
duration: item.duration,
shipment_range: item.shipment_duration_range,
shipment_unit: item.shipment_duration_unit,
price: item.price,
- service_type: courier_service_code,
+ service_type: item.courier_service_code,
description: item.description,
};
+ if (codeKey && acc[codeKey]) {
+ acc[codeKey].service_type[item.courier_service_code] = svc;
+ }
+ if (nameKey && acc[nameKey]) {
+ acc[nameKey].service_type[item.courier_service_code] = svc;
+ }
return acc;
}, {});
- // Iterasi berdasarkan couriersOdoo
- return couriersOdoo.map((courierOdoo) => {
- const courierNameKey = courierOdoo.label.toLowerCase();
- const carrierId = courierOdoo.carrierId;
+ // Petakan Odoo ke map Biteship dan FILTER hanya yg punya layanan
+ return couriersOdoo
+ .map((courierOdoo) => {
+ const key = (courierOdoo.label || '').toLowerCase();
+ const matched = courierMap[key] || null;
- const mappedCourier = courierMap[courierNameKey] || false;
+ if (!matched) return { ...courierOdoo, courier: false };
- if (!mappedCourier) {
return {
...courierOdoo,
- courier: false,
+ courier: {
+ ...matched,
+ courier_id_odoo: courierOdoo.carrierId, // penting: simpan id Odoo di sini
+ },
};
- }
-
- return {
- ...courierOdoo,
- courier: {
- ...mappedCourier,
- courier_id_odoo: carrierId,
- },
- };
- });
+ })
+ .filter(
+ (x) =>
+ x.courier &&
+ x.courier.service_type &&
+ Object.keys(x.courier.service_type).length > 0
+ );
}
function mappingCourier(couriersOdoo, couriers, notIncludeInstant = false) {
@@ -214,7 +224,7 @@ export default function SectionExpedition({ products }) {
let data = {
products: JSON.stringify(productsMapped),
- }
+ };
const res = await odooApi('POST', `/api/v1/product/variants/sla`, data);
setSlaProducts(res);
} catch (error) {
@@ -328,13 +338,13 @@ export default function SectionExpedition({ products }) {
};
useEffect(() => {
- if (serviceOptions.length > 0) {
- setSavedServiceOptions(serviceOptions);
- }
-}, [serviceOptions]);
+ if (serviceOptions.length > 0) {
+ setSavedServiceOptions(serviceOptions);
+ }
+ }, [serviceOptions]);
return (
- <form >
+ <form>
<div className='px-4 py-2'>
<div className='flex justify-between items-center'>
<div className='font-medium'>Pilih Ekspedisi: </div>
@@ -371,27 +381,40 @@ export default function SectionExpedition({ products }) {
<p className='font-semibold'>SELF PICKUP</p>
</div>
</div>
- {couriers?.map((courier) => (
- <div
- key={courier?.courier?.courier_code}
- onClick={() => onCourierChange(courier)}
- className='flex justify-between p-2 items-center hover:bg-gray-100 cursor-pointer'
- >
- <div>
- <p className='font-semibold'>
- {courier?.label}
- </p>
+ {couriers
+ ?.map((c) => c) // sudah ter-filter di reverseMappingCourier, tapi aman buat double-check
+ .filter(
+ (c) =>
+ c.courier &&
+ Object.keys(c.courier.service_type).length > 0
+ )
+ .map((courier) => (
+ <div
+ key={
+ courier?.courier?.courier_code ||
+ courier?.label
+ }
+ onClick={() => onCourierChange(courier)}
+ className='flex justify-between p-2 items-center hover:bg-gray-100 cursor-pointer'
+ >
+ <div>
+ <p className='font-semibold'>
+ {courier?.label}
+ </p>
+ </div>
+ <span className='font-semibold'>
+ <Image
+ src={courier?.logo}
+ alt={
+ courier?.courier?.courier_name ||
+ courier?.label
+ }
+ width={50}
+ height={50}
+ />
+ </span>
</div>
- <span className='font-semibold'>
- <Image
- src={courier?.logo}
- alt={courier?.courier?.courier_name}
- width={50}
- height={50}
- />
- </span>
- </div>
- ))}
+ ))}
</>
) : (
<>
@@ -432,8 +455,7 @@ export default function SectionExpedition({ products }) {
)}
</div>
- {(serviceOptions.length > 0 ||
- selectedService )&&
+ {(serviceOptions.length > 0 || selectedService) &&
selectedCourier &&
selectedCourier !== 32 &&
selectedCourier !== 0 && (
diff --git a/src/lib/checkout/components/SectionQuotationExpedition.jsx b/src/lib/checkout/components/SectionQuotationExpedition.jsx
index b8ea04ef..817cd21b 100644
--- a/src/lib/checkout/components/SectionQuotationExpedition.jsx
+++ b/src/lib/checkout/components/SectionQuotationExpedition.jsx
@@ -239,7 +239,7 @@ export default function SectionExpeditionQuotation({ products }) {
<div className='px-4 py-2'>
<div className='flex justify-between items-center'>
<div className='font-medium'>Pilih Ekspedisi: </div>
- <div className='w-[350px]'>
+ <div className='relative w-[350px]'>
<div
className='w-full p-2 border rounded-lg bg-white cursor-pointer'
onClick={() => setOnFocuseSelectedCourier(!onFocusSelectedCourier)}
@@ -253,7 +253,10 @@ export default function SectionExpeditionQuotation({ products }) {
)}
</div>
{onFocusSelectedCourier && (
- <div className='absolute bg-white border rounded-lg mt-1 shadow-lg z-10 max-h-[200px] overflow-y-auto w-[350px]'>
+ <div
+ className='absolute left-0 top-full mt-1 bg-white border rounded-lg shadow-lg z-50
+ max-h-[200px] overflow-y-auto w-full sm:w-[350px]'
+ >
{!isLoading ? (
<>
<div
@@ -297,8 +300,8 @@ export default function SectionExpeditionQuotation({ products }) {
{checkWeigth && (
<p className='mt-4 text-gray-600'>
- Mohon maaf, pengiriman hanya tersedia untuk self pickup karena ada barang
- yang belum memiliki berat. Silakan hubungi admin via{' '}
+ Mohon maaf, pengiriman hanya tersedia untuk self pickup karena ada
+ barang yang belum memiliki berat. Silakan hubungi admin via{' '}
<a
className='text-blue-600 underline'
href='https://api.whatsapp.com/send?phone=6281717181922'
@@ -316,7 +319,7 @@ export default function SectionExpeditionQuotation({ products }) {
selectedCourier !== 0 && (
<div className='mt-4 flex justify-between'>
<div className='font-medium mb-2'>Tipe Layanan Ekspedisi:</div>
- <div className='relative w-[350px]'>
+ <div className='relative w-full sm:w-[350px]'>
<div
className='p-2 border rounded-lg bg-white cursor-pointer'
onClick={() => setIsOpen(!isOpen)}
@@ -331,11 +334,13 @@ export default function SectionExpeditionQuotation({ products }) {
</span>
</div>
) : (
- <span className='text-gray-500'>Pilih layanan pengiriman</span>
+ <span className='text-gray-500'>
+ Pilih layanan pengiriman
+ </span>
)}
</div>
{isOpen && (
- <div className='absolute bg-white border rounded-lg mt-1 shadow-lg z-10 w-full'>
+ <div className='absolute left-0 top-full mt-1 bg-white border rounded-lg shadow-lg z-50 w-full'>
{serviceOptions.map((service) => (
<div
key={service.service_type}