diff options
| author | trisusilo48 <tri.susilo@altama.co.id> | 2024-07-10 15:58:51 +0700 |
|---|---|---|
| committer | trisusilo48 <tri.susilo@altama.co.id> | 2024-07-10 15:58:51 +0700 |
| commit | 2e3c726bc8217f3960cfecec44b81303b03de72b (patch) | |
| tree | 1b85ced7f61f3e4c3f1f27b577b37aa161615065 /src-migrate/modules/product-promo/components/Card.tsx | |
| parent | 2b3bd9c0a454dbad69ce29cee877bfb1fca5dfa6 (diff) | |
| parent | a99bf6480eea556e53b85e6db45f3b8c2361e693 (diff) | |
Merge branch 'release' into development
# Conflicts:
# src/pages/shop/product/variant/[slug].jsx
Diffstat (limited to 'src-migrate/modules/product-promo/components/Card.tsx')
| -rw-r--r-- | src-migrate/modules/product-promo/components/Card.tsx | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src-migrate/modules/product-promo/components/Card.tsx b/src-migrate/modules/product-promo/components/Card.tsx new file mode 100644 index 00000000..56e29e38 --- /dev/null +++ b/src-migrate/modules/product-promo/components/Card.tsx @@ -0,0 +1,206 @@ +import style from "../styles/card.module.css" + +import React, { useEffect, useMemo, useState } from 'react' +import { InfoIcon, PlusIcon } from "lucide-react" +import { Skeleton, Tooltip } from '@chakra-ui/react' +import { motion } from "framer-motion" + +import { PROMO_CATEGORY } from "~/constants/promotion" +import { getVariantById } from "~/services/productVariant" + +import { IProductVariantPromo, IPromotion } from '~/types/promotion' +import formatCurrency from '~/libs/formatCurrency' +import clsxm from '~/libs/clsxm' + +import ProductPromoItem from './Item' +import ProductPromoAddToCart from "./AddToCart" +import ProductPromoCardCountdown from "./CardCountdown" + +import MobileView from '../../../../src/core/components/views/MobileView'; +import DesktopView from '../../../../src/core/components/views/DesktopView'; + +type Props = { + promotion: IPromotion + +} + +const ProductPromoCard = ({ promotion}: Props) => { + const [products, setProducts] = useState<IProductVariantPromo[]>([]) + const [freeProducts, setFreeProducts] = useState<IProductVariantPromo[]>([]) + const [error, setError] = useState<string | null>(null) + + useEffect(() => { + const getProducts = async () => { + try { + const datas = [] + for (const product of promotion.products) { + const res = await getVariantById(product.product_id) + res.data.qty = product.qty + datas.push(res.data) + } + setProducts(datas) + } catch (err) { + setError('Failed to fetch product variants.') + console.error(err) + } + } + + getProducts() + }, [promotion.products]) + + useEffect(() => { + const getFreeProducts = async () => { + try { + const datas = [] + for (const product of promotion.free_products) { + const res = await getVariantById(product.product_id) + res.data.qty = product.qty + datas.push(res.data) + } + setFreeProducts(datas) + } catch (err) { + setError('Failed to fetch free product variants.') + console.error(err) + } + } + + getFreeProducts() + }, [promotion.free_products]) + + const priceTotal = useMemo(() => { + let total = 0; + [...products, ...freeProducts].forEach((product) => { + total += product.price.price_discount * product.qty + }) + return total + }, [products, freeProducts]) + + const allProducts = [...products, ...freeProducts] + + + + return ( + <div> + <MobileView> + <div className={style.card}> + <ProductPromoCardCountdown promotion={promotion} /> + + <div className='px-4 mt-4 text-caption-1'> + <div className="flex justify-between items-center"> + <div className={style.title}>{promotion.name}</div> + + <Tooltip label={PROMO_CATEGORY[promotion.type.value].description} placement="top" bgColor='red.600' p={1} rounded={6}> + {/* <div className={style.badgeType} > */} + {/* Paket {PROMO_CATEGORY[promotion.type.value].alias} */} + <InfoIcon className={style.badgeType} size={25} /> + {/* </div> */} + </Tooltip> + </div> + + <Skeleton className={clsxm(style.productSection, { 'justify-center': allProducts.length === 2 })} isLoaded={allProducts.length > 0}> + {allProducts.map((product, index) => ( + <React.Fragment key={product.id}> + <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.6 }}> + <ProductPromoItem + variant={product} + isFree={index + 1 > products.length && promotion.type.value === 'merchandise'} + // isFree={index + 1 > products.length } + /> + </motion.div> + <motion.div initial={{ y: 30, opacity: 0 }} animate={{ y: 0, opacity: 1 }} transition={{ duration: 0.5, delay: 0.1 }}> + {index + 1 < allProducts.length && ( + <div className="h-fit p-1 rounded-full border border-danger-500 text-danger-500 mt-[38px]"> + <PlusIcon size={14} strokeWidth='2px' /> + </div> + )} + </motion.div> + </React.Fragment> + ))} + </Skeleton> + + <div className={style.priceSection}> + <div className={style.priceCol}> + <Skeleton className={style.priceRow} isLoaded={priceTotal > 0}> + <span className={style.basePrice}>Rp{formatCurrency(priceTotal)}</span> + <span className="text-[11px]">Hemat <span className={style.savingAmt}>Rp {formatCurrency(priceTotal - promotion.price)}</span></span> + </Skeleton> + + <div className={style.priceRow}> + <span className={style.price}>Rp{formatCurrency(promotion.price)}</span> + <span className={style.totalItems}>(Total {promotion.total_qty} barang)</span> + </div> + + </div> + <div> + <ProductPromoAddToCart promotion={promotion} /> + </div> + + </div> + </div> + </div> + </MobileView> + <DesktopView> + <div className={style.card}> + <ProductPromoCardCountdown promotion={promotion} /> + + <div className='px-4 mt-4 text-caption-1'> + <div className="flex justify-between items-center"> + <div className={style.title}>{promotion.name}</div> + + <Tooltip label={PROMO_CATEGORY[promotion.type.value].description} placement="top" bgColor='red.600' p={2} rounded={6}> + <div className={style.badgeType}> + Paket {PROMO_CATEGORY[promotion.type.value].alias} + <InfoIcon size={16} /> + </div> + </Tooltip> + </div> + + <Skeleton className={clsxm(style.productSection, { 'justify-center': allProducts.length === 2 })} isLoaded={allProducts.length > 0}> + {allProducts.map((product, index) => ( + <React.Fragment key={product.id}> + <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.6 }}> + <ProductPromoItem + variant={product} + isFree={index + 1 > products.length && promotion.type.value === 'merchandise'} + // isFree={index + 1 > products.length } + /> + </motion.div> + <motion.div initial={{ y: 30, opacity: 0 }} animate={{ y: 0, opacity: 1 }} transition={{ duration: 0.5, delay: 0.1 }}> + {index + 1 < allProducts.length && ( + <div className="h-fit p-1 rounded-full border border-danger-500 text-danger-500 mt-[38px]"> + <PlusIcon size={14} strokeWidth='2px' /> + </div> + )} + </motion.div> + </React.Fragment> + ))} + </Skeleton> + + <div className={style.priceSection}> + <div className={style.priceCol}> + <Skeleton className={style.priceRow} isLoaded={priceTotal > 0}> + <span className={style.basePrice}>Rp{formatCurrency(priceTotal)}</span> + <span>Hemat <span className={style.savingAmt}>Rp {formatCurrency(priceTotal - promotion.price)}</span></span> + </Skeleton> + + <div className={style.priceRow}> + <span className={style.price}>Rp{formatCurrency(promotion.price)}</span> + <span className={style.totalItems}>(Total {promotion.total_qty} barang)</span> + </div> + </div> + <div> + <ProductPromoAddToCart promotion={promotion} /> + </div> + + </div> + </div> + </div> + </DesktopView> + </div> + // shouldRender && ( + + // ) + ) +} + +export default ProductPromoCard |
