update 27/01
This commit is contained in:
@@ -1,52 +1,55 @@
|
|||||||
|
import { articleList } from "@/data/articles";
|
||||||
|
import ArticleItem from "@/components/shared/ArticleItem";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export default function Article() {
|
export default function Article() {
|
||||||
|
// id: 5 - Tin tức Công nghệ
|
||||||
|
const techNews = articleList
|
||||||
|
.find(article => article.id === 5)
|
||||||
|
?.list.slice(0, 5) || [];
|
||||||
|
|
||||||
|
// id: 19 - Chuyên trang Khuyến mãi
|
||||||
|
const promoNews = articleList
|
||||||
|
.find(article => article.id === 19)
|
||||||
|
?.list.slice(0, 5) || [];
|
||||||
|
|
||||||
return(
|
return(
|
||||||
|
( techNews.length > 0 || promoNews.length > 0) && (
|
||||||
<div className="home-article-container bg-white rounded-[24px] p-6 my-8">
|
<div className="home-article-container bg-white rounded-[24px] p-6 my-8">
|
||||||
|
{techNews &&
|
||||||
<div className="mb-8 promotion-news-group">
|
<div className="mb-8 promotion-news-group">
|
||||||
<div className="flex items-center justify-between flex-wrap mb-4 leading-9 gap-4 text-16 font-600">
|
<div className="flex items-center justify-between flex-wrap mb-4 leading-9 gap-4 text-16 font-600">
|
||||||
<h2 className="text-[28px] m-0 text-[#004BA4] leading-9"> Chuyên trang Khuyến mãi </h2>
|
<h2 className="text-[28px] m-0 text-[#004BA4] leading-9"> Chuyên trang Khuyến mãi </h2>
|
||||||
<a href="/tin-khuyen-mai" className="text-[#0678DB]"> Xem tất cả <i className="bx bx-chevron-right align-middle ml-[-2px] mt-[-1px] text-18"></i> </a>
|
<Link href="/tin-khuyen-mai" className="text-[#0678DB]"> Xem tất cả <i className="bx bx-chevron-right align-middle ml-[-2px] mt-[-1px] text-18"></i> </Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-4 gap-6">
|
<div className="grid grid-cols-4 gap-6">
|
||||||
|
{
|
||||||
<div className="art-item">
|
techNews.map( (item:any) => (
|
||||||
<a href="" className="art-img">
|
<ArticleItem key={item.id} item={item} />
|
||||||
<img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1" />
|
))
|
||||||
</a>
|
}
|
||||||
|
|
||||||
<div className="art-text">
|
|
||||||
<a href="" className="art-title">
|
|
||||||
<h3> Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum? </h3>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div className="art-summary">
|
|
||||||
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="art-time">
|
|
||||||
<i className='bx bx-calendar-alt text-16 text-[#A0A5AC]'></i>
|
|
||||||
<time> 23/4/2024 </time>
|
|
||||||
<i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i>
|
|
||||||
<span> Mai Văn Học </span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC] mx-1"></i><span>Mai Văn Học</span></div></div></div><div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt text-16 text-[#A0A5AC]"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i><span>Mai Văn Học</span></div></div></div><div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt text-16 text-[#A0A5AC]"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i><span>Mai Văn Học</span></div></div></div><div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt text-16 text-[#A0A5AC]"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i><span>Mai Văn Học</span></div></div></div>
|
{promoNews &&
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between flex-wrap mb-4 leading-9 gap-4 text-16 font-600">
|
<div className="flex items-center justify-between flex-wrap mb-4 leading-9 gap-4 text-16 font-600">
|
||||||
<h2 className="text-[28px] m-0 text-[#004BA4] leading-9"> Tin tức Công nghệ </h2>
|
<h2 className="text-[28px] m-0 text-[#004BA4] leading-9"> Tin tức Công nghệ </h2>
|
||||||
<a href="/tin-cong-nghe" className="text-[#0678DB]"> Xem tất cả <i className="bx bx-chevron-right align-middle ml-[-2px] mt-[-1px] text-18"></i> </a>
|
<Link href="/tin-cong-nghe" className="text-[#0678DB]"> Xem tất cả <i className="bx bx-chevron-right align-middle ml-[-2px] mt-[-1px] text-18"></i> </Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-4 gap-6">
|
<div className="grid grid-cols-4 gap-6">
|
||||||
<div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC] mx-1"></i><span>Mai Văn Học</span></div></div></div><div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt text-16 text-[#A0A5AC]"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i><span>Mai Văn Học</span></div></div></div><div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt text-16 text-[#A0A5AC]"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i><span>Mai Văn Học</span></div></div></div><div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt text-16 text-[#A0A5AC]"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i><span>Mai Văn Học</span></div></div></div><div className="art-item"><a href="" className="art-img"><img src="https://hoanghapccdn.com/media/news/14_100__c___u_h__nh_m__y_t__nh_______h___a_theo_ng__n_s__ch.jpg" alt="" width="1" height="1"/></a><div className="art-text"><a href="" className="art-title"><h3>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eum quidem asperiores provident dicta veniam deleniti eaque repudiandae cum esse, ducimus officiis quibusdam pariatur neque voluptates voluptas. Quisquam qui minus dolorum?</h3></a><div className="art-summary">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit, obcaecati ducimus veritatis aliquid sunt accusamus unde nisi nostrum fugit facere illo quos. Ad error suscipit, quidem optio aut laudantium at!</div><div className="art-time"><i className="bx bx-calendar-alt text-16 text-[#A0A5AC]"></i><time>23/4/2024</time><i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i><span>Mai Văn Học</span></div></div></div>
|
{
|
||||||
|
promoNews.map( (item:any) => (
|
||||||
|
<ArticleItem key={item.id} item={item} />
|
||||||
|
))
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ import { Swiper, SwiperSlide } from 'swiper/react';
|
|||||||
import { Navigation, Pagination, Autoplay } from 'swiper/modules';
|
import { Navigation, Pagination, Autoplay } from 'swiper/modules';
|
||||||
import { dealList } from "@/data/deals"
|
import { dealList } from "@/data/deals"
|
||||||
import DealItem from "@/components/shared/DealItem"
|
import DealItem from "@/components/shared/DealItem"
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
export default function Collection() {
|
export default function Collection() {
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ export default function Collection() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href='/deal' className="text-16 font-600"> Xem tất cả <i className="bx bx-chevron-right align-middle ml-[-2px] mt-[-1px]"></i> </a>
|
<Link href='/deal' className="text-16 font-600"> Xem tất cả <i className="bx bx-chevron-right align-middle ml-[-2px] mt-[-1px]"></i> </Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="group relative z-[1] bg-white rounded-[12px] relative min-h-[450px] px-4 pt-6 pb-8">
|
<div className="group relative z-[1] bg-white rounded-[12px] relative min-h-[450px] px-4 pt-6 pb-8">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { categories } from "@/data/categories"
|
|||||||
import { productList } from '@/data/products';
|
import { productList } from '@/data/products';
|
||||||
import CategoryIcon from "./CategoryIcon"
|
import CategoryIcon from "./CategoryIcon"
|
||||||
import ProductItem from "@/components/shared/ProductItem"
|
import ProductItem from "@/components/shared/ProductItem"
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
export default function ProductCategories() {
|
export default function ProductCategories() {
|
||||||
|
|
||||||
@@ -34,12 +35,12 @@ export default function ProductCategories() {
|
|||||||
item.children
|
item.children
|
||||||
.slice(0, 4)
|
.slice(0, 4)
|
||||||
.map((child: any) =>
|
.map((child: any) =>
|
||||||
<a href={child.url} key={child.id}
|
<Link href={child.url} key={child.id}
|
||||||
className="px-2 rounded-[30px] bg-[#EAF1FF]"
|
className="px-2 rounded-[30px] bg-[#EAF1FF]"
|
||||||
> {child.title} </a>
|
> {child.title} </Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<a href={item.url}> Xem tất cả <i className="bx bx-chevron-right text-20 align-middle"></i> </a>
|
<Link href={item.url}> Xem tất cả <i className="bx bx-chevron-right text-20 align-middle"></i> </Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import Link from "next/link";
|
||||||
import { categories } from "@/data/categories";
|
import { categories } from "@/data/categories";
|
||||||
|
|
||||||
export default function FeaturedProductCategories() {
|
export default function FeaturedProductCategories() {
|
||||||
@@ -32,7 +33,7 @@ export default function FeaturedProductCategories() {
|
|||||||
<div className="grid grid-cols-10 gap-6">
|
<div className="grid grid-cols-10 gap-6">
|
||||||
{featuredCategories
|
{featuredCategories
|
||||||
.map( (item:any) =>
|
.map( (item:any) =>
|
||||||
<a href={item.url} className="item" key={item.id}>
|
<Link href={item.url} className="item" key={item.id}>
|
||||||
<i className="image lazy"
|
<i className="image lazy"
|
||||||
style={{ backgroundImage: `url(${item.thumnail ? item.thumnail : '/images/avatar-admin.png'})` }}
|
style={{ backgroundImage: `url(${item.thumnail ? item.thumnail : '/images/avatar-admin.png'})` }}
|
||||||
></i>
|
></i>
|
||||||
@@ -40,7 +41,7 @@ export default function FeaturedProductCategories() {
|
|||||||
<span className="block">
|
<span className="block">
|
||||||
{item.title}
|
{item.title}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export default function ProductFilter() {
|
export default function ProductFilter({data}: any) {
|
||||||
|
console.log( data)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p className="uppercase font-500 text-center border text-[#0678DB] leading-10 border-[#114CDD] rounded-[8px] mb-6">
|
<p className="uppercase font-500 text-center border text-[#0678DB] leading-10 border-[#114CDD] rounded-[8px] mb-6">
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
export default function Paging() {
|
|
||||||
return (
|
|
||||||
<div className="text-center mt-12">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="mb-3 bg-btn text-white rounded-[30px] h-10 font-500 text-16 table max-w-[240px] w-full m-auto mb-3"
|
|
||||||
aria-label="Xem thêm"
|
|
||||||
>
|
|
||||||
TẢI THÊM
|
|
||||||
</button>
|
|
||||||
<p className="text-14 leading-[18px] m-0">
|
|
||||||
{" "}
|
|
||||||
Hiển thị 1 - 24 trên tổng số 124 sản phẩm{" "}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,22 +1,23 @@
|
|||||||
|
import { productCategory } from "@/data/productCategory";
|
||||||
|
|
||||||
import ProductFilter from "./filter";
|
import ProductFilter from "./filter";
|
||||||
import Static from "./static";
|
import Static from "./static";
|
||||||
import FAQ from "./faq";
|
import FAQ from "./faq";
|
||||||
import Banner from "./banner";
|
import Banner from "./banner";
|
||||||
import SortByCollection from "./sort";
|
import SortByCollection from "./sort";
|
||||||
import ProductList from "./productList";
|
import ProductList from "./productList";
|
||||||
import Paging from "./paging";
|
|
||||||
|
|
||||||
export default function ProductCategory({ slug }: { slug: string }) {
|
|
||||||
|
|
||||||
|
export default function ProductCategory({ slug }: any) {
|
||||||
|
const { name,id, static_html } = productCategory.current_category
|
||||||
return(
|
return(
|
||||||
<div className="product-page container">
|
<div className="product-page container">
|
||||||
<h1 className="text-[#004BA4] text-[32px] leading-10 mb-4 font-600">
|
<h1 className="text-[#004BA4] text-[32px] leading-10 mb-4 font-600">
|
||||||
PC THIẾT KẾ ĐỒ HỌA 3D
|
{name}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div className="product-page-content flex flex-wrap items-start gap-4 mb-5">
|
<div className="product-page-content flex flex-wrap items-start gap-4 mb-5">
|
||||||
<div className="col-left-group w-[264px] rounded-[16px] bg-white p-4 pb-6">
|
<div className="col-left-group w-[264px] rounded-[16px] bg-white p-4 pb-6">
|
||||||
<ProductFilter />
|
<ProductFilter data={slug} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-right-group w-[968px]">
|
<div className="col-right-group w-[968px]">
|
||||||
@@ -25,12 +26,12 @@ export default function ProductCategory({ slug }: { slug: string }) {
|
|||||||
|
|
||||||
<SortByCollection />
|
<SortByCollection />
|
||||||
|
|
||||||
<ProductList />
|
<ProductList id={id}/>
|
||||||
|
|
||||||
<Paging />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Static />
|
{static_html &&
|
||||||
|
<Static data={static_html} />
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
54
src/components/shared/ArticleItem.tsx
Normal file
54
src/components/shared/ArticleItem.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { formatArticleTime } from "@/lib/utils";
|
||||||
|
|
||||||
|
export default function ArticleItem({ item }: any) {
|
||||||
|
const url = item.external_url ? item.external_url : item.url;
|
||||||
|
const time = item.article_time ? item.article_time : item.lastUpdate;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="art-item" data-id={item.id}>
|
||||||
|
<Link href={url} className="art-img"
|
||||||
|
{...(item.external_url ? {
|
||||||
|
target: "_blank",
|
||||||
|
rel: "noopener noreferrer"
|
||||||
|
} : {})}
|
||||||
|
>
|
||||||
|
<img src={item.image.original}
|
||||||
|
alt={item.title}
|
||||||
|
width={100}
|
||||||
|
height={100} />
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="art-text">
|
||||||
|
<Link href={url} className="art-title"
|
||||||
|
{...(item.external_url ? {
|
||||||
|
target: "_blank",
|
||||||
|
rel: "noopener noreferrer"
|
||||||
|
} : {})}
|
||||||
|
>
|
||||||
|
<h3> {item.title} </h3>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="art-summary">
|
||||||
|
{item.summary}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="art-time">
|
||||||
|
<i className='bx bx-calendar-alt text-16 text-[#A0A5AC]'></i>
|
||||||
|
<time>
|
||||||
|
{ formatArticleTime(time) }
|
||||||
|
</time>
|
||||||
|
|
||||||
|
{ item.create_by_name && (
|
||||||
|
<>
|
||||||
|
<i className="w-[1.5px] h-[12px] bg-[#A0A5AC]"></i>
|
||||||
|
<span> {item.create_by_name} </span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,13 +3,21 @@ import Link from "next/link";
|
|||||||
import { formatPrice } from "@/lib/utils";
|
import { formatPrice } from "@/lib/utils";
|
||||||
import { useProductItem } from "@/hooks/useProductItem"
|
import { useProductItem } from "@/hooks/useProductItem"
|
||||||
import { useCart } from '@/hooks/useCart';
|
import { useCart } from '@/hooks/useCart';
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export default function ProductItem({item}:any){
|
export default function ProductItem({item}:any){
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const product = useProductItem(item);
|
const product = useProductItem(item);
|
||||||
if (!product) return null;
|
|
||||||
|
|
||||||
const { addToCart, isInCart } = useCart();
|
const { addToCart, isInCart } = useCart();
|
||||||
|
|
||||||
|
if (!mounted || !product) return null;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
productId,
|
productId,
|
||||||
productUrl,
|
productUrl,
|
||||||
@@ -123,7 +131,8 @@ export default function ProductItem({item}:any){
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="tooltip-spec">
|
<div className="tooltip-spec">
|
||||||
<div dangerouslySetInnerHTML={{ __html: displaySummary }}/>
|
<div suppressHydrationWarning
|
||||||
|
dangerouslySetInnerHTML={{ __html: displaySummary }}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -136,7 +145,8 @@ export default function ProductItem({item}:any){
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="tooltip-offer rounded-[8px] bg-[#FEF2F2] px-2 py-4">
|
<div className="tooltip-offer rounded-[8px] bg-[#FEF2F2] px-2 py-4">
|
||||||
<div dangerouslySetInnerHTML={{ __html: displayOffer }}/>
|
<div suppressHydrationWarning
|
||||||
|
dangerouslySetInnerHTML={{ __html: displayOffer }}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
605
src/data/productCategory/index.tsx
Normal file
605
src/data/productCategory/index.tsx
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -23,16 +23,14 @@ export function useCart() {
|
|||||||
setCartItems(getCartItems());
|
setCartItems(getCartItems());
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Listen to cart changes from ANY source
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleCartChange = () => {
|
const handleCartChange = () => {
|
||||||
setCartItems(getCartItems());
|
setCartItems(getCartItems());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Listen to custom event
|
|
||||||
window.addEventListener(CART_CHANGE_EVENT, handleCartChange);
|
window.addEventListener(CART_CHANGE_EVENT, handleCartChange);
|
||||||
|
|
||||||
// Also listen to storage event (for changes from other tabs)
|
|
||||||
window.addEventListener('storage', (e) => {
|
window.addEventListener('storage', (e) => {
|
||||||
if (e.key === 'cart_products') {
|
if (e.key === 'cart_products') {
|
||||||
handleCartChange();
|
handleCartChange();
|
||||||
@@ -51,18 +49,16 @@ export function useCart() {
|
|||||||
|
|
||||||
const addToCart = useCallback((productId: number, quantity: number = 1) => {
|
const addToCart = useCallback((productId: number, quantity: number = 1) => {
|
||||||
const result = addProductToCart(productId, quantity);
|
const result = addProductToCart(productId, quantity);
|
||||||
// Không cần refresh() nữa vì event listener sẽ tự động update
|
|
||||||
return result;
|
return result;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const removeFromCart = useCallback((productId: number) => {
|
const removeFromCart = useCallback((productId: number) => {
|
||||||
removeProductFromCart(productId);
|
removeProductFromCart(productId);
|
||||||
// Không cần refresh()
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const increase = useCallback((productId: number, amount: number = 1) => {
|
const increase = useCallback((productId: number, amount: number = 1) => {
|
||||||
const success = increaseQuantity(productId, amount);
|
const success = increaseQuantity(productId, amount);
|
||||||
// Không cần refresh()
|
|
||||||
return success;
|
return success;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -71,7 +67,7 @@ export function useCart() {
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
console.log('Số lượng tối thiểu: 1');
|
console.log('Số lượng tối thiểu: 1');
|
||||||
}
|
}
|
||||||
// Không cần refresh()
|
|
||||||
return success;
|
return success;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -80,13 +76,13 @@ export function useCart() {
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
console.log('Số lượng phải lớn hơn hoặc bằng 1');
|
console.log('Số lượng phải lớn hơn hoặc bằng 1');
|
||||||
}
|
}
|
||||||
// Không cần refresh()
|
|
||||||
return success;
|
return success;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const clear = useCallback(() => {
|
const clear = useCallback(() => {
|
||||||
clearCart();
|
clearCart();
|
||||||
// Không cần setCartItems([]) nữa, event sẽ tự động update
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const isInCart = useCallback(
|
const isInCart = useCallback(
|
||||||
|
|||||||
@@ -6,60 +6,53 @@ export function useTooltip() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tooltip = document.getElementById('js-tooltip') as HTMLDivElement | null;
|
const tooltip = document.getElementById('js-tooltip') as HTMLDivElement | null;
|
||||||
if (!tooltip) return;
|
if (!tooltip) return;
|
||||||
|
const tooltipElement = tooltip!;
|
||||||
|
|
||||||
const pad = 10;
|
const pad = 10;
|
||||||
|
|
||||||
function onMouseMove(e: MouseEvent) {
|
function onMouseMove(e: MouseEvent) {
|
||||||
const img = e.currentTarget as HTMLElement | null;
|
const target = e.target as HTMLElement;
|
||||||
if (!img) return;
|
const product = target.closest('.js-p-item');
|
||||||
|
if (!product) {
|
||||||
const product = img.closest('.js-p-item');
|
tooltipElement.style.display = 'none';
|
||||||
const content = product?.querySelector<HTMLElement>('.p-tooltip');
|
|
||||||
|
|
||||||
if (!content) {
|
|
||||||
tooltip.style.display = 'none';
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tooltip.innerHTML = content.innerHTML;
|
const content = product.querySelector<HTMLElement>('.p-tooltip');
|
||||||
tooltip.style.display = 'block';
|
if (!content) return;
|
||||||
|
|
||||||
const w = tooltip.offsetWidth;
|
tooltipElement.innerHTML = content.innerHTML;
|
||||||
const h = tooltip.offsetHeight;
|
tooltipElement.style.display = 'block';
|
||||||
|
|
||||||
const wrapRight = window.innerWidth;
|
const w = tooltipElement.offsetWidth;
|
||||||
const wrapTop = window.scrollY;
|
const h = tooltipElement.offsetHeight;
|
||||||
|
|
||||||
const left =
|
const left = e.pageX + w > window.innerWidth
|
||||||
e.pageX + w > wrapRight
|
|
||||||
? e.pageX - w - pad
|
? e.pageX - w - pad
|
||||||
: e.pageX + pad;
|
: e.pageX + pad;
|
||||||
|
|
||||||
const top =
|
const top = e.pageY - h < window.scrollY
|
||||||
e.pageY - h < wrapTop
|
? window.scrollY
|
||||||
? wrapTop
|
|
||||||
: e.pageY - h - pad;
|
: e.pageY - h - pad;
|
||||||
|
|
||||||
tooltip.style.left = `${left}px`;
|
tooltipElement.style.left = `${left}px`;
|
||||||
tooltip.style.top = `${top}px`;
|
tooltipElement.style.top = `${top}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMouseOut() {
|
function onMouseOut(e: MouseEvent) {
|
||||||
tooltip.style.display = 'none';
|
const target = e.target as HTMLElement;
|
||||||
|
if (!target.closest('.js-p-item')) {
|
||||||
|
tooltipElement.style.display = 'none';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const images = document.querySelectorAll<HTMLImageElement>('.js-p-item img');
|
document.addEventListener('mousemove', onMouseMove);
|
||||||
|
document.addEventListener('mouseout', onMouseOut);
|
||||||
images.forEach(img => {
|
|
||||||
img.addEventListener('mousemove', onMouseMove);
|
|
||||||
img.addEventListener('mouseout', onMouseOut);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
images.forEach(img => {
|
document.removeEventListener('mousemove', onMouseMove);
|
||||||
img.removeEventListener('mousemove', onMouseMove);
|
document.removeEventListener('mouseout', onMouseOut);
|
||||||
img.removeEventListener('mouseout', onMouseOut);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// src/lib/articlePage.ts
|
// src/lib/articlePage.ts
|
||||||
import { categories } from "@/data/categories";
|
import { categories } from "@/data/categories";
|
||||||
|
import { articleList } from "@/data/articles";
|
||||||
|
|
||||||
export type ArticleResult =
|
export type ArticleResult =
|
||||||
| { type: "article_home"; data: any }
|
| { type: "article_home"; data: any }
|
||||||
@@ -29,8 +30,10 @@ export function resolveArticlePage(slug: string): ArticleResult | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DETAIL
|
// DETAIL
|
||||||
const isValidSlugFormat = slug.includes('-') && slug.length > 5;
|
const allArticles = articleList.flatMap(article => article.list);
|
||||||
if (!isValidSlugFormat) {
|
for (const article of allArticles) {
|
||||||
return null;
|
if (article.url === url) {
|
||||||
|
return { type: "article_detail", data: { slug } };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { notFound } from "next/navigation";
|
|
||||||
import { resolveArticlePage } from "./resolveArticlePage";
|
import { resolveArticlePage } from "./resolveArticlePage";
|
||||||
import { resolveProductPage } from "./resolveProductPage";
|
import { resolveProductPage } from "./resolveProductPage";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
|
|
||||||
|
|
||||||
// Add tất cả sp trong data product vào 1 mảng
|
// Add tất cả sp trong data product vào 1 mảng
|
||||||
import { productList } from '@/data/products';
|
import { productList } from '@/data/products';
|
||||||
|
|
||||||
@@ -56,3 +53,23 @@ export function calculateDiscount(
|
|||||||
if (price <= 0 || marketPrice <= price) return 0;
|
if (price <= 0 || marketPrice <= price) return 0;
|
||||||
return Math.ceil(((marketPrice - price) / marketPrice) * 100);
|
return Math.ceil(((marketPrice - price) / marketPrice) * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatArticleTime(article_time:string) {
|
||||||
|
let day: string;
|
||||||
|
let month: string;
|
||||||
|
let year: string;
|
||||||
|
|
||||||
|
if (article_time.toLowerCase().includes('hôm nay')) {
|
||||||
|
const time = new Date();
|
||||||
|
day = (time.getDate() <= 9) ? '0' + time.getDate() : String(time.getDate());
|
||||||
|
month = (time.getMonth()+1 <= 9) ? '0' + (time.getMonth()+1) : String(time.getMonth()+1);
|
||||||
|
year = String(time.getFullYear());
|
||||||
|
} else {
|
||||||
|
day = article_time.substring(0,2);
|
||||||
|
month = article_time.substring(3,5);
|
||||||
|
year = article_time.substring(6,10);
|
||||||
|
}
|
||||||
|
return `${day}/${month}/${year}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
{
|
{
|
||||||
"name": "next"
|
"name": "next"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"ignoreDeprecations": "6.0"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
|
|||||||
Reference in New Issue
Block a user