update
This commit is contained in:
11
package-lock.json
generated
11
package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fancyapps/ui": "^6.1.7",
|
"@fancyapps/ui": "^6.1.7",
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"framer-motion": "^12.23.26",
|
"framer-motion": "^12.23.26",
|
||||||
"lightgallery": "^2.9.0",
|
"lightgallery": "^2.9.0",
|
||||||
"next": "16.0.10",
|
"next": "16.0.10",
|
||||||
@@ -2749,6 +2750,16 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/date-fns": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/kossnocorp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fancyapps/ui": "^6.1.7",
|
"@fancyapps/ui": "^6.1.7",
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"framer-motion": "^12.23.26",
|
"framer-motion": "^12.23.26",
|
||||||
"lightgallery": "^2.9.0",
|
"lightgallery": "^2.9.0",
|
||||||
"next": "16.0.10",
|
"next": "16.0.10",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import NotFound from '../pages/404';
|
|||||||
import { resolvePageType } from '@/lib/resolvePageType';
|
import { resolvePageType } from '@/lib/resolvePageType';
|
||||||
|
|
||||||
import CategoryPage from '@/app/pages/Product/Category';
|
import CategoryPage from '@/app/pages/Product/Category';
|
||||||
|
import ProductSearchPage from '@/app/pages/Product/ProductSearch';
|
||||||
import ProductDetailPage from '@/app/pages/Product/ProductDetail';
|
import ProductDetailPage from '@/app/pages/Product/ProductDetail';
|
||||||
import ArticlePage from '@/app/pages/Article/HomeArticlePage';
|
import ArticlePage from '@/app/pages/Article/HomeArticlePage';
|
||||||
import ArticleCategoryPage from '@/app/pages/Article/CategoryPage';
|
import ArticleCategoryPage from '@/app/pages/Article/CategoryPage';
|
||||||
@@ -18,6 +19,8 @@ export default function DynamicPage() {
|
|||||||
switch (pageType) {
|
switch (pageType) {
|
||||||
case 'category':
|
case 'category':
|
||||||
return <CategoryPage slug={fullSlug} />;
|
return <CategoryPage slug={fullSlug} />;
|
||||||
|
case 'product-search':
|
||||||
|
return <ProductSearchPage slug={fullSlug} />;
|
||||||
case 'product-detail':
|
case 'product-detail':
|
||||||
return <ProductDetailPage slug={fullSlug} />;
|
return <ProductDetailPage slug={fullSlug} />;
|
||||||
case 'article-home':
|
case 'article-home':
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import { Metadata } from 'next';
|
|||||||
import { Breadcrumb } from '@components/Common/Breadcrumb';
|
import { Breadcrumb } from '@components/Common/Breadcrumb';
|
||||||
import { bannerData } from '@/data/banner';
|
import { bannerData } from '@/data/banner';
|
||||||
import { ListDealData } from '@/data/deal';
|
import { ListDealData } from '@/data/deal';
|
||||||
import { formatCurrency } from '@/lib/formatPrice';
|
import ItemDeal from '@components/Deal/ItemDeal';
|
||||||
import CounDown from '@/components/Common/CounDown';
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Danh sách deal',
|
title: 'Danh sách deal',
|
||||||
@@ -16,6 +15,7 @@ export const metadata: Metadata = {
|
|||||||
|
|
||||||
export default function DealPage() {
|
export default function DealPage() {
|
||||||
const breadcrumbItems = [{ name: 'Danh sách deal', url: '/deal' }];
|
const breadcrumbItems = [{ name: 'Danh sách deal', url: '/deal' }];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="container">
|
<div className="container">
|
||||||
@@ -39,85 +39,9 @@ export default function DealPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="box-list-item-deal grid grid-cols-4 gap-3" id="js-deal-page">
|
<div className="box-list-item-deal grid grid-cols-4 gap-3 pb-10" id="js-deal-page">
|
||||||
{ListDealData.map((Item, index) => (
|
{ListDealData.map((Item, index) => (
|
||||||
<div className="product-item" key={index}>
|
<ItemDeal key={index} Item={Item} />
|
||||||
<div className="item-deal">
|
|
||||||
<Link
|
|
||||||
href={Item.product_info.productUrl}
|
|
||||||
className="product-image position-relative"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={Item.product_info.productImage.large}
|
|
||||||
width={250}
|
|
||||||
height={250}
|
|
||||||
alt={Item.product_info.productName}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
<div className="product-info flex-1">
|
|
||||||
<Link href={Item.product_info.productUrl}>
|
|
||||||
<h3 className="product-title line-clamp-3">
|
|
||||||
{Item.product_info.productName}
|
|
||||||
</h3>
|
|
||||||
</Link>
|
|
||||||
<div className="product-martket-main flex items-center">
|
|
||||||
{Item.product_info.marketPrice > 0 && (
|
|
||||||
<>
|
|
||||||
<p className="product-market-price">
|
|
||||||
{Item.product_info.marketPrice.toLocaleString()} ₫
|
|
||||||
</p>
|
|
||||||
<div className="product-percent-price">
|
|
||||||
-{Item.product_info.price_off || 0}%
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="product-price-main font-bold">
|
|
||||||
{Item.product_info.price > '0'
|
|
||||||
? `${formatCurrency(Item.product_info.price)}đ`
|
|
||||||
: 'Liên hệ'}
|
|
||||||
</div>
|
|
||||||
<div className="p-quantity-sale">
|
|
||||||
<i className="sprite sprite-fire-deal"></i>
|
|
||||||
<div className="bg-gradient"></div>
|
|
||||||
{(() => {
|
|
||||||
const percentRemaining =
|
|
||||||
((Number(Item.quantity) - Number(Item.sale_quantity)) /
|
|
||||||
Number(Item.quantity)) *
|
|
||||||
100;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<p
|
|
||||||
className="js-line-deal-left"
|
|
||||||
style={{ width: `${percentRemaining}%` }}
|
|
||||||
></p>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
<span>
|
|
||||||
Còn {Number(Item.quantity) - Number(Item.sale_quantity)}/
|
|
||||||
{Number(Item.quantity)} sản phẩm
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="js-item-deal-time js-item-time-25404">
|
|
||||||
<div className="time-deal-page flex items-center">
|
|
||||||
<div>Kết thúc sau </div>
|
|
||||||
<CounDown deadline={new Date(Item.to_time)} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<a href="javascript:buyNow(25404)" className="buy-now-deal">
|
|
||||||
Mua giá sốc
|
|
||||||
</a>
|
|
||||||
<Link
|
|
||||||
href="/bts-gaming-02"
|
|
||||||
className="text-deal-item color-primary mt-3 hidden font-bold"
|
|
||||||
>
|
|
||||||
Xem sản phẩm
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { FaCaretRight } from 'react-icons/fa';
|
|||||||
|
|
||||||
import { ListDealData } from '@/data/deal';
|
import { ListDealData } from '@/data/deal';
|
||||||
|
|
||||||
import CounDown from '../../../../components/Common/CounDown';
|
import CounDown from '@components/Common/CounDown';
|
||||||
import ProductItem from './ProductItem';
|
import ProductItem from './ProductItem';
|
||||||
|
|
||||||
const BoxProductDeal: React.FC = () => {
|
const BoxProductDeal: React.FC = () => {
|
||||||
@@ -19,7 +19,7 @@ const BoxProductDeal: React.FC = () => {
|
|||||||
<h2 className="title font-bold">Giá tốt mỗi ngày</h2>
|
<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>
|
<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">
|
<div className="global-time-deal flex items-center gap-2">
|
||||||
<CounDown deadline={new Date('2025-12-31T23:59:59')} />
|
<CounDown deadline={'31-01-2026, 9:30 am'} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Link href="/deal" className="button-deal color-white mb-10 flex items-center">
|
<Link href="/deal" className="button-deal color-white mb-10 flex items-center">
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import { findCategoryBySlug } from '@/lib/product/category';
|
|||||||
import { Breadcrumb } from '@/components/Common/Breadcrumb';
|
import { Breadcrumb } from '@/components/Common/Breadcrumb';
|
||||||
import BannerCategory from './BannerCategory';
|
import BannerCategory from './BannerCategory';
|
||||||
import ItemCategoryChild from './ItemCategoryChild';
|
import ItemCategoryChild from './ItemCategoryChild';
|
||||||
import BoxFilter from './BoxFilter';
|
import BoxFilter from '@components/Product/BoxFilter';
|
||||||
import BoxSort from './BoxSort';
|
import BoxSort from '@components/Product/BoxSort';
|
||||||
import ItemProduct from '@/components/Common/ItemProduct';
|
import ItemProduct from '@/components/Common/ItemProduct';
|
||||||
|
|
||||||
interface CategoryPageProps {
|
interface CategoryPageProps {
|
||||||
|
|||||||
@@ -1,52 +1,61 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import type { ProductDetailData } from '@/types';
|
import type { ProductDetailData } from '@/types';
|
||||||
import CounDown from '@/components/Common/CounDown';
|
import CounDown from '@/components/Common/CounDown';
|
||||||
import { formatCurrency } from '@/lib/formatPrice';
|
import { formatCurrency } from '@/lib/formatPrice';
|
||||||
|
|
||||||
export const BoxPrice = (item: ProductDetailData) => {
|
export const BoxPrice = (item: ProductDetailData) => {
|
||||||
|
const [now, setNow] = useState(() => Date.now());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{item.product_info.sale_rules.type == 'deal' && (
|
{item.product_info.sale_rules.type == 'deal' &&
|
||||||
<div className="box-flash-sale boder-radius-10 flex items-center">
|
Number(item.product_info.sale_rules.to_time) > now && (
|
||||||
<div className="box-left relative flex items-center">
|
<div className="box-flash-sale boder-radius-10 flex items-center">
|
||||||
<i className="sprite sprite-flashsale-detail"></i>
|
<div className="box-left relative flex items-center">
|
||||||
<p className="title-deal font-weight-800">flash sale</p>
|
<i className="sprite sprite-flashsale-detail"></i>
|
||||||
</div>
|
<p className="title-deal font-weight-800">flash sale</p>
|
||||||
<div className="box-middle product-time-holder global-time-deal flex gap-2">
|
</div>
|
||||||
<CounDown deadline={item.product_info.sale_rules.to_time} />
|
<div className="box-middle product-time-holder global-time-deal flex gap-2">
|
||||||
</div>
|
<CounDown deadline={Number(item.product_info.sale_rules.to_time)} />
|
||||||
<div className="box-right">
|
</div>
|
||||||
<div className="box-product-deal">
|
<div className="box-right">
|
||||||
<p className="text-deal-detail">
|
<div className="box-product-deal">
|
||||||
Còn{' '}
|
<p className="text-deal-detail">
|
||||||
{(() => {
|
Còn{' '}
|
||||||
const deal = item.product_info.deal_list[0];
|
{(() => {
|
||||||
return Number(deal.quantity) - deal.sale_order;
|
const deal = item.product_info.deal_list[0];
|
||||||
})()}
|
return Number(deal.quantity) - deal.sale_order;
|
||||||
/{item.product_info.deal_list[0].quantity} sản phẩm
|
})()}
|
||||||
</p>
|
/{item.product_info.deal_list[0].quantity} sản phẩm
|
||||||
|
</p>
|
||||||
|
|
||||||
<div className="p-quantity-sale" data-quantity-left="3" data-quantity-sale-total="5">
|
<div
|
||||||
<i className="sprite sprite-fire-deal"></i>
|
className="p-quantity-sale"
|
||||||
<div className="bg-gradient"></div>
|
data-quantity-left="3"
|
||||||
{(() => {
|
data-quantity-sale-total="5"
|
||||||
const deal = item.product_info.deal_list[0];
|
>
|
||||||
const percentRemaining =
|
<i className="sprite sprite-fire-deal"></i>
|
||||||
((Number(deal.quantity) - deal.sale_order) / Number(deal.quantity)) * 100;
|
<div className="bg-gradient"></div>
|
||||||
|
{(() => {
|
||||||
|
const deal = item.product_info.deal_list[0];
|
||||||
|
const percentRemaining =
|
||||||
|
((Number(deal.quantity) - deal.sale_order) / Number(deal.quantity)) * 100;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p
|
<p
|
||||||
className="js-line-deal-left"
|
className="js-line-deal-left"
|
||||||
style={{ width: `${percentRemaining}%` }}
|
style={{ width: `${percentRemaining}%` }}
|
||||||
></p>
|
></p>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
{/* giá */}
|
{/* giá */}
|
||||||
|
|
||||||
{item.product_info.marketPrice > '0' && item.product_info.sale_rules.type == 'deal' && (
|
{item.product_info.marketPrice > '0' && item.product_info.sale_rules.type == 'deal' && (
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export const ListComment = () => {
|
|||||||
<b className="user-name">{item.user_name}</b>
|
<b className="user-name">{item.user_name}</b>
|
||||||
</div>
|
</div>
|
||||||
<div className="comment-form-right flex items-center gap-2 text-sm text-gray-500">
|
<div className="comment-form-right flex items-center gap-2 text-sm text-gray-500">
|
||||||
<i className="fa-regular fa-clock"></i> <span>{item.post_time}</span>
|
<i className="fa-regular fa-clock"></i>{' '}
|
||||||
|
<span>{new Date(Number(item.post_time) * 1000).toLocaleDateString('vi-VN')}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>{' '}
|
</div>{' '}
|
||||||
{/* content */}
|
{/* content */}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export const ListReview = () => {
|
|||||||
{/* reply list */}
|
{/* reply list */}
|
||||||
<div className="reply-holder reply-list-container">
|
<div className="reply-holder reply-list-container">
|
||||||
{review.new_replies.map((reply) => (
|
{review.new_replies.map((reply) => (
|
||||||
<div key={reply.id} className="item_reply mt-3">
|
<div key={reply.id} className="item_reply relative mt-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="comment-left-form item-center flex gap-2">
|
<div className="comment-left-form item-center flex gap-2">
|
||||||
<b className="avatar-user avatar-admin">
|
<b className="avatar-user avatar-admin">
|
||||||
@@ -86,7 +86,9 @@ export const ListReview = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="info_feeback comment-right-form">
|
<div className="info_feeback comment-right-form">
|
||||||
<span style={{ color: '#787878', fontSize: 12 }}>({reply.post_time})</span>
|
<span style={{ color: '#787878', fontSize: 12 }}>
|
||||||
|
({new Date(Number(reply.post_time) * 1000).toLocaleDateString()})
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="comment-content boder-radius-10">{reply.content}</div>
|
<div className="comment-content boder-radius-10">{reply.content}</div>
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
'use client';
|
||||||
|
import React from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { useSearchParams } from 'next/navigation';
|
||||||
|
|
||||||
|
import { ErrorLink } from '@/components/Common/error';
|
||||||
|
import type { TypeProductSearch } from '@/types/product/search';
|
||||||
|
import { ProductSearchData } from '@/data/product/search';
|
||||||
|
import { findSearchBySlug } from '@/lib/product/search';
|
||||||
|
|
||||||
|
import { Breadcrumb } from '@/components/Common/Breadcrumb';
|
||||||
|
import BoxFilter from '@components/Product/BoxFilter';
|
||||||
|
import BoxSort from '@components/Product/BoxSort';
|
||||||
|
import ItemProduct from '@/components/Common/ItemProduct';
|
||||||
|
|
||||||
|
interface ProductSearchPageProps {
|
||||||
|
slug: string; // khai báo prop slug
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProductSearchPage: React.FC<ProductSearchPageProps> = ({ slug }) => {
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const keys = searchParams.get('q');
|
||||||
|
|
||||||
|
const Searchs = ProductSearchData as unknown as TypeProductSearch[];
|
||||||
|
const Pages = findSearchBySlug(keys, Searchs);
|
||||||
|
|
||||||
|
const breadcrumbItems = [
|
||||||
|
{ name: 'Trang chủ', url: '/' },
|
||||||
|
{ name: `Tìm kiếm "${keys}"`, url: `/tim?q=${Pages?.keywords}` },
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!Pages) {
|
||||||
|
return <ErrorLink />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lấy sản phẩm
|
||||||
|
const products = Object.values(Pages.product_list);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="container">
|
||||||
|
<Breadcrumb items={breadcrumbItems} />
|
||||||
|
</div>
|
||||||
|
<section className="page-category page-search container">
|
||||||
|
<div className="current-cate-title flex items-center gap-2">
|
||||||
|
<h1 className="current-cate-text font-bold"> Tìm kiếm : {Pages.keywords} </h1>
|
||||||
|
<span className="current-cate-total">(Tổng {Pages.product_count} sản phẩm)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{Pages.product_list ? (
|
||||||
|
<div className="box-content-category">
|
||||||
|
{/* filter */}
|
||||||
|
<BoxFilter filters={Pages} />
|
||||||
|
<div className="box-list-product-category boder-radius-10">
|
||||||
|
{/* filter sort */}
|
||||||
|
<BoxSort sort_by_collection={Pages.sort_by_collection} product_display_type="grid" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* list product */}
|
||||||
|
|
||||||
|
<div className="list-product-category grid grid-cols-5 gap-3">
|
||||||
|
{products.map((item, index) => (
|
||||||
|
<ItemProduct key={index} item={item} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="paging flex items-center justify-center">
|
||||||
|
{Pages.paging_collection.map((item, index) => (
|
||||||
|
<Link
|
||||||
|
key={index}
|
||||||
|
href={item.url}
|
||||||
|
className={`item ${item.is_active === '1' ? 'current' : ''}`}
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="text-center" style={{ padding: 20, fontSize: 15 }}>
|
||||||
|
<p style={{ fontSize: 24, margin: '15px 0 25px 0', fontWeight: 'bold' }}>
|
||||||
|
Rất tiếc, chúng tôi không tìm thấy kết quả của ${Pages.keywords}
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
textAlign: 'left',
|
||||||
|
border: 'solid 1px #ccc',
|
||||||
|
maxWidth: '500px',
|
||||||
|
padding: '20px',
|
||||||
|
margin: '15px auto',
|
||||||
|
lineHeight: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p style={{ textAlign: 'center', margin: '0 0 8px 0' }}>
|
||||||
|
<b>Để tìm được kết quả chính xác hơn, xin vui lòng</b>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Kiểm tra lại chính tả của từ khóa đã nhập</li>
|
||||||
|
<li>Thử lại bằng từ khóa khác</li>
|
||||||
|
<li>Thử lại bằng các từ khóa tổng quát hơn</li>
|
||||||
|
<li>Thử lại bằng các từ khóa ngắn gọn hơn</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<Link href="/">
|
||||||
|
<i className="fa fa-long-arrow-alt-left"></i> Quay lại trang chủ{' '}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductSearchPage;
|
||||||
|
|||||||
95
src/components/Deal/ItemDeal.tsx
Normal file
95
src/components/Deal/ItemDeal.tsx
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
'use client';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { parse } from 'date-fns';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import CounDown from '@/components/Common/CounDown';
|
||||||
|
import { DealType } from '@/types';
|
||||||
|
import { formatCurrency } from '@/lib/formatPrice';
|
||||||
|
|
||||||
|
type ItemDealProps = {
|
||||||
|
Item: DealType;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ItemDeal: React.FC<ItemDealProps> = ({ Item }) => {
|
||||||
|
const [now] = useState(() => Date.now());
|
||||||
|
|
||||||
|
// ép kiểu to_time sang số (timestamp) hoặc Date
|
||||||
|
const deadline = parse(Item.to_time, 'dd-MM-yyyy, h:mm a', new Date()).getTime();
|
||||||
|
|
||||||
|
// chỉ hiển thị nếu deadline còn lớn hơn thời gian hiện tại
|
||||||
|
if (deadline <= now) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="product-item">
|
||||||
|
<div className="item-deal">
|
||||||
|
<Link href={Item.product_info.productUrl} className="product-image position-relative">
|
||||||
|
<Image
|
||||||
|
src={Item.product_info.productImage.large}
|
||||||
|
width={250}
|
||||||
|
height={250}
|
||||||
|
alt={Item.product_info.productName}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
<div className="product-info flex-1">
|
||||||
|
<Link href={Item.product_info.productUrl}>
|
||||||
|
<h3 className="product-title line-clamp-3">{Item.product_info.productName}</h3>
|
||||||
|
</Link>
|
||||||
|
<div className="product-martket-main flex items-center">
|
||||||
|
{Item.product_info.marketPrice > 0 && (
|
||||||
|
<>
|
||||||
|
<p className="product-market-price">
|
||||||
|
{Item.product_info.marketPrice.toLocaleString()} ₫
|
||||||
|
</p>
|
||||||
|
<div className="product-percent-price">-{Item.product_info.price_off || 0}%</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="product-price-main font-bold">
|
||||||
|
{Item.product_info.price > '0'
|
||||||
|
? `${formatCurrency(Item.product_info.price)}đ`
|
||||||
|
: 'Liên hệ'}
|
||||||
|
</div>
|
||||||
|
<div className="p-quantity-sale">
|
||||||
|
<i className="sprite sprite-fire-deal"></i>
|
||||||
|
<div className="bg-gradient"></div>
|
||||||
|
{(() => {
|
||||||
|
const percentRemaining =
|
||||||
|
((Number(Item.quantity) - Number(Item.sale_quantity)) / Number(Item.quantity)) *
|
||||||
|
100;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className="js-line-deal-left" style={{ width: `${percentRemaining}%` }}></p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
<span>
|
||||||
|
Còn {Number(Item.quantity) - Number(Item.sale_quantity)}/{Number(Item.quantity)} sản
|
||||||
|
phẩm
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="js-item-deal-time js-item-time-25404">
|
||||||
|
<div className="time-deal-page flex items-center justify-center gap-2">
|
||||||
|
<div>Kết thúc sau: </div>
|
||||||
|
<CounDown deadline={Item.to_time} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="javascript:buyNow(25404)" className="buy-now-deal">
|
||||||
|
Mua giá sốc
|
||||||
|
</a>
|
||||||
|
<Link
|
||||||
|
href="/bts-gaming-02"
|
||||||
|
className="text-deal-item color-primary mt-3 hidden font-bold"
|
||||||
|
>
|
||||||
|
Xem sản phẩm
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ItemDeal;
|
||||||
@@ -32,7 +32,7 @@ const BoxFilter: React.FC<BoxFilterProps> = ({ filters }) => {
|
|||||||
>
|
>
|
||||||
<Link href={ItemPrice.url}>{ItemPrice.name}</Link>
|
<Link href={ItemPrice.url}>{ItemPrice.name}</Link>
|
||||||
<a href={ItemPrice.url}>
|
<a href={ItemPrice.url}>
|
||||||
(${ItemPrice.is_selected == '1' ? 'Xóa' : ItemPrice.count})
|
({ItemPrice.is_selected == '1' ? 'Xóa' : ItemPrice.count})
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { parse } from 'date-fns';
|
||||||
|
|
||||||
interface CountDownProps {
|
interface CountDownProps {
|
||||||
deadline: Date | string;
|
deadline: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CounDown: React.FC<CountDownProps> = ({ deadline }) => {
|
const CounDown: React.FC<CountDownProps> = ({ deadline }) => {
|
||||||
@@ -13,8 +14,10 @@ const CounDown: React.FC<CountDownProps> = ({ deadline }) => {
|
|||||||
|
|
||||||
const getTime = () => {
|
const getTime = () => {
|
||||||
let time: number;
|
let time: number;
|
||||||
if (deadline instanceof Date) {
|
|
||||||
time = deadline.getTime() - Date.now();
|
if (typeof deadline == 'string') {
|
||||||
|
const parsed = parse(deadline as string, 'dd-MM-yyyy, h:mm a', new Date());
|
||||||
|
time = parsed.getTime() - Date.now();
|
||||||
} else {
|
} else {
|
||||||
time = Number(deadline) * 1000 - Date.now();
|
time = Number(deadline) * 1000 - Date.now();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const ListDealData: TypeListProductDeal = [
|
|||||||
min_purchase: '1',
|
min_purchase: '1',
|
||||||
max_purchase: '0',
|
max_purchase: '0',
|
||||||
from_time: '19-12-2025, 8:00 am',
|
from_time: '19-12-2025, 8:00 am',
|
||||||
to_time: '22-12-2025, 9:30 am',
|
to_time: '31-01-2026, 9:30 am',
|
||||||
is_featured: '0',
|
is_featured: '0',
|
||||||
last_update: '1766109733',
|
last_update: '1766109733',
|
||||||
last_update_by: '0',
|
last_update_by: '0',
|
||||||
@@ -287,6 +287,291 @@ export const ListDealData: TypeListProductDeal = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: '560',
|
||||||
|
pro_id: '27720',
|
||||||
|
title: 'Bộ PC Gaming Intel Core i5-13400F, RAM 16GB, RTX 5060 Ti [TẶNG MÀN HÌNH]',
|
||||||
|
price: '24990000',
|
||||||
|
customer_group_price: '[]',
|
||||||
|
quantity: '5',
|
||||||
|
min_purchase: '1',
|
||||||
|
max_purchase: '0',
|
||||||
|
from_time: '08-12-2025, 8:00 am',
|
||||||
|
to_time: '31-01-2026, 9:30 am',
|
||||||
|
is_featured: '0',
|
||||||
|
last_update: '1766108851',
|
||||||
|
last_update_by: '0',
|
||||||
|
ordering: '0',
|
||||||
|
sale_order: '3',
|
||||||
|
sale_quantity: '3',
|
||||||
|
views: '1',
|
||||||
|
rating: '0',
|
||||||
|
review_count: '0',
|
||||||
|
auto_renew: '0',
|
||||||
|
auto_renew_history: null,
|
||||||
|
counter: 6,
|
||||||
|
request_path: '/deal/560',
|
||||||
|
deal_time_happen: 971685,
|
||||||
|
deal_time_left: 243315,
|
||||||
|
is_start: 1,
|
||||||
|
is_end: 0,
|
||||||
|
is_active: '1',
|
||||||
|
product_info: {
|
||||||
|
id: 27720,
|
||||||
|
productId: 27720,
|
||||||
|
priceUnit: 'chiếc',
|
||||||
|
marketPrice: 27690000,
|
||||||
|
price: '24990000',
|
||||||
|
price_off: 6,
|
||||||
|
currency: 'vnd',
|
||||||
|
sale_rules: {
|
||||||
|
price: '24990000',
|
||||||
|
normal_price: 25990000,
|
||||||
|
min_purchase: '1',
|
||||||
|
max_purchase: '0',
|
||||||
|
remain_quantity: 1,
|
||||||
|
from_time: '1765155600',
|
||||||
|
to_time: '1766370600',
|
||||||
|
type: 'deal',
|
||||||
|
type_id: '560',
|
||||||
|
},
|
||||||
|
lastUpdate: '2025-12-18 15:39:17',
|
||||||
|
warranty: 'Bảo hành dài theo từng linh kiện',
|
||||||
|
productName: 'Bộ PC Gaming Intel Core i5-13400F, RAM 16GB, RTX 5060 Ti [TẶNG MÀN HÌNH]',
|
||||||
|
productSummary:
|
||||||
|
'CPU Intel Core i5-13400F Tray New (Up To 4.60GHz, 10 Nhân 16 Luồng, 20 MB Cache, LGA 1700)\r\nMainboard BIOSTAR Z690MX2-E D4 (Intel Z690, Socket 1700, 2xDDR4, mATX)\r\nRAM Colorful Battle AX 16GB DDR4 3200MHz\r\nỔ Cứng SSD Acer FA100 512GB (NVMe PCIe/ Gen3x4 M2.2280/ 3200MB/s/ 2200MB/s)\r\nCard Màn Hình MSI RTX 5060 Ti 8GB SHADOW 2X OC Plus\r\nNguồn máy tính MIK C750B 750W PLUS BRONZE\r\nVỏ Case Xigmatek BLAST M (M-ATX) - Black\r\nTản Nhiệt Khí JONSBO CR-1000 EVO BLACK (Color RGB)\r\nFan Tản Nhiệt JUNGLE LEOPARD Prism 6Pro Black\r\n',
|
||||||
|
package_accessory: '',
|
||||||
|
productImage: {
|
||||||
|
small: 'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-25251326.jpg',
|
||||||
|
large: 'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-25251326.jpg',
|
||||||
|
original: '',
|
||||||
|
},
|
||||||
|
imageCollection: [
|
||||||
|
{
|
||||||
|
image: {
|
||||||
|
small:
|
||||||
|
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-001.jpg',
|
||||||
|
large:
|
||||||
|
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-001.jpg',
|
||||||
|
original: '',
|
||||||
|
},
|
||||||
|
alt: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: {
|
||||||
|
small:
|
||||||
|
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-1.jpg',
|
||||||
|
large:
|
||||||
|
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-1.jpg',
|
||||||
|
original: '',
|
||||||
|
},
|
||||||
|
alt: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: {
|
||||||
|
small:
|
||||||
|
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-2.jpg',
|
||||||
|
large:
|
||||||
|
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-2.jpg',
|
||||||
|
original: '',
|
||||||
|
},
|
||||||
|
alt: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: {
|
||||||
|
small:
|
||||||
|
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-3.jpg',
|
||||||
|
large:
|
||||||
|
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-3.jpg',
|
||||||
|
original: '',
|
||||||
|
},
|
||||||
|
alt: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: {
|
||||||
|
small:
|
||||||
|
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-4.jpg',
|
||||||
|
large:
|
||||||
|
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-4.jpg',
|
||||||
|
original: '',
|
||||||
|
},
|
||||||
|
alt: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: {
|
||||||
|
small: 'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-25251326.jpg',
|
||||||
|
large: 'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-25251326.jpg',
|
||||||
|
original: '',
|
||||||
|
},
|
||||||
|
alt: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
productUrl: '/pc-gaming-ncpc-15',
|
||||||
|
brand: {
|
||||||
|
id: 124,
|
||||||
|
brand_index: 'ncpc',
|
||||||
|
name: 'NCPC',
|
||||||
|
image: '',
|
||||||
|
url: '/brand/ncpc',
|
||||||
|
},
|
||||||
|
visit: 39556,
|
||||||
|
rating: 5,
|
||||||
|
reviewCount: 1,
|
||||||
|
review: {
|
||||||
|
rate: 5,
|
||||||
|
total: 1,
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
rate: 5,
|
||||||
|
total: 3,
|
||||||
|
},
|
||||||
|
quantity: 1,
|
||||||
|
productSKU: '',
|
||||||
|
productModel: '',
|
||||||
|
hasVAT: 0,
|
||||||
|
condition: 'Mới',
|
||||||
|
config_count: 0,
|
||||||
|
configurable: 0,
|
||||||
|
component_count: 0,
|
||||||
|
specialOffer: {
|
||||||
|
other: [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
title:
|
||||||
|
'<p><span style="font-size: 10pt;"><strong><span style="color: #ff0000;">TẶNG MÀN HÌNH : Màn hình Gaming cong MSI MAG 276CF E20 27\' FHD VA 200Hz 0.5Ms</span></strong></span></p>\r\n<p><span style="font-size: 10pt;"><strong>Giá PC khi không lấy quà tặng : 23.490.000đ</strong></span></p>\r\n<p><a href="https://khuyenmai.nguyencongpc.vn/build-pc"><img src="https://nguyencongpc.vn/media/lib/24-09-2025/z7044410660344_5550774fd1a8b1c78c2735d5f4aab705.jpg" alt="" width="100%" /></a></p>',
|
||||||
|
type: '',
|
||||||
|
thumbnail: '',
|
||||||
|
cash_value: 0,
|
||||||
|
quantity: 1,
|
||||||
|
from_time: '',
|
||||||
|
to_time: '',
|
||||||
|
url: '',
|
||||||
|
description: '',
|
||||||
|
status: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
all: [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
title:
|
||||||
|
'<p><span style="font-size: 10pt;"><strong><span style="color: #ff0000;">TẶNG MÀN HÌNH : Màn hình Gaming cong MSI MAG 276CF E20 27\' FHD VA 200Hz 0.5Ms</span></strong></span></p>\r\n<p><span style="font-size: 10pt;"><strong>Giá PC khi không lấy quà tặng : 23.490.000đ</strong></span></p>\r\n<p><a href="https://khuyenmai.nguyencongpc.vn/build-pc"><img src="https://nguyencongpc.vn/media/lib/24-09-2025/z7044410660344_5550774fd1a8b1c78c2735d5f4aab705.jpg" alt="" width="100%" /></a></p>',
|
||||||
|
type: '',
|
||||||
|
thumbnail: '',
|
||||||
|
cash_value: 0,
|
||||||
|
quantity: 1,
|
||||||
|
from_time: '',
|
||||||
|
to_time: '',
|
||||||
|
url: '',
|
||||||
|
description: '',
|
||||||
|
status: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
specialOfferGroup: [],
|
||||||
|
productType: {
|
||||||
|
isNew: 0,
|
||||||
|
isHot: 0,
|
||||||
|
isBestSale: 0,
|
||||||
|
isSaleOff: 0,
|
||||||
|
'online-only': 0,
|
||||||
|
},
|
||||||
|
bulk_price: [],
|
||||||
|
thum_poster: '0',
|
||||||
|
thum_poster_type: '',
|
||||||
|
addon: [],
|
||||||
|
variants: [],
|
||||||
|
variant_option: [],
|
||||||
|
extend: {
|
||||||
|
buy_count: '492',
|
||||||
|
pixel_code: '',
|
||||||
|
review_count: '43',
|
||||||
|
review_score: '4.3',
|
||||||
|
},
|
||||||
|
weight: 0,
|
||||||
|
promotion_price: null,
|
||||||
|
deal_list: [
|
||||||
|
{
|
||||||
|
id: '560',
|
||||||
|
pro_id: '27720',
|
||||||
|
title: 'Bộ PC Gaming Intel Core i5-13400F, RAM 16GB, RTX 5060 Ti [TẶNG MÀN HÌNH]',
|
||||||
|
price: '24990000',
|
||||||
|
quantity: '5',
|
||||||
|
min_purchase: '1',
|
||||||
|
max_purchase: '0',
|
||||||
|
is_featured: '0',
|
||||||
|
from_time: '1765155600',
|
||||||
|
to_time: '1766370600',
|
||||||
|
is_started: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
pricing_traces: [
|
||||||
|
{
|
||||||
|
price: '11690000',
|
||||||
|
type: 'deal',
|
||||||
|
type_id: '565',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: '7600000',
|
||||||
|
type: 'deal',
|
||||||
|
type_id: '563',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: '6990000',
|
||||||
|
type: 'deal',
|
||||||
|
type_id: '562',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: '24990000',
|
||||||
|
type: 'deal',
|
||||||
|
type_id: '560',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
id: '1829',
|
||||||
|
catPath: ':1829:0',
|
||||||
|
name: 'PC GAMING',
|
||||||
|
url: '/pc-gaming',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3468',
|
||||||
|
catPath: ':3468:1829:0',
|
||||||
|
name: 'CHỌN THEO NHU CẦU',
|
||||||
|
url: '/chon-theo-nhu-cau-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3432',
|
||||||
|
catPath: ':3432:3468:1829:0',
|
||||||
|
name: 'PC ESPORT',
|
||||||
|
url: '/pc-esport',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3433',
|
||||||
|
catPath: ':3433:3468:1829:0',
|
||||||
|
name: 'PC GAME AAA',
|
||||||
|
url: '/pc-game-aaa',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3434',
|
||||||
|
catPath: ':3434:3468:1829:0',
|
||||||
|
name: 'PC STREAM GAME',
|
||||||
|
url: '/pc-stream-game',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3469',
|
||||||
|
catPath: ':3469:1829:0',
|
||||||
|
name: 'CHỌN THEO KHOẢNG GIÁ',
|
||||||
|
url: '/chon-theo-khoang-gia-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3472',
|
||||||
|
catPath: ':3472:3469:1829:0',
|
||||||
|
name: '20 Triệu - 30 Triệu',
|
||||||
|
url: '/20-trieu-30-trieu-1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: '564',
|
id: '564',
|
||||||
pro_id: '28304',
|
pro_id: '28304',
|
||||||
@@ -1376,289 +1661,4 @@ export const ListDealData: TypeListProductDeal = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: '560',
|
|
||||||
pro_id: '27720',
|
|
||||||
title: 'Bộ PC Gaming Intel Core i5-13400F, RAM 16GB, RTX 5060 Ti [TẶNG MÀN HÌNH]',
|
|
||||||
price: '24990000',
|
|
||||||
customer_group_price: '[]',
|
|
||||||
quantity: '5',
|
|
||||||
min_purchase: '1',
|
|
||||||
max_purchase: '0',
|
|
||||||
from_time: '08-12-2025, 8:00 am',
|
|
||||||
to_time: '22-12-2025, 9:30 am',
|
|
||||||
is_featured: '0',
|
|
||||||
last_update: '1766108851',
|
|
||||||
last_update_by: '0',
|
|
||||||
ordering: '0',
|
|
||||||
sale_order: '3',
|
|
||||||
sale_quantity: '3',
|
|
||||||
views: '1',
|
|
||||||
rating: '0',
|
|
||||||
review_count: '0',
|
|
||||||
auto_renew: '0',
|
|
||||||
auto_renew_history: null,
|
|
||||||
counter: 6,
|
|
||||||
request_path: '/deal/560',
|
|
||||||
deal_time_happen: 971685,
|
|
||||||
deal_time_left: 243315,
|
|
||||||
is_start: 1,
|
|
||||||
is_end: 0,
|
|
||||||
is_active: '1',
|
|
||||||
product_info: {
|
|
||||||
id: 27720,
|
|
||||||
productId: 27720,
|
|
||||||
priceUnit: 'chiếc',
|
|
||||||
marketPrice: 27690000,
|
|
||||||
price: '24990000',
|
|
||||||
price_off: 6,
|
|
||||||
currency: 'vnd',
|
|
||||||
sale_rules: {
|
|
||||||
price: '24990000',
|
|
||||||
normal_price: 25990000,
|
|
||||||
min_purchase: '1',
|
|
||||||
max_purchase: '0',
|
|
||||||
remain_quantity: 1,
|
|
||||||
from_time: '1765155600',
|
|
||||||
to_time: '1766370600',
|
|
||||||
type: 'deal',
|
|
||||||
type_id: '560',
|
|
||||||
},
|
|
||||||
lastUpdate: '2025-12-18 15:39:17',
|
|
||||||
warranty: 'Bảo hành dài theo từng linh kiện',
|
|
||||||
productName: 'Bộ PC Gaming Intel Core i5-13400F, RAM 16GB, RTX 5060 Ti [TẶNG MÀN HÌNH]',
|
|
||||||
productSummary:
|
|
||||||
'CPU Intel Core i5-13400F Tray New (Up To 4.60GHz, 10 Nhân 16 Luồng, 20 MB Cache, LGA 1700)\r\nMainboard BIOSTAR Z690MX2-E D4 (Intel Z690, Socket 1700, 2xDDR4, mATX)\r\nRAM Colorful Battle AX 16GB DDR4 3200MHz\r\nỔ Cứng SSD Acer FA100 512GB (NVMe PCIe/ Gen3x4 M2.2280/ 3200MB/s/ 2200MB/s)\r\nCard Màn Hình MSI RTX 5060 Ti 8GB SHADOW 2X OC Plus\r\nNguồn máy tính MIK C750B 750W PLUS BRONZE\r\nVỏ Case Xigmatek BLAST M (M-ATX) - Black\r\nTản Nhiệt Khí JONSBO CR-1000 EVO BLACK (Color RGB)\r\nFan Tản Nhiệt JUNGLE LEOPARD Prism 6Pro Black\r\n',
|
|
||||||
package_accessory: '',
|
|
||||||
productImage: {
|
|
||||||
small: 'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-25251326.jpg',
|
|
||||||
large: 'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-25251326.jpg',
|
|
||||||
original: '',
|
|
||||||
},
|
|
||||||
imageCollection: [
|
|
||||||
{
|
|
||||||
image: {
|
|
||||||
small:
|
|
||||||
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-001.jpg',
|
|
||||||
large:
|
|
||||||
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-001.jpg',
|
|
||||||
original: '',
|
|
||||||
},
|
|
||||||
alt: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: {
|
|
||||||
small:
|
|
||||||
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-1.jpg',
|
|
||||||
large:
|
|
||||||
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-1.jpg',
|
|
||||||
original: '',
|
|
||||||
},
|
|
||||||
alt: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: {
|
|
||||||
small:
|
|
||||||
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-2.jpg',
|
|
||||||
large:
|
|
||||||
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-2.jpg',
|
|
||||||
original: '',
|
|
||||||
},
|
|
||||||
alt: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: {
|
|
||||||
small:
|
|
||||||
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-3.jpg',
|
|
||||||
large:
|
|
||||||
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-3.jpg',
|
|
||||||
original: '',
|
|
||||||
},
|
|
||||||
alt: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: {
|
|
||||||
small:
|
|
||||||
'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-4.jpg',
|
|
||||||
large:
|
|
||||||
'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-intel-core-i5-13400f-ram-16g-vga-rtx-5060-ti-4.jpg',
|
|
||||||
original: '',
|
|
||||||
},
|
|
||||||
alt: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: {
|
|
||||||
small: 'https://nguyencongpc.vn/media/product/75-27720-pc-gaming-25251326.jpg',
|
|
||||||
large: 'https://nguyencongpc.vn/media/product/250-27720-pc-gaming-25251326.jpg',
|
|
||||||
original: '',
|
|
||||||
},
|
|
||||||
alt: '',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
productUrl: '/pc-gaming-ncpc-15',
|
|
||||||
brand: {
|
|
||||||
id: 124,
|
|
||||||
brand_index: 'ncpc',
|
|
||||||
name: 'NCPC',
|
|
||||||
image: '',
|
|
||||||
url: '/brand/ncpc',
|
|
||||||
},
|
|
||||||
visit: 39556,
|
|
||||||
rating: 5,
|
|
||||||
reviewCount: 1,
|
|
||||||
review: {
|
|
||||||
rate: 5,
|
|
||||||
total: 1,
|
|
||||||
},
|
|
||||||
comment: {
|
|
||||||
rate: 5,
|
|
||||||
total: 3,
|
|
||||||
},
|
|
||||||
quantity: 1,
|
|
||||||
productSKU: '',
|
|
||||||
productModel: '',
|
|
||||||
hasVAT: 0,
|
|
||||||
condition: 'Mới',
|
|
||||||
config_count: 0,
|
|
||||||
configurable: 0,
|
|
||||||
component_count: 0,
|
|
||||||
specialOffer: {
|
|
||||||
other: [
|
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
title:
|
|
||||||
'<p><span style="font-size: 10pt;"><strong><span style="color: #ff0000;">TẶNG MÀN HÌNH : Màn hình Gaming cong MSI MAG 276CF E20 27\' FHD VA 200Hz 0.5Ms</span></strong></span></p>\r\n<p><span style="font-size: 10pt;"><strong>Giá PC khi không lấy quà tặng : 23.490.000đ</strong></span></p>\r\n<p><a href="https://khuyenmai.nguyencongpc.vn/build-pc"><img src="https://nguyencongpc.vn/media/lib/24-09-2025/z7044410660344_5550774fd1a8b1c78c2735d5f4aab705.jpg" alt="" width="100%" /></a></p>',
|
|
||||||
type: '',
|
|
||||||
thumbnail: '',
|
|
||||||
cash_value: 0,
|
|
||||||
quantity: 1,
|
|
||||||
from_time: '',
|
|
||||||
to_time: '',
|
|
||||||
url: '',
|
|
||||||
description: '',
|
|
||||||
status: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
all: [
|
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
title:
|
|
||||||
'<p><span style="font-size: 10pt;"><strong><span style="color: #ff0000;">TẶNG MÀN HÌNH : Màn hình Gaming cong MSI MAG 276CF E20 27\' FHD VA 200Hz 0.5Ms</span></strong></span></p>\r\n<p><span style="font-size: 10pt;"><strong>Giá PC khi không lấy quà tặng : 23.490.000đ</strong></span></p>\r\n<p><a href="https://khuyenmai.nguyencongpc.vn/build-pc"><img src="https://nguyencongpc.vn/media/lib/24-09-2025/z7044410660344_5550774fd1a8b1c78c2735d5f4aab705.jpg" alt="" width="100%" /></a></p>',
|
|
||||||
type: '',
|
|
||||||
thumbnail: '',
|
|
||||||
cash_value: 0,
|
|
||||||
quantity: 1,
|
|
||||||
from_time: '',
|
|
||||||
to_time: '',
|
|
||||||
url: '',
|
|
||||||
description: '',
|
|
||||||
status: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
specialOfferGroup: [],
|
|
||||||
productType: {
|
|
||||||
isNew: 0,
|
|
||||||
isHot: 0,
|
|
||||||
isBestSale: 0,
|
|
||||||
isSaleOff: 0,
|
|
||||||
'online-only': 0,
|
|
||||||
},
|
|
||||||
bulk_price: [],
|
|
||||||
thum_poster: '0',
|
|
||||||
thum_poster_type: '',
|
|
||||||
addon: [],
|
|
||||||
variants: [],
|
|
||||||
variant_option: [],
|
|
||||||
extend: {
|
|
||||||
buy_count: '492',
|
|
||||||
pixel_code: '',
|
|
||||||
review_count: '43',
|
|
||||||
review_score: '4.3',
|
|
||||||
},
|
|
||||||
weight: 0,
|
|
||||||
promotion_price: null,
|
|
||||||
deal_list: [
|
|
||||||
{
|
|
||||||
id: '560',
|
|
||||||
pro_id: '27720',
|
|
||||||
title: 'Bộ PC Gaming Intel Core i5-13400F, RAM 16GB, RTX 5060 Ti [TẶNG MÀN HÌNH]',
|
|
||||||
price: '24990000',
|
|
||||||
quantity: '5',
|
|
||||||
min_purchase: '1',
|
|
||||||
max_purchase: '0',
|
|
||||||
is_featured: '0',
|
|
||||||
from_time: '1765155600',
|
|
||||||
to_time: '1766370600',
|
|
||||||
is_started: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
pricing_traces: [
|
|
||||||
{
|
|
||||||
price: '11690000',
|
|
||||||
type: 'deal',
|
|
||||||
type_id: '565',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
price: '7600000',
|
|
||||||
type: 'deal',
|
|
||||||
type_id: '563',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
price: '6990000',
|
|
||||||
type: 'deal',
|
|
||||||
type_id: '562',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
price: '24990000',
|
|
||||||
type: 'deal',
|
|
||||||
type_id: '560',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
categories: [
|
|
||||||
{
|
|
||||||
id: '1829',
|
|
||||||
catPath: ':1829:0',
|
|
||||||
name: 'PC GAMING',
|
|
||||||
url: '/pc-gaming',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3468',
|
|
||||||
catPath: ':3468:1829:0',
|
|
||||||
name: 'CHỌN THEO NHU CẦU',
|
|
||||||
url: '/chon-theo-nhu-cau-1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3432',
|
|
||||||
catPath: ':3432:3468:1829:0',
|
|
||||||
name: 'PC ESPORT',
|
|
||||||
url: '/pc-esport',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3433',
|
|
||||||
catPath: ':3433:3468:1829:0',
|
|
||||||
name: 'PC GAME AAA',
|
|
||||||
url: '/pc-game-aaa',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3434',
|
|
||||||
catPath: ':3434:3468:1829:0',
|
|
||||||
name: 'PC STREAM GAME',
|
|
||||||
url: '/pc-stream-game',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3469',
|
|
||||||
catPath: ':3469:1829:0',
|
|
||||||
name: 'CHỌN THEO KHOẢNG GIÁ',
|
|
||||||
url: '/chon-theo-khoang-gia-1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3472',
|
|
||||||
catPath: ':3472:3469:1829:0',
|
|
||||||
name: '20 Triệu - 30 Triệu',
|
|
||||||
url: '/20-trieu-30-trieu-1',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|||||||
13214
src/data/product/search/index.ts
Normal file
13214
src/data/product/search/index.ts
Normal file
File diff suppressed because it is too large
Load Diff
14
src/lib/product/search/index.ts
Normal file
14
src/lib/product/search/index.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { TypeProductSearch } from '@/types/product/search';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tìm danh mục theo mảng slug (ví dụ: ["pc-gaming","cao-cap","rtx-4090"])
|
||||||
|
*/
|
||||||
|
export function findSearchBySlug(
|
||||||
|
keys: string | null,
|
||||||
|
categories: TypeProductSearch[],
|
||||||
|
): TypeProductSearch | null {
|
||||||
|
console.log('Searching for keys:', keys);
|
||||||
|
|
||||||
|
const found = categories.find((item) => item.keywords === keys);
|
||||||
|
return found ?? null;
|
||||||
|
}
|
||||||
@@ -4,11 +4,17 @@ import { ArticleCateDetailPageData } from '@/data/article/ArticleCateDetailPageD
|
|||||||
import { ArticleDetailPageData } from '@/data/article/ArticleDetailPageData';
|
import { ArticleDetailPageData } from '@/data/article/ArticleDetailPageData';
|
||||||
|
|
||||||
export function resolvePageType(slug: string) {
|
export function resolvePageType(slug: string) {
|
||||||
// kiểm tra danh mục
|
// hiển thị trang danh mục sản phẩm
|
||||||
if (productCategoryData.some((c) => c.current_category.url == slug)) {
|
if (productCategoryData.some((c) => c.current_category.url == slug)) {
|
||||||
return 'category';
|
return 'category';
|
||||||
}
|
}
|
||||||
// kiểm tra sản phẩm
|
|
||||||
|
// hiển thị trang tìm kiếm
|
||||||
|
if ('/tim' == slug) {
|
||||||
|
return 'product-search';
|
||||||
|
}
|
||||||
|
|
||||||
|
// hiển thị trang chi tiết sản phẩm
|
||||||
if (productDetailData.some((c) => c.product_info.productUrl == slug)) {
|
if (productDetailData.some((c) => c.product_info.productUrl == slug)) {
|
||||||
return 'product-detail';
|
return 'product-detail';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2909,6 +2909,8 @@ textarea::placeholder {
|
|||||||
-ms-transform-origin: top left;
|
-ms-transform-origin: top left;
|
||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
padding: 14px 10px;
|
padding: 14px 10px;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
.page-category .box-content-category .list-filter-category .item:hover ul {
|
.page-category .box-content-category .list-filter-category .item:hover ul {
|
||||||
-webkit-transform: scale(1);
|
-webkit-transform: scale(1);
|
||||||
@@ -4437,6 +4439,20 @@ textarea::placeholder {
|
|||||||
.page-deal .box-list-item-deal .product-item:nth-child(2) .text-deal-item {
|
.page-deal .box-list-item-deal .product-item:nth-child(2) .text-deal-item {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
.page-deal .time-deal-page p {
|
||||||
|
background: #000;
|
||||||
|
color: #fff;
|
||||||
|
width: 25px;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.page-deal .time-deal-page span {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.page-cart {
|
.page-cart {
|
||||||
background: #f0f0f0;
|
background: #f0f0f0;
|
||||||
padding: 20px 0 40px;
|
padding: 20px 0 40px;
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ export interface ImageCollectionItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Brand {
|
export interface Brand {
|
||||||
id: number;
|
id: number | string;
|
||||||
brand_index: string;
|
brand_index?: string;
|
||||||
name: string;
|
name: string;
|
||||||
image: string;
|
image: string;
|
||||||
url: string;
|
url: string;
|
||||||
@@ -19,10 +19,10 @@ export interface Brand {
|
|||||||
|
|
||||||
export interface SaleRules {
|
export interface SaleRules {
|
||||||
price: string | number;
|
price: string | number;
|
||||||
normal_price: number;
|
normal_price: number | string;
|
||||||
min_purchase: string | number;
|
min_purchase: string | number;
|
||||||
max_purchase: string | number;
|
max_purchase: string | number;
|
||||||
remain_quantity: number;
|
remain_quantity: number | string;
|
||||||
from_time: string | number;
|
from_time: string | number;
|
||||||
to_time: string | number;
|
to_time: string | number;
|
||||||
type: string;
|
type: string;
|
||||||
@@ -63,24 +63,24 @@ export interface Extend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SpecialOfferItem {
|
export interface SpecialOfferItem {
|
||||||
id: number;
|
id: number | string;
|
||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
thumbnail: string;
|
thumbnail: string;
|
||||||
cash_value: number;
|
cash_value: number | string;
|
||||||
quantity: number;
|
quantity: number | string;
|
||||||
from_time: string;
|
from_time: string;
|
||||||
to_time: string;
|
to_time: string;
|
||||||
url: string;
|
url: string;
|
||||||
description: string;
|
description: string;
|
||||||
status: number;
|
status: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Product {
|
export interface Product {
|
||||||
id: number;
|
id: number | string;
|
||||||
productId: number;
|
productId: number | string;
|
||||||
priceUnit: string;
|
priceUnit: string;
|
||||||
marketPrice: number;
|
marketPrice: number | string;
|
||||||
price: string | number;
|
price: string | number;
|
||||||
price_off: number | string;
|
price_off: number | string;
|
||||||
currency: string;
|
currency: string;
|
||||||
@@ -94,27 +94,27 @@ export interface Product {
|
|||||||
imageCollection: ImageCollectionItem[];
|
imageCollection: ImageCollectionItem[];
|
||||||
productUrl: string;
|
productUrl: string;
|
||||||
brand: Brand;
|
brand: Brand;
|
||||||
visit: number;
|
visit: number | string;
|
||||||
rating: number;
|
rating: number | string;
|
||||||
reviewCount: number;
|
reviewCount: number | string;
|
||||||
review: { rate: number; total: number };
|
review: { rate: number | string; total: number | string };
|
||||||
comment: { rate: number; total: number };
|
comment: { rate: number | string; total: number | string };
|
||||||
quantity: number;
|
quantity: number | string;
|
||||||
productSKU: string;
|
productSKU: string;
|
||||||
productModel: string;
|
productModel: string;
|
||||||
hasVAT: number;
|
hasVAT: number | string;
|
||||||
condition: string;
|
condition: string;
|
||||||
config_count: number;
|
config_count: number | string;
|
||||||
configurable: number;
|
configurable: number | string;
|
||||||
component_count: number;
|
component_count: number | string;
|
||||||
specialOffer: { other?: SpecialOfferItem[]; all?: SpecialOfferItem[] };
|
specialOffer: { other?: SpecialOfferItem[]; all?: SpecialOfferItem[] };
|
||||||
specialOfferGroup: [];
|
specialOfferGroup: [];
|
||||||
productType: {
|
productType: {
|
||||||
isNew: number;
|
isNew: number | string;
|
||||||
isHot: number;
|
isHot: number | string;
|
||||||
isBestSale: number;
|
isBestSale: number | string;
|
||||||
isSaleOff: number;
|
isSaleOff: number | string;
|
||||||
'online-only': number;
|
'online-only': number | string;
|
||||||
};
|
};
|
||||||
bulk_price: [];
|
bulk_price: [];
|
||||||
thum_poster: string;
|
thum_poster: string;
|
||||||
@@ -123,8 +123,8 @@ export interface Product {
|
|||||||
variants: [];
|
variants: [];
|
||||||
variant_option: [];
|
variant_option: [];
|
||||||
extend: Extend;
|
extend: Extend;
|
||||||
weight: number;
|
weight: number | string;
|
||||||
promotion_price: number | null;
|
promotion_price: number | null | string;
|
||||||
deal_list: Deal[];
|
deal_list: Deal[];
|
||||||
pricing_traces: PricingTrace[];
|
pricing_traces: PricingTrace[];
|
||||||
categories: Category[];
|
categories: Category[];
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export interface ChildCategory {
|
|||||||
is_featured: string;
|
is_featured: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
}
|
}
|
||||||
interface FilterCollection {
|
export interface FilterCollection {
|
||||||
url: string;
|
url: string;
|
||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -21,22 +21,24 @@ export interface SortCollection {
|
|||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
interface DisplayCollection {
|
export interface DisplayCollection {
|
||||||
url: string;
|
url: string;
|
||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
interface PagingCollection {
|
export interface PagingCollection {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
is_active: string;
|
is_active: string;
|
||||||
}
|
}
|
||||||
interface CategoryCollection {
|
|
||||||
|
export interface CategoryCollection {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
count: string;
|
count: string;
|
||||||
is_selected: string;
|
is_selected: string;
|
||||||
|
category_url?: string;
|
||||||
}
|
}
|
||||||
export interface BrandFilter {
|
export interface BrandFilter {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
33
src/types/product/search/index.ts
Normal file
33
src/types/product/search/index.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import {
|
||||||
|
DisplayCollection,
|
||||||
|
FilterCollection,
|
||||||
|
SortCollection,
|
||||||
|
PagingCollection,
|
||||||
|
Product,
|
||||||
|
BrandFilter,
|
||||||
|
AttributeFilterList,
|
||||||
|
PriceFilter,
|
||||||
|
CategoryCollection,
|
||||||
|
} from '@/types';
|
||||||
|
|
||||||
|
export interface TypeProductSearch {
|
||||||
|
keywords: string;
|
||||||
|
description: string;
|
||||||
|
title: string;
|
||||||
|
favicon: string;
|
||||||
|
canonical: string;
|
||||||
|
image: string;
|
||||||
|
search_query: string;
|
||||||
|
other_filter_collection: FilterCollection[];
|
||||||
|
sort_by_collection: SortCollection[];
|
||||||
|
display_by_collection: DisplayCollection[];
|
||||||
|
paging_collection: PagingCollection[];
|
||||||
|
paging: string;
|
||||||
|
paging_count: string;
|
||||||
|
product_count: string;
|
||||||
|
product_list: Record<string, Product>;
|
||||||
|
attribute_filter_list: AttributeFilterList[];
|
||||||
|
brand_filter_list: BrandFilter[];
|
||||||
|
price_filter_list: PriceFilter[];
|
||||||
|
category_collection: CategoryCollection[];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user