update
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
|
import NotFound from '../pages/404';
|
||||||
|
import { resolvePageType } from '@/lib/resolvePageType';
|
||||||
|
|
||||||
import CategoryPage from '@/components/Product/Category';
|
import CategoryPage from '@/components/Product/Category';
|
||||||
import ProductDetailPage from '@/components/Product/ProductDetail';
|
import ProductDetailPage from '@/components/Product/ProductDetail';
|
||||||
|
import ArticlePage from '@/components/Article';
|
||||||
import { resolvePageType } from '@/lib/resolvePageType';
|
|
||||||
|
|
||||||
export default function DynamicPage() {
|
export default function DynamicPage() {
|
||||||
const { slug } = useParams();
|
const { slug } = useParams();
|
||||||
@@ -16,7 +18,9 @@ export default function DynamicPage() {
|
|||||||
return <CategoryPage slug={fullSlug} />;
|
return <CategoryPage slug={fullSlug} />;
|
||||||
case 'product-detail':
|
case 'product-detail':
|
||||||
return <ProductDetailPage slug={fullSlug} />;
|
return <ProductDetailPage slug={fullSlug} />;
|
||||||
|
case 'article-home':
|
||||||
|
return <ArticlePage />;
|
||||||
default:
|
default:
|
||||||
return <div>404 Không tìm thấy</div>;
|
return <NotFound />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/app/pages/404.tsx
Normal file
55
src/app/pages/404.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
'use client';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
const NotFound = () => {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-slate-50 via-white to-blue-100 px-4">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
transition={{ duration: 0.4 }}
|
||||||
|
className="w-full max-w-md rounded-3xl bg-white p-8 text-center shadow-xl"
|
||||||
|
>
|
||||||
|
{/* Icon lỗi link */}
|
||||||
|
<motion.div
|
||||||
|
animate={{ y: [0, -4, 0] }}
|
||||||
|
transition={{ repeat: Infinity, duration: 1.8 }}
|
||||||
|
className="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-orange-100"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="h-10 w-10 text-orange-500"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M13.828 10.172a4 4 0 00-5.656 5.656M7 7a7 7 0 019.9 9.9M12 12l.01.01"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<h1 className="text-2xl font-bold text-gray-800">Đường dẫn không hợp lệ</h1>
|
||||||
|
|
||||||
|
<p className="mt-3 text-sm text-gray-600">
|
||||||
|
Bạn truy cập không tồn tại hoặc đường dẫn đã bị thay đổi.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<div className="mt-8 flex flex-col gap-3">
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="rounded-xl bg-blue-600 px-6 py-3 text-sm font-semibold text-white transition hover:bg-blue-700"
|
||||||
|
>
|
||||||
|
← Về trang chủ
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NotFound;
|
||||||
40
src/app/send-cart/page.tsx
Normal file
40
src/app/send-cart/page.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Gửi đơn hàng',
|
||||||
|
description: 'Gửi đơn hàng',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function SendCartPage() {
|
||||||
|
return (
|
||||||
|
<section className="box-send-cart py-[100px]">
|
||||||
|
<div className="container">
|
||||||
|
<div className="send-cart-success">
|
||||||
|
<div className="send-cart-title">
|
||||||
|
<p className="send-cart-title-name pb-3">
|
||||||
|
<i className="sprite-sub sprite-icon-check-cart"></i>
|
||||||
|
ĐƠN HÀNG ĐÃ ĐƯỢC TIẾP NHẬN
|
||||||
|
</p>
|
||||||
|
<div className="send-cart-title-descreption leading-[150%]">
|
||||||
|
Cảm ơn quý khách đã đặt hàng tại Đơn hàng đã được tiếp nhận. Để kiểm tra đơn hàng hoặc
|
||||||
|
thay đổi thông tin, vui lòng
|
||||||
|
<Link href="/dang-nhap" className="red-text px-2">
|
||||||
|
Đăng nhập
|
||||||
|
</Link>
|
||||||
|
vào website. Nếu khách hàng có yêu cầu đặc biệt, vui lòng liên hệ nhân viên tư vấn tại
|
||||||
|
<Link href="https://www.facebook.com/MAY.TINH.NGUYEN.CONG" className="red-text px-1">
|
||||||
|
Facebook
|
||||||
|
</Link>
|
||||||
|
hoặc Mua hàng trực tuyến: Hotline:
|
||||||
|
<b className="red-text">
|
||||||
|
<Link href="tel:0989336366">Điện thoại: 0989336366</Link>
|
||||||
|
</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
src/components/Article/HomeArticle/ArticleTopLeft/index.tsx
Normal file
19
src/components/Article/HomeArticle/ArticleTopLeft/index.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import ItemArticle from '@/components/Common/ItemArticle';
|
||||||
|
import { DataListArticleNews } from '@/data/article/ListArticleNews';
|
||||||
|
|
||||||
|
export const ArticleTopLeft = () => {
|
||||||
|
return (
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<div className="box-left">
|
||||||
|
{DataListArticleNews.slice(0, 1).map((item, index) => (
|
||||||
|
<ItemArticle item={item} key={index} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="box-right flex flex-1 flex-col gap-3">
|
||||||
|
{DataListArticleNews.slice(0, 4).map((item, index) => (
|
||||||
|
<ItemArticle item={item} key={index} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
32
src/components/Article/HomeArticle/ArticleTopRight/index.tsx
Normal file
32
src/components/Article/HomeArticle/ArticleTopRight/index.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { DataListArticleNews } from '@/data/article/ListArticleNews';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export const ArticleTopRight = () => {
|
||||||
|
return (
|
||||||
|
<div className="col-right-article box-view-article flex-1">
|
||||||
|
<form
|
||||||
|
method="get"
|
||||||
|
action="/tim-bai"
|
||||||
|
name="search"
|
||||||
|
className="boder-radius-10 border-box-article article-search-container"
|
||||||
|
>
|
||||||
|
<input type="text" name="q" placeholder="Tìm kiếm bài viết" defaultValue="" />
|
||||||
|
<button type="submit" className="fas fa-search"></button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div className="boder-radius-10 border-box-article">
|
||||||
|
<div className="title-box-article font-bold">Xem nhiều</div>
|
||||||
|
<ul className="list-most-view-article flex flex-col gap-4">
|
||||||
|
{DataListArticleNews.slice(0, 6).map((item, index) => (
|
||||||
|
<li className="item-most-view-article flex items-center gap-2" key={index}>
|
||||||
|
<span className="number flex items-center justify-center font-[600]"></span>
|
||||||
|
<Link href={item.url} className="line-clamp-2 flex-1">
|
||||||
|
{item.title}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
57
src/components/Article/HomeArticle/BoxArticleMid/index.tsx
Normal file
57
src/components/Article/HomeArticle/BoxArticleMid/index.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import ItemArticle from '@/components/Common/ItemArticle';
|
||||||
|
import { DataListArticleNews } from '@/data/article/ListArticleNews';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
export const BoxArticleMid = () => {
|
||||||
|
return (
|
||||||
|
<div className="box-article-home-middle flex justify-between gap-2">
|
||||||
|
<div className="box-article-tech col-left-article boder-radius-10 border-box-article">
|
||||||
|
<p className="title-box-article font-[600]">Tin công nghệ</p>
|
||||||
|
<div className="list-article-tech">
|
||||||
|
{DataListArticleNews.slice(0, 9).map((item, index) => (
|
||||||
|
<ItemArticle item={item} key={index} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href="/tin-cong-nghe"
|
||||||
|
className="btn-article-col flex items-center justify-center gap-2 font-[500]"
|
||||||
|
>
|
||||||
|
Xem tất cả
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="col-right-article flex-1">
|
||||||
|
<div className="box-article-hot border-box-article boder-radius-10">
|
||||||
|
<p className="title-box-article font-bold">Tin nổi bật</p>
|
||||||
|
<div className="list-article-hot">
|
||||||
|
{DataListArticleNews.slice(0, 5).map((item, index) => (
|
||||||
|
<div className="item-article flex gap-4" key={index}>
|
||||||
|
<Link href={item.url} className="img-article boder-radius-10 relative">
|
||||||
|
<Image
|
||||||
|
className="boder-radius-10"
|
||||||
|
src={item.image.original}
|
||||||
|
fill
|
||||||
|
alt={item.title}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<i className="sprite sprite-icon-play-video-detail icon-video-feature incon-play-youtube"></i>
|
||||||
|
<i className="sprite sprite-play-youtube incon-play-youtube"></i>
|
||||||
|
</Link>
|
||||||
|
<div className="content-article content-article-item flex flex-1 flex-col">
|
||||||
|
<Link href="/tuyen-dung-nhan-vien-ky-thuat-1-2" className="title-article">
|
||||||
|
<h3 className="line-clamp-2 font-[400]">{item.title}</h3>
|
||||||
|
</Link>
|
||||||
|
<p className="time-article flex items-center gap-2">
|
||||||
|
<i className="sprite sprite-clock-item-article"></i>
|
||||||
|
<span>{item.createDate}</span>
|
||||||
|
</p>
|
||||||
|
<p className="descreption-article line-clamp-2">{item.summary}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||||
|
import { Autoplay, Navigation, Pagination, Thumbs } from 'swiper/modules';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { DataListArticleNews } from '@/data/article/ListArticleNews';
|
||||||
|
|
||||||
|
export const BoxArticleReview = () => {
|
||||||
|
return (
|
||||||
|
<div className="box-article-category page-hompage">
|
||||||
|
<div className="box-article-global box-artice-review">
|
||||||
|
<div className="title-box-product-home mb-5 flex flex-col items-center">
|
||||||
|
<p className="title font-[500]">Review sản phẩm</p>
|
||||||
|
<p className="border-title"></p>
|
||||||
|
</div>
|
||||||
|
<div className="list-article-global">
|
||||||
|
<Swiper
|
||||||
|
modules={[Autoplay, Navigation, Pagination, Thumbs]}
|
||||||
|
spaceBetween={15}
|
||||||
|
slidesPerView={3}
|
||||||
|
loop={true}
|
||||||
|
>
|
||||||
|
{DataListArticleNews.map((item, index) => (
|
||||||
|
<SwiperSlide key={index}>
|
||||||
|
<div className="item-article">
|
||||||
|
<Link href={item.url} className="img-article">
|
||||||
|
<Image src={item.image.original} fill alt={item.title} />
|
||||||
|
</Link>
|
||||||
|
<div className="content-article-item">
|
||||||
|
<Link href={item.url} className="title font-weight-500 line-clamp-2">
|
||||||
|
{item.title}
|
||||||
|
</Link>
|
||||||
|
<div className="time-aricle-item flex items-center">
|
||||||
|
<i className="sprite sprite-clock-item-article"></i>
|
||||||
|
<span>{item.createDate}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
</Swiper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
123
src/components/Article/HomeArticle/BoxVideoArticle/index.tsx
Normal file
123
src/components/Article/HomeArticle/BoxVideoArticle/index.tsx
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
import { FaYoutube } from 'react-icons/fa6';
|
||||||
|
import { DataListArticleVideo } from '@/data/article/ListAricleVideo';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import useFancybox from '@/hooks/useFancybox';
|
||||||
|
|
||||||
|
export const BoxVideoArticle = () => {
|
||||||
|
const getYoutubeEmbedUrl = (url: string): string => {
|
||||||
|
try {
|
||||||
|
const urlObj = new URL(url);
|
||||||
|
// nếu là link youtube dạng watch?v=...
|
||||||
|
if (urlObj.hostname.includes('youtube.com')) {
|
||||||
|
const videoId = urlObj.searchParams.get('v');
|
||||||
|
if (videoId) {
|
||||||
|
return `https://www.youtube.com/embed/${videoId}?autoplay=1`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// nếu là link youtu.be/xxxx
|
||||||
|
if (urlObj.hostname.includes('youtu.be')) {
|
||||||
|
const videoId = urlObj.pathname.replace('/', '');
|
||||||
|
if (videoId) {
|
||||||
|
return `https://www.youtube.com/embed/${videoId}?autoplay=1`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fallback: trả về chính url
|
||||||
|
return url;
|
||||||
|
} catch {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const [fancyboxRef] = useFancybox({
|
||||||
|
closeButton: 'auto',
|
||||||
|
dragToClose: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="box-video-article boder-radius-10">
|
||||||
|
<div className="title-video-article flex justify-between">
|
||||||
|
<p className="title font-bold">Youtube channel</p>
|
||||||
|
<Link
|
||||||
|
href="https://www.youtube.com/c/NGUYENCONGPC"
|
||||||
|
className="follow-youtube flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<FaYoutube />
|
||||||
|
<span className="font-bold">Theo dõi trên YouTube</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="list-video-article flex justify-between gap-2">
|
||||||
|
<div className="box-left" ref={fancyboxRef}>
|
||||||
|
{DataListArticleVideo.slice(0, 1).map((item, index) => (
|
||||||
|
<div className="item-article-video d-flex w-50 gap-10" key={index}>
|
||||||
|
<Link
|
||||||
|
href={getYoutubeEmbedUrl(item.external_url)}
|
||||||
|
className="img-article img-article-video boder-radius-10 relative"
|
||||||
|
data-fancybox
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={item.image.original}
|
||||||
|
width={430}
|
||||||
|
height={310}
|
||||||
|
className="boder-radius-10"
|
||||||
|
alt={item.title}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<i className="sprite sprite-big-play-video-article icon-play"></i>
|
||||||
|
<Image
|
||||||
|
className="icon-play-small"
|
||||||
|
src="https://nguyencongpc.vn/static/assets/nguyencong_2023/images/small-play-youtube.png"
|
||||||
|
alt="play"
|
||||||
|
width={58}
|
||||||
|
height={41}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href={getYoutubeEmbedUrl(item.external_url)}
|
||||||
|
className="title-article-video flex-1"
|
||||||
|
data-fancybox
|
||||||
|
>
|
||||||
|
{item.title}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="box-right grid grid-cols-2 gap-2">
|
||||||
|
{DataListArticleVideo.slice(1, 7).map((item, index) => (
|
||||||
|
<div className="item-article-video flex w-50 gap-2" key={index}>
|
||||||
|
<Link
|
||||||
|
href={getYoutubeEmbedUrl(item.external_url)}
|
||||||
|
className="img-article img-article-video boder-radius-10 relative"
|
||||||
|
data-fancybox
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={item.image.original}
|
||||||
|
width={430}
|
||||||
|
height={310}
|
||||||
|
className="boder-radius-10"
|
||||||
|
alt={item.title}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<i className="sprite sprite-big-play-video-article icon-play"></i>
|
||||||
|
<Image
|
||||||
|
className="icon-play-small"
|
||||||
|
src="https://nguyencongpc.vn/static/assets/nguyencong_2023/images/small-play-youtube.png"
|
||||||
|
alt="play"
|
||||||
|
width={58}
|
||||||
|
height={41}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href={getYoutubeEmbedUrl(item.external_url)}
|
||||||
|
className="title-article-video flex-1"
|
||||||
|
data-fancybox
|
||||||
|
>
|
||||||
|
{item.title}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
51
src/components/Article/index.tsx
Normal file
51
src/components/Article/index.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
'use client';
|
||||||
|
import React from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Breadcrumb } from '@components/Common/Breadcrumb';
|
||||||
|
import { DataArticleCategory } from '@/data/article/ListCategory';
|
||||||
|
|
||||||
|
import { ArticleTopLeft } from './HomeArticle/ArticleTopLeft';
|
||||||
|
import { ArticleTopRight } from './HomeArticle/ArticleTopRight';
|
||||||
|
import { BoxVideoArticle } from './HomeArticle/BoxVideoArticle';
|
||||||
|
import { BoxArticleMid } from './HomeArticle/BoxArticleMid';
|
||||||
|
import { BoxArticleReview } from './HomeArticle/BoxArticleReview';
|
||||||
|
|
||||||
|
const ArticleHome = () => {
|
||||||
|
const breadcrumbItems = [{ name: 'Tin tức', url: '/tin-tuc' }];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="page-article pb-10">
|
||||||
|
<div className="container">
|
||||||
|
<Breadcrumb items={breadcrumbItems} />
|
||||||
|
|
||||||
|
<div className="tabs-category-article flex items-center">
|
||||||
|
{DataArticleCategory.map((item, index) => (
|
||||||
|
<Link href={item.url} key={index} className="item-tab-article">
|
||||||
|
<h2 className="title-cate-article font-[400]">{item.title}</h2>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="box-article-home-top flex gap-3">
|
||||||
|
<div className="col-left-article border-box-article box-new-article boder-radius-10">
|
||||||
|
<div className="flex gap-12">
|
||||||
|
<ArticleTopLeft />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ArticleTopRight />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* box video */}
|
||||||
|
<BoxVideoArticle />
|
||||||
|
|
||||||
|
{/* box mid */}
|
||||||
|
<BoxArticleMid />
|
||||||
|
|
||||||
|
{/* review */}
|
||||||
|
<BoxArticleReview />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ArticleHome;
|
||||||
@@ -1,8 +1,46 @@
|
|||||||
import { useState } from 'react';
|
'use client';
|
||||||
|
import { useState, forwardRef, useImperativeHandle } from 'react';
|
||||||
|
|
||||||
export const FormCart = () => {
|
export interface FormCartRef {
|
||||||
|
validateForm: () => boolean;
|
||||||
|
}
|
||||||
|
export const FormCart = forwardRef<FormCartRef, object>((props, ref) => {
|
||||||
const [showTax, setShowTax] = useState(false);
|
const [showTax, setShowTax] = useState(false);
|
||||||
|
|
||||||
|
const validateForm = () => {
|
||||||
|
const name = (document.getElementById('buyer_name') as HTMLInputElement)?.value.trim();
|
||||||
|
const tel = (document.getElementById('buyer_tel') as HTMLInputElement)?.value.trim();
|
||||||
|
const address = (document.getElementById('buyer_address') as HTMLInputElement)?.value.trim();
|
||||||
|
|
||||||
|
// Regex kiểm tra ký tự đặc biệt (chỉ cho phép chữ cái, số, khoảng trắng)
|
||||||
|
const regexNoSpecial = /^[\p{L}\p{N}\s]+$/u;
|
||||||
|
// Regex số điện thoại Việt Nam (10 số, bắt đầu bằng 0)
|
||||||
|
const regexPhone = /^0\d{9}$/;
|
||||||
|
|
||||||
|
// Kiểm tra tên
|
||||||
|
if (!name || name.length <= 4 || !regexNoSpecial.test(name)) {
|
||||||
|
alert('Bạn nhập tên chưa đúng định dạng!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kiểm tra số điện thoại
|
||||||
|
if (!tel || !regexPhone.test(tel)) {
|
||||||
|
alert('Số điện thoại không hợp lệ! (Ví dụ: 0912345678)');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kiểm tra địa chỉ
|
||||||
|
if (!address || address.length <= 4 || !regexNoSpecial.test(address)) {
|
||||||
|
alert('Địa chỉ chưa hợp lệ!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nếu hợp lệ thì xử lý đặt hàng
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({ validateForm }));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="box-cart-info-customer">
|
<div className="box-cart-info-customer">
|
||||||
@@ -79,4 +117,6 @@ export const FormCart = () => {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
|
FormCart.displayName = 'FormCart';
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useState } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
import { FaChevronLeft } from 'react-icons/fa6';
|
import { FaChevronLeft } from 'react-icons/fa6';
|
||||||
import { Breadcrumb } from '@/components/Common/Breadcrumb';
|
import { Breadcrumb } from '@/components/Common/Breadcrumb';
|
||||||
import { TypeCartItem } from '@/types/cart';
|
import { TypeCartItem } from '@/types/cart';
|
||||||
import { ItemCart } from './ItemCart';
|
import { ItemCart } from './ItemCart';
|
||||||
import { FormCart } from './FormCart';
|
import { FormCart, FormCartRef } from './FormCart';
|
||||||
import { formatCurrency } from '@/lib/formatPrice';
|
import { formatCurrency } from '@/lib/formatPrice';
|
||||||
|
|
||||||
const HomeCart = () => {
|
const HomeCart = () => {
|
||||||
|
const router = useRouter();
|
||||||
const breadcrumbItems = [{ name: 'Giỏ hàng', url: '/cart' }];
|
const breadcrumbItems = [{ name: 'Giỏ hàng', url: '/cart' }];
|
||||||
const [cart, setCart] = useState<TypeCartItem[]>(() => {
|
const [cart, setCart] = useState<TypeCartItem[]>(() => {
|
||||||
const storedCart = localStorage.getItem('cart');
|
const storedCart = localStorage.getItem('cart');
|
||||||
@@ -18,6 +20,8 @@ const HomeCart = () => {
|
|||||||
|
|
||||||
const [payMethod, setPayMethod] = useState('2');
|
const [payMethod, setPayMethod] = useState('2');
|
||||||
|
|
||||||
|
const formRef = useRef<FormCartRef>(null);
|
||||||
|
|
||||||
const updateCartItem = (id: string, quantity: number) => {
|
const updateCartItem = (id: string, quantity: number) => {
|
||||||
const newCart = cart.map((item) =>
|
const newCart = cart.map((item) =>
|
||||||
item._id === id
|
item._id === id
|
||||||
@@ -57,6 +61,12 @@ const HomeCart = () => {
|
|||||||
return formatCurrency(cart.reduce((sum, item) => sum + Number(item.in_cart.total_price), 0));
|
return formatCurrency(cart.reduce((sum, item) => sum + Number(item.in_cart.total_price), 0));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClickOrder = () => {
|
||||||
|
if (formRef.current?.validateForm()) {
|
||||||
|
router.push('/send-cart');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="container">
|
<div className="container">
|
||||||
@@ -106,7 +116,7 @@ const HomeCart = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* form mua hàng */}
|
{/* form mua hàng */}
|
||||||
<FormCart />
|
<FormCart ref={formRef} />
|
||||||
<div className="box-payment">
|
<div className="box-payment">
|
||||||
<p className="title-section-cart font-bold">Phương thức thanh toán</p>
|
<p className="title-section-cart font-bold">Phương thức thanh toán</p>
|
||||||
<div className="list-method-payment">
|
<div className="list-method-payment">
|
||||||
@@ -141,7 +151,7 @@ const HomeCart = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="list-btn-cart">
|
<div className="list-btn-cart">
|
||||||
<button type="submit" className="js-send-cart font-bold">
|
<button type="submit" onClick={handleClickOrder} className="js-send-cart font-bold">
|
||||||
Đặt hàng
|
Đặt hàng
|
||||||
</button>
|
</button>
|
||||||
<div className="list-print-cart flex justify-between gap-2">
|
<div className="list-print-cart flex justify-between gap-2">
|
||||||
|
|||||||
56
src/components/common/ItemArticle/index.tsx
Normal file
56
src/components/common/ItemArticle/index.tsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
'use client';
|
||||||
|
import React from 'react';
|
||||||
|
import { Article } from '@/types';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
type ItemArticleProps = {
|
||||||
|
item: Article;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ItemArticle: React.FC<ItemArticleProps> = ({ item }) => {
|
||||||
|
// chọn link: nếu có external_url thì dùng, ngược lại dùng url
|
||||||
|
const linkHref = item.external_url && item.external_url !== '' ? item.external_url : item.url;
|
||||||
|
|
||||||
|
// chọn ảnh: nếu có original thì dùng, ngược lại ảnh mặc định
|
||||||
|
const imageSrc =
|
||||||
|
item.image?.original && item.image.original !== ''
|
||||||
|
? item.image.original
|
||||||
|
: '/static/assets/nguyencong_2023/images/not-image.png';
|
||||||
|
|
||||||
|
// chọn thời gian: ưu tiên article_time, fallback createDate
|
||||||
|
const timeDisplay =
|
||||||
|
item.article_time && item.article_time !== '' ? item.article_time : item.createDate;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="item-article flex gap-3">
|
||||||
|
<Link href={linkHref} className="img-article boder-radius-10 position-relative">
|
||||||
|
<Image
|
||||||
|
className="boder-radius-10"
|
||||||
|
src={imageSrc}
|
||||||
|
fill
|
||||||
|
alt={item.title}
|
||||||
|
sizes="(max-width: 768px) 100vw, 265px"
|
||||||
|
/>
|
||||||
|
{/* icon video nếu cần */}
|
||||||
|
<i className="sprite sprite-icon-play-video-detail icon-video-feature incon-play-youtube"></i>
|
||||||
|
<i className="sprite sprite-play-youtube incon-play-youtube"></i>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="content-article content-article-item flex flex-1 flex-col">
|
||||||
|
<Link href={linkHref} className="title-article">
|
||||||
|
<h3 className="line-clamp-2 font-[400]">{item.title}</h3>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<p className="time-article flex items-center gap-1">
|
||||||
|
<i className="sprite sprite-clock-item-article"></i>
|
||||||
|
<span>{timeDisplay}</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className="descreption-article line-clamp-2">{item.summary}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ItemArticle;
|
||||||
264
src/data/article/ListAricleVideo.ts
Normal file
264
src/data/article/ListAricleVideo.ts
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
import { ListArticle } from '@/types/article/TypeListArticle'
|
||||||
|
|
||||||
|
export const DataListArticleVideo: ListArticle = [
|
||||||
|
{
|
||||||
|
"id": 4185,
|
||||||
|
"title": "Chuyện RAM ĐẮT - Góc nhìn mà anh em chưa thấy",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "28-11-2025, 11:51 am",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "28-11-2025, 11:51 am",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 8,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=rH9Aq_2yZEc",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 1,
|
||||||
|
"url": "/chuyen-ram-dat-goc-nhin-ma-anh-em-chua-thay",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4185---efwegweg.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4185---efwegweg.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4184,
|
||||||
|
"title": "Build PC GAMING tầm giá 20 Triệu trong mùa BÃO RAM - Cũng KHOAI phết",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "28-11-2025, 11:49 am",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "28-11-2025, 11:49 am",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 32,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=c-JQPclPXmg",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 2,
|
||||||
|
"url": "/build-pc-gaming-tam-gia-20-trieu-trong-mua-bao-ram-cung-khoai-phet",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4184-maxresdefault.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4184-maxresdefault.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4171,
|
||||||
|
"title": "Điểm dừng cho PC GAMING - Nhiều tiền thì cũng PHÍ",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "10-11-2025, 2:41 pm",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "10-11-2025, 2:41 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 11,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=xUpMSpaa_H0",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 3,
|
||||||
|
"url": "/diem-dung-cho-pc-gaming-nhieu-tien-thi-cung-phi",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4171-dvsdfgrsdf.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4171-dvsdfgrsdf.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3683,
|
||||||
|
"title": "Bộ PC KHỦNG BỐ tới đâu mà đích thân Chủ Tịch MaxHome phải tự đi build ???",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "12-03-2025, 9:59 am",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "12-03-2025, 9:59 am",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 64,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=Ir9zlznA9ms",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 4,
|
||||||
|
"url": "/bo-pc-khung-bo-toi-dau-ma-dich-than-chu-tich-maxhome-phai-tu-di-build",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-3683-tymyumyj.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/3683-tymyumyj.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4107,
|
||||||
|
"title": "Intel ĐẮT quá nên BUILD PC với AMD chỉ 17 TRIỆU mà chiến ALL GAME",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "04-10-2025, 5:39 pm",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "04-10-2025, 5:40 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 8,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=DBuud_Lwt6w",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 5,
|
||||||
|
"url": "/intel-dat-qua-nen-build-pc-voi-amd-chi-17-trieu-ma-chien-all-game",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4107---gherthert.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4107---gherthert.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4079,
|
||||||
|
"title": "Tôi thấy chán PC HIỆU NĂNG/GIÁ THÀNH sau khi thấy bộ PC này",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "20-09-2025, 10:42 am",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "20-09-2025, 10:42 am",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 29,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=ceT_nSB1JCA",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 6,
|
||||||
|
"url": "/toi-thay-chan-pc-hieu-nang-gia-thanh-sau-khi-thay-bo-pc-nay",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4079-ewgergherth.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4079-ewgergherth.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4004,
|
||||||
|
"title": "Sinh Viên ĐỒ HOẠ lên cấu hình PC nào dưới 20 TRIỆU trong 2025",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "15-08-2025, 2:04 pm",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "15-08-2025, 2:04 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 90,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=k6rIzVmU9bA",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 7,
|
||||||
|
"url": "/sinh-vien-do-hoa-len-cau-hinh-pc-nao-duoi-20-trieu-trong-2025",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4004-dhtrhj.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4004-dhtrhj.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3951,
|
||||||
|
"title": "Cấu hình PC 10 Triệu cả Màn hình - Test GAME AAA vẫn OK",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "19-07-2025, 4:57 pm",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "19-07-2025, 4:57 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 47,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=QCQwdLcosQc",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 8,
|
||||||
|
"url": "/cau-hinh-pc-10-trieu-ca-man-hinh-test-game-aaa-van-ok",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-3951-dfbeadbeat.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/3951-dfbeadbeat.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3950,
|
||||||
|
"title": "Tại sao mình ít làm video CORE ULTRA - Có đáng không 40 Triệu cho Ultra 7 265K + RTX 5070",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "19-07-2025, 4:56 pm",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "19-07-2025, 5:00 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 52,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=Y6PBwYe5My0",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 9,
|
||||||
|
"url": "/tai-sao-minh-it-lam-video-core-ultra-co-dang-khong-40-trieu-cho-ultra-7-265k-rtx-5070",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-3950-maxresdefault.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/3950-maxresdefault.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3949,
|
||||||
|
"title": "Cấu hình PC PHỔ BIẾN nhất THẾ GIỚI gaming - Cũng rẻ phết",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "19-07-2025, 4:54 pm",
|
||||||
|
"createBy": "53",
|
||||||
|
"lastUpdate": "19-07-2025, 4:54 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 28,
|
||||||
|
"is_featured": 0,
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "https://www.youtube.com/watch?v=KXfA10koGDk",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 10,
|
||||||
|
"url": "/cau-hinh-pc-pho-bien-nhat-the-gioi-gaming-cung-re-phet",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-3949----herthrtn.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/3949----herthrtn.jpg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
274
src/data/article/ListArticleNews.ts
Normal file
274
src/data/article/ListArticleNews.ts
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
import { ListArticle } from '@/types/article/TypeListArticle'
|
||||||
|
|
||||||
|
export const DataListArticleNews: ListArticle = [
|
||||||
|
{
|
||||||
|
"id": 4200,
|
||||||
|
"title": "Top PC 15 triệu tối ưu hiệu năng nhất trong mùa bão giá RAM",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Chỉ với 15 triệu đồng, người dùng đã có thể sở hữu một bộ máy tính tối ưu hiệu năng cho nhu cầu học tập, làm việc và giải trí. Nguyễn Công PC mang đến nhiều cấu hình cân bằng giữa sức mạnh và giá trị, đảm bảo hoạt động mượt mà trong mọi tác vụ. Đây là lựa chọn lý tưởng cho những ai muốn đầu tư một hệ thống mạnh mẽ với chi phí hợp lý.",
|
||||||
|
"createDate": "10-12-2025, 5:44 pm",
|
||||||
|
"createBy": "75",
|
||||||
|
"lastUpdate": "24-12-2025, 11:11 am",
|
||||||
|
"lastUpdateBy": "75",
|
||||||
|
"visit": 198,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Diệu Linh",
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Diệu Linh",
|
||||||
|
"counter": 7,
|
||||||
|
"url": "/top-pc-15-trieu-toi-uu-hieu-nang-cho-gaming-va-lam-viec",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4200-chi-voi-15-trieu-ban-da-co-ngay-mot-bo-pc-chat-luong-dam-bao-hieu-nang1.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4200-chi-voi-15-trieu-ban-da-co-ngay-mot-bo-pc-chat-luong-dam-bao-hieu-nang1.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4195,
|
||||||
|
"title": "Cách nhận chứng chỉ Google Gemini Educator làm đẹp CV của bạn ngay hôm nay!",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Chứng chỉ Google Gemini Educator giúp bạn khẳng định kỹ năng sử dụng AI trong giáo dục và công nghệ. Việc sở hữu chứng chỉ này không chỉ tăng tính chuyên nghiệp cho CV mà còn mở ra nhiều cơ hội nghề nghiệp mới. Bài viết sẽ hướng dẫn bạn cách đăng ký, học và nhận chứng chỉ nhanh chóng nhất.",
|
||||||
|
"createDate": "08-12-2025, 11:26 am",
|
||||||
|
"createBy": "75",
|
||||||
|
"lastUpdate": "08-12-2025, 12:07 pm",
|
||||||
|
"lastUpdateBy": "75",
|
||||||
|
"visit": 3440,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Diệu Linh",
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Diệu Linh",
|
||||||
|
"counter": 4,
|
||||||
|
"url": "/cach-nhan-chung-chi-google-gemini-educator-mien-phi-nam-2025",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4195-cach-nhan-chung-chi-google-gemini-educator-mien-phi-nam-20251.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4195-cach-nhan-chung-chi-google-gemini-educator-mien-phi-nam-20251.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2722,
|
||||||
|
"title": "Top 100+ cấu hình PC Gaming giá tốt nhất năm 2025",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Trong bài viết, Nguyễn Công PC đã tổng hợp hơn 100 cấu hình PC gaming tối ưu nhất năm 2025, phù hợp với nhiều mức ngân sách từ phổ thông đến cao cấp. Mỗi cấu hình cân bằng giữa hiệu năng và giá thành, đáp ứng nhu cầu chơi game mượt mà, đồ họa sắc nét và khả năng nâng cấp linh hoạt trong tương lai.\r\n\r\n\r\n",
|
||||||
|
"createDate": "16-01-2024, 10:52 am",
|
||||||
|
"createBy": "50",
|
||||||
|
"lastUpdate": "06-12-2025, 4:30 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 37078,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Trần Mạnh",
|
||||||
|
"article_time": "07-11-2025, 9:00 am",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 2,
|
||||||
|
"url": "/top-100-cau-hinh-pc-gaming-gia-tot-nhat",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-2722-pc-gaming.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/2722-pc-gaming.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2718,
|
||||||
|
"title": "Top 50 cấu hình PC đồ họa giá tốt nhất hiện nay",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Với đà phát triển của truyền thông, công nghệ số, kỹ thuật số,... Cần rất nhiều công cụ để hỗ trợ cho công việc, làm việc của bạn. Sức mạnh ngành chuyền thông nói riêng cũng như công nghệ nói chung càng ngày càng phát triển mạnh mẽ, vượt trội, chính vì để hỗ trợ cho việc xây dựng các bộ (PC Render) làm việc cũng như giải trí đang là nhu cầu lơn trên thị trường hiện nay.\r\n\r\n",
|
||||||
|
"createDate": "15-01-2024, 1:39 pm",
|
||||||
|
"createBy": "50",
|
||||||
|
"lastUpdate": "24-11-2025, 10:23 am",
|
||||||
|
"lastUpdateBy": "74",
|
||||||
|
"visit": 24523,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Anh Tuấn",
|
||||||
|
"article_time": "05-11-2025, 10:00 am",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Anh Tuấn",
|
||||||
|
"counter": 1,
|
||||||
|
"url": "/top-cau-hinh-do-hoa-gia-tot-nhat",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-2718-pc-do-hoa.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/2718-pc-do-hoa.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4203,
|
||||||
|
"title": "NGUYỄN CÔNG PC - NHÀ TÀI TRỢ KIM CƯƠNG CHÀO TÂN SINH VIÊN ĐẠI HỌC KIẾN TRÚC HÀ NỘI 2025",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Máy tính Nguyễn Công tiếp tục khẳng định vị thế là đối tác tin cậy hàng đầu khi vinh dự trở thành Nhà Tài Trợ Kim Cương liên tục trong 7 năm (2019 – 2025) cho chương trình Chào Tân Sinh Viên của Đại học Kiến Trúc Hà Nội (HAU).",
|
||||||
|
"createDate": "15-12-2025, 10:09 am",
|
||||||
|
"createBy": "74",
|
||||||
|
"lastUpdate": "15-12-2025, 4:00 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 63,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Trần Mạnh",
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 8,
|
||||||
|
"url": "/nguyen-cong-pc-nha-tai-tro-kim-cuong-chao-tan-sinh-vien-dai-hoc-kien-truc-ha-noi-2025",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4203-nguyen-cong-pc-nha-tai-tro-kim-cuong-chao-tan-sinh-vien-dai-hoc-kien-truc-ha-noi-2025-06.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4203-nguyen-cong-pc-nha-tai-tro-kim-cuong-chao-tan-sinh-vien-dai-hoc-kien-truc-ha-noi-2025-06.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4199,
|
||||||
|
"title": "Đại chiến đồ họa: Canva và Photoshop: Ai là \"Vua\" thiết kế hiện nay",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Canva và Photoshop đang là hai nền tảng thiết kế phổ biến nhất, mỗi công cụ sở hữu những ưu – nhược điểm riêng. Trong khi Canva mang đến sự tiện lợi và tốc độ, Photoshop lại vượt trội về sức mạnh xử lý và khả năng sáng tạo chuyên sâu. Cuộc đối đầu này giúp người dùng lựa chọn đúng công cụ phù hợp với nhu cầu thiết kế của mình.",
|
||||||
|
"createDate": "09-12-2025, 6:56 pm",
|
||||||
|
"createBy": "75",
|
||||||
|
"lastUpdate": "11-12-2025, 2:21 pm",
|
||||||
|
"lastUpdateBy": "75",
|
||||||
|
"visit": 83,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Diệu Linh",
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Diệu Linh",
|
||||||
|
"counter": 6,
|
||||||
|
"url": "/dai-chien-do-hoa-canva-va-photoshop-ai-la-vua-thiet-ke-hien-nay",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4199-dai-chien-do-hoa-canva-va-photoshop-ai-la-vua-thiet-ke-hien-nay5.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4199-dai-chien-do-hoa-canva-va-photoshop-ai-la-vua-thiet-ke-hien-nay5.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4197,
|
||||||
|
"title": "Người dùng nên nâng cấp Windows 11 hiện đại hay tiếp tục sử dụng Windows 10 ổn định? ",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "",
|
||||||
|
"createDate": "09-12-2025, 11:03 am",
|
||||||
|
"createBy": "75",
|
||||||
|
"lastUpdate": "09-12-2025, 5:23 pm",
|
||||||
|
"lastUpdateBy": "75",
|
||||||
|
"visit": 108,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Diệu Linh",
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Diệu Linh",
|
||||||
|
"counter": 5,
|
||||||
|
"url": "/nguoi-dung-nen-nang-cap-windows-11-hien-dai-hay-tiep-tuc-su-dung-windows-10-on-dinh",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4197-nguoi-dung-nen-nang-cap-windows-11-hien-dai-hay-tiep-tuc-su-dung-windows-10-on-dinh2.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4197-nguoi-dung-nen-nang-cap-windows-11-hien-dai-hay-tiep-tuc-su-dung-windows-10-on-dinh2.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3954,
|
||||||
|
"title": "Hướng Dẫn Các Bước Cài Đặt Plugin Sketch Up Nhanh Chóng, Đơn Giản Nhất",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Theo dõi các hướng dẫn chi tiết cách cài đặt plugin cho phần mềm SketchUp cùng Nguyễn Công PC để giúp người dùng mở rộng chức năng, tiết kiệm thời gian thiết kế và nâng cao hiệu suất làm việc. ",
|
||||||
|
"createDate": "21-07-2025, 10:39 am",
|
||||||
|
"createBy": "75",
|
||||||
|
"lastUpdate": "22-07-2025, 9:06 am",
|
||||||
|
"lastUpdateBy": "75",
|
||||||
|
"visit": 6972,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Diệu Linh",
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Diệu Linh",
|
||||||
|
"counter": 3,
|
||||||
|
"url": "/huong-dan-cac-buoc-cai-dat-plugin-sketch-up-nhanh-chong-don-gian-nhat",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-3954-huong-dan-cac-buoc-cai-dat-plugin-sketch-up-nhanh-chong-don-gian-nhat10.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/3954-huong-dan-cac-buoc-cai-dat-plugin-sketch-up-nhanh-chong-don-gian-nhat10.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4212,
|
||||||
|
"title": "Trải nghiệm Photoshop 2026: Tính năng AI đỉnh cao và Cách cài đặt nhanh chóng",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Phiên bản Photoshop 2026 tập trung vào việc ứng dụng AI để rút ngắn thời gian chỉnh sửa và nâng cao độ chính xác. Giao diện được tối ưu giúp người dùng thao tác nhanh hơn trên nhiều thiết bị cấu hình khác nhau. Nhờ đó, cả designer chuyên nghiệp lẫn người mới đều có thể khai thác tối đa sức mạnh phần mềm.",
|
||||||
|
"createDate": "18-12-2025, 3:20 pm",
|
||||||
|
"createBy": "75",
|
||||||
|
"lastUpdate": "24-12-2025, 4:31 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 250,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Trần Mạnh",
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 9,
|
||||||
|
"url": "/trai-nghiem-photoshop-2026-tinh-nang-ai-dinh-cao-va-cach-cai-dat-nhanh-chong",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4212-z7359296182053_5ab9b88e01d2b87a466f12e021064a29.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4212-z7359296182053_5ab9b88e01d2b87a466f12e021064a29.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4213,
|
||||||
|
"title": "Top 30+ Hình Nền 2K 4K Tết Nguyên Đán Bính Ngọ 2026 Cực Hot ",
|
||||||
|
"extend": {
|
||||||
|
"pixel_code": ""
|
||||||
|
},
|
||||||
|
"summary": "Bài viết giới thiệu bộ sưu tập hơn 30 hình nền Tết Nguyên Đán Bính Ngọ 2026 với độ phân giải 2K và 4K sắc nét. Nội dung tập trung vào các chủ đề truyền thống như hoa mai, hoa đào, linh vật Ngọ và không khí xuân rộn ràng. Đây là lựa chọn lý tưởng để trang trí màn hình PC, laptop và điện thoại dịp đầu năm mới.",
|
||||||
|
"createDate": "19-12-2025, 11:46 am",
|
||||||
|
"createBy": "75",
|
||||||
|
"lastUpdate": "24-12-2025, 4:30 pm",
|
||||||
|
"lastUpdateBy": "53",
|
||||||
|
"visit": 169,
|
||||||
|
"is_featured": 0,
|
||||||
|
"lastUpdateByUser": "Trần Mạnh",
|
||||||
|
"article_time": "",
|
||||||
|
"review_rate": 0,
|
||||||
|
"review_count": 0,
|
||||||
|
"video_code": "",
|
||||||
|
"external_url": "",
|
||||||
|
"author": "Trần Mạnh",
|
||||||
|
"counter": 10,
|
||||||
|
"url": "/top-30-hinh-nen-tet-2026-cuc-hot-cho-nguoi-dung",
|
||||||
|
"image": {
|
||||||
|
"thum": "https://nguyencongpc.vn/media/news/120-4213-top-30-hinh-nen-tet-2026-cuc-hot-cho-nguoi-dung18.jpg",
|
||||||
|
"original": "https://nguyencongpc.vn/media/news/4213-top-30-hinh-nen-tet-2026-cuc-hot-cho-nguoi-dung18.jpg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
187
src/data/article/ListCategory.ts
Normal file
187
src/data/article/ListCategory.ts
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
|
||||||
|
import { TypeArticleCategory } from '@/types/article/ListCategoryArticle'
|
||||||
|
|
||||||
|
export const DataArticleCategory: TypeArticleCategory[] = [
|
||||||
|
{
|
||||||
|
"id": "243",
|
||||||
|
"title": "C\u00f4ng ngh\u1ec7",
|
||||||
|
"summary": "",
|
||||||
|
"parentId": "0",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "0",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/tin-cong-nghe",
|
||||||
|
"item_count": "2787",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2490",
|
||||||
|
"title": "Review",
|
||||||
|
"summary": "0",
|
||||||
|
"parentId": "0",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "0",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/tin-tuc-review",
|
||||||
|
"item_count": "1235",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2491",
|
||||||
|
"title": "H\u01b0\u1edbng d\u1eabn",
|
||||||
|
"summary": "0",
|
||||||
|
"parentId": "0",
|
||||||
|
"isParent": "1",
|
||||||
|
"thumbnail": "0",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/tin-tuc-huong-dan",
|
||||||
|
"item_count": "1828",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "2493",
|
||||||
|
"title": "Ki\u1ebfn th\u1ee9c m\u00e1y t\u00ednh",
|
||||||
|
"summary": "0",
|
||||||
|
"parentId": "2491",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "0",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/kien-thuc-may-tinh",
|
||||||
|
"item_count": "1558",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2494",
|
||||||
|
"title": "Ph\u1ea7n m\u1ec1m \u0111\u1ed3 h\u1ecda",
|
||||||
|
"summary": "0",
|
||||||
|
"parentId": "2491",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "0",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/phan-mem-do-hoa",
|
||||||
|
"item_count": "174",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2495",
|
||||||
|
"title": "Ph\u1ea7n m\u1ec1m v\u0103n ph\u00f2ng",
|
||||||
|
"summary": "0",
|
||||||
|
"parentId": "2491",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "0",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/phan-mem-van-phong",
|
||||||
|
"item_count": "71",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "263",
|
||||||
|
"title": "Tuy\u1ec3n d\u1ee5ng",
|
||||||
|
"summary": "0",
|
||||||
|
"parentId": "0",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "0",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/tuyen-dung",
|
||||||
|
"item_count": "19",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2488",
|
||||||
|
"title": "Tin t\u1ee9c khuy\u1ebfn m\u1ea1i",
|
||||||
|
"summary": "0",
|
||||||
|
"parentId": "0",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "0",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/tin-tuc-khuyen-mai",
|
||||||
|
"item_count": "90",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2497",
|
||||||
|
"title": "Tin t\u1ee9c build PC",
|
||||||
|
"summary": "",
|
||||||
|
"parentId": "0",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/tin-tuc-build-pc",
|
||||||
|
"item_count": "36",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2505",
|
||||||
|
"title": "Game",
|
||||||
|
"summary": "",
|
||||||
|
"parentId": "0",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/game",
|
||||||
|
"item_count": "16",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2501",
|
||||||
|
"title": "S\u1ef1 ki\u1ec7n",
|
||||||
|
"summary": "",
|
||||||
|
"parentId": "0",
|
||||||
|
"isParent": "1",
|
||||||
|
"thumbnail": "",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/su-kien",
|
||||||
|
"item_count": "65",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "2504",
|
||||||
|
"title": "Chung",
|
||||||
|
"summary": "",
|
||||||
|
"parentId": "2501",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/chung",
|
||||||
|
"item_count": "30",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2500",
|
||||||
|
"title": "COMPUTEX 2025",
|
||||||
|
"summary": "",
|
||||||
|
"parentId": "2501",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/computex-2025",
|
||||||
|
"item_count": "16",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2502",
|
||||||
|
"title": "Ng\u00e0y h\u1ed9i tuy\u1ec3n sinh 2025",
|
||||||
|
"summary": "",
|
||||||
|
"parentId": "2501",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/ngay-hoi-tuyen-sinh-2025",
|
||||||
|
"item_count": "6",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2503",
|
||||||
|
"title": "Ch\u00e0o t\u00e2n sinh vi\u00ean",
|
||||||
|
"summary": "",
|
||||||
|
"parentId": "2501",
|
||||||
|
"isParent": "0",
|
||||||
|
"thumbnail": "",
|
||||||
|
"type": "article",
|
||||||
|
"url": "\/chao-tan-sinh-vien",
|
||||||
|
"item_count": "15",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -10,5 +10,9 @@ export function resolvePageType(slug: string) {
|
|||||||
if (productDetailData.some((c) => c.product_info.productUrl == slug)) {
|
if (productDetailData.some((c) => c.product_info.productUrl == slug)) {
|
||||||
return 'product-detail';
|
return 'product-detail';
|
||||||
}
|
}
|
||||||
|
// tin tức
|
||||||
|
if ('/tin-tuc' == slug) {
|
||||||
|
return 'article-home'
|
||||||
|
}
|
||||||
return '404';
|
return '404';
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/types/article/ListCategoryArticle.ts
Normal file
12
src/types/article/ListCategoryArticle.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export interface TypeArticleCategory {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
summary: string;
|
||||||
|
parentId: string;
|
||||||
|
isParent: string;
|
||||||
|
thumbnail: string;
|
||||||
|
type: string;
|
||||||
|
url: string;
|
||||||
|
item_count: string;
|
||||||
|
children: TypeArticleCategory[];
|
||||||
|
}
|
||||||
34
src/types/article/TypeListArticle.ts
Normal file
34
src/types/article/TypeListArticle.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// types/Article.ts
|
||||||
|
export interface ArticleImage {
|
||||||
|
thum: string;
|
||||||
|
original: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ArticleExtend {
|
||||||
|
pixel_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Article {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
extend: ArticleExtend;
|
||||||
|
summary: string;
|
||||||
|
createDate: string;
|
||||||
|
createBy: string;
|
||||||
|
lastUpdate: string;
|
||||||
|
lastUpdateBy: string;
|
||||||
|
visit: number;
|
||||||
|
is_featured: number;
|
||||||
|
lastUpdateByUser?: string;
|
||||||
|
article_time: string;
|
||||||
|
review_rate: number;
|
||||||
|
review_count: number;
|
||||||
|
video_code: string;
|
||||||
|
external_url: string;
|
||||||
|
author: string;
|
||||||
|
counter: number;
|
||||||
|
url: string;
|
||||||
|
image: ArticleImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListArticle = Article[];
|
||||||
Reference in New Issue
Block a user