This commit is contained in:
2026-03-13 13:54:45 +07:00
parent a8e30f32a0
commit 25111ff10e
120 changed files with 4213 additions and 4859 deletions

View File

@@ -0,0 +1,78 @@
import React from 'react';
import { DealType } from '@/types';
import { formatCurrency } from '@/lib/formatPrice';
import Image from 'next/image';
type ProductItemProps = {
item: DealType;
};
const ProductItem: React.FC<ProductItemProps> = ({ item }) => {
const { product_info } = item;
const offers = product_info.specialOffer?.all ?? [];
return (
<div className="product-item">
<a href={product_info.productUrl} className="product-image relative">
{product_info.productImage.large ? (
<Image
src={product_info.productImage.large}
width="164"
height="164"
alt={product_info.productName}
className="lazy"
/>
) : (
<Image
src="/static/assets/nguyencong_2023/images/not-image.png"
width="164"
height="164"
alt={product_info.productName}
className="lazy"
/>
)}
<span className="p-type-holder">
{product_info.productType.isHot === 1 && <i className="p-icon-type p-icon-hot"></i>}
{product_info.productType.isNew === 1 && <i className="p-icon-type p-icon-new"></i>}
</span>
</a>
<div className="product-info">
<a href={product_info.productUrl}>
<h3 className="product-title line-clamp-3">{product_info.productName}</h3>
</a>
<div className="product-martket-main flex items-center">
{product_info.marketPrice > 0 ? (
<p className="product-market-price">{product_info.marketPrice.toLocaleString()} </p>
) : (
<p className="product-market-price">
{product_info.sale_rules.normal_price.toLocaleString()}
</p>
)}
<div className="product-percent-price">-{product_info.price_off || 0}%</div>
</div>
<div className="product-price-main font-bold">
{item.price > '0' ? `${formatCurrency(product_info.price)}đ` : 'Liên hệ'}
</div>
<div className="p-quantity-sale">
<i className="sprite sprite-fire-deal"></i>
<div className="bg-gradient"></div>
<p className="js-line-deal-left"></p>
<span>
Còn {Number(item.quantity) - Number(item.sale_quantity)}/{Number(item.quantity)} sản
phẩm
</span>
</div>
{offers.length > 0 && (
<div
className="product-offer line-clamp-2"
dangerouslySetInnerHTML={{
__html: product_info.specialOffer!.all![0].title,
}}
/>
)}
</div>
</div>
);
};
export default ProductItem;

View File

@@ -0,0 +1,64 @@
'use client';
import React, { useEffect, useState } from 'react';
import Link from 'next/link';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Autoplay, Navigation, Pagination } from 'swiper/modules';
import { FaCaretRight } from 'react-icons/fa';
import { TypeListProductDeal } from '@/types';
import { getDeals } from '@/lib/api/deal';
import CountDown from '@/components/Common/CountDown';
import ProductItem from './ProductItem';
const BoxProductDeal: React.FC = () => {
const [deals, setDeals] = useState<TypeListProductDeal>([]);
const [expired, setExpired] = useState(false);
useEffect(() => {
getDeals().then(setDeals).catch(console.error);
}, []);
if (expired) return null;
const deadline = deals[0]?.to_time ?? '31-01-2026, 9:30 am';
return (
<div className="box-product-deal boder-radius-10">
<div className="box-title-deal flex items-center justify-between">
<div className="title-deal flex items-center justify-center gap-10">
<i className="sprite sprite-icon-deal-home"></i>
<h2 className="title font-bold">Giá tốt mỗi ngày</h2>
<span className="text-time-deal-home color-white fz-16 font-bold">Kết thúc sau</span>
<div className="global-time-deal flex items-center gap-2">
<CountDown deadline={deadline} onExpire={() => setExpired(true)} />
</div>
</div>
<Link href="/deal" className="button-deal color-white mb-10 flex items-center">
Xem thêm khuyến mãi <FaCaretRight size={16} />
</Link>
</div>
<div className="box-list-item-deal swiper-box-deal">
<Swiper
modules={[Autoplay, Navigation, Pagination]}
spaceBetween={12}
loop={true}
navigation={true}
breakpoints={{
320: { slidesPerView: 2 },
640: { slidesPerView: 3 },
768: { slidesPerView: 4 },
1024: { slidesPerView: 5 },
1280: { slidesPerView: 6 },
}}
>
{deals.map((item) => (
<SwiperSlide key={item.id}>
<ProductItem item={item} />
</SwiperSlide>
))}
</Swiper>
</div>
</div>
);
};
export default BoxProductDeal;