diff options
Diffstat (limited to 'src-migrate')
4 files changed, 194 insertions, 76 deletions
diff --git a/src-migrate/modules/product-promo/components/AddToCart.tsx b/src-migrate/modules/product-promo/components/AddToCart.tsx index 192dd231..87017c14 100644 --- a/src-migrate/modules/product-promo/components/AddToCart.tsx +++ b/src-migrate/modules/product-promo/components/AddToCart.tsx @@ -7,6 +7,9 @@ import { getAuth } from '~/libs/auth' import { upsertUserCart } from '~/services/cart' import { IPromotion } from '~/types/promotion' +import DesktopView from '../../../../src/core/components/views/DesktopView'; +import MobileView from '../../../../src/core/components/views/MobileView'; + type Props = { promotion: IPromotion } @@ -55,21 +58,42 @@ const ProductPromoAddToCart = ({ promotion }: Props) => { }, [status]) return ( - <Button - colorScheme='yellow' - px={2} - w='110px' - gap={1} - isDisabled={status === 'loading'} - onClick={handleButton} - > - {status === 'success' && <CheckIcon size={16} />} - {status === 'loading' && <Spinner size='xs' mr={1.5} />} - {status === 'idle' && <PlusIcon size={16} />} + <div> + <MobileView> + <Button + colorScheme='yellow' + px={2} + w='36px' + gap={1} + isDisabled={status === 'loading'} + onClick={handleButton} + > + {status === 'success' && <CheckIcon size={16} />} + {status === 'loading' && <Spinner size='xs' mr={1.5} />} + {status === 'idle' && <PlusIcon size={16} />} + + {status === 'success' && <span>Berhasil</span>} + {/* {status !== 'success' && <span>Keranjang</span>} */} + </Button> + </MobileView> + <DesktopView> + <Button + colorScheme='yellow' + px={2} + w='110px' + gap={1} + isDisabled={status === 'loading'} + onClick={handleButton} + > + {status === 'success' && <CheckIcon size={16} />} + {status === 'loading' && <Spinner size='xs' mr={1.5} />} + {status === 'idle' && <PlusIcon size={16} />} - {status === 'success' && <span>Berhasil</span>} - {status !== 'success' && <span>Keranjang</span>} - </Button> + {status === 'success' && <span>Berhasil</span>} + {status !== 'success' && <span>Keranjang</span>} + </Button> + </DesktopView> + </div> ) } diff --git a/src-migrate/modules/product-promo/components/Card.tsx b/src-migrate/modules/product-promo/components/Card.tsx index 59110098..56e29e38 100644 --- a/src-migrate/modules/product-promo/components/Card.tsx +++ b/src-migrate/modules/product-promo/components/Card.tsx @@ -16,38 +16,52 @@ 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 ProductPromoCard = ({ promotion}: Props) => { const [products, setProducts] = useState<IProductVariantPromo[]>([]) + const [freeProducts, setFreeProducts] = useState<IProductVariantPromo[]>([]) + const [error, setError] = useState<string | null>(null) useEffect(() => { const getProducts = async () => { - const datas = [] - for (const product of promotion.products) { - const res = await getVariantById(product.product_id) - res.data.qty = product.qty - datas.push(res.data) + 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) } - setProducts(datas) } getProducts() }, [promotion.products]) - const [freeProducts, setFreeProducts] = useState<IProductVariantPromo[]>([]) - useEffect(() => { const getFreeProducts = async () => { - 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) + 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) } - setFreeProducts(datas) } getFreeProducts() @@ -63,62 +77,130 @@ const ProductPromoCard = ({ promotion }: Props) => { const allProducts = [...products, ...freeProducts] - return ( - <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> + 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> - <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} /> + <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> - </Tooltip> - </div> - - <Skeleton className={clsxm(style.productSection, { 'justify-center': allProducts.length === 2 })} isLoaded={allProducts.length > 0}> - {allProducts.map((product, index) => ( - <> - <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.6 }}> - <ProductPromoItem - variant={product} - isFree={index + 1 > products.length && promotion.type.value === 'merchandise'} - /> - </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> - </> - ))} - </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> + <ProductPromoAddToCart promotion={promotion} /> </div> + </div> - <div> - <ProductPromoAddToCart promotion={promotion} /> + </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
\ No newline at end of file +export default ProductPromoCard diff --git a/src-migrate/modules/product-promo/components/Section.tsx b/src-migrate/modules/product-promo/components/Section.tsx index 5fc0da4c..4e8a7dd5 100644 --- a/src-migrate/modules/product-promo/components/Section.tsx +++ b/src-migrate/modules/product-promo/components/Section.tsx @@ -50,7 +50,7 @@ const ProductPromoSection = ({ productId }: Props) => { > {promotions?.data.map((promotion) => ( <div key={promotion.id} className="min-w-[400px] max-w-[400px]"> - <ProductPromoCard promotion={promotion} /> + <ProductPromoCard promotion={promotion} /> </div> ))} </Skeleton> diff --git a/src-migrate/modules/product-promo/styles/card.module.css b/src-migrate/modules/product-promo/styles/card.module.css index a2ad9af6..faa3b370 100644 --- a/src-migrate/modules/product-promo/styles/card.module.css +++ b/src-migrate/modules/product-promo/styles/card.module.css @@ -44,3 +44,15 @@ .totalItems { @apply text-gray_r-9; } + +@media only screen and (max-width: 384px) { + .basePrice { + @apply text-[13px]; + } + .price{ + @apply text-[15px]; + } + .totalItems{ + @apply text-[11px]; + } + }
\ No newline at end of file |
