From 07138ddc724233f688de9c16de59c1b61b885520 Mon Sep 17 00:00:00 2001
From: "HATEC\\SPVDEV001" <tri.susilo@altama.co.id>
Date: Fri, 1 Mar 2024 16:59:35 +0700
Subject: create component address dan expedisi

---
 src/lib/quotation/components/Quotation.jsx | 376 +++++++++++++++++++++++------
 1 file changed, 300 insertions(+), 76 deletions(-)

(limited to 'src/lib/quotation/components/Quotation.jsx')

diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx
index 8c379ead..baf1492c 100644
--- a/src/lib/quotation/components/Quotation.jsx
+++ b/src/lib/quotation/components/Quotation.jsx
@@ -1,102 +1,265 @@
-import Alert from '@/core/components/elements/Alert/Alert'
-import Divider from '@/core/components/elements/Divider/Divider'
-import Link from '@/core/components/elements/Link/Link'
-import useAuth from '@/core/hooks/useAuth'
-import CartApi from '@/lib/cart/api/CartApi'
-import { ExclamationCircleIcon } from '@heroicons/react/24/outline'
-import { useEffect, useState } from 'react'
-import _ from 'lodash'
-import { deleteItemCart, getCart, getItemCart } from '@/core/utils/cart'
-import currencyFormat from '@/core/utils/currencyFormat'
-import { toast } from 'react-hot-toast'
+import Alert from '@/core/components/elements/Alert/Alert';
+import Divider from '@/core/components/elements/Divider/Divider';
+import Link from '@/core/components/elements/Link/Link';
+import useAuth from '@/core/hooks/useAuth';
+import CartApi from '@/lib/cart/api/CartApi';
+import { ExclamationCircleIcon } from '@heroicons/react/24/outline';
+import { useEffect, useRef, useState } from 'react';
+import _ from 'lodash';
+import { deleteItemCart, getCart, getItemCart } from '@/core/utils/cart';
+import currencyFormat from '@/core/utils/currencyFormat';
+import { toast } from 'react-hot-toast';
 // 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'
-import DesktopView from '@/core/components/views/DesktopView'
-import Image from '@/core/components/elements/Image/Image'
-import { useQuery } from 'react-query'
-import CardProdcuctsList from '@/core/components/elements/Product/cartProductsList'
+import { useRouter } from 'next/router';
+import VariantGroupCard from '@/lib/variant/components/VariantGroupCard';
+import MobileView from '@/core/components/views/MobileView';
+import DesktopView from '@/core/components/views/DesktopView';
+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 {
+  PickupAddress,
+  SectionAddress,
+  SectionExpedisi,
+  SectionListService,
+  SectionValidation,
+} from '../../checkout/components/CheckoutSection';
+import addressesApi from '@/lib/address/api/addressesApi';
+import { getItemAddress } from '@/core/utils/address';
+import ExpedisiList from '../../checkout/api/ExpedisiList';
+import axios from 'axios';
 
-const { checkoutApi } = require('@/lib/checkout/api/checkoutApi')
-const { getProductsCheckout } = require('@/lib/checkout/api/checkoutApi')
+const { checkoutApi } = require('@/lib/checkout/api/checkoutApi');
+const { getProductsCheckout } = require('@/lib/checkout/api/checkoutApi');
 
 const Quotation = () => {
-  const router = useRouter()
-  const auth = useAuth()
+  const router = useRouter();
+  const auth = useAuth();
 
-  const { data: cartCheckout } = useQuery('cartCheckout', () => getProductsCheckout())
+  const { data: cartCheckout } = useQuery('cartCheckout', () =>
+    getProductsCheckout()
+  );
 
-  const [products, setProducts] = useState(null)
-  const [totalAmount, setTotalAmount] = useState(0)
-  const [totalDiscountAmount, setTotalDiscountAmount] = useState(0)
+  const SELF_PICKUP_ID = 32;
+
+  const [products, setProducts] = useState(null);
+  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 expedisiValidation = useRef(null);
+
+  const [selectedAddress, setSelectedAddress] = useState({
+    shipping: null,
+    invoicing: null,
+  });
+
+  const [addresses, setAddresses] = useState(null);
+
+  useEffect(() => {
+    if (!auth) return;
+
+    const getAddresses = async () => {
+      const dataAddresses = await addressesApi();
+      setAddresses(dataAddresses);
+    };
+
+    getAddresses();
+  }, [auth]);
+
+  useEffect(() => {
+    if (!addresses) return;
+
+    const matchAddress = (key) => {
+      const addressToMatch = getItemAddress(key);
+      const foundAddress = addresses.filter(
+        (address) => address.id == addressToMatch
+      );
+      if (foundAddress.length > 0) {
+        return foundAddress[0];
+      }
+      return addresses[0];
+    };
+
+    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) {
+      console.log('masuk');
+      loadServiceRajaOngkir();
+    } else {
+      setListServiceExpedisi();
+      setBiayaKirim(0);
+      setselectedExpedisiService();
+      setEtd();
+    }
+  }, [selectedCarrier, selectedAddress, totalWeight]);
+
+  useEffect(() => {
+    if (selectedExpedisi) {
+      let serviceType = selectedExpedisi.split(',');
+      if (serviceType[0] === 0) return;
+
+      setselectedCarrier(serviceType[0]);
+      setselectedCarrierId(serviceType[1]);
+      setListServiceExpedisi([]);
+    }
+  }, [selectedExpedisi]);
+
+  // end set up address and carrier
 
   useEffect(() => {
     const loadProducts = async () => {
-      const cart = getCart()
+      const cart = getCart();
       const variantIds = _.filter(cart, (o) => o.selected == true)
         .map((o) => o.productId)
-        .join(',')
-      const dataProducts = await CartApi({ variantIds })
+        .join(',');
+      const dataProducts = await CartApi({ variantIds });
       const productsWithQuantity = dataProducts?.map((product) => {
         return {
           ...product,
-          quantity: getItemCart({ productId: product.id }).quantity
-        }
-      })
+          quantity: getItemCart({ productId: product.id }).quantity,
+        };
+      });
       if (productsWithQuantity) {
         Promise.all(productsWithQuantity).then((resolvedProducts) => {
-          setProducts(resolvedProducts)
-        })
+          setProducts(resolvedProducts);
+        });
       }
-    }
+    };
+    loadExpedisi();
     // loadProducts()
-  }, [])
+  }, []);
 
   useEffect(() => {
-    setProducts(cartCheckout?.products)
-  }, [cartCheckout])
+    setProducts(cartCheckout?.products);
+    setCheckWeight(cartCheckout?.hasProductWithoutWeight);
+    setTotalWeight(cartCheckout?.totalWeight.g);
+    console.log(cartCheckout);
+  }, [cartCheckout]);
 
   useEffect(() => {
     if (products) {
-      let calculateTotalAmount = 0
-      let calculateTotalDiscountAmount = 0
+      let calculateTotalAmount = 0;
+      let calculateTotalDiscountAmount = 0;
       products.forEach((product) => {
-        calculateTotalAmount += product.price.price * product.quantity
+        calculateTotalAmount += product.price.price * product.quantity;
         calculateTotalDiscountAmount +=
-          (product.price.price - product.price.priceDiscount) * product.quantity
-      })
-      setTotalAmount(calculateTotalAmount)
-      setTotalDiscountAmount(calculateTotalDiscountAmount)
+          (product.price.price - product.price.priceDiscount) *
+          product.quantity;
+      });
+      setTotalAmount(calculateTotalAmount);
+      setTotalDiscountAmount(calculateTotalDiscountAmount);
     }
-  }, [products])
+  }, [products]);
 
-  const [isLoading, setIsLoading] = useState(false)
+  const [isLoading, setIsLoading] = useState(false);
 
   const checkout = async () => {
-    if (!products || products.length == 0) return
-    setIsLoading(true)
+    // validation checkout
+    if (selectedExpedisi === 0) {
+      setCheckoutValidation(true);
+      if (expedisiValidation.current) {
+        const position = expedisiValidation.current.getBoundingClientRect();
+        window.scrollTo({
+          top: position.top - 300 + window.pageYOffset,
+          behavior: 'smooth',
+        });
+      }
+      return;
+    }
+    if (selectedCarrier != 1 && biayaKirim == 0) {
+      toast.error('Maaf, layanan tidak tersedia. Mohon pilih expedisi lain.');
+      return;
+    }
+
+    if (!products || products.length == 0) return;
+    setIsLoading(true);
     const productOrder = products.map((product) => ({
       product_id: product.id,
-      quantity: product.quantity
-    }))
+      quantity: product.quantity,
+    }));
     let data = {
       partner_shipping_id: auth.partnerId,
       partner_invoice_id: auth.partnerId,
       user_id: auth.id,
-      order_line: JSON.stringify(productOrder)
-    }
-    const isSuccess = await checkoutApi({ data })
-    setIsLoading(false)
+      order_line: JSON.stringify(productOrder),
+    };
+    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}`)
-      return
+      for (const product of products) deleteItemCart({ productId: product.id });
+      router.push(`/shop/quotation/finish?id=${isSuccess.id}`);
+      return;
     }
-    toast.error('Gagal melakukan transaksi, terjadi kesalahan internal')
-  }
+    toast.error('Gagal melakukan transaksi, terjadi kesalahan internal');
+  };
 
-  const taxTotal = (totalAmount - totalDiscountAmount) * 0.11
+  const taxTotal = (totalAmount - totalDiscountAmount) * 0.11;
 
   return (
     <>
@@ -107,8 +270,8 @@ const Quotation = () => {
               <ExclamationCircleIcon className='w-7 text-blue-700' />
             </div>
             <span className='leading-5'>
-              Jika mengalami kesulitan dalam melakukan pembelian di website Indoteknik. Hubungi kami
-              disini
+              Jika mengalami kesulitan dalam melakukan pembelian di website
+              Indoteknik. Hubungi kami disini
             </span>
           </Alert>
         </div>
@@ -116,7 +279,9 @@ const Quotation = () => {
         <Divider />
 
         <div className='p-4 flex flex-col gap-y-4'>
-          {products && <VariantGroupCard openOnClick={false} variants={products} />}
+          {products && (
+            <VariantGroupCard openOnClick={false} variants={products} />
+          )}
         </div>
 
         <Divider />
@@ -124,7 +289,9 @@ const Quotation = () => {
         <div className='p-4'>
           <div className='flex justify-between items-center'>
             <div className='font-medium'>Ringkasan Penawaran</div>
-            <div className='text-gray_r-11 text-caption-1'>{products?.length} Barang</div>
+            <div className='text-gray_r-11 text-caption-1'>
+              {products?.length} Barang
+            </div>
           </div>
           <hr className='my-4 border-gray_r-6' />
           <div className='flex flex-col gap-y-4'>
@@ -134,7 +301,9 @@ const Quotation = () => {
             </div>
             <div className='flex gap-x-2 justify-between'>
               <div className='text-gray_r-11'>Diskon Produk</div>
-              <div className='text-danger-500'>- {currencyFormat(cartCheckout?.totalDiscount)}</div>
+              <div className='text-danger-500'>
+                - {currencyFormat(cartCheckout?.totalDiscount)}
+              </div>
             </div>
             <div className='flex gap-x-2 justify-between'>
               <div className='text-gray_r-11'>Subtotal</div>
@@ -152,9 +321,12 @@ const Quotation = () => {
               {currencyFormat(cartCheckout?.grandTotal)}
             </div>
           </div>
-          <p className='text-caption-2 text-gray_r-10 mb-2'>*) Belum termasuk biaya pengiriman</p>
+          <p className='text-caption-2 text-gray_r-10 mb-2'>
+            *) Belum termasuk biaya pengiriman
+          </p>
           <p className='text-caption-2 text-gray_r-10 leading-5'>
-            Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui{' '}
+            Dengan melakukan pembelian melalui website Indoteknik, saya
+            menyetujui{' '}
             <Link href='/syarat-ketentuan' className='inline font-normal'>
               Syarat & Ketentuan
             </Link>{' '}
@@ -165,7 +337,11 @@ const Quotation = () => {
         <Divider />
 
         <div className='flex gap-x-3 p-4'>
-          <button className='flex-1 btn-yellow' onClick={checkout} disabled={isLoading}>
+          <button
+            className='flex-1 btn-yellow'
+            onClick={checkout}
+            disabled={isLoading}
+          >
             {isLoading ? 'Loading...' : 'Quotation'}
           </button>
         </div>
@@ -174,15 +350,62 @@ 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'>
-            <div className='font-medium'>Detail Barang</div>
-            <CardProdcuctsList isLoading={isLoading} products={products} source='checkout' />
+            {selectedCarrierId == SELF_PICKUP_ID && (
+              <PickupAddress label='Alamat Pickup' />
+            )}
+            {selectedCarrierId != SELF_PICKUP_ID && (
+              <Skeleton
+                isLoaded={
+                  !!selectedAddress.invoicing && !!selectedAddress.shipping
+                }
+                minHeight={290}
+              >
+                <SectionAddress
+                  address={selectedAddress.shipping}
+                  label='Alamat Pengiriman'
+                  url='/my/address?select=shipping'
+                />
+                <Divider />
+                <SectionAddress
+                  address={selectedAddress.invoicing}
+                  label='Alamat Penagihan'
+                  url='/my/address?select=invoice'
+                />
+              </Skeleton>
+            )}
+            <Divider />
+            <SectionValidation address={selectedAddress.invoicing} />
+            <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'> */}
+            <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'>
             <div className='sticky top-48 border border-gray_r-6 bg-white rounded p-4'>
               <div className='flex justify-between items-center'>
                 <div className='font-medium'>Ringkasan Pesanan</div>
-                <div className='text-gray_r-11 text-caption-1'>{products?.length} Barang</div>
+                <div className='text-gray_r-11 text-caption-1'>
+                  {products?.length} Barang
+                </div>
               </div>
 
               <hr className='my-4 border-gray_r-6' />
@@ -219,7 +442,8 @@ const Quotation = () => {
                 *) Belum termasuk biaya pengiriman
               </p>
               <p className='text-caption-2 text-gray_r-11 leading-5'>
-                Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui{' '}
+                Dengan melakukan pembelian melalui website Indoteknik, saya
+                menyetujui{' '}
                 <Link href='/syarat-ketentuan' className='inline font-normal'>
                   Syarat & Ketentuan
                 </Link>{' '}
@@ -240,7 +464,7 @@ const Quotation = () => {
         </div>
       </DesktopView>
     </>
-  )
-}
+  );
+};
 
-export default Quotation
+export default Quotation;
-- 
cgit v1.2.3

