diff options
Diffstat (limited to 'src-migrate/modules/cart/components/Summary.tsx')
| -rw-r--r-- | src-migrate/modules/cart/components/Summary.tsx | 201 |
1 files changed, 169 insertions, 32 deletions
diff --git a/src-migrate/modules/cart/components/Summary.tsx b/src-migrate/modules/cart/components/Summary.tsx index 0af5ab18..68db6323 100644 --- a/src-migrate/modules/cart/components/Summary.tsx +++ b/src-migrate/modules/cart/components/Summary.tsx @@ -1,20 +1,19 @@ -import style from '../styles/summary.module.css' - -import React from 'react' -import formatCurrency from '~/libs/formatCurrency' -import clsxm from '~/libs/clsxm' -import { Skeleton } from '@chakra-ui/react' -import _ from 'lodash' +import style from '../styles/summary.module.css'; +import React, { useEffect, useState, useMemo } from 'react'; +import formatCurrency from '~/libs/formatCurrency'; +import clsxm from '~/libs/clsxm'; +import { Skeleton, Box, useColorModeValue, Text } from '@chakra-ui/react'; type Props = { - total?: number - discount?: number - subtotal?: number - tax?: number - shipping?: number - grandTotal?: number - isLoaded: boolean -} + total?: number; + discount?: number; + subtotal?: number; + tax?: number; + shipping?: number; + grandTotal?: number; + isLoaded: boolean; + products?: any[]; // Added to detect changes in selected products +}; const CartSummary = ({ total, @@ -24,53 +23,191 @@ const CartSummary = ({ shipping, grandTotal, isLoaded = false, + products = [], }: Props) => { - const PPN : number = process.env.NEXT_PUBLIC_PPN ? parseFloat(process.env.NEXT_PUBLIC_PPN) : 0; - return ( - <> - <div className='text-h-sm font-medium'>Ringkasan Pesanan</div> + const PPN: number = process.env.NEXT_PUBLIC_PPN + ? parseFloat(process.env.NEXT_PUBLIC_PPN) + : 0; + const [isMounted, setIsMounted] = useState(false); + + // Local state to store calculated values + const [summaryValues, setSummaryValues] = useState({ + subtotal: 0, + discount: 0, + total: 0, + tax: 0, + shipping: 0, + grandTotal: 0, + }); + + // This fixes hydration issues by ensuring the component only renders fully after mounting + useEffect(() => { + setIsMounted(true); + }, []); + + // Calculate summary based on products whenever products change + useMemo(() => { + if (!products || products.length === 0) return; + + // Only count selected products + const selectedProducts = products.filter((product) => product.selected); + + // Calculate values based on selected products + let calculatedSubtotal = 0; + let calculatedDiscount = 0; + + selectedProducts.forEach((product) => { + // Get raw price and discount from product + const productBasePrice = product.price?.price || 0; + const productQty = product.quantity || 1; + const productDiscountedPrice = + product.price?.price_discount || productBasePrice; + const productDiscount = productBasePrice - productDiscountedPrice; + + calculatedSubtotal += productBasePrice * productQty; + calculatedDiscount += productDiscount * productQty; + }); + + const calculatedTotal = calculatedSubtotal - calculatedDiscount; + const calculatedTax = calculatedTotal * (PPN - 1); + const calculatedShipping = shipping || 0; + const calculatedGrandTotal = + calculatedTotal + calculatedTax + calculatedShipping; + + // If calculated values are different from props, use calculated ones + const shouldUpdateValues = + Math.abs((subtotal || 0) - calculatedSubtotal) > 0.01 || + Math.abs((discount || 0) - calculatedDiscount) > 0.01 || + Math.abs((total || 0) - calculatedTotal) > 0.01 || + Math.abs((tax || 0) - calculatedTax) > 0.01 || + Math.abs((grandTotal || 0) - calculatedGrandTotal) > 0.01; - <div className="h-6" /> + if (shouldUpdateValues && isLoaded) { + setSummaryValues({ + subtotal: calculatedSubtotal, + discount: calculatedDiscount, + total: calculatedTotal, + tax: calculatedTax, + shipping: calculatedShipping, + grandTotal: calculatedGrandTotal, + }); + } else if (isLoaded) { + // Use values from props when available + setSummaryValues({ + subtotal: subtotal || 0, + discount: discount || 0, + total: total || 0, + tax: tax || 0, + shipping: shipping || 0, + grandTotal: grandTotal || 0, + }); + } + }, [ + products, + isLoaded, + subtotal, + discount, + total, + tax, + shipping, + grandTotal, + PPN, + ]); + + // Update local values whenever props change + useEffect(() => { + if (isLoaded) { + setSummaryValues({ + subtotal: subtotal || 0, + discount: discount || 0, + total: total || 0, + tax: tax || 0, + shipping: shipping || 0, + grandTotal: grandTotal || 0, + }); + } + }, [isLoaded, subtotal, discount, total, tax, shipping, grandTotal]); + + if (!isMounted) { + return ( + <Box p={4} borderWidth='1px' borderRadius='lg' boxShadow='sm'> + <Text fontSize='lg' fontWeight='medium' mb={4}> + Ringkasan Pesanan + </Text> + {Array(6) + .fill(0) + .map((_, index) => ( + <Skeleton key={index} height='24px' my={2} /> + ))} + </Box> + ); + } + + // Use local state for rendering to ensure responsiveness + const { + subtotal: displaySubtotal, + discount: displayDiscount, + total: displayTotal, + tax: displayTax, + shipping: displayShipping, + grandTotal: displayGrandTotal, + } = summaryValues; + + return ( + <div className={style.summaryContainer}> + <Text fontSize='lg' fontWeight='medium' mb={4}> + Ringkasan Pesanan + </Text> <div className='flex flex-col gap-y-3'> <Skeleton isLoaded={isLoaded} className={style.line}> <span className={style.label}>Total Belanja</span> - <span className={style.value}>Rp {formatCurrency(subtotal || 0)}</span> + <span className={style.value}> + Rp {formatCurrency(displaySubtotal)} + </span> </Skeleton> <Skeleton isLoaded={isLoaded} className={style.line}> <span className={style.label}>Total Diskon</span> - <span className={clsxm(style.value, style.discount)}>- Rp {formatCurrency(discount || 0)}</span> + <span className={clsxm(style.value, style.discount)}> + - Rp {formatCurrency(displayDiscount)} + </span> </Skeleton> <div className={style.divider} /> <Skeleton isLoaded={isLoaded} className={style.line}> <span className={style.label}>Subtotal</span> - <span className={style.value}>Rp {formatCurrency(total || 0)}</span> + <span className={style.value}>Rp {formatCurrency(displayTotal)}</span> </Skeleton> <Skeleton isLoaded={isLoaded} className={style.line}> - <span className={style.label}>Tax {((PPN - 1) * 100).toFixed(0)}%</span> - <span className={style.value}>Rp {formatCurrency(tax || 0)}</span> + <span className={style.label}> + Tax {((PPN - 1) * 100).toFixed(0)}% + </span> + <span className={style.value}>Rp {formatCurrency(displayTax)}</span> </Skeleton> <Skeleton isLoaded={isLoaded} className={style.line}> <span className={style.label}>Biaya Kirim</span> - <span className={style.value}>Rp {formatCurrency(shipping || 0)}</span> + <span className={style.value}> + Rp {formatCurrency(displayShipping)} + </span> </Skeleton> <div className={style.divider} /> - <Skeleton isLoaded={isLoaded} className={style.line}> + <Skeleton isLoaded={isLoaded}> <span className={clsxm(style.label, style.grandTotal)}> Grand Total </span> - <span className={style.value}>Rp {formatCurrency(grandTotal || 0)}</span> + <span className={clsxm(style.value, style.grandTotalValue)}> + Rp {formatCurrency(displayGrandTotal)} + </span> </Skeleton> </div> - </> - ) -} + </div> + ); +}; -export default CartSummary
\ No newline at end of file +export default CartSummary; |
