Compare commits

...

2 Commits

Author SHA1 Message Date
5fc49b68d3 update 27/01 2026-01-27 17:07:25 +07:00
f1f925bab1 update 27/01 2026-01-27 17:02:26 +07:00
21 changed files with 1716 additions and 12373 deletions

View File

@@ -1,52 +1,55 @@
import { articleList } from "@/data/articles";
import ArticleItem from "@/components/shared/ArticleItem";
import Link from "next/link";
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(
( techNews.length > 0 || promoNews.length > 0) && (
<div className="home-article-container bg-white rounded-[24px] p-6 my-8">
<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">
<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>
</div>
<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 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>
{techNews &&
<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">
<h2 className="text-[28px] m-0 text-[#004BA4] leading-9"> Chuyên trang Khuyến mãi </h2>
<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 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="grid grid-cols-4 gap-6">
{
techNews.map( (item:any) => (
<ArticleItem key={item.id} item={item} />
))
}
</div>
</div>
}
</div>
{promoNews &&
<div>
<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>
<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="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>
<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>
<div className="grid grid-cols-4 gap-6">
{
promoNews.map( (item:any) => (
<ArticleItem key={item.id} item={item} />
))
}
</div>
</div>
<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>
</div>
</div>
}
</div>
)
)
}

View File

@@ -3,6 +3,7 @@ import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation, Pagination, Autoplay } from 'swiper/modules';
import { dealList } from "@/data/deals"
import DealItem from "@/components/shared/DealItem"
import Link from 'next/link';
export default function Collection() {
@@ -24,7 +25,7 @@ export default function Collection() {
</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 className="group relative z-[1] bg-white rounded-[12px] relative min-h-[450px] px-4 pt-6 pb-8">

View File

@@ -5,6 +5,7 @@ import { categories } from "@/data/categories"
import { productList } from '@/data/products';
import CategoryIcon from "./CategoryIcon"
import ProductItem from "@/components/shared/ProductItem"
import Link from 'next/link';
export default function ProductCategories() {
@@ -34,12 +35,12 @@ export default function ProductCategories() {
item.children
.slice(0, 4)
.map((child: any) =>
<a href={child.url} key={child.id}
<Link href={child.url} key={child.id}
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>

View File

@@ -1,3 +1,4 @@
import Link from "next/link";
import { categories } from "@/data/categories";
export default function FeaturedProductCategories() {
@@ -32,7 +33,7 @@ export default function FeaturedProductCategories() {
<div className="grid grid-cols-10 gap-6">
{featuredCategories
.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"
style={{ backgroundImage: `url(${item.thumnail ? item.thumnail : '/images/avatar-admin.png'})` }}
></i>
@@ -40,7 +41,7 @@ export default function FeaturedProductCategories() {
<span className="block">
{item.title}
</span>
</a>
</Link>
)
}
</div>

View File

@@ -1,4 +1,5 @@
export default function ProductFilter() {
export default function ProductFilter({data}: any) {
console.log( data)
return (
<>
<p className="uppercase font-500 text-center border text-[#0678DB] leading-10 border-[#114CDD] rounded-[8px] mb-6">

View File

@@ -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

View File

@@ -1,22 +1,23 @@
import { productCategory } from "@/data/productCategory";
import ProductFilter from "./filter";
import Static from "./static";
import FAQ from "./faq";
import Banner from "./banner";
import SortByCollection from "./sort";
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(
<div className="product-page container">
<h1 className="text-[#004BA4] text-[32px] leading-10 mb-4 font-600">
PC THIẾT KẾ Đ HỌA 3D
{name}
</h1>
<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">
<ProductFilter />
<ProductFilter data={slug} />
</div>
<div className="col-right-group w-[968px]">
@@ -25,12 +26,12 @@ export default function ProductCategory({ slug }: { slug: string }) {
<SortByCollection />
<ProductList />
<Paging />
<ProductList id={id}/>
</div>
<Static />
{static_html &&
<Static data={static_html} />
}
</div>
</div>

File diff suppressed because one or more lines are too long

View 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>
</>
)
}

View File

@@ -3,13 +3,21 @@ import Link from "next/link";
import { formatPrice } from "@/lib/utils";
import { useProductItem } from "@/hooks/useProductItem"
import { useCart } from '@/hooks/useCart';
import { useEffect, useState } from "react";
export default function ProductItem({item}:any){
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
const product = useProductItem(item);
if (!product) return null;
const { addToCart, isInCart } = useCart();
if (!mounted || !product) return null;
const {
productId,
productUrl,
@@ -123,7 +131,8 @@ export default function ProductItem({item}:any){
</p>
<div className="tooltip-spec">
<div dangerouslySetInnerHTML={{ __html: displaySummary }}/>
<div suppressHydrationWarning
dangerouslySetInnerHTML={{ __html: displaySummary }}/>
</div>
</div>
}
@@ -136,7 +145,8 @@ export default function ProductItem({item}:any){
</p>
<div className="tooltip-offer rounded-[8px] bg-[#FEF2F2] px-2 py-4">
<div dangerouslySetInnerHTML={{ __html: displayOffer }}/>
<div suppressHydrationWarning
dangerouslySetInnerHTML={{ __html: displayOffer }}/>
</div>
</div>
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -23,16 +23,14 @@ export function useCart() {
setCartItems(getCartItems());
}, []);
// Listen to cart changes from ANY source
useEffect(() => {
const handleCartChange = () => {
setCartItems(getCartItems());
};
// Listen to custom event
window.addEventListener(CART_CHANGE_EVENT, handleCartChange);
// Also listen to storage event (for changes from other tabs)
window.addEventListener('storage', (e) => {
if (e.key === 'cart_products') {
handleCartChange();
@@ -51,18 +49,16 @@ export function useCart() {
const addToCart = useCallback((productId: number, quantity: number = 1) => {
const result = addProductToCart(productId, quantity);
// Không cần refresh() nữa vì event listener sẽ tự động update
return result;
}, []);
const removeFromCart = useCallback((productId: number) => {
removeProductFromCart(productId);
// Không cần refresh()
}, []);
const increase = useCallback((productId: number, amount: number = 1) => {
const success = increaseQuantity(productId, amount);
// Không cần refresh()
return success;
}, []);
@@ -71,7 +67,7 @@ export function useCart() {
if (!success) {
console.log('Số lượng tối thiểu: 1');
}
// Không cần refresh()
return success;
}, []);
@@ -80,13 +76,13 @@ export function useCart() {
if (!success) {
console.log('Số lượng phải lớn hơn hoặc bằng 1');
}
// Không cần refresh()
return success;
}, []);
const clear = useCallback(() => {
clearCart();
// Không cần setCartItems([]) nữa, event sẽ tự động update
}, []);
const isInCart = useCallback(

View File

@@ -16,9 +16,9 @@ export function useProductItem(item: ProductItemProps) {
const productImage = item.productImage.large;
const productName = item.productName;
const specialOffer = item.specialOffer.all[0]?.title ?? null;
const displayOffer = specialOffer
? formatTextList(specialOffer)
: null;
const displayOffer = specialOffer
? formatTextList(specialOffer)
: null;
const warranty = item.warranty;
const productSummary = item.productSummary;

View File

@@ -6,60 +6,53 @@ export function useTooltip() {
useEffect(() => {
const tooltip = document.getElementById('js-tooltip') as HTMLDivElement | null;
if (!tooltip) return;
const tooltipElement = tooltip!;
const pad = 10;
function onMouseMove(e: MouseEvent) {
const img = e.currentTarget as HTMLElement | null;
if (!img) return;
const product = img.closest('.js-p-item');
const content = product?.querySelector<HTMLElement>('.p-tooltip');
if (!content) {
tooltip.style.display = 'none';
const target = e.target as HTMLElement;
const product = target.closest('.js-p-item');
if (!product) {
tooltipElement.style.display = 'none';
return;
}
tooltip.innerHTML = content.innerHTML;
tooltip.style.display = 'block';
const content = product.querySelector<HTMLElement>('.p-tooltip');
if (!content) return;
const w = tooltip.offsetWidth;
const h = tooltip.offsetHeight;
tooltipElement.innerHTML = content.innerHTML;
tooltipElement.style.display = 'block';
const wrapRight = window.innerWidth;
const wrapTop = window.scrollY;
const w = tooltipElement.offsetWidth;
const h = tooltipElement.offsetHeight;
const left =
e.pageX + w > wrapRight
? e.pageX - w - pad
: e.pageX + pad;
const left = e.pageX + w > window.innerWidth
? e.pageX - w - pad
: e.pageX + pad;
const top =
e.pageY - h < wrapTop
? wrapTop
: e.pageY - h - pad;
const top = e.pageY - h < window.scrollY
? window.scrollY
: e.pageY - h - pad;
tooltip.style.left = `${left}px`;
tooltip.style.top = `${top}px`;
tooltipElement.style.left = `${left}px`;
tooltipElement.style.top = `${top}px`;
}
function onMouseOut() {
tooltip.style.display = 'none';
function onMouseOut(e: MouseEvent) {
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');
images.forEach(img => {
img.addEventListener('mousemove', onMouseMove);
img.addEventListener('mouseout', onMouseOut);
});
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseout', onMouseOut);
return () => {
images.forEach(img => {
img.removeEventListener('mousemove', onMouseMove);
img.removeEventListener('mouseout', onMouseOut);
});
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseout', onMouseOut);
};
}, []);
}

View File

@@ -1,5 +1,6 @@
// src/lib/articlePage.ts
import { categories } from "@/data/categories";
import { articleList } from "@/data/articles";
export type ArticleResult =
| { type: "article_home"; data: any }
@@ -29,8 +30,10 @@ export function resolveArticlePage(slug: string): ArticleResult | null {
}
// DETAIL
const isValidSlugFormat = slug.includes('-') && slug.length > 5;
if (!isValidSlugFormat) {
return null;
const allArticles = articleList.flatMap(article => article.list);
for (const article of allArticles) {
if (article.url === url) {
return { type: "article_detail", data: { slug } };
}
}
}

View File

@@ -1,4 +1,3 @@
import { notFound } from "next/navigation";
import { resolveArticlePage } from "./resolveArticlePage";
import { resolveProductPage } from "./resolveProductPage";

View File

@@ -1,6 +1,3 @@
import { ReactNode } from 'react';
// Add tất cả sp trong data product vào 1 mảng
import { productList } from '@/data/products';
@@ -56,3 +53,23 @@ export function calculateDiscount(
if (price <= 0 || marketPrice <= price) return 0;
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}`;
}

View File

@@ -27,7 +27,8 @@
{
"name": "next"
}
]
],
"ignoreDeprecations": "6.0"
},
"include": [
"next-env.d.ts",