From c9366090153e8aba3a673b2b77cbc8acc24e59a5 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 15 Dec 2023 17:15:32 +0700 Subject: Update promotion program feature --- src-migrate/modules/product/PromoCard.module.css | 62 +++++++++++ src-migrate/modules/product/PromoCard.tsx | 117 +++++++++++++++++++++ .../modules/product/PromoProduct.module.css | 15 +++ src-migrate/modules/product/PromoProduct.tsx | 22 ++++ .../modules/product/PromoSection.module.css | 11 ++ src-migrate/modules/product/PromoSection.tsx | 42 ++++++++ 6 files changed, 269 insertions(+) create mode 100644 src-migrate/modules/product/PromoCard.module.css create mode 100644 src-migrate/modules/product/PromoCard.tsx create mode 100644 src-migrate/modules/product/PromoProduct.module.css create mode 100644 src-migrate/modules/product/PromoProduct.tsx create mode 100644 src-migrate/modules/product/PromoSection.module.css create mode 100644 src-migrate/modules/product/PromoSection.tsx (limited to 'src-migrate/modules/product') diff --git a/src-migrate/modules/product/PromoCard.module.css b/src-migrate/modules/product/PromoCard.module.css new file mode 100644 index 00000000..4d98671f --- /dev/null +++ b/src-migrate/modules/product/PromoCard.module.css @@ -0,0 +1,62 @@ +.card { + @apply border border-gray_r-7 + rounded-lg + min-w-[360px] + max-w-[360px] + py-3; +} + +.countdownSection { + @apply w-fit p-2.5 pr-6 + rounded-r-full + font-medium + flex items-center gap-x-2.5; +} + +.countdown { + @apply flex gap-x-1; +} + +.countdown span { + @apply py-0.5 w-8 bg-red-600 text-gray_r-4 rounded-md text-center; +} + +.title { + @apply font-semibold text-h-md; +} + +.productSection { + @apply flex gap-x-3 mt-4 min-h-[180px]; +} + +.priceSection { + @apply flex items-center justify-between mt-4; +} + +.priceCol { + @apply flex flex-col gap-y-1; +} + +.priceRow { + @apply flex gap-x-2 items-center; +} + +.basePrice { + @apply line-through; +} + +.savingAmt { + @apply text-success-600 font-medium; +} + +.price { + @apply text-body-1 text-danger-600 font-medium; +} + +.totalItems { + @apply text-gray_r-9; +} + +.addToCartBtn { + @apply btn-yellow flex items-center gap-x-1 px-2 rounded-lg; +} diff --git a/src-migrate/modules/product/PromoCard.tsx b/src-migrate/modules/product/PromoCard.tsx new file mode 100644 index 00000000..8bb48155 --- /dev/null +++ b/src-migrate/modules/product/PromoCard.tsx @@ -0,0 +1,117 @@ +import React, { useEffect, useMemo, useState } from 'react' +import style from "./PromoCard.module.css" +import { ClockIcon, PlusIcon } from "lucide-react" +import { IProductVariantPromo, IPromotion } from '~/common/types/promotion' +import formatCurrency from '~/common/libs/formatCurrency' +import PromoProduct from './PromoProduct' +import { Skeleton, Spinner } from '@chakra-ui/react' +import clsxm from '~/common/libs/clsxm' +import { useCountdown } from 'usehooks-ts' + +type Props = { + promotion: IPromotion +} + +const PromoCard = ({ promotion }: Props) => { + // TODO: useCountdown() + const [products, setProducts] = useState([]) + + useEffect(() => { + const getProducts = async () => { + const datas = [] + for (const product of promotion.products) { + const response = await fetch(`/api/product-variant/${product.product_id}`) + const res = await response.json() + res.data.qty = product.qty + datas.push(res.data) + } + setProducts(datas) + } + + getProducts() + }, [promotion.products]) + + const [freeProducts, setFreeProducts] = useState([]) + + useEffect(() => { + const getFreeProducts = async () => { + const datas = [] + for (const product of promotion.free_products) { + const response = await fetch(`/api/product-variant/${product.product_id}`) + const res = await response.json() + res.data.qty = product.qty + datas.push(res.data) + } + setFreeProducts(datas) + } + + getFreeProducts() + }, [promotion.free_products]) + + const priceTotal = useMemo(() => { + let total = 0; + [...products, ...freeProducts].forEach((product) => { + total += product.price.price_discount * product.qty + console.log({ product }); + + }) + return total + }, [products, freeProducts]) + + const countdownClass = { + 'text-white': true, + 'bg-[#312782]': promotion.type.value === 'bundling', + 'bg-[#329E44]': promotion.type.value === 'discount_loading', + 'bg-[#FAD147]': promotion.type.value === 'merchandise', + 'text-gray-700': promotion.type.value === 'merchandise', + } + + return ( +
+
+ + + + Berakhir dalam +
+ 00 + 01 + 35 +
+
+ +
+
{promotion.name}
+ + 0}> + {products.map((product) => )} + {freeProducts.map((product) => )} + + +
+
+ 0}> + Rp{formatCurrency(priceTotal)} + Hemat Rp {formatCurrency(priceTotal - promotion.price)} + + +
+ Rp{formatCurrency(promotion.price)} + (Total {promotion.total_qty} barang) +
+
+
+ +
+ +
+
+
+ ) +} + +export default PromoCard \ No newline at end of file diff --git a/src-migrate/modules/product/PromoProduct.module.css b/src-migrate/modules/product/PromoProduct.module.css new file mode 100644 index 00000000..c13bccb8 --- /dev/null +++ b/src-migrate/modules/product/PromoProduct.module.css @@ -0,0 +1,15 @@ +.product { + @apply w-4/12; +} + +.image { + @apply border border-gray_r-6 p-2.5 rounded-lg; +} + +.fillDesc { + @apply mt-2 text-danger-600; +} + +.name { + @apply mt-1 line-clamp-3 font-medium; +} diff --git a/src-migrate/modules/product/PromoProduct.tsx b/src-migrate/modules/product/PromoProduct.tsx new file mode 100644 index 00000000..83b05e88 --- /dev/null +++ b/src-migrate/modules/product/PromoProduct.tsx @@ -0,0 +1,22 @@ +import React from 'react' +import style from './PromoProduct.module.css' +import { IProductVariantPromo } from '~/common/types/promotion' +import Image from 'next/image' + +type Props = { + variant: IProductVariantPromo +} + +const PromoProduct = ({ variant }: Props) => { + return ( +
+
+ {variant.display_name} +
+
Isi {variant.qty} barang
+
{variant.name}
+
+ ) +} + +export default PromoProduct \ No newline at end of file diff --git a/src-migrate/modules/product/PromoSection.module.css b/src-migrate/modules/product/PromoSection.module.css new file mode 100644 index 00000000..a9c9b704 --- /dev/null +++ b/src-migrate/modules/product/PromoSection.module.css @@ -0,0 +1,11 @@ +.titleWrapper { + @apply w-full mb-4 h-20 bg-[#C70817] rounded-lg flex items-center justify-between px-4 py-1; +} + +.seeMore { + @apply py-2 px-3 btn-yellow rounded-lg text-body-2; +} + +.title { + @apply font-semibold text-xl text-white; +} diff --git a/src-migrate/modules/product/PromoSection.tsx b/src-migrate/modules/product/PromoSection.tsx new file mode 100644 index 00000000..299cbb78 --- /dev/null +++ b/src-migrate/modules/product/PromoSection.tsx @@ -0,0 +1,42 @@ +import React from 'react' +import style from "./PromoSection.module.css" +import PromoCard from './PromoCard' +import { useQuery } from 'react-query' +import { Skeleton } from '@chakra-ui/react' +import { IPromotion } from '~/common/types/promotion' + +type Props = { + productId: number +} + +const PromoSection = ({ productId }: Props) => { + const promotionsQuery = useQuery( + `promotions-highlight:${productId}`, + async () => await fetch(`/api/product-variant/${productId}/promotion/highlight`).then((res) => res.json()) as { data: IPromotion[] }, + ) + + const promotions = promotionsQuery.data + + const handleSeeMore = () => { } + + return ( +
+ {promotions?.data && promotions?.data.length > 0 && ( +
+ Promo Tersedia + +
+ )} + + + {promotions?.data.map((promotion) => ( + + ))} + +
+ ) +} + +export default PromoSection \ No newline at end of file -- cgit v1.2.3