summaryrefslogtreecommitdiff
path: root/src/lib/quotation
diff options
context:
space:
mode:
authorIndoteknik . <andrifebriyadiputra@gmail.com>2025-08-16 14:46:48 +0700
committerIndoteknik . <andrifebriyadiputra@gmail.com>2025-08-16 14:46:48 +0700
commitc6b75363821e5c1153d8a9e2c1a4326568ab6026 (patch)
treed5940768d254d3aa6862c32012002d5274467227 /src/lib/quotation
parentba157d5e0cd30ae2ed13edba051038c2c7bb1a1f (diff)
parente3bf34095ac7571d04ebddba6f04815d7a71ed13 (diff)
fix merge
Diffstat (limited to 'src/lib/quotation')
-rw-r--r--src/lib/quotation/components/Quotation.jsx390
1 files changed, 154 insertions, 236 deletions
diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx
index 2f4d6c46..f0791512 100644
--- a/src/lib/quotation/components/Quotation.jsx
+++ b/src/lib/quotation/components/Quotation.jsx
@@ -10,7 +10,6 @@ import { deleteItemCart, getCart, getItemCart } from '@/core/utils/cart';
import currencyFormat from '@/core/utils/currencyFormat';
import { toast } from 'react-hot-toast';
import { useProductCartContext } from '@/contexts/ProductCartContext';
-// import checkoutApi from '@/lib/checkout/api/checkoutApi'
import { useRouter } from 'next/router';
import VariantGroupCard from '@/lib/variant/components/VariantGroupCard';
import MobileView from '@/core/components/views/MobileView';
@@ -19,11 +18,11 @@ import Image from '@/core/components/elements/Image/Image';
import { useQuery } from 'react-query';
import CardProdcuctsList from '@/core/components/elements/Product/cartProductsList';
import { Skeleton } from '@chakra-ui/react';
+import { useAddress } from '@/lib/checkout/stores/useAdress';
+import { useCheckout } from '@/lib/checkout/stores/stateCheckout';
import {
PickupAddress,
SectionAddress,
- SectionExpedisi,
- SectionListService,
SectionValidation,
calculateEstimatedArrival,
splitDuration,
@@ -31,7 +30,8 @@ import {
import addressesApi from '@/lib/address/api/addressesApi';
import { getItemAddress } from '@/core/utils/address';
import ExpedisiList from '../../checkout/api/ExpedisiList';
-import axios from 'axios';
+import SectionQuotationExpedition from '@/lib/checkout/components/SectionQuotationExpedition';
+import { useQuotation } from '@/lib/checkout/stores/stateQuotation';
const { checkoutApi } = require('@/lib/checkout/api/checkoutApi');
const { getProductsCheckout } = require('@/lib/checkout/api/checkoutApi');
@@ -51,41 +51,48 @@ const Quotation = () => {
const { setRefreshCart } = useProductCartContext();
const SELF_PICKUP_ID = 32;
- const [products, setProducts] = useState(null);
- const [totalAmount, setTotalAmount] = useState(0);
+ const [totalAmount, setTotalAmount] = useState(0);
const [totalDiscountAmount, setTotalDiscountAmount] = useState(0);
-
- //start set up address and carrier
- const [selectedCarrierId, setselectedCarrierId] = useState(0);
- const [listExpedisi, setExpedisi] = useState([]);
- const [selectedExpedisi, setSelectedExpedisi] = useState(0);
- const [checkWeigth, setCheckWeight] = useState(false);
- const [checkoutValidation, setCheckoutValidation] = useState(false);
- const [loadingRajaOngkir, setLoadingRajaOngkir] = useState(false);
-
- const [listserviceExpedisi, setListServiceExpedisi] = useState([]);
- const [selectedServiceType, setSelectedServiceType] = useState(null);
-
- const [selectedCarrier, setselectedCarrier] = useState(0);
- const [totalWeight, setTotalWeight] = useState(0);
-
- const [biayaKirim, setBiayaKirim] = useState(0);
- 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('');
+ const [isLoading, setIsLoading] = useState(false);
+ const [etdFix, setEtdFix] = useState(null);
+
+ const {
+ selectedAddress,
+ setSelectedAddress,
+ addresses,
+ setAddresses,
+ setAddressMaps,
+ setCoordinate,
+ setPostalCode,
+ } = useAddress();
+
+ const {
+ products,
+ setProducts,
+ checkWeigth,
+ setCheckWeight,
+ checkoutValidation,
+ setCheckoutValidation,
+ biayaKirim,
+ etd,
+ unit,
+ selectedCourier,
+ selectedCourierId,
+ selectedService,
+ listExpedisi,
+ setExpedisi,
+ productSla,
+ setProductSla,
+ setBiayaKirim,
+ setUnit,
+ setEtd,
+ setSelectedCourier,
+ setSelectedService,
+ setSelectedCourierId
+ } = useQuotation();
+
useEffect(() => {
if (!auth) return;
@@ -116,198 +123,145 @@ const Quotation = () => {
return addresses[0];
};
+ let ship = matchAddress('shipping');
+
setSelectedAddress({
shipping: matchAddress('shipping'),
invoicing: matchAddress('invoicing'),
});
- }, [addresses]);
-
- const loadExpedisi = async () => {
- let dataExpedisi = await ExpedisiList();
- dataExpedisi = dataExpedisi.map((expedisi) => ({
- value: expedisi.id,
- label: expedisi.name,
- carrierId: expedisi.deliveryCarrierId,
- }));
- setExpedisi(dataExpedisi);
- };
-
- const loadServiceRajaOngkir = async () => {
- setLoadingRajaOngkir(true);
- const body = {
- origin: 2127,
- destination: selectedAddress.shipping.rajaongkirCityId,
- weight: totalWeight,
- courier: selectedCarrier,
- originType: 'subdistrict',
- destinationType: 'subdistrict',
- };
- setBiayaKirim(0);
- const dataService = await axios(
- '/api/rajaongkir-service?body=' + JSON.stringify(body)
- );
- setLoadingRajaOngkir(false);
- setListServiceExpedisi(dataService.data[0].costs);
- if (dataService.data[0].costs[0]) {
- setBiayaKirim(dataService.data[0].costs[0]?.cost[0].value);
- setselectedExpedisiService(
- dataService.data[0].costs[0]?.description +
- '-' +
- dataService.data[0].costs[0]?.service
- );
- setEtd(dataService.data[0].costs[0]?.cost[0].etd);
- toast.success('Harap pilih tipe layanan pengiriman');
- } else {
- toast.error('Maaf, layanan tidak tersedia. Mohon pilih expedisi lain.');
- }
- };
-
- useEffect(() => {
- setCheckoutValidation(false);
-
- if (selectedCarrier != 0 && selectedCarrier != 1 && totalWeight > 0) {
- loadServiceRajaOngkir();
- } else {
- setListServiceExpedisi();
- setBiayaKirim(0);
- setselectedExpedisiService();
- setEtd();
+ setPostalCode(ship?.zip);
+ if (ship?.addressMap) {
+ setAddressMaps(ship?.addressMap);
+ setCoordinate({
+ destination_latitude: ship?.latitude,
+ destination_longitude: ship?.longtitude,
+ });
}
- }, [selectedCarrier, selectedAddress, totalWeight]);
+ }, [addresses]);
useEffect(() => {
- if (selectedExpedisi) {
- let serviceType = selectedExpedisi.split(',');
- if (serviceType[0] === 0) return;
+ const loadExpedisi = async () => {
+ let dataExpedisi = await ExpedisiList();
+ dataExpedisi = dataExpedisi.map((expedisi) => ({
+ value: expedisi.id,
+ label: expedisi.name,
+ carrierId: expedisi.deliveryCarrierId,
+ logo: expedisi.image,
+ }));
+ setExpedisi(dataExpedisi);
+ };
+
+ loadExpedisi();
- setselectedCarrier(serviceType[0]);
- setselectedCarrierId(serviceType[1]);
- setListServiceExpedisi([]);
- }
- }, [selectedExpedisi]);
+ const handlePopState = () => {
+ router.push('/shop/cart');
+ };
- useEffect(() => {
- if (selectedServiceType) {
- let serviceType = selectedServiceType.split(',');
- setBiayaKirim(serviceType[0]);
- setselectedExpedisiService(serviceType[1]);
- setEtd(serviceType[2]);
- }
- }, [selectedServiceType]);
+ window.onpopstate = handlePopState;
- useEffect(() => {
- if (etd) setEtdFix(calculateEstimatedArrival(etd));
- }, [etd]);
+ return () => {
+ window.onpopstate = null;
+ };
+ }, []);
useEffect(() => {
if (isApproval) {
- setselectedCarrierId(1);
- setselectedExpedisiService('indoteknik');
+ setSelectedCourierId(1);
+ setSelectedCourier('indoteknik');
}
}, [isApproval]);
- // end set up address and carrier
-
- useEffect(() => {
- const loadProducts = async () => {
- const cart = getCart();
- const variantIds = _.filter(cart, (o) => o.selected == true)
- .map((o) => o.productId)
- .join(',');
- const dataProducts = await CartApi({ variantIds });
- const productsWithQuantity = dataProducts?.map((product) => {
- return {
- ...product,
- quantity: getItemCart({ productId: product.id }).quantity,
- };
- });
- if (productsWithQuantity) {
- Promise.all(productsWithQuantity).then((resolvedProducts) => {
- setProducts(resolvedProducts);
- });
- }
- };
- loadExpedisi();
- // loadProducts()
- }, []);
-
useEffect(() => {
- setProducts(cartCheckout?.products);
- setCheckWeight(cartCheckout?.hasProductWithoutWeight);
- setTotalWeight(cartCheckout?.totalWeight.g);
+ if (cartCheckout) {
+ setProducts(cartCheckout?.products);
+ setCheckWeight(cartCheckout?.hasProductWithoutWeight);
+ }
}, [cartCheckout]);
useEffect(() => {
if (products) {
- let calculateTotalAmount = 0;
- let calculateTotalDiscountAmount = 0;
- products.forEach((product) => {
- calculateTotalAmount += product.price.price * product.quantity;
- calculateTotalDiscountAmount +=
- (product.price.price - product.price.priceDiscount) *
- product.quantity;
- });
- setTotalAmount(calculateTotalAmount);
- setTotalDiscountAmount(calculateTotalDiscountAmount);
+ const calculateTotals = () => {
+ let calculateTotalAmount = 0;
+ let calculateTotalDiscountAmount = 0;
+
+ products.forEach((product) => {
+ calculateTotalAmount += product.price.price * product.quantity;
+ calculateTotalDiscountAmount +=
+ (product.price.price - product.price.priceDiscount) * product.quantity;
+ });
+
+ setTotalAmount(calculateTotalAmount);
+ setTotalDiscountAmount(calculateTotalDiscountAmount);
+ };
+
+ calculateTotals();
}
}, [products]);
- const [isLoading, setIsLoading] = useState(false);
+ useEffect(() => {
+ if (etd) {
+ setEtdFix(calculateEstimatedArrival(etd));
+ }
+ }, [etd]);
const checkout = async () => {
- // validation checkout
- if (selectedExpedisi === 0 && !isApproval) {
+ // Validation
+ if (!selectedCourierId && !isApproval) {
setCheckoutValidation(true);
- if (expedisiValidation.current) {
- const position = expedisiValidation.current.getBoundingClientRect();
- window.scrollTo({
- top: position.top - 300 + window.pageYOffset,
- behavior: 'smooth',
- });
- }
+ toast.error('Silahkan pilih ekspedisi');
return;
}
- if (selectedCarrier != 1 && biayaKirim == 0 && !isApproval) {
+
+ if (selectedCourierId !== SELF_PICKUP_ID && biayaKirim === 0 && !isApproval) {
toast.error('Maaf, layanan tidak tersedia. Mohon pilih expedisi lain.');
return;
}
- if (!products || products.length == 0) return;
+ if (!products || products.length === 0) return;
- if (isApproval && note_websiteText == '') {
+ if (isApproval && note_websiteText === '') {
toast.error('Maaf, Note wajib dimasukkan.');
return;
}
setIsLoading(true);
- const productOrder = products.map((product) => ({
- product_id: product.id,
- quantity: product.quantity,
- }));
- let data = {
- partner_shipping_id: selectedAddress.shipping.id,
- partner_invoice_id: selectedAddress.invoicing.id,
- user_id: auth.id,
- order_line: JSON.stringify(productOrder),
- delivery_amount: biayaKirim,
- carrier_id: selectedCarrierId,
- estimated_arrival_days: splitDuration(etd),
- delivery_service_type: selectedExpedisiService,
- note_website: note_websiteText,
- };
-
- const isSuccess = await checkoutApi({ data });
- setIsLoading(false);
- if (isSuccess?.id) {
- for (const product of products) deleteItemCart({ productId: product.id });
- router.push(`/shop/quotation/finish?id=${isSuccess.id}`);
- setRefreshCart(true);
- return;
+ try {
+ const productOrder = products.map((product) => ({
+ product_id: product.id,
+ quantity: product.quantity,
+ }));
+
+ const data = {
+ partner_shipping_id: selectedAddress.shipping.id,
+ partner_invoice_id: selectedAddress.invoicing.id,
+ user_id: auth.id,
+ order_line: JSON.stringify(productOrder),
+ delivery_amount: biayaKirim,
+ carrier_id: selectedCourierId,
+ estimated_arrival_days: splitDuration(etd),
+ delivery_service_type: selectedService?.service_type || selectedCourier,
+ note_website: note_websiteText,
+ };
+
+ const isSuccess = await checkoutApi({ data });
+
+ if (isSuccess?.id) {
+ for (const product of products) {
+ deleteItemCart({ productId: product.id });
+ }
+ router.push(`/shop/quotation/finish?id=${isSuccess.id}`);
+ setRefreshCart(true);
+ } else {
+ toast.error('Gagal melakukan transaksi, terjadi kesalahan internal');
+ }
+ } catch (error) {
+ toast.error('Terjadi kesalahan saat memproses quotation');
+ } finally {
+ setIsLoading(false);
}
-
- toast.error('Gagal melakukan transaksi, terjadi kesalahan internal');
};
+
const taxTotal = (totalAmount - totalDiscountAmount) * (PPN - 1);
return (
@@ -327,21 +281,21 @@ const Quotation = () => {
<Divider />
- {selectedCarrierId == SELF_PICKUP_ID && (
+ {selectedCourierId == SELF_PICKUP_ID && (
<div className='p-4'>
<div
- class='flex items-center p-4 mb-4 text-sm border border-yellow-500 text-yellow-800 rounded-lg bg-yellow-50'
+ className='flex items-center p-4 mb-4 text-sm border border-yellow-500 text-yellow-800 rounded-lg bg-yellow-50'
role='alert'
>
<svg
- class='flex-shrink-0 inline w-4 h-4 mr-3'
+ className='flex-shrink-0 inline w-4 h-4 mr-3'
aria-hidden='true'
fill='currentColor'
viewBox='0 0 20 20'
>
<path d='M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z' />
</svg>
- <span class='sr-only'>Info</span>
+ <span className='sr-only'>Info</span>
<div className='text-justify'>
Fitur Self Pickup, hanya berlaku untuk customer di area jakarta.
Apa bila memilih fitur ini, anda akan dihubungi setelah barang
@@ -351,10 +305,10 @@ const Quotation = () => {
</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}
@@ -374,32 +328,14 @@ const Quotation = () => {
)}
<Divider />
<SectionValidation address={selectedAddress.invoicing} />
- {!isApproval && (
- <>
- <SectionExpedisi
- address={selectedAddress.shipping}
- listExpedisi={listExpedisi}
- setSelectedExpedisi={setSelectedExpedisi}
- checkWeigth={checkWeigth}
- checkoutValidation={checkoutValidation}
- expedisiValidation={expedisiValidation}
- loadingRajaOngkir={loadingRajaOngkir}
- />
- <Divider />
- </>
- )}
-
- <SectionListService
- listserviceExpedisi={listserviceExpedisi}
- setSelectedServiceType={setSelectedServiceType}
- />
-
+
<div className='p-4 flex flex-col gap-y-4'>
{products && (
<VariantGroupCard openOnClick={false} variants={products} />
)}
</div>
+ <SectionQuotationExpedition products={products} />
<Divider />
<div className='p-4'>
@@ -497,10 +433,10 @@ const Quotation = () => {
<DesktopView>
<div className='container mx-auto py-10 flex'>
<div className='w-3/4 border border-gray_r-6 rounded bg-white p-4'>
- {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
@@ -522,31 +458,16 @@ const Quotation = () => {
)}
<Divider />
<SectionValidation address={selectedAddress.invoicing} />
- {!isApproval && (
- <SectionExpedisi
- address={selectedAddress.shipping}
- listExpedisi={listExpedisi}
- setSelectedExpedisi={setSelectedExpedisi}
- checkWeigth={checkWeigth}
- checkoutValidation={checkoutValidation}
- expedisiValidation={expedisiValidation}
- loadingRajaOngkir={loadingRajaOngkir}
- />
- )}
-
+
+ <SectionQuotationExpedition products={products} />
<Divider />
- <SectionListService
- listserviceExpedisi={listserviceExpedisi}
- setSelectedServiceType={setSelectedServiceType}
- />
- {/* <div className='p-4'> */}
+
<div className='font-medium mb-6'>Detail Barang</div>
<CardProdcuctsList
isLoading={isLoading}
products={products}
source='checkout'
/>
- {/* </div> */}
</div>
<div className='w-1/4 pl-4'>
@@ -601,9 +522,6 @@ const Quotation = () => {
)}
</div>
</div>
- {/* <p className='text-caption-2 text-gray_r-11 mb-2'>
- *) Belum termasuk biaya pengiriman
- </p> */}
<p className='text-caption-2 text-gray_r-11 leading-5'>
Dengan melakukan pembelian melalui website Indoteknik, saya
menyetujui{' '}
@@ -655,4 +573,4 @@ const Quotation = () => {
);
};
-export default Quotation;
+export default Quotation; \ No newline at end of file