This commit is contained in:
2025-12-25 19:03:33 +07:00
24 changed files with 3440 additions and 2578 deletions

View File

@@ -0,0 +1,46 @@
'use client';
import Link from 'next/link';
import { FaHouse, FaAngleRight } from 'react-icons/fa6';
interface BreadcrumbItem {
name: string | undefined;
url: string | undefined;
}
export const Breadcrumb = ({ items }: { items: BreadcrumbItem[] }) => {
return (
<nav className="box-breadcrumb-global mb-4 text-sm text-gray-600">
<ol itemScope itemType="http://schema.org/BreadcrumbList" className="flex gap-2">
<li
itemProp="itemListElement"
itemScope
itemType="http://schema.org/ListItem"
className="flex items-center gap-2"
>
<Link href="/" itemProp="item">
<span itemProp="name" className="flex items-center gap-2">
<span style={{ fontSize: 0 }}>Trang chủ</span> <FaHouse className="text-gray-700" />
</span>
</Link>{' '}
<FaAngleRight className="text-gray-700" />
<meta itemProp="position" content="1" />
</li>
{items.map((item, idx) => (
<li
key={idx}
itemProp="itemListElement"
itemScope
itemType="http://schema.org/ListItem"
className="flex items-center"
>
<Link href={item.url ?? '/'} itemProp="item">
<span itemProp="name">{item?.name}</span>
</Link>
<meta itemProp="position" content={(idx + 1).toString()} />
{idx < items.length - 1 && <span className="mx-1">/</span>}
</li>
))}
</ol>
</nav>
);
};

View File

@@ -0,0 +1,84 @@
import React from 'react';
import Tippy from '@tippyjs/react';
import 'tippy.js/dist/tippy.css';
import { Product } from '@/types';
import Image from 'next/image';
import Link from 'next/link';
type ProductItemProps = {
item: Product;
};
const formatCurrency = (value: number | string) => {
const num = typeof value === 'string' ? parseInt(value) : value;
return num.toLocaleString('vi-VN');
};
const ItemProduct: React.FC<ProductItemProps> = ({ item }) => {
const offers = item.specialOffer?.all ?? [];
return (
<div className="product-item js-p-item">
<a href={item.productUrl} className="product-image relative">
{item.productImage.large ? (
<Image src={item.productImage.large} width="203" height="203" alt={item.productName} />
) : (
<Image
src="https://nguyencongpc.vn/static/assets/nguyencong_2023/images/not-image.png"
alt={item.productName}
/>
)}
<span className="p-type-holder">
{item.productType.isHot === 1 && <i className="p-icon-type p-icon-hot"></i>}
{item.productType.isNew === 1 && <i className="p-icon-type p-icon-new"></i>}
</span>
<span className="p-type-holder p-type-holder-2">
{item.productType.isBestSale === 1 && <i className="p-icon-type p-icon-best-sale"></i>}
</span>
</a>
<div className="product-info">
<Link href={item.productUrl}>
<h3 className="product-title line-clamp-3">{item.productName}</h3>
</Link>
{item.marketPrice > 0 ? (
<div className="product-martket-main flex items-center">
<p className="product-market-price">
{item.marketPrice.toLocaleString()}
<u>đ</u>
</p>
<div className="product-percent-price">-{Math.round(item.price_off)} %</div>
</div>
) : (
<div className="product-martket-main flex items-center"></div>
)}
<div className="product-price-main font-[600]">
{item.price > '0' ? `${formatCurrency(item.price)}đ` : 'Liên hệ'}
</div>
{item.specialOffer?.all?.length ? (
<div
className="product-offer line-clamp-2"
dangerouslySetInnerHTML={{
__html: item.specialOffer!.all![0].title,
}}
/>
) : (
<div className="product-offer line-clamp-2"></div>
)}
{item.extend?.buy_count ? (
<div style={{ height: 18 }}>
{' '}
<b>Đã bán: </b> <span>{item.extend.buy_count}</span>{' '}
</div>
) : (
<div style={{ height: 18, display: 'block' }}> </div>
)}
</div>
</div>
);
};
export default ItemProduct;