From 67398e6f10d6f7729d8f1ace7005ef13d32c5ddd Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 4 Jan 2024 10:05:25 +0700 Subject: Update promotion program feature --- src/lib/cart/components/Cartheader.jsx | 181 ---- src/lib/checkout/components/Checkout.jsx | 930 ++++++++++----------- src/lib/home/api/categoryHomeApi.js | 15 +- .../product/components/Product/ProductDesktop.jsx | 763 +++++++++-------- .../product/components/Product/ProductMobile.jsx | 411 +++++---- src/lib/product/components/ProductSearch.jsx | 379 +++++---- 6 files changed, 1353 insertions(+), 1326 deletions(-) (limited to 'src/lib') diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index 580dfc8c..19f79bc9 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -1,14 +1,9 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { getCartApi } from '../api/CartApi' -import currencyFormat from '@/core/utils/currencyFormat' -import Image from '@/core/components/elements/Image/Image' -import { createSlug } from '@/core/utils/slug' import useAuth from '@/core/hooks/useAuth' import { useRouter } from 'next/router' import odooApi from '@/core/api/odooApi' import { useProductCartContext } from '@/contexts/ProductCartContext' -import whatsappUrl from '@/core/utils/whatsappUrl' -import { AnimatePresence, motion } from 'framer-motion' const { ShoppingCartIcon, PhotoIcon } = require('@heroicons/react/24/outline') const { default: Link } = require('next/link') @@ -114,182 +109,6 @@ const Cardheader = (cartCount) => { - - - {isHovered && ( - <> - - - - -
-
Keranjang Belanja
- - Lihat Semua - -
-
-
- {!auth && ( -
-

- Silahkan{' '} - - Login - {' '} - Untuk Melihat Daftar Keranjang Belanja Anda -

-
- )} - {isLoading && - itemLoading.map((item) => ( -
-
-
- -
-
-
-
-
-
-
-
- ))} - {auth && products.length === 0 && !isLoading && ( -
-

- Tidak Ada Produk di Keranjang Belanja Anda -

-
- )} - {auth && products.length > 0 && !isLoading && ( - <> -
    - {products && - products?.map((product, index) => ( - <> -
  • -
    -
    - - {product?.name} - -
    -
    - - {' '} -

    - {product.parent.name} -

    - - - {product?.hasFlashsale && ( -
    -
    - {product?.price?.discountPercentage}% -
    -
    - {currencyFormat(product?.price?.price)} -
    -
    - )} -
    -
    - {product?.price?.priceDiscount > 0 ? ( - currencyFormat(product?.price?.priceDiscount) - ) : ( - - - Call For Price - - - )} -
    -
    -
    -
    -
  • - - ))} -
-
- - )} -
- {auth && products.length > 0 && !isLoading && ( - <> -
- Subtotal Sebelum PPN : - {currencyFormat(subTotal)} -
-
- -
- - )} -
-
- - )} -
) } diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 9a799010..eb31b9dc 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -1,191 +1,199 @@ -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 { getItemAddress } from '@/core/utils/address' -import addressesApi from '@/lib/address/api/addressesApi' +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 { getItemAddress } from '@/core/utils/address'; +import addressesApi from '@/lib/address/api/addressesApi'; import { BanknotesIcon, ChevronLeftIcon, ClockIcon, - ExclamationCircleIcon -} from '@heroicons/react/24/outline' -import React, { useEffect, useRef, useState } from 'react' -import _ from 'lodash' -import { deleteItemCart, getCartApi } from '@/core/utils/cart' -import currencyFormat from '@/core/utils/currencyFormat' -import { toast } from 'react-hot-toast' -import getFileBase64 from '@/core/utils/getFileBase64' -import { useRouter } from 'next/router' -import VariantGroupCard from '@/lib/variant/components/VariantGroupCard' -import axios from 'axios' -import Image from '@/core/components/elements/Image/Image' -import MobileView from '@/core/components/views/MobileView' -import DesktopView from '@/core/components/views/DesktopView' -import ExpedisiList from '../api/ExpedisiList' -import whatsappUrl from '@/core/utils/whatsappUrl' -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import { useQuery } from 'react-query' -import { gtagPurchase } from '@/core/utils/googleTag' -import { findVoucher, getVoucher } from '../api/getVoucher' -import CardProdcuctsList from '@/core/components/elements/Product/cartProductsList' -import { Spinner } from '@chakra-ui/react' -import { AnimatePresence, motion } from 'framer-motion' - -const SELF_PICKUP_ID = 32 - -const { checkoutApi } = require('../api/checkoutApi') -const { getProductsCheckout } = require('../api/checkoutApi') + ExclamationCircleIcon, +} from '@heroicons/react/24/outline'; +import React, { useEffect, useRef, useState } from 'react'; +import _ from 'lodash'; +import { deleteItemCart } from '@/core/utils/cart'; +import currencyFormat from '@/core/utils/currencyFormat'; +import { toast } from 'react-hot-toast'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import { useRouter } from 'next/router'; +import axios from 'axios'; +import Image from '@/core/components/elements/Image/Image'; +import MobileView from '@/core/components/views/MobileView'; +import DesktopView from '@/core/components/views/DesktopView'; +import ExpedisiList from '../api/ExpedisiList'; +import whatsappUrl from '@/core/utils/whatsappUrl'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import { useQuery } from 'react-query'; +import { gtagPurchase } from '@/core/utils/googleTag'; +import { findVoucher, getVoucher } from '../api/getVoucher'; +import { Spinner } from '@chakra-ui/react'; +import { AnimatePresence, motion } from 'framer-motion'; +import snakecaseKeys from 'snakecase-keys'; +import CartItem from '~/modules/cart/components/Item.tsx'; + +const SELF_PICKUP_ID = 32; + +const { checkoutApi } = require('../api/checkoutApi'); +const { getProductsCheckout } = require('../api/checkoutApi'); const Checkout = () => { - const router = useRouter() - const query = router.query.source ?? null - const auth = useAuth() + const router = useRouter(); + const query = router.query.source ?? null; + const auth = useAuth(); - const [activeVoucher, SetActiveVoucher] = useState(null) + const [activeVoucher, SetActiveVoucher] = useState(null); const { data: cartCheckout } = useQuery('cartCheckout-' + activeVoucher, () => getProductsCheckout(activeVoucher, query) - ) + ); const [selectedAddress, setSelectedAddress] = useState({ shipping: null, - invoicing: null - }) - const [addresses, setAddresses] = useState(null) + invoicing: null, + }); + const [addresses, setAddresses] = useState(null); useEffect(() => { - if (!auth) return + if (!auth) return; const getAddresses = async () => { - const dataAddresses = await addressesApi() - setAddresses(dataAddresses) - } + const dataAddresses = await addressesApi(); + setAddresses(dataAddresses); + }; - getAddresses() - }, [auth]) + getAddresses(); + }, [auth]); useEffect(() => { - if (!addresses) return + if (!addresses) return; const matchAddress = (key) => { - const addressToMatch = getItemAddress(key) - const foundAddress = addresses.filter((address) => address.id == addressToMatch) + const addressToMatch = getItemAddress(key); + const foundAddress = addresses.filter( + (address) => address.id == addressToMatch + ); if (foundAddress.length > 0) { - return foundAddress[0] + return foundAddress[0]; } - return addresses[0] - } + return addresses[0]; + }; setSelectedAddress({ shipping: matchAddress('shipping'), - invoicing: matchAddress('invoicing') - }) - }, [addresses]) - - const [products, setProducts] = useState(null) - const [totalWeight, setTotalWeight] = useState(0) - const [priceCheck, setPriceCheck] = useState(false) - const [listExpedisi, setExpedisi] = useState([]) - const [listserviceExpedisi, setListServiceExpedisi] = useState([]) - const [selectedExpedisi, setSelectedExpedisi] = useState(0) - const [selectedCarrierId, setselectedCarrierId] = useState(0) - const [selectedCarrier, setselectedCarrier] = useState(0) - const [biayaKirim, setBiayaKirim] = useState(0) - const [checkWeigth, setCheckWeight] = useState(false) - const [selectedServiceType, setSelectedServiceType] = useState(null) - const [selectedExpedisiService, setselectedExpedisiService] = useState(null) - const [etd, setEtd] = useState(null) - const [etdFix, setEtdFix] = useState(null) - const [bottomPopup, SetBottomPopup] = useState(null) - const [bottomPopupTnC, SetBottomPopupTnC] = useState(null) - const [itemTnC, setItemTnC] = useState(null) - const [listVouchers, SetListVoucher] = useState(null) - const [discountVoucher, SetDiscountVoucher] = useState(0) - const [codeVoucher, SetCodeVoucher] = useState(null) - const [findCodeVoucher, SetFindVoucher] = useState(null) - const [selisihHargaCode, SetSelisihHargaCode] = useState(null) - const [buttonTerapkan, SetButtonTerapkan] = useState(false) - const [checkoutValidation, setCheckoutValidation] = useState(false) - const [loadingVoucher, setLoadingVoucher] = useState(true) - const [loadingRajaOngkir, setLoadingRajaOngkir] = useState(false) - - const expedisiValidation = useRef(null) + invoicing: matchAddress('invoicing'), + }); + }, [addresses]); + + const [products, setProducts] = useState(null); + const [totalWeight, setTotalWeight] = useState(0); + const [priceCheck, setPriceCheck] = useState(false); + const [listExpedisi, setExpedisi] = useState([]); + const [listserviceExpedisi, setListServiceExpedisi] = useState([]); + const [selectedExpedisi, setSelectedExpedisi] = useState(0); + const [selectedCarrierId, setselectedCarrierId] = useState(0); + const [selectedCarrier, setselectedCarrier] = useState(0); + const [biayaKirim, setBiayaKirim] = useState(0); + const [checkWeigth, setCheckWeight] = useState(false); + const [selectedServiceType, setSelectedServiceType] = useState(null); + const [selectedExpedisiService, setselectedExpedisiService] = useState(null); + const [etd, setEtd] = useState(null); + const [etdFix, setEtdFix] = useState(null); + const [bottomPopup, SetBottomPopup] = useState(null); + const [bottomPopupTnC, SetBottomPopupTnC] = useState(null); + const [itemTnC, setItemTnC] = useState(null); + const [listVouchers, SetListVoucher] = useState(null); + const [discountVoucher, SetDiscountVoucher] = useState(0); + const [codeVoucher, SetCodeVoucher] = useState(null); + const [findCodeVoucher, SetFindVoucher] = useState(null); + const [selisihHargaCode, SetSelisihHargaCode] = useState(null); + const [buttonTerapkan, SetButtonTerapkan] = useState(false); + const [checkoutValidation, setCheckoutValidation] = useState(false); + const [loadingVoucher, setLoadingVoucher] = useState(true); + const [loadingRajaOngkir, setLoadingRajaOngkir] = useState(false); + + const expedisiValidation = useRef(null); const voucher = async () => { if (!listVouchers) { try { - let dataVoucher = await getVoucher(auth?.id, query) - SetListVoucher(dataVoucher) + let dataVoucher = await getVoucher(auth?.id, query); + SetListVoucher(dataVoucher); } finally { - setLoadingVoucher(false) + setLoadingVoucher(false); } } - } + }; const VoucherCode = async (code) => { - let dataVoucher = await findVoucher(code, auth.id, query) + let dataVoucher = await findVoucher(code, auth.id, query); if (dataVoucher.length <= 0) { - SetFindVoucher(1) - return + SetFindVoucher(1); + return; } - let addNewLine = dataVoucher[0] - let checkList = listVouchers.findIndex((voucher) => voucher.code == addNewLine.code) + let addNewLine = dataVoucher[0]; + let checkList = listVouchers.findIndex( + (voucher) => voucher.code == addNewLine.code + ); if (checkList >= 0) { if (listVouchers[checkList].canApply) { - ToggleSwitch(code) - SetCodeVoucher(null) + ToggleSwitch(code); + SetCodeVoucher(null); } else { - SetSelisihHargaCode(listVouchers[checkList].differenceToApply) - SetFindVoucher(2) + SetSelisihHargaCode(listVouchers[checkList].differenceToApply); + SetFindVoucher(2); } - return + return; } if (cartCheckout?.subtotal < addNewLine.minPurchaseAmount) { - SetSelisihHargaCode(currencyFormat(addNewLine.minPurchaseAmount - cartCheckout?.subtotal)) - SetFindVoucher(2) - return + SetSelisihHargaCode( + currencyFormat(addNewLine.minPurchaseAmount - cartCheckout?.subtotal) + ); + SetFindVoucher(2); + return; } else { - SetFindVoucher(3) - SetButtonTerapkan(true) + SetFindVoucher(3); + SetButtonTerapkan(true); } - SetListVoucher((prevList) => [addNewLine, ...prevList]) - SetActiveVoucher(addNewLine.code) - } + SetListVoucher((prevList) => [addNewLine, ...prevList]); + SetActiveVoucher(addNewLine.code); + }; useEffect(() => { - SetFindVoucher(null) - }, [bottomPopup]) + SetFindVoucher(null); + }, [bottomPopup]); useEffect(() => { const loadExpedisi = async () => { - let dataExpedisi = await ExpedisiList() + let dataExpedisi = await ExpedisiList(); dataExpedisi = dataExpedisi.map((expedisi) => ({ value: expedisi.id, label: expedisi.name, - carrierId: expedisi.deliveryCarrierId - })) - setExpedisi(dataExpedisi) - } - loadExpedisi() + carrierId: expedisi.deliveryCarrierId, + })); + setExpedisi(dataExpedisi); + }; + loadExpedisi(); const handlePopState = () => { - router.push('/shop/cart') - } + router.push('/shop/cart'); + }; - window.onpopstate = handlePopState + window.onpopstate = handlePopState; return () => { - window.onpopstate = null - } + window.onpopstate = null; + }; // voucher() - }, []) + }, []); const hitungDiscountVoucher = (code) => { - let dataVoucherIndex = listVouchers.findIndex((voucher) => voucher.code == code) - let dataActiveVoucher = listVouchers[dataVoucherIndex] + let dataVoucherIndex = listVouchers.findIndex( + (voucher) => voucher.code == code + ); + let dataActiveVoucher = listVouchers[dataVoucherIndex]; - let countDiscount = dataActiveVoucher.discountVoucher + let countDiscount = dataActiveVoucher.discountVoucher; /*if (dataActiveVoucher.discountType === 'percentage') { countDiscount = cartCheckout?.subtotal * (dataActiveVoucher.discountAmount / 100) @@ -199,116 +207,122 @@ const Checkout = () => { countDiscount = dataActiveVoucher.discountAmount }*/ - return countDiscount - } + return countDiscount; + }; useEffect(() => { - if (!listVouchers) return - if (!activeVoucher) return + if (!listVouchers) return; + if (!activeVoucher) return; - const countDiscount = hitungDiscountVoucher(activeVoucher) + const countDiscount = hitungDiscountVoucher(activeVoucher); - SetDiscountVoucher(countDiscount) - }, [activeVoucher, listVouchers]) + SetDiscountVoucher(countDiscount); + }, [activeVoucher, listVouchers]); useEffect(() => { - setProducts(cartCheckout?.products) - setCheckWeight(cartCheckout?.hasProductWithoutWeight) - setTotalWeight(cartCheckout?.totalWeight.g) - }, [cartCheckout]) + setProducts(cartCheckout?.products); + setCheckWeight(cartCheckout?.hasProductWithoutWeight); + setTotalWeight(cartCheckout?.totalWeight.g); + }, [cartCheckout]); useEffect(() => { - setCheckoutValidation(false) + setCheckoutValidation(false); const loadServiceRajaOngkir = async () => { - setLoadingRajaOngkir(true) + 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) + 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) + 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') + 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.') + toast.error('Maaf, layanan tidak tersedia. Mohon pilih expedisi lain.'); } - } + }; if (selectedCarrier != 0 && selectedCarrier != 1 && totalWeight > 0) { - loadServiceRajaOngkir() + loadServiceRajaOngkir(); } else { - setListServiceExpedisi() - setBiayaKirim(0) - setselectedExpedisiService() - setEtd() + setListServiceExpedisi(); + setBiayaKirim(0); + setselectedExpedisiService(); + setEtd(); } - }, [selectedCarrier, selectedAddress, totalWeight]) + }, [selectedCarrier, selectedAddress, totalWeight]); useEffect(() => { if (selectedServiceType) { - let serviceType = selectedServiceType.split(',') - setBiayaKirim(serviceType[0]) - setselectedExpedisiService(serviceType[1]) - setEtd(serviceType[2]) + let serviceType = selectedServiceType.split(','); + setBiayaKirim(serviceType[0]); + setselectedExpedisiService(serviceType[1]); + setEtd(serviceType[2]); } - }, [selectedServiceType]) + }, [selectedServiceType]); useEffect(() => { - if (etd) setEtdFix(calculateEstimatedArrival(etd)) - }, [etd]) + if (etd) setEtdFix(calculateEstimatedArrival(etd)); + }, [etd]); useEffect(() => { if (selectedExpedisi) { - let serviceType = selectedExpedisi.split(',') - if (serviceType[0] === 0) return + let serviceType = selectedExpedisi.split(','); + if (serviceType[0] === 0) return; - setselectedCarrier(serviceType[0]) - setselectedCarrierId(serviceType[1]) - setListServiceExpedisi([]) + setselectedCarrier(serviceType[0]); + setselectedCarrierId(serviceType[1]); + setListServiceExpedisi([]); } - }, [selectedExpedisi]) + }, [selectedExpedisi]); - const poNumber = useRef(null) - const poFile = useRef(null) + const poNumber = useRef(null); + const poFile = useRef(null); - const [isLoading, setIsLoading] = useState(false) + const [isLoading, setIsLoading] = useState(false); const checkout = async () => { - const file = poFile.current.files[0] + const file = poFile.current.files[0]; if (typeof file !== 'undefined' && file.size > 5000000) { - toast.error('Maksimal ukuran file adalah 5MB', { position: 'bottom-center' }) - return + toast.error('Maksimal ukuran file adalah 5MB', { + position: 'bottom-center', + }); + return; } if (selectedExpedisi === 0) { - setCheckoutValidation(true) + setCheckoutValidation(true); if (expedisiValidation.current) { - const position = expedisiValidation.current.getBoundingClientRect() + const position = expedisiValidation.current.getBoundingClientRect(); window.scrollTo({ top: position.top - 300 + window.pageYOffset, - behavior: 'smooth' - }) + behavior: 'smooth', + }); } - return + return; } if (selectedCarrier != 1 && biayaKirim == 0) { - toast.error('Maaf, layanan tidak tersedia. Mohon pilih expedisi lain.') - return + toast.error('Maaf, layanan tidak tersedia. Mohon pilih expedisi lain.'); + return; } - setIsLoading(true) + 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, @@ -319,80 +333,82 @@ const Checkout = () => { estimated_arrival_days: splitDuration(etd), delivery_service_type: selectedExpedisiService, voucher: activeVoucher, - type: 'sale_order' - } + type: 'sale_order', + }; if (query) { - data.source = 'buy' + data.source = 'buy'; } - if (poNumber.current.value) data.po_number = poNumber.current.value - if (typeof file !== 'undefined') data.po_file = await getFileBase64(file) + if (poNumber.current.value) data.po_number = poNumber.current.value; + if (typeof file !== 'undefined') data.po_file = await getFileBase64(file); - const isCheckouted = await checkoutApi({ data }) + const isCheckouted = await checkoutApi({ data }); if (!isCheckouted?.id) { - toast.error('Gagal melakukan transaksi, terjadi kesalahan internal') - return + toast.error('Gagal melakukan transaksi, terjadi kesalahan internal'); + return; } - gtagPurchase(products, biayaKirim, isCheckouted.name) + gtagPurchase(products, biayaKirim, isCheckouted.name); const midtrans = async () => { - for (const product of products) deleteItemCart({ productId: product.id }) + for (const product of products) deleteItemCart({ productId: product.id }); const payment = await axios.post( `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/midtrans-payment?transactionId=${isCheckouted.id}` - ) - setIsLoading(false) - window.location.href = payment.data.redirectUrl - } + ); + setIsLoading(false); + window.location.href = payment.data.redirectUrl; + }; gtag('event', 'conversion', { send_to: 'AW-954540379/nDymCL3BhaQYENvClMcD', - value: cartCheckout?.grandTotal + Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000, + value: + cartCheckout?.grandTotal + + Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000, currency: 'IDR', transaction_id: isCheckouted.id, - event_callback: midtrans - }) - } + event_callback: midtrans, + }); + }; const handlingActivateCode = async () => { - VoucherCode(codeVoucher) - } + VoucherCode(codeVoucher); + }; const handleUseVoucher = async (code, isCheck) => { if (isCheck) { if (code === activeVoucher) { - SetActiveVoucher(null) - SetDiscountVoucher(0) + SetActiveVoucher(null); + SetDiscountVoucher(0); } else { - SetActiveVoucher(code) - SetFindVoucher(null) - document.getElementById('uniqCode').value = '' - SetButtonTerapkan(false) + SetActiveVoucher(code); + SetFindVoucher(null); + document.getElementById('uniqCode').value = ''; + SetButtonTerapkan(false); } } else { - SetActiveVoucher(code) - SetFindVoucher(null) - document.getElementById('uniqCode').value = '' - SetButtonTerapkan(false) + SetActiveVoucher(code); + SetFindVoucher(null); + document.getElementById('uniqCode').value = ''; + SetButtonTerapkan(false); } - } + }; const onChangeCodeVoucher = async (e) => { - SetCodeVoucher(e.target.value) - SetButtonTerapkan(false) - } + SetCodeVoucher(e.target.value); + SetButtonTerapkan(false); + }; - const [isChecked, setIsChecked] = useState(false) + const [isChecked, setIsChecked] = useState(false); const ToggleSwitch = (code) => { - setIsChecked(!isChecked) - handleUseVoucher(code, !isChecked) - } + setIsChecked(!isChecked); + handleUseVoucher(code, !isChecked); + }; const handlingTnC = async (item) => { - setItemTnC(item) - SetBottomPopupTnC(true) - } + setItemTnC(item); + SetBottomPopupTnC(true); + }; // const taxTotal = (totalAmount - totalDiscountAmount - discountVoucher) * 0.11 return ( @@ -401,13 +417,17 @@ const Checkout = () => { className='w-full md:!w-[40%] !min-h-[90vh]' active={bottomPopupTnC} close={() => { - SetBottomPopupTnC(false) - SetBottomPopup(false) + SetBottomPopupTnC(false); + SetBottomPopup(false); }} title={
- {' '}
} @@ -420,13 +440,17 @@ const Checkout = () => { {' '} Berakhir dalam :{' '} - {itemTnC?.remainingTime} lagi + + {itemTnC?.remainingTime} lagi +
Kode Voucher : - {itemTnC?.code} + + {itemTnC?.code} +
@@ -441,6 +465,7 @@ const Checkout = () => {
+ { title='Gunakan Promo' >
-
-
+
+
{ {findCodeVoucher === 1 && (
- Kode voucher salah / sudah tidak berlaku lagi. Coba voucher lainnya, ya. + Kode voucher salah / sudah tidak berlaku lagi. Coba voucher + lainnya, ya.
)} {findCodeVoucher === 2 && (
- Tambah {selisihHargaCode} untuk pakai promo - ini + Tambah {selisihHargaCode}{' '} + untuk pakai promo ini
)} @@ -500,15 +526,21 @@ const Checkout = () => {

Tidak ada voucher tersedia

-

Maaf, saat ini tidak ada voucher yang tersedia.

+

+ Maaf, saat ini tidak ada voucher yang tersedia. +

) : ( -

Promo Khusus Untuk {auth?.name}

+

+ Promo Khusus Untuk {auth?.name} +

)} {loadingVoucher && ( <> -
+
{
-
+
{ >

Voucher tidak bisa di gunakan,{' '} - Baca Selengkapnya ! + + Baca Selengkapnya ! +

)} @@ -589,14 +625,20 @@ const Checkout = () => {
)}
- {item.name} + {item.name}

{item.name}

- {item.description} + + {item.description}{' '} +
@@ -605,7 +647,9 @@ const Checkout = () => { type='checkbox' value='' class='sr-only peer' - checked={activeVoucher === item.code ? true : false} + checked={ + activeVoucher === item.code ? true : false + } onChange={() => ToggleSwitch(item.code)} />
@@ -616,11 +660,15 @@ const Checkout = () => {

Kode Voucher :{' '} - {item.code} + + {item.code} +

{activeVoucher === item.code && ( - Voucher digunakan + + Voucher digunakan{' '} + )}

@@ -642,7 +690,10 @@ const Checkout = () => {
Berakhir dalam{' '} - {item.remainingTime} lagi,{' '} + + {item.remainingTime} + {' '} + lagi,{' '}
{
+
@@ -677,8 +729,8 @@ const Checkout = () => {
- Jika mengalami kesulitan dalam melakukan pembelian di website Indoteknik. Hubungi kami - disini + Jika mengalami kesulitan dalam melakukan pembelian di website + Indoteknik. Hubungi kami disini
@@ -701,14 +753,17 @@ const Checkout = () => { Info
- Fitur Self Pickup, hanya berlaku untuk customer di area jakarta. Apa bila memilih - fitur ini, anda akan dihubungi setelah barang siap diambil. + Fitur Self Pickup, hanya berlaku untuk customer di area jakarta. + Apa bila memilih fitur ini, anda akan dihubungi setelah barang + siap diambil.
)} - {selectedCarrierId == SELF_PICKUP_ID && } + {selectedCarrierId == SELF_PICKUP_ID && ( + + )} {selectedCarrierId != SELF_PICKUP_ID && ( <> { />
- {products && } + {!!products && + snakecaseKeys(products).map((item, index) => ( + + ))}
@@ -750,7 +808,6 @@ const Checkout = () => {
Ringkasan Pesanan
-
{products?.length} Barang

{!cartCheckout ? ( @@ -804,7 +861,9 @@ const Checkout = () => { {activeVoucher && (
Diskon Voucher
-
- {currencyFormat(discountVoucher)}
+
+ - {currencyFormat(discountVoucher)} +
)}
@@ -819,7 +878,11 @@ const Checkout = () => {
Biaya Kirim

{etdFix}

-
{currencyFormat(Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000)}
+
+ {currencyFormat( + Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000 + )} +
)} @@ -840,7 +903,8 @@ const Checkout = () => {
Grand Total
{currencyFormat( - cartCheckout?.grandTotal + Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000 + cartCheckout?.grandTotal + + Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000 )}
@@ -852,8 +916,8 @@ const Checkout = () => {
{/*

*) Belum termasuk biaya pengiriman

*/}

- Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui{' '} + Dengan melakukan pembelian melalui website Indoteknik, saya + menyetujui{' '} Syarat & Ketentuan {' '} @@ -911,10 +976,16 @@ const Checkout = () => {

- +
-

Ukuran dokumen PO Maksimal 5MB

+

+ Ukuran dokumen PO Maksimal 5MB +

@@ -923,7 +994,9 @@ const Checkout = () => { @@ -957,8 +1030,9 @@ const Checkout = () => { Info
- Fitur Self Pickup, hanya berlaku untuk customer di area jakarta. Apa bila memilih - fitur ini, anda akan dihubungi setelah barang siap diambil. + Fitur Self Pickup, hanya berlaku untuk customer di area jakarta. + Apa bila memilih fitur ini, anda akan dihubungi setelah barang + siap diambil.
)} @@ -966,7 +1040,9 @@ const Checkout = () => {
{' '}
- {selectedCarrierId == SELF_PICKUP_ID && } + {selectedCarrierId == SELF_PICKUP_ID && ( + + )} {selectedCarrierId != SELF_PICKUP_ID && ( <> { />
-
Detail Pesanan
- - - {/* - - - - - - - - - - {!products ? ( - - - - ) : ( - products?.map((product) => ( - <> - - - - - - - {product.program && - product.program.items && - product.program.items.map((item) => ( - <> - - - - - - - - - ))} - - )) - )} - -
Nama ProdukJumlahHargaSubtotal
-
-
-
-
-
-
-
-
- {product?.name} -
-
-
- {product?.parent?.name} -
-
- {product?.code}{' '} - {product?.attributes.length > 0 - ? `| ${product?.attributes.join(', ')}` - : ''} -
-
- Berat item : {product?.weight} Kg -
-
-
- - - {product?.hasFlashsale ? ( - <> -
-
- {currencyFormat(product?.price?.price)} -
-
- {product?.price?.discountPercentage}% -
-
-
- {currencyFormat(product?.price?.priceDiscount)} -
- - ) : ( -
- {product.price.priceDiscount > 0 - ? currencyFormat(product?.price?.priceDiscount) - : 'Call for Inquiry'} -
- )} -
-
- {product.price.priceDiscount > 0 ? ( - currencyFormat(product?.price?.priceDiscount * product?.quantity) - ) : ( - - Call for Inquiry{' '} - - )} -
-
-
- {item.name} -
-
-
- - {product.program.type.label} - -
-
{item.name}
-
-
- - - {item?.price?.discountPercentage > 0 && ( -
-
- {currencyFormat(product?.price?.price)} -
-
- )} -
- {item?.price.priceDiscount > 0 ? 'Gratis' : ''} -
-
-
- {item.price.priceDiscount > 0 ? 'Gratis' : ''} -
-
*/} +
Detail Pesanan
+
+ {!!products && + snakecaseKeys(products).map((item, index) => ( + + ))} +
@@ -1171,7 +1090,8 @@ const Checkout = () => {
Ringkasan Pesanan
- {products?.length} Barang - {cartCheckout?.totalWeight.kg} Kg + {cartCheckout?.totalWeight.kg}{' '} + Kg
@@ -1227,7 +1147,9 @@ const Checkout = () => { {activeVoucher && (
Diskon Voucher
-
- {currencyFormat(discountVoucher)}
+
+ - {currencyFormat(discountVoucher)} +
)}
@@ -1244,7 +1166,9 @@ const Checkout = () => {

{etdFix}

- {currencyFormat(Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000)} + {currencyFormat( + Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000 + )}
@@ -1279,8 +1203,8 @@ const Checkout = () => {

- Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui{' '} + Dengan melakukan pembelian melalui website Indoteknik, saya + menyetujui{' '} Syarat & Ketentuan {' '} @@ -1322,7 +1247,8 @@ const Checkout = () => {


- Purchase Order (Opsional) + Purchase Order{' '} + (Opsional)
@@ -1337,17 +1263,28 @@ const Checkout = () => {
- +
-

Ukuran dokumen PO Maksimal 5MB

+

+ Ukuran dokumen PO Maksimal 5MB +


@@ -1367,8 +1304,8 @@ const Checkout = () => {
- ) -} + ); +}; const SectionAddress = ({ address, label, url }) => (
@@ -1382,7 +1319,9 @@ const SectionAddress = ({ address, label, url }) => ( {address && (
- {address.type.charAt(0).toUpperCase() + address.type.slice(1) + ' Address'} + {address.type.charAt(0).toUpperCase() + + address.type.slice(1) + + ' Address'}

{address.name}

{address.mobile}

@@ -1392,7 +1331,7 @@ const SectionAddress = ({ address, label, url }) => (
)}
-) +); const SectionValidation = ({ address }) => address?.rajaongkirCityId == 0 && ( @@ -1409,7 +1348,7 @@ const SectionValidation = ({ address }) =>
- ) + ); const SectionExpedisi = ({ address, @@ -1418,7 +1357,7 @@ const SectionExpedisi = ({ checkWeigth, checkoutValidation, expedisiValidation, - loadingRajaOngkir + loadingRajaOngkir, }) => address?.rajaongkirCityId > 0 && (
@@ -1427,7 +1366,9 @@ const SectionExpedisi = ({
setSelectedServiceType(e.target.value)}> + @@ -1520,73 +1469,73 @@ const SectionListService = ({ listserviceExpedisi, setSelectedServiceType }) =>
- ) + ); function addDays(date, days) { - const result = new Date(date) - result.setDate(result.getDate() + days) - return result + const result = new Date(date); + result.setDate(result.getDate() + days); + return result; } function formatDate(date) { - const day = date.getDate() - const month = date.toLocaleString('default', { month: 'short' }) - return `${day} ${month}` + const day = date.getDate(); + const month = date.toLocaleString('default', { month: 'short' }); + return `${day} ${month}`; } function calculateEstimatedArrival(duration) { if (duration) { - let estimationDate = duration.split('-') - estimationDate[0] = parseInt(estimationDate[0]) - estimationDate[1] = parseInt(estimationDate[1]) - const from = addDays(new Date(), estimationDate[0] + 3) - const to = addDays(new Date(), estimationDate[1] + 3) + let estimationDate = duration.split('-'); + estimationDate[0] = parseInt(estimationDate[0]); + estimationDate[1] = parseInt(estimationDate[1]); + const from = addDays(new Date(), estimationDate[0] + 3); + const to = addDays(new Date(), estimationDate[1] + 3); - let etdText = `*Estimasi tiba ${formatDate(from)}` + let etdText = `*Estimasi tiba ${formatDate(from)}`; if (estimationDate[1] > estimationDate[0]) { - etdText += ` - ${formatDate(to)}` + etdText += ` - ${formatDate(to)}`; } - return etdText + return etdText; } - return '' + return ''; } function splitDuration(duration) { if (duration) { - let estimationDate = null + let estimationDate = null; if (duration.includes('-')) { - estimationDate = duration.split('-') - estimationDate = parseInt(estimationDate[1]) + estimationDate = duration.split('-'); + estimationDate = parseInt(estimationDate[1]); } else { - estimationDate = parseInt(duration) + estimationDate = parseInt(duration); } - return estimationDate + return estimationDate; } - return '' + return ''; } const extractDuration = (text) => { - const matches = text.match(/\d+(?:-\d+)?/g) + const matches = text.match(/\d+(?:-\d+)?/g); if (matches && matches.length === 1) { - const parts = matches[0].split('-') - const min = parseInt(parts[0]) - const max = parseInt(parts[1]) + const parts = matches[0].split('-'); + const min = parseInt(parts[0]); + const max = parseInt(parts[1]); if (min === max) { - return min.toString() + return min.toString(); } - return matches[0] + return matches[0]; } - return '' -} + return ''; +}; const PickupAddress = ({ label }) => (
@@ -1596,13 +1545,14 @@ const PickupAddress = ({ label }) => (

Indoteknik

- Jl. Bandengan Utara Raya No.85, RT.3/RW.16, Penjaringan, Kec. Penjaringan, Kota Jkt Utara, - Daerah Khusus Ibukota Jakarta, Indonesia Kodepos : 14440 + Jl. Bandengan Utara Raya No.85, RT.3/RW.16, Penjaringan, Kec. + Penjaringan, Kota Jkt Utara, Daerah Khusus Ibukota Jakarta, Indonesia + Kodepos : 14440

Telp : 021-2933 8828/29

Mobile : 0813 9000 7430

-) +); -export default Checkout +export default Checkout; diff --git a/src/lib/home/api/categoryHomeApi.js b/src/lib/home/api/categoryHomeApi.js index 9e7d1402..e5def608 100644 --- a/src/lib/home/api/categoryHomeApi.js +++ b/src/lib/home/api/categoryHomeApi.js @@ -1,11 +1,10 @@ -import odooApi from '@/core/api/odooApi' -import axios from 'axios' +import axios from 'axios'; const categoryHomeIdApi = async ({ id }) => { - // const dataCategoryHomeIdO = await odooApi('GET', `/api/v1/product/category-homepage?id=${id}`) - // console.log('ini adalah odoo', dataCategoryHomeIdO) - const dataCategoryHomeId = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/product-homepage?id=` + id) - return dataCategoryHomeId.data -} + const dataCategoryHomeId = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/product-homepage?id=` + id + ); + return dataCategoryHomeId.data; +}; -export default categoryHomeIdApi +export default categoryHomeIdApi; diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index 5f034c09..4074f243 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -1,416 +1,441 @@ -import Image from '@/core/components/elements/Image/Image' -import Link from '@/core/components/elements/Link/Link' -import DesktopView from '@/core/components/views/DesktopView' -import currencyFormat from '@/core/utils/currencyFormat' -import { HeartIcon } from '@heroicons/react/24/outline' -import { useCallback, useEffect, useRef, useState } from 'react' -import LazyLoad from 'react-lazy-load' -import ProductSimilar from '../ProductSimilar' -import { toast } from 'react-hot-toast' -import { updateItemCart } from '@/core/utils/cart' -import { useRouter } from 'next/router' -import { createSlug } from '@/core/utils/slug' -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import ProductCard from '../ProductCard' -import productSimilarApi from '../../api/productSimilarApi' -import whatsappUrl from '@/core/utils/whatsappUrl' -import odooApi from '@/core/api/odooApi' -import PromotionType from '@/lib/promotinProgram/components/PromotionType' -import useAuth from '@/core/hooks/useAuth' -import ImageNext from 'next/image' -import CountDown2 from '@/core/components/elements/CountDown/CountDown2' -import { LazyLoadComponent } from 'react-lazy-load-image-component' -import ColumnsSLA from './ColumnsSLA' -import { useProductCartContext } from '@/contexts/ProductCartContext' -import { Box, Skeleton, Tooltip } from '@chakra-ui/react' -import { Info } from 'lucide-react' -import Breadcrumb from './Breadcrumb' -import { sellingProductFormat } from '@/core/utils/formatValue' +import { useEffect, useRef, useState } from 'react'; +import ImageNext from 'next/image'; +import { LazyLoadComponent } from 'react-lazy-load-image-component'; +import { Box, Skeleton, Tooltip } from '@chakra-ui/react'; +import { HeartIcon } from '@heroicons/react/24/outline'; +import { Info } from 'lucide-react'; +import LazyLoad from 'react-lazy-load'; +import { toast } from 'react-hot-toast'; +import { useRouter } from 'next/router'; + +import Image from '@/core/components/elements/Image/Image'; +import Link from '@/core/components/elements/Link/Link'; +import DesktopView from '@/core/components/views/DesktopView'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import CountDown2 from '@/core/components/elements/CountDown/CountDown2'; + +import currencyFormat from '@/core/utils/currencyFormat'; +import { updateItemCart } from '@/core/utils/cart'; +import { createSlug } from '@/core/utils/slug'; +import whatsappUrl from '@/core/utils/whatsappUrl'; +import { sellingProductFormat } from '@/core/utils/formatValue'; + +import odooApi from '@/core/api/odooApi'; +import useAuth from '@/core/hooks/useAuth'; + +import { useProductCartContext } from '@/contexts/ProductCartContext'; + +import PromotionType from '@/lib/promotinProgram/components/PromotionType'; + +import ProductSimilar from '../ProductSimilar'; +import ProductCard from '../ProductCard'; +import productSimilarApi from '../../api/productSimilarApi'; +import ColumnsSLA from './ColumnsSLA'; +import Breadcrumb from './Breadcrumb'; + +import ProductPromoSection from '~/modules/product-promo/components/Section'; const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { - const router = useRouter() - const auth = useAuth() - const { slug } = router.query + const router = useRouter(); + const auth = useAuth(); + const { slug } = router.query; - const [quantityActive, setQuantity] = useState(null) - const [lowestPrice, setLowestPrice] = useState(null) - const [product, setProducts] = useState(products) + const [quantityActive, setQuantity] = useState(null); + const [lowestPrice, setLowestPrice] = useState(null); + const [product, setProducts] = useState(products); - const [addCartAlert, setAddCartAlert] = useState(false) - const [isLoadingSLA, setIsLoadingSLA] = useState(true) - const [promotionType, setPromotionType] = useState(false) - const [promotionActiveId, setPromotionActiveId] = useState(null) - const [selectVariantPromoActive, setSelectVariantPromoActive] = useState(null) - const [backgorundFlashSale, setBackgorundFlashSale] = useState(null) + const [addCartAlert, setAddCartAlert] = useState(false); + const [isLoadingSLA, setIsLoadingSLA] = useState(true); + const [promotionType, setPromotionType] = useState(false); + const [promotionActiveId, setPromotionActiveId] = useState(null); + const [selectVariantPromoActive, setSelectVariantPromoActive] = + useState(null); + const [backgorundFlashSale, setBackgorundFlashSale] = useState(null); - const { setRefreshCart, refreshCart } = useProductCartContext() + const { setRefreshCart, refreshCart } = useProductCartContext(); useEffect(() => { - setLowestPrice({ price: product?.lowestPrice }) - }, [product]) + setLowestPrice({ price: product?.lowestPrice }); + }, [product]); useEffect(() => { const getBackgound = async () => { - const get = await odooApi('GET', '/api/v1/banner?type=flash-sale-background-banner') - setBackgorundFlashSale(get[0].image) - } - getBackgound() - }, []) + const get = await odooApi( + 'GET', + '/api/v1/banner?type=flash-sale-background-banner' + ); + setBackgorundFlashSale(get[0].image); + }; + getBackgound(); + }, []); - const [informationTab, setInformationTab] = useState(informationTabOptions[0].value) + const [informationTab, setInformationTab] = useState( + informationTabOptions[0].value + ); - const variantQuantityRefs = useRef([]) + const variantQuantityRefs = useRef([]); const setVariantQuantityRef = (variantId) => (element) => { if (element) { - let variantIndex = product.variants.findIndex((varian) => varian.id == variantId) - product.variants[variantIndex].quantity = element?.value + let variantIndex = product.variants.findIndex( + (varian) => varian.id == variantId + ); + product.variants[variantIndex].quantity = element?.value; } - variantQuantityRefs.current[variantId] = element - } + variantQuantityRefs.current[variantId] = element; + }; const validQuantity = (quantity) => { - let isValid = true + let isValid = true; if (!quantity || quantity < 1 || isNaN(parseInt(quantity))) { - toast.error('Jumlah barang minimal 1') - isValid = false + toast.error('Jumlah barang minimal 1'); + isValid = false; } - return isValid - } + return isValid; + }; const updateCart = (variantId, quantity, source) => { let dataUpdate = { productId: variantId, quantity, selected: true, - source: source === 'buy' ? 'buy' : null - } + source: source === 'buy' ? 'buy' : null, + }; if (product.variants.length > 1) { - let variantIndex = product.variants.findIndex((varian) => varian.id == variantId) - dataUpdate['programLineId'] = product.variants[variantIndex].programActive + let variantIndex = product.variants.findIndex( + (varian) => varian.id == variantId + ); + dataUpdate['programLineId'] = + product.variants[variantIndex].programActive; } else { - dataUpdate['programLineId'] = promotionActiveId + dataUpdate['programLineId'] = promotionActiveId; } - updateItemCart(dataUpdate) - } + updateItemCart(dataUpdate); + }; const redirectToLogin = (action, variantId, quantity) => { - const nextURL = `/shop/product/${slug}?action=${action}&variantId=${variantId}&qty=${quantity}` - router.push(`/login?next=${encodeURIComponent(nextURL)}`) - return true - } + const nextURL = `/shop/product/${slug}?action=${action}&variantId=${variantId}&qty=${quantity}`; + router.push(`/login?next=${encodeURIComponent(nextURL)}`); + return true; + }; const handleAddToCart = (variantId) => { - const quantity = variantQuantityRefs.current[variantId].value + const quantity = variantQuantityRefs.current[variantId].value; - if (!validQuantity(quantity)) return + if (!validQuantity(quantity)) return; if (!auth) { - return redirectToLogin('add_to_cart', variantId, quantity) + return redirectToLogin('add_to_cart', variantId, quantity); } - let source = 'cart' - updateCart(variantId, quantity, source) - setRefreshCart(true) - setAddCartAlert(true) - } + let source = 'cart'; + updateCart(variantId, quantity, source); + setRefreshCart(true); + setAddCartAlert(true); + }; const handleQuantityChange = (variantId) => (event) => { - const { value } = event.target - const variantIndex = product.variants.findIndex((variant) => variant.id === variantId) + const { value } = event.target; + const variantIndex = product.variants.findIndex( + (variant) => variant.id === variantId + ); if (variantIndex !== -1) { - product.variants[variantIndex].quantity = parseInt(value, 10) // Pastikan untuk mengubah ke tipe number jika diperlukan + product.variants[variantIndex].quantity = parseInt(value, 10); // Pastikan untuk mengubah ke tipe number jika diperlukan // Lakukan sesuatu jika nilai quantity diubah } - } + }; const handleBuy = (variant) => { - const quantity = variantQuantityRefs.current[variant].value - if (!validQuantity(quantity)) return + const quantity = variantQuantityRefs.current[variant].value; + if (!validQuantity(quantity)) return; if (!auth) { - return redirectToLogin('buy', variant, quantity) + return redirectToLogin('buy', variant, quantity); } - let source = 'buy' - updateCart(variant, quantity, source) - router.push(`/shop/checkout?source=buy`) - } + let source = 'buy'; + updateCart(variant, quantity, source); + router.push(`/shop/checkout?source=buy`); + }; - const variantSectionRef = useRef(null) + const variantSectionRef = useRef(null); const goToVariantSection = () => { if (variantSectionRef.current) { - const position = variantSectionRef.current.getBoundingClientRect() + const position = variantSectionRef.current.getBoundingClientRect(); window.scrollTo({ top: position.top - 120 + window.pageYOffset, - behavior: 'smooth' - }) + behavior: 'smooth', + }); } - } + }; const handlePromoClick = (variantId) => { - setSelectVariantPromoActive(variantId) - setPromotionType(true) - } + setSelectVariantPromoActive(variantId); + setPromotionType(true); + }; const productSimilarQuery = [ product?.name, `fq=-product_id_i:${product.id}`, - `fq=-manufacture_id_i:${product.manufacture?.id || 0}` - ].join('&') + `fq=-manufacture_id_i:${product.manufacture?.id || 0}`, + ].join('&'); - const [productSimilarInBrand, setProductSimilarInBrand] = useState(null) + const [productSimilarInBrand, setProductSimilarInBrand] = useState(null); useEffect(() => { const loadProductSimilarInBrand = async () => { - const productSimilarQuery = [product?.name, `fq=-product_id_i:${product.id}`].join('&') - const source = 'right' - const dataProductSimilar = await productSimilarApi({ query: productSimilarQuery, source }) - setProductSimilarInBrand(dataProductSimilar.products) - } - if (!productSimilarInBrand) loadProductSimilarInBrand() - }, [product, productSimilarInBrand]) + const productSimilarQuery = [ + product?.name, + `fq=-product_id_i:${product.id}`, + ].join('&'); + const source = 'right'; + const dataProductSimilar = await productSimilarApi({ + query: productSimilarQuery, + source, + }); + setProductSimilarInBrand(dataProductSimilar.products); + }; + if (!productSimilarInBrand) loadProductSimilarInBrand(); + }, [product, productSimilarInBrand]); useEffect(() => { const fetchData = async () => { const promises = product.variants.map(async (variant) => { - const dataSLA = await odooApi('GET', `/api/v1/product_variant/${variant.id}/stock`) + const dataSLA = await odooApi( + 'GET', + `/api/v1/product_variant/${variant.id}/stock` + ); return { ...variant, - sla: dataSLA - } - }) - const variantData = await Promise.all(promises) - product.variants = variantData + sla: dataSLA, + }; + }); + const variantData = await Promise.all(promises); + product.variants = variantData; - setIsLoadingSLA(false) - } - if (product.variantTotal == 1) fetchData() - }, [product]) + setIsLoadingSLA(false); + }; + if (product.variantTotal == 1) fetchData(); + }, [product]); return (
-
-
-
-
- {product?.flashSale?.remainingTime > 0 && - lowestPrice?.price.discountPercentage > 0 && ( -
-
- -
-
-
-
- - {Math.floor(product.lowestPrice.discountPercentage)}% - -
-
- - - {product?.flashSale?.tag != 'false' || product?.flashSale?.tag - ? product?.flashSale?.tag - : 'FLASH SALE'} - -
-
- -
+ +
+
+
+ {product?.flashSale?.remainingTime > 0 && + lowestPrice?.price.discountPercentage > 0 && ( +
+
+ +
+
+
+
+ + {Math.floor(product.lowestPrice.discountPercentage)} + % + +
+
+ + + {product?.flashSale?.tag != 'false' || + product?.flashSale?.tag + ? product?.flashSale?.tag + : 'FLASH SALE'} + +
+
+
- )} - {product.name} -
-
-

- Keterangan : Gambar atau foto berperan - sebagai ilustrasi produk. Kadang tidak sesuai dengan kondisi terbaru dengan - berbagai perubahan dan perbaikan. Hubungi tim sales kami untuk informasi yang - lebih baik perihal gambar di 021-2933 8828. -

-
-
- -
-

{product?.name}

-
-
-
Nomor SKU
-
SKU-{product.id}
-
-
-
Part Number
-
{product.code || '-'}
-
-
-
Manufacture
-
- {product.manufacture?.name ? ( - - {product.manufacture?.name} - - ) : ( -
-
- )}
-
-
-
Persiapan Barang
-
- {product.variants.length > 1 && ( - - )} + )} + {product.name} +
+
+

+ Keterangan : Gambar atau + foto berperan sebagai ilustrasi produk. Kadang tidak sesuai + dengan kondisi terbaru dengan berbagai perubahan dan perbaikan. + Hubungi tim sales kami untuk informasi yang lebih baik perihal + gambar di 021-2933 8828. +

+
+
- {product.variants.length === 1 && ( - <> - {!product.variants[0]?.sla && } - {product.variants[0]?.sla && ( - - - {product.variants[0]?.sla?.slaDate} - - - - )} - - )} -
+
+

+ {product?.name} +

+
+
+
Nomor SKU
+
SKU-{product.id}
+
+
+
Part Number
+
{product.code || '-'}
+
+
+
Manufacture
+
+ {product.manufacture?.name ? ( + + {product.manufacture?.name} + + ) : ( +
-
+ )}
+
+
+
Persiapan Barang
+
+ {product.variants.length > 1 && ( + + )} - {product.variants.length === 1 && ( -
-
Stock
-
- {!product.variants[0]?.sla && } - {product?.variants[0].sla?.qty > 0 && ( - {product?.variants[0].sla?.qty} + {product.variants.length === 1 && ( + <> + {!product.variants[0]?.sla && ( + )} - {product?.variants[0].sla?.qty == 0 && ( - - Tanya Admin - + + {product.variants[0]?.sla?.slaDate} + + + )} -
-
- )} + + )} +
+
-
1 ? '' : 'bg-gray_r-4'} `}> -
Berat Barang
+ {product.variants.length === 1 && ( +
+
Stock
- {product?.weight > 0 && {product?.weight} KG} - {product?.weight == 0 && ( + {!product.variants[0]?.sla && ( + + )} + {product?.variants[0].sla?.qty > 0 && ( + {product?.variants[0].sla?.qty} + )} + {product?.variants[0].sla?.qty == 0 && ( - Tanya Berat + Tanya Admin )}
- {product.variants.length <= 1 && ( -
-
- -
-
- )} -
-
+ )} -
-
-
Informasi Produk
-
- {informationTabOptions.map((option) => ( - setInformationTab(option.value)} +
1 ? '' : 'bg-gray_r-4' + } `} + > +
Berat Barang
+
+ {product?.weight > 0 && {product?.weight} KG} + {product?.weight == 0 && ( + - {option.label} - - ))} + Tanya Berat + + )}
-
-
- - - - - - Belum ada informasi. - +
+ {product.variants.length <= 1 && ( +
+
+ +
-
+ )}
-
- {product.variants.length > 1 && product.lowestPrice.priceDiscount > 0 && ( -
Harga mulai dari:
- )} +
+ {product.variants.length > 1 && + product.lowestPrice.priceDiscount > 0 && ( +
Harga mulai dari:
+ )} {/* {lowestPrice?.discountPercentage > 0 && (
@@ -441,7 +466,8 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { {sellingProductFormat(product?.qtySold) + ' Terjual'}
)} - {product?.flashSale?.id && lowestPrice?.price.discountPercentage > 0 ? ( + {product?.flashSale?.id && + lowestPrice?.price.discountPercentage > 0 ? ( <>
@@ -456,7 +482,10 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
Termasuk PPN:{' '} - {currencyFormat(lowestPrice?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN)} + {currencyFormat( + lowestPrice?.price.priceDiscount * + process.env.NEXT_PUBLIC_PPN + )}
) : ( @@ -466,7 +495,9 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { {currencyFormat(lowestPrice?.price.price)}
Termasuk PPN:{' '} - {currencyFormat(lowestPrice?.price.price * process.env.NEXT_PUBLIC_PPN)} + {currencyFormat( + lowestPrice?.price.price * process.env.NEXT_PUBLIC_PPN + )}
) : ( @@ -476,7 +507,12 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { href={whatsappUrl('product', { name: product.name, manufacture: product.manufacture?.name, - url: createSlug('/shop/product/', product.name, product.id, true) + url: createSlug( + '/shop/product/', + product.name, + product.id, + true + ), })} className='text-danger-500 underline' rel='noopener noreferrer' @@ -524,7 +560,10 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { )}
- - ) -} + ); +}; const TabContent = ({ children, active, className = '', ...props }) => (
{children}
-) +); -export default ProductDesktop +export default ProductDesktop; diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx index e23e2fb9..e9e64469 100644 --- a/src/lib/product/components/Product/ProductMobile.jsx +++ b/src/lib/product/components/Product/ProductMobile.jsx @@ -1,60 +1,66 @@ -import Divider from '@/core/components/elements/Divider/Divider' -import Image from '@/core/components/elements/Image/Image' -import Link from '@/core/components/elements/Link/Link' -import currencyFormat from '@/core/utils/currencyFormat' -import { useEffect, useState } from 'react' -import Select from 'react-select' -import ProductSimilar from '../ProductSimilar' -import LazyLoad from 'react-lazy-load' -import { updateItemCart } from '@/core/utils/cart' -import { HeartIcon } from '@heroicons/react/24/outline' -import { useRouter } from 'next/router' -import MobileView from '@/core/components/views/MobileView' -import { toast } from 'react-hot-toast' -import { createSlug } from '@/core/utils/slug' -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import whatsappUrl from '@/core/utils/whatsappUrl' -import PromotionType from '@/lib/promotinProgram/components/PromotionType' -import { gtagAddToCart } from '@/core/utils/googleTag' -import odooApi from '@/core/api/odooApi' -import ImageNext from 'next/image' -import CountDown2 from '@/core/components/elements/CountDown/CountDown2' -import Breadcrumb from './Breadcrumb' -import useAuth from '@/core/hooks/useAuth' -import { sellingProductFormat } from '@/core/utils/formatValue' +import Divider from '@/core/components/elements/Divider/Divider'; +import Image from '@/core/components/elements/Image/Image'; +import Link from '@/core/components/elements/Link/Link'; +import currencyFormat from '@/core/utils/currencyFormat'; +import { useEffect, useState } from 'react'; +import Select from 'react-select'; +import ProductSimilar from '../ProductSimilar'; +import LazyLoad from 'react-lazy-load'; +import { updateItemCart } from '@/core/utils/cart'; +import { HeartIcon } from '@heroicons/react/24/outline'; +import { useRouter } from 'next/router'; +import MobileView from '@/core/components/views/MobileView'; +import { toast } from 'react-hot-toast'; +import { createSlug } from '@/core/utils/slug'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import whatsappUrl from '@/core/utils/whatsappUrl'; +import PromotionType from '@/lib/promotinProgram/components/PromotionType'; +import { gtagAddToCart } from '@/core/utils/googleTag'; +import odooApi from '@/core/api/odooApi'; +import ImageNext from 'next/image'; +import CountDown2 from '@/core/components/elements/CountDown/CountDown2'; +import Breadcrumb from './Breadcrumb'; +import useAuth from '@/core/hooks/useAuth'; +import { sellingProductFormat } from '@/core/utils/formatValue'; +import ProductPromoSection from '~/modules/product-promo/components/Section'; const ProductMobile = ({ product, wishlist, toggleWishlist }) => { - const router = useRouter() - const auth = useAuth() - const { slug } = router.query - - const [quantity, setQuantity] = useState('1') - const [selectedVariant, setSelectedVariant] = useState(null) - const [informationTab, setInformationTab] = useState(informationTabOptions[0].value) - const [addCartAlert, setAddCartAlert] = useState(false) - - const [isLoadingSLA, setIsLoadingSLA] = useState(true) - const [promotionType, setPromotionType] = useState(false) - const [promotionActiveId, setPromotionActiveId] = useState(null) - const [backgorundFlashSale, setBackgorundFlashSale] = useState(null) + const router = useRouter(); + const auth = useAuth(); + const { slug } = router.query; + + const [quantity, setQuantity] = useState('1'); + const [selectedVariant, setSelectedVariant] = useState(null); + const [informationTab, setInformationTab] = useState( + informationTabOptions[0].value + ); + const [addCartAlert, setAddCartAlert] = useState(false); + + const [isLoadingSLA, setIsLoadingSLA] = useState(true); + const [promotionType, setPromotionType] = useState(false); + const [promotionActiveId, setPromotionActiveId] = useState(null); + const [backgorundFlashSale, setBackgorundFlashSale] = useState(null); const getLowestPrice = () => { - const prices = product.variants.map((variant) => variant.price) + const prices = product.variants.map((variant) => variant.price); const lowest = prices.reduce((lowest, price) => { - return price.priceDiscount < lowest.priceDiscount ? price : lowest - }, prices[0]) - return lowest - } + return price.priceDiscount < lowest.priceDiscount ? price : lowest; + }, prices[0]); + return lowest; + }; useEffect(() => { const getBackgound = async () => { - const get = await odooApi('GET', '/api/v1/banner?type=flash-sale-background-banner') + const get = await odooApi( + 'GET', + '/api/v1/banner?type=flash-sale-background-banner' + ); if (get.length > 0) { - setBackgorundFlashSale(get[0].image) + setBackgorundFlashSale(get[0].image); } - } - getBackgound() - }, []) + }; + getBackgound(); + }, []); const [activeVariant, setActiveVariant] = useState({ id: null, @@ -64,40 +70,44 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { stock: product.stockTotal, weight: product.weight, hasProgram: false, - qtySold: product.qtySold - }) + qtySold: product.qtySold, + }); const variantOptions = product.variants?.map((variant) => { - let label = [] + let label = []; if (variant.isFlashsale) { - label.push("🗲") + label.push("🗲"); } if (variant.code) { - label.push(`[${variant.code}]`) + label.push(`[${variant.code}]`); } if (variant.attributes.length > 0) { - label.push(variant.attributes.join(', ')) + label.push(variant.attributes.join(', ')); } else { - label.push(product.name) + label.push(product.name); } return { value: variant.id, - label: label.join(' ') - } - }) + label: label.join(' '), + }; + }); useEffect(() => { if (!selectedVariant && variantOptions.length == 1) { - setSelectedVariant(variantOptions[0]) + setSelectedVariant(variantOptions[0]); } - }, [selectedVariant, variantOptions]) + }, [selectedVariant, variantOptions]); useEffect(() => { if (selectedVariant) { - const variant = product.variants.find((variant) => variant.id == selectedVariant.value) + const variant = product.variants.find( + (variant) => variant.id == selectedVariant.value + ); const variantAttributes = - variant.attributes.length > 0 ? ' - ' + variant.attributes.join(', ') : '' + variant.attributes.length > 0 + ? ' - ' + variant.attributes.join(', ') + : ''; const newActiveVariant = { id: variant.id, @@ -108,60 +118,63 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { weight: variant.weight, hasProgram: variant.hasProgram, isFlashsale: variant.isFlashsale, - qtySold: variant.qtySold - } + qtySold: variant.qtySold, + }; - setActiveVariant(newActiveVariant) + setActiveVariant(newActiveVariant); const fetchSLA = async () => { - const dataSLA = await odooApi('GET', `/api/v1/product_variant/${variant.id}/stock`) - setActiveVariant({ ...newActiveVariant, sla: dataSLA }) - } - fetchSLA() + const dataSLA = await odooApi( + 'GET', + `/api/v1/product_variant/${variant.id}/stock` + ); + setActiveVariant({ ...newActiveVariant, sla: dataSLA }); + }; + fetchSLA(); } - }, [selectedVariant, product]) + }, [selectedVariant, product]); const validAction = () => { - let isValid = true + let isValid = true; if (!selectedVariant) { - toast.error('Pilih varian terlebih dahulu') - isValid = false + toast.error('Pilih varian terlebih dahulu'); + isValid = false; } if (!quantity || quantity < 1 || isNaN(parseInt(quantity))) { - toast.error('Jumlah barang minimal 1') - isValid = false + toast.error('Jumlah barang minimal 1'); + isValid = false; } - return isValid - } + return isValid; + }; const redirectToLogin = (action) => { - const nextURL = `/shop/product/${slug}?action=${action}&variantId=${activeVariant.id}&qty=${quantity}` - router.push(`/login?next=${encodeURIComponent(nextURL)}`) - return true - } + const nextURL = `/shop/product/${slug}?action=${action}&variantId=${activeVariant.id}&qty=${quantity}`; + router.push(`/login?next=${encodeURIComponent(nextURL)}`); + return true; + }; const handleClickCart = () => { - if (!validAction()) return - gtagAddToCart(activeVariant, quantity) + if (!validAction()) return; + gtagAddToCart(activeVariant, quantity); if (!auth) { - return redirectToLogin('add_to_cart') + return redirectToLogin('add_to_cart'); } updateItemCart({ productId: activeVariant.id, quantity, programLineId: promotionActiveId, - selected: true - }) - setAddCartAlert(true) - } + selected: true, + }); + setAddCartAlert(true); + }; const handleClickBuy = () => { - if (!validAction()) return + if (!validAction()) return; if (!auth) { - return redirectToLogin('buy') + return redirectToLogin('buy'); } updateItemCart({ @@ -169,58 +182,62 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { quantity, programLineId: promotionActiveId, selected: true, - source: 'buy' - }) - router.push(`/shop/checkout?source=buy`) - } + source: 'buy', + }); + router.push(`/shop/checkout?source=buy`); + }; const productSimilarQuery = [ product?.name, `fq=-product_id_i:${product.id}`, - `fq=-manufacture_id_i:${product.manufacture?.id || 0}` - ].join('&') + `fq=-manufacture_id_i:${product.manufacture?.id || 0}`, + ].join('&'); return (
- {product?.flashSale?.remainingTime > 0 && activeVariant?.price.discountPercentage > 0 && ( -
-
- -
-
-
-
- - {Math.floor(product.lowestPrice.discountPercentage)}% - -
-
- - - {product?.flashSale?.tag != 'false' || product?.flashSale?.tag - ? product?.flashSale?.tag - : 'FLASH SALE'} - -
-
- + {product?.flashSale?.remainingTime > 0 && + activeVariant?.price.discountPercentage > 0 && ( +
+
+ +
+
+
+
+ + {Math.floor(product.lowestPrice.discountPercentage)}% + +
+
+ + + {product?.flashSale?.tag != 'false' || + product?.flashSale?.tag + ? product?.flashSale?.tag + : 'FLASH SALE'} + +
+
+ +
-
- )} + )} {product.name} {
{product.manufacture?.name ? ( {product.manufacture?.name} @@ -249,18 +270,25 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {

{activeVariant?.name}

{product?.qtySold > 0 && ( -
{sellingProductFormat(activeVariant?.qtySold) + ' Terjual'}
+
+ {sellingProductFormat(activeVariant?.qtySold) + ' Terjual'} +
)} {product.variants.length > 1 && activeVariant.price.priceDiscount > 0 && !selectedVariant && ( -
Harga mulai dari:
+
+ Harga mulai dari:{' '} +
)} - {activeVariant.isFlashsale && activeVariant?.price?.discountPercentage > 0 ? ( + {activeVariant.isFlashsale && + activeVariant?.price?.discountPercentage > 0 ? ( <>
-
{Math.floor(activeVariant?.price?.discountPercentage)}%
+
+ {Math.floor(activeVariant?.price?.discountPercentage)}% +
{currencyFormat(activeVariant?.price?.price)}
@@ -270,7 +298,9 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
Termasuk PPN:{' '} - {currencyFormat(activeVariant?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN)} + {currencyFormat( + activeVariant?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN + )}
) : ( @@ -280,7 +310,9 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { {currencyFormat(activeVariant?.price?.price)}
Termasuk PPN:{' '} - {currencyFormat(activeVariant?.price.price * process.env.NEXT_PUBLIC_PPN)} + {currencyFormat( + activeVariant?.price.price * process.env.NEXT_PUBLIC_PPN + )}
) : ( @@ -289,7 +321,12 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { @@ -307,13 +344,17 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {