Compare commits

...

10 Commits

Author SHA1 Message Date
641ac01582 last day 2026-03-02 11:57:37 +07:00
a7e23cb983 28/02 2026-02-28 11:59:17 +07:00
4d3949abaa 27-02 2026-02-27 16:59:36 +07:00
b567aef3d8 26/02 2026-02-26 17:14:40 +07:00
a8df344207 25-05-2026 2026-02-25 17:25:45 +07:00
2516e78720 24-02 2026-02-24 17:19:30 +07:00
756cf6410c 12/02/2026 2026-02-12 17:14:04 +07:00
2bc93383a0 11/02/2026 2026-02-11 17:27:55 +07:00
9851c311b3 10/02 2026-02-10 17:11:24 +07:00
87bddca6c3 update 09/02 2026-02-09 16:46:26 +07:00
148 changed files with 14225 additions and 230 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

View File

@@ -1,4 +1,4 @@
body{color:#333333;font-size:14px;line-height: 18px;font-family:'SF Pro Display',sans-serif;position:relative;word-break:break-word;counter-reset:section;font-weight:400;word-break: break-word;overflow-x:hidden} body{color:#333333;font-size:14px;line-height: 18px;font-family:'SF Pro Display',sans-serif;position:relative;word-break:break-word;counter-reset:section;font-weight:400;word-break: break-word;}
.fancybox__container .for-video.is-selected {border: 2px solid red;} .fancybox__container .for-video.is-selected {border: 2px solid red;}
/* css loading */ /* css loading */

View File

@@ -0,0 +1,15 @@
import BuildPc from "@/components/buildpc"
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Xây Dựng Cấu Hình PC, Build PC Chuẩn Nhất✔Giá Rẻ",
description: "Xây dựng cấu hình máy tính PC chuyên nghiệp ✳️ máy tính đồ họa, máy tính làm việc giá rẻ ✳️ Build PC.",
};
import "@/styles/buildpc.css";
export default function Home() {
return(
<BuildPc />
)
}

View File

@@ -0,0 +1,13 @@
import CartHome from "@/components/cart/home";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Giỏ hàng của bạn",
description: "",
};
export default function Home() {
return (
<CartHome />
)
}

View File

@@ -0,0 +1,15 @@
import RegisterPage from "@/components/customer/Register"
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Đăng nhập tài khoản",
description: "",
};
import "@/styles/customer.css";
export default function Home() {
return (
<RegisterPage />
)
}

View File

@@ -0,0 +1,15 @@
import LoginPage from "@/components/customer/Login";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Đăng nhập tài khoản",
description: "",
};
import "@/styles/customer.css";
export default function Home() {
return (
<LoginPage />
)
}

View File

@@ -0,0 +1,13 @@
import DealPage from "@/components/deal"
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Flash Sale Mỗi Ngày Cực Sốc - Hoàng Hà PC ",
description: "Flash Sale Mỗi Ngày Cực Sốc - Hoàng Hà PC",
};
export default function Home() {
return(
<DealPage />
)
}

View File

@@ -0,0 +1,37 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { findBySlug } from "@/lib/slug/slugMap";
import { metadataBySlug } from "@/app/[slug]/metadataBySlug";
import { SLUG_CONFIG } from "@/app/[slug]/slugConfig";
import { renderBySlug } from "@/app/[slug]/renderBySlug";
import LayoutTypeSetter from "@/components/layout/LayoutTypeSetter"
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;
const result = await findBySlug(slug);
return metadataBySlug(result);
}
export default async function SlugPage({ params }: { params: { slug: string } }) {
const { slug } = await params;
const result = await findBySlug(slug);
if (!result) notFound();
const config = SLUG_CONFIG[result.type];
if (!config) notFound();
return (
<LayoutTypeSetter layout="main">
{renderBySlug(result)}
</LayoutTypeSetter>
);
}

View File

@@ -0,0 +1,14 @@
import DesignerTool from "@/components/designer-tool";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "PC Đồ Họa Tool | Chọn cấu hình theo phần mềm ",
description: "Công cụ chọn PC đồ họa theo phần mềm: Photoshop, Illustrator, Lumion, AutoCAD… Đề xuất cấu hình chuẩn cho thiết kế 2D, 3D, CAD và render.",
};
export default function Home() {
return (
<DesignerTool />
)
}

View File

@@ -0,0 +1,9 @@
import type { ReactNode } from 'react';
export default function MainLayout({ children }: { children: ReactNode }) {
return (
<>
{children}
</>
);
}

12
src/app/(main)/page.tsx Normal file
View File

@@ -0,0 +1,12 @@
import Home from "@/components/home";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Homepage- Local Pc",
description: "hoanghapc",
};
export default function HomePage() {
return (
<Home />
)
}

View File

@@ -0,0 +1,13 @@
import ForgotPassword from "@/components/customer/ForgotPassword";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Quên mật khẩu",
description: "",
};
export default function Home() {
return (
<ForgotPassword />
)
}

View File

@@ -1,5 +1,10 @@
import SendResult from "@/components/cart/send"; import SendResult from "@/components/cart/send";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Gửi đơn hàng",
description: "",
};
export default function SendCartPage() { export default function SendCartPage() {
return ( return (

View File

@@ -0,0 +1,14 @@
import Layout from "@/components/account";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Tài khoản của tôi",
description: "Thông tin tài khoản người dùng",
};
export default function Home() {
return (
<Layout />
)
}

View File

@@ -0,0 +1,37 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { findBySlug } from "@/lib/slug/slugMap";
import { metadataBySlug } from "@/app/[slug]/metadataBySlug";
import { SLUG_CONFIG } from "@/app/[slug]/slugConfig";
import { renderBySlug } from "@/app/[slug]/renderBySlug";
import LayoutTypeSetter from "@/components/layout/LayoutTypeSetter"
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;
const result = await findBySlug(slug);
return metadataBySlug(result);
}
export default async function SlugPage({ params }: { params: { slug: string } }) {
const { slug } = await params;
const result = await findBySlug(slug);
if (!result) notFound();
const config = SLUG_CONFIG[result.type];
if (!config) notFound();
return (
<LayoutTypeSetter layout="main">
{renderBySlug(result)}
</LayoutTypeSetter>
);
}

View File

@@ -0,0 +1,13 @@
import ProductSearch from "@/components/search"
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Danh sách tìm kiếm ",
description: "Danh sách kết quả thỏa mãn",
};
export default function Search() {
return(
<ProductSearch />
)
}

View File

@@ -0,0 +1,11 @@
import Info from "@/components/about/Info"
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Giới Thiệu Về Hoàng Hà PC",
description: "Hoàng Hà PC được thành lập vào năm 2008. Đến nay, Hoàng Hà PC đã trở thành công ty hàng đầu trong lĩnh vực kinh doanh máy tính tại Việt Nam.",
};
export default function Home() {
return <Info />;
}

View File

@@ -0,0 +1,11 @@
import HeThongCuaHang from "@/components/static/store";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Hệ Thống Cửa Hàng - Hoàng Hà PC",
description: "Hệ Thống Cửa Hàng máy tính với 4 Showroom lớn Hoàng Hà PC Chuyên cung cấp máy tính cao cấp, máy tính đồ họa và linh kiện máy tính uy tín.",
};
export default function Home() {
return <HeThongCuaHang />;
}

View File

@@ -0,0 +1,16 @@
import type { ReactNode } from 'react';
import LayoutTypeSetter from "@/components/layout/LayoutTypeSetter";
import '@/styles/static_page.css';
import '@/styles/tuyen_dung.css';
export default function StaticLayout({ children }: { children: ReactNode }) {
return (
<>
<LayoutTypeSetter layout="static">
{children}
</LayoutTypeSetter>
</>
);
}

View File

@@ -0,0 +1,11 @@
import Contact from "@/components/about/Contact"
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Thông tin liên hệ",
description: "Thông tin liên hệ bao gồm điện thoại, địa chỉ cửa hàng",
};
export default function Home() {
return <Contact />;
}

View File

@@ -0,0 +1,11 @@
import RecruitPage from "../../../components/recruit";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Tuyển dụng nhân sự - Cơ hội việc làm tại Hoàng Hà PC",
description: "Tìm kiếm việc làm tại Hoàng Hà PC",
};
export default function Home() {
return <RecruitPage />;
}

View File

@@ -0,0 +1,20 @@
'use client';
import { useEffect } from "react";
import { useLayout } from "../../components/layout/LayoutContext";
export default function SlugLayoutSetter({
layout,
children,
}: {
layout: "main" | "static";
children: React.ReactNode;
}) {
const { setLayout } = useLayout();
useEffect(() => {
setLayout(layout);
}, [layout, setLayout]);
return <>{children}</>;
}

View File

@@ -1,7 +1,7 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
export function metadataBySlug(result: any): Metadata { export function metadataBySlug(result: any): Metadata {
switch (result.type) { switch (result.type) {
case "product_category": case "product_category":
return { return {
@@ -54,15 +54,35 @@ export function metadataBySlug(result: any): Metadata {
case "article_detail": case "article_detail":
return { return {
title: result.data.title, title: result.data.title,
description: result.data.excerpt, description: result.data.meta_description,
openGraph: { openGraph: {
type: 'article', type: 'article',
} }
}; };
default: case "job_detail":
return { return {
title: "Local PC", title: result.data.title,
description: result.data.meta_description,
openGraph: {
type: 'article',
}
};
case "designer_detail":
return {
title: result.data.title,
description: result.data.meta_description,
openGraph: {
type: 'website',
}
};
default:
return {
title: result.meta_title || "Local PC",
description: result.data.meta_description || "",
openGraph: { openGraph: {
type: 'website', type: 'website',
images: [ images: [

View File

@@ -1,18 +1,11 @@
// app/[slug]/page.tsx
import { cache } from "react";
import { renderBySlug } from "./renderBySlug"; import { renderBySlug } from "./renderBySlug";
import { metadataBySlug } from "./metadataBySlug"; import { metadataBySlug } from "./metadataBySlug";
import { findBySlug } from "@/lib/slug/slugMap"; import { findBySlug } from "@/lib/slug/slugMap";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import type { Metadata } from "next"; import type { Metadata } from "next";
import LayoutTypeSetter from "@/components/layout/LayoutTypeSetter"
import { SLUG_CONFIG } from "./slugConfig";
// Cache findBySlug để tránh gọi 2 lần
const getCachedSlugData = cache(async (slug: string) => {
if (!slug) return null;
// fetch data
return findBySlug(slug);
});
export async function generateMetadata({ export async function generateMetadata({
params, params,
@@ -20,26 +13,22 @@ export async function generateMetadata({
params: Promise<{ slug: string }>; params: Promise<{ slug: string }>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { slug } = await params; const { slug } = await params;
const result = await getCachedSlugData(slug); const result = await findBySlug(slug);
if (!result) {
return { title: "Local PC" };
}
return metadataBySlug(result); return metadataBySlug(result);
} }
export default async function SlugPage({ export default async function SlugPage({ params }: { params: { slug: string } }) {
params, const { slug } = await params;
}: { const result = await findBySlug(slug);
params: Promise<{ slug: string }>; if (!result) notFound();
}) {
const { slug } = await params; const config = SLUG_CONFIG[result.type];
const result = await getCachedSlugData(slug); if (!config) notFound();
if (!result) { return (
notFound(); <LayoutTypeSetter layout={config.layout}>
} {renderBySlug(result)}
</LayoutTypeSetter>
return renderBySlug(result, slug); );
} }

View File

@@ -1,29 +1,11 @@
// app/[slug]/renderBySlug.tsx
import { SLUG_CONFIG } from "./slugConfig";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import ProductCategory from "@/components/product/category"; export function renderBySlug(result: any) {
import ProductDetail from "@/components/product/detail"; const config = SLUG_CONFIG[result.type];
import ArticleCategory from "@/components/article/category";
import ArticleDetail from "@/components/article/detail"; if (!config) notFound();
import ArticleHome from "@/components/article/home";
export function renderBySlug(result: any, slug: string) { return config.render(result.data);
switch (result.type) {
case "product_category":
return <ProductCategory slug={result.data} />;
case "product_detail":
return <ProductDetail slug={result.data} />;
case "article_home":
return <ArticleHome slug={slug} />;
case "article_category":
return <ArticleCategory slug={result.data} />;
case "article_detail":
return <ArticleDetail slug={result.data} />;
default:
notFound();
}
} }

View File

@@ -0,0 +1,47 @@
// app/[slug]/slugConfig.ts
import ProductCategory from "@/components/product/category";
import ProductDetail from "@/components/product/detail";
import ArticleCategory from "@/components/article/category";
import ArticleDetail from "@/components/article/detail";
import ArticleHome from "@/components/article/home";
import JobDetail from "@/components/recruit/Detail";
import DesignerDetail from "@/components/designer-tool/Detail";
export type SlugLayout = "main" | "static";
export const SLUG_CONFIG:
Record<string,{
layout: SlugLayout;
render: (data: any) => JSX.Element;
}> =
{
product_category: {
layout: "main",
render: (data) => <ProductCategory slug={data} />,
},
product_detail: {
layout: "main",
render: (data) => <ProductDetail slug={data} />,
},
article_home: {
layout: "main",
render: () => <ArticleHome />,
},
article_category: {
layout: "main",
render: (data) => <ArticleCategory slug={data} />,
},
article_detail: {
layout: "main",
render: (data) => <ArticleDetail slug={data} />,
},
designer_detail: {
layout: "main",
render: (data) => <DesignerDetail slug={data} />,
},
job_detail: {
layout: "static",
render: (data) => <JobDetail slug={data} />,
},
};

View File

@@ -1,8 +0,0 @@
import CartHome from "@/components/cart/home";
export default function Home() {
return (
<CartHome />
)
}

View File

@@ -1,39 +1,21 @@
import type { Metadata } from "next"; import { Toaster } from "sonner";
import type { ReactNode } from 'react';
import { Toaster } from 'sonner';
import Header from "@/components/other/header";
import Footer from "@/components/other/footer";
import TooltipProvider from "@/components/providers/TooltipProvider"; import TooltipProvider from "@/components/providers/TooltipProvider";
import '../styles/globals.css'; import HeaderFooterSwitch from "@/components/other/HeaderFooterSwitch";
import { LayoutProvider } from "@/components/layout/LayoutContext";
import "@/styles/globals.css";
export const metadata: Metadata = { export default function RootLayout({ children }: { children: React.ReactNode }) {
title: "Homepage- Local Pc",
description: "hoanghapc",
};
export default function RootLayout({
children,
}: {
children: ReactNode;
}) {
return ( return (
<html lang="vi"> <html lang="vi">
<body> <body>
<Header /> <LayoutProvider>
<HeaderFooterSwitch>
<TooltipProvider>{children}</TooltipProvider>
</HeaderFooterSwitch>
<TooltipProvider> <Toaster position="top-right" closeButton richColors />
{children} </LayoutProvider>
</TooltipProvider> </body>
<Footer />
<Toaster
position="top-right"
closeButton
richColors
/>
</body>
</html> </html>
); );
} }

View File

@@ -1,4 +1,9 @@
import Link from "next/link" import Link from "next/link";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "404 - Không tìm thấy trang | Hoàng Hà PC",
description: "hoanghapc",
};
export default function NotFound() { export default function NotFound() {
return ( return (

View File

@@ -1,8 +0,0 @@
import Home from "@/components/home";
export default function HomePage() {
return (
<Home />
)
}

View File

@@ -0,0 +1,144 @@
export default function Contact() {
return (
<>
<h1 style={{ position: 'absolute', top: '-999px' }}>Liên hệ</h1>
<div className="contact-info-page main-content">
<div className="contact-info text-20">
<div className="container">
<div className="contact-info-header py-6">
<div className="contact-info-header-text">
<h2 className="text-20 mb-3">
Công ty tin rằng khách hàng chính nhân tố quan trọng cho phát triển của <b className="font-weight-600 color-blue-1">Hoàng PC</b>. vậy, mọi hoạt đng kinh doanh của công ty luôn hướng tới mục tiêu tôn trọng bảo đm quyền lợi cho khách hàng, chinh phục khách hàng bằng chất lượng sản phẩm dịch vụ tốt nhất.
</h2>
<p>
Đ đưc phục vụ cũng như giải đáp mọi thắc mắc, Quý khách vui lòng liên hệ với chúng tôi theo các thông tin sau:
</p>
</div>
<div className="contact-info-header-image">
<img src="/images/static-contact-info-pic-1.png" alt="contact-info" />
</div>
</div>
<div className="contact-info-content d-flex flex-wrap">
<div className="contact-info-box d-flex flex-column align-items-center">
<i className="static-icons static-icon-location-3" />
<h3 className="text-20 font-weight-bold">Showroom bán hàng</h3>
<h4 className="text-24 font-weight-bold mb-4 mt-2">PHƯỜNG CẦU GIẤY, NỘI</h4>
<p className="text-16 pb-3x text-center">41 Khúc Thừa Dụ, Phường Cầu Giấy, Nội</p>
<div className="w-full pb-4x">
<a href="https://goo.gl/maps/56ARHjWKoVhpWBCF6" className="btn btn-blue-2 w-full" target="_blank">Nhận chỉ đưng</a>
</div>
<ul className="contact-list d-flex flex-column">
<li className="d-flex align-items-center">
<i className="static-icons static-icon-phone" />
<a className="text-14" href="tel:0969.123.666">Điện thoại: 0969.123.666</a>
</li>
<li className="d-flex align-items-center">
<i className="static-icons static-icon-mail" />
<a className="text-14" href="mailto:hoanghapcws@gmail.com">Email: hoanghapcws@gmail.com</a>
</li>
<li className="d-flex align-items-center">
<i className="static-icons static-icon-clock" />
<p className="text-14 m-0">Thời gian làm việc: 8h00 - 18h30</p>
</li>
</ul>
</div>
{/* QUẬN ĐỐNG ĐA, HÀ NỘI */}
<div className="contact-info-box d-flex flex-column align-items-center">
<i className="static-icons static-icon-location-3" />
<h3 className="text-20 font-weight-bold">Showroom bán hàng</h3>
<h4 className="text-24 font-weight-bold mb-4 mt-2">PHƯỜNG ĐNG ĐA, NỘI</h4>
<p className="text-16 pb-3x text-center">94E-94F Đưng Láng , Phường Đng Đa, Nội</p>
<div className="w-full pb-4x">
<a href="https://g.page/hoanghapc?share" className="btn btn-blue-2 w-full" target="_blank">Nhận chỉ đưng</a>
</div>
<ul className="contact-list d-flex flex-column">
<li className="d-flex align-items-center">
<i className="static-icons static-icon-phone" />
<a className="text-14" href="tel: 0396.122.999">Điện thoại: 0396.122.999</a>
</li>
<li className="d-flex align-items-center">
<i className="static-icons static-icon-mail" />
<a className="text-14" href="mailto:hoanghapcws@gmail.com">Email: hoanghapcws@gmail.com</a>
</li>
<li className="d-flex align-items-center">
<i className="static-icons static-icon-clock" />
<p className="text-14 m-0">Thời gian làm việc: 8h00 - 18h30</p>
</li>
</ul>
</div>
{/* VINH, NGHỆ AN */}
<div className="contact-info-box d-flex flex-column align-items-center">
<i className="static-icons static-icon-location-3" />
<h3 className="text-20 font-weight-bold">Showroom bán hàng</h3>
<h4 className="text-24 font-weight-bold mb-4 mt-2">VINH, NGHỆ AN</h4>
<p className="text-16 pb-3x text-center">72 Lợi, Thành Vinh, Nghệ An</p>
<div className="w-full pb-4x">
<a href="https://goo.gl/maps/1HQrD6mdf4VMYccs6" className="btn btn-blue-2 w-full" target="_blank">Nhận chỉ đưng</a>
</div>
<ul className="contact-list d-flex flex-column">
<li className="d-flex align-items-center">
<i className="static-icons static-icon-phone" />
<a className="text-14" href="tel:0988.163.666">Điện thoại: 0988.163.666</a>
</li>
<li className="d-flex align-items-center">
<i className="static-icons static-icon-mail" />
<a className="text-14" href="mailto:hoanghapcws@gmail.com">Email: hoanghapcws@gmail.com</a>
</li>
<li className="d-flex align-items-center">
<i className="static-icons static-icon-clock" />
<p className="text-14 m-0">Thời gian làm việc: 8h00 - 18h30</p>
</li>
</ul>
</div>
{/* HỒ CHÍ MINH */}
<div className="contact-info-box d-flex flex-column align-items-center">
<i className="static-icons static-icon-location-3" />
<h3 className="text-20 font-weight-bold">Showroom bán hàng</h3>
<h4 className="text-24 font-weight-bold mb-4 mt-2">HỒ CHÍ MINH</h4>
<p className="text-16 pb-3x text-center">K8bis Bửu Long, Phường Hòa Hưng, Hồ Chí Minh</p>
<div className="w-full pb-4x">
<a href="https://g.page/hoanghapchcm?share" className="btn btn-blue-2 w-full" target="_blank">Nhận chỉ đưng</a>
</div>
<ul className="contact-list d-flex flex-column">
<li className="d-flex align-items-center">
<i className="static-icons static-icon-phone" />
<a className="text-14" href="tel:0968.123.666">Điện thoại: 0968.123.666</a>
</li>
<li className="d-flex align-items-center">
<i className="static-icons static-icon-mail" />
<a className="text-14" href="mailto:hoanghapcws@gmail.com">Email: hoanghapcws@gmail.com</a>
</li>
<li className="d-flex align-items-center">
<i className="static-icons static-icon-clock" />
<p className="text-14 m-0">Thời gian làm việc: 8h00 - 18h30</p>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</>
)
}

View File

@@ -0,0 +1,285 @@
export default function Info() {
return (
<>
<h1 style={{ position: 'absolute', top: '-99999px' }}>Giới Thiệu Hoàng PC</h1>
<div className="about-us-page">
<div className="about-us text-16">
<div className="about-us-header">
<div className="about-us-header-bg section-hero" />
<div className="container">
<div className="text-box d-flex align-items-center flex-column font-weight-bold">
<i className="static-icons static-icon-logo" />
<h3 className="text-28 text-white mt-3">
GIỚI THIỆU VỀ HOÀNG PC
</h3>
</div>
</div>
<div className="deco-header deco-header-1" />
<div className="deco-header deco-header-2" />
</div>
<div className="about-us-content">
<div className="wrap">
<div className="container">
<h4 className="text-center text-16">
<span className="font-weight-bold color-primary">Hoàng PC</span>
đưc thành lập vào năm 2008 với tên gọi Trung Tâm Tin Học
Hoàng nhằm đáp ng nhu cầu của thị trường lúc bấy giờ như
lắp đt hệ thống máy tính văn phòng, máy tính gaming, lắp đt
thi công quán net các sản phẩm máy tính cao cấp dành cho
thiết kế đ họa.
</h4>
</div>
</div>
<div className="summary py-6">
<div className="container">
<div className="grid grid--content-1">
<div className="summary-text">
<h3 className="text-28 color-primary font-weight-600 pb-3">
LƯỢC
</h3>
<p className="my-3">
Suốt nhiều năm hoạt đng từ khi mới thành lập cho tới nay,
<span className="color-primary font-weight-bold">Hoàng PC</span>
đã luôn phát triển tạo dựng đưc niềm tin với khách
hàng từ chất lượng dịch vụ đến mức giá hợp . Trong
khoảng thời gian hoạt đng, Trung Tâm Tin Học Hoàng
quyết đnh đi tên thành
<span className="color-primary font-weight-bold">Công ty TNHH Dịch Vụ Công Nghệ Hoàng
</span>
vào năm 2016 với mục tiêu trở thành đơn vị cung cấp máy
tính chuyên dụng cao cấp tiên phong tại Việt Nam, đi đu
về xu hướng công nghệ mới vấn giải pháp tối ưu phần
cứng máy tính cho các nhu cầu của người sử dụng.
</p>
<p className="mb-3">
Đến nay,
<span className="color-primary font-weight-bold">Hoàng PC</span>
tự hào đơn vị cung cấp các sản phẩm chính hãng nổi
tiếng như:
<span className="color-primary font-weight-bold">Supermicro, Intel, AMD, Nvidia, Zotac,
Gigabyte, Asus,
Asrock, MSI, Seasonic, Gskill, Corsair</span>
đáp ng yêu cầu của khách hàng trong lĩnh vực Server,
Workstation giữ nguyên tiêu chí từ khi Hoàng PC mới
thành lập chính khách hàng.
</p>
<p className="mb-3">
Nhờ nỗ lực phát triển không ngừng, Hoàng PC đã đón nhận
những thành viên mới, tạo nên một tập thể đoàn kết vững
mạnh với đi ngũ nhân viên 100 thành viên, nhiều năm
kinh nghiệm làm việc thực tế, am hiểu sâu về hệ thống phần
cứng phần mềm đc biệt luôn tận tâm với khách hàng..
</p>
<p>
<span className="color-primary font-weight-bold">Hoàng PC</span>
đã vươn lên trở thành công ty hàng đu trong lĩnh vực lắp
đt máy tính cao cấp, luôn đưa ra các chính sách về hỗ trợ
khách hàng từ bảo hành, hỗ trợ vấn giải pháp tối ưu
giá trị ngân sách một cách hiệu quả nhất một cách nhanh
chóng chu đáo nhất.
</p>
</div>
<div className="summary-image">
<img src="/images/static-about-us-pic-1.png" alt="About image" />
</div>
</div>
</div>
</div>
<div className="core-values py-6">
<div className="container">
<div className="core-values-header heading-primary text-center pb-3">
<h3 className="text-28 color-primary mb-3 font-weight-bold">
GIÁ TRỊ CỐT LÕI HOÀNG PC
</h3>
<p>
Văn hóa của Hoàng PC đưc hình thành từ tiêu chí <span className="font-weight-bold color-primary"> khách hàng</span>, đây yếu tố quan trọng mang
lại không chỉ sự phát
triển của
<span className="font-weight-bold color-primary">Hoàng PC</span>
còn cả giá trị tinh thần cùng to lớn cho nhân viên của
<span className="font-weight-bold color-primary">Hoàng PC</span>. vậy giá trị cốt lõi của
Hoàng PC chính :
<span className="font-weight-bold color-primary"><span className="gradient-color gradient-color-1">Nỗ
lực</span>
-
<span className="gradient-color gradient-color-2">Cải tiến</span>
-
<span className="gradient-color gradient-color-3">Sáng tạo</span>
-
<span className="gradient-color gradient-color-4">Trách nhiệm</span>:</span>
</p>
</div>
<div className="core-values-content">
<ul className="grid grid--4-cols grid--gap-2">
<li className="p-3">
<i className="static-icons static-icon-try-hard mx-auto" />
<p className="text-20 font-weight-bold text-center my-2 gradient-color gradient-color-1">
Nỗ lực
</p>
<span>Hoàng PC luôn cống hiến hết sức mình cho mục tiêu đ
ra. Đưa ra giải pháp tốt nhất cho khách hàng.</span>
</li>
<li className="p-3">
<i className="static-icons static-icon-upgrade mx-auto" />
<p className="text-20 font-weight-600 text-center my-2 gradient-color gradient-color-2">
Cải tiến
</p>
<span>Hoàng PC không ngừng cải tiến đ mang đến chính sách
phù hợp với KH nhất, vươn lên dẫn đu trong lĩnh vực lắp
đt máy tính</span>
</li>
<li className="p-3">
<i className="static-icons static-icon-creation mx-auto" />
<p className="text-20 font-weight-600 text-center my-2 gradient-color gradient-color-3">
Sáng tạo
</p>
<span>Hoàng PC luôn đ cao sự sáng tạo kết hợp giữa giá
trị hiện ý tưởng mới tạo nên sự khác biệt so với
các công ty khác.</span>
</li>
<li className="p-3">
<i className="static-icons static-icon-shield-2 mx-auto" />
<p className="text-20 font-weight-600 text-center my-2 gradient-color gradient-color-4">
Trách nhiệm
</p>
<span>Hoàng PC luôn duy trì tinh thần trách nhiệm cao đ
đt đưc các kết quả nhất quán với đnh hướng: Khách
Hàng.</span>
</li>
</ul>
</div>
</div>
</div>
<div className="organization py-6">
<div className="container">
<h3 className="text-28 color-primary font-weight-600 pb-3x">
Đ TỔ CHỨC HOÀNG PC
</h3>
<div className="organization-content">
<div className="grid grid--2-cols grid--gap-2">
<img src="/images/static-about-us-pic-2.png" alt="organization" />
<img src="/images/static-about-us-pic-5.png" alt="organization" />
</div>
</div>
</div>
</div>
<div className="business py-6">
<div className="container">
<div className="grid grid--2-cols grid--gap-2">
<div className="business-text">
<h3 className="text-28 color-primary font-weight-600 mb-1">
CÁC LĨNH VỰC KINH DOANH
</h3>
<p className="pb-3x">
Đc biệt trong lĩnh vực Tin học, Hoàng PC chú trọng các
hoạt đng như:
</p>
<ul>
<li className="d-flex align-items-center pr-4 mb-3">
<div className="wraper-icon">
<i className="static-icons static-icon-polygon-6" />
<span className="text-20 font-weight-bold gradient-color gradient-color-4">1</span>
</div>
<p className="font-weight-600 ml-2">
Cung cấp giải pháp: Máy chủ, máy tính đ họa, máy tính
workstation, máy tính văn phòng các linh kiện máy
tính.
</p>
</li>
<li className="d-flex align-items-center pr-4 mb-3">
<div className="wraper-icon">
<i className="static-icons static-icon-polygon-6" />
<span className="text-20 font-weight-bold gradient-color gradient-color-4">2</span>
</div>
<p className="font-weight-600 ml-2">
Thiết kế giải pháp tổng thể (thiết kế hệ thống, xây
dựng mạng LAN, WAN,..)
</p>
</li>
<li className="d-flex align-items-center pr-4 mb-3">
<div className="wraper-icon">
<i className="static-icons static-icon-polygon-6" />
<span className="text-20 font-weight-bold gradient-color gradient-color-4">3</span>
</div>
<p className="font-weight-600 ml-2">
vấn đào tạo cho khách hàng.
</p>
</li>
<li className="d-flex align-items-center pr-4 mb-3">
<div className="wraper-icon">
<i className="static-icons static-icon-polygon-6" />
<span className="text-20 font-weight-bold gradient-color gradient-color-4">4</span>
</div>
<p className="font-weight-600 ml-2">
Các dịch vụ bảo hành, bảo trì.
</p>
</li>
</ul>
</div>
<div className="business-image">
<img src="/images/static-about-us-pic-3.png" alt="business-image" />
</div>
</div>
</div>
</div>
<div className="achievement py-6">
<div className="container">
<h3 className="heading-primary text-28 color-primary font-weight-600 pb-3 text-center">
Những Thành Tựu Hoàng PC Đã Đt Đưc
</h3>
<ul className="ul grid grid--4-cols grid--gap-2 text-center">
<li className="p-3">
<i className="static-icons static-icon-top-10 mx-auto" />
<p className="text-20 font-weight-600 mt-2">
Top 10 nhà cung cấp máy tính tốt nhất việt nam
</p>
</li>
<li className="p-3">
<i className="static-icons static-icon-rocket mx-auto" />
<p className="text-20 font-weight-600 mt-2">
Tốc đ tăng trưởng đt 200%
</p>
</li>
<li className="p-3">
<i className="static-icons static-icon-tetris mx-auto" />
<p className="text-20 font-weight-600 mt-2">
Đi tác chiến lược của Intel, AMD, Asus, Gigabyte, MSI
</p>
</li>
<li className="p-3">
<i className="static-icons static-icon-10-years mx-auto" />
<p className="text-20 font-weight-600 mt-2">
10 Năm kinh nghiệm trong lĩnh vực máy tính đ họa, PC
workstation
</p>
</li>
</ul>
</div>
</div>
<div className="customer py-6 text-white font-weight-bold" style={{ backgroundColor: '#1988ec' }}>
<div className="container">
<h3 className="heading-primary text-28 pb-3 text-center">
Khách Hàng Của Hoàng PC
</h3>
<div className="grid grid--2-cols grid--gap-2">
<div className="customer-image">
<img src="/images/static-about-us-pic-4.png" alt="customer-image" />
</div>
<ul className="ul customer-list text-20">
<li><span/> Doanh nghiệp nhà nước </li>
<li><span/> Tập đoàn lớn </li>
<li><span/> Doanh nghiệp nhân vừa nhỏ </li>
<li><span/> Tổ chức phi chính phủ </li>
<li><span/> Doanh nghiệp vốn đu nước ngoài </li>
<li><span/> Trường học, bệnh viện </li>
<li><span/> Team Youtube, MMO </li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}

View File

@@ -0,0 +1,115 @@
export default function ChangeInfo({ customer }: any) {
return (
<div className="change-info">
<h3 className="title">Thông tin tài khoản</h3>
<form method="post" encType="multipart/form-data" name="account_form" className="col-right-tbl" id="js-customer-info">
<table cellPadding={5} border={0} style={{
borderCollapse: 'collapse',
width: '100%',
borderColor: '#CCCCCC'
}}>
<tbody>
<tr>
<td>Họ tên</td>
<td>
<input
type="text"
className="form-control"
name="fullname"
size={40}
defaultValue={customer?.name}
/>
</td>
</tr>
<tr>
<td>Giới tính</td>
<td>
<label className="inline-flex items-center gap-1 mr-3 cursor-pointer">
<input type="radio" name="sex" defaultValue="male" defaultChecked />
<span> Nam </span>
</label>
<label className="inline-flex items-center gap-1 cursor-pointer">
<input type="radio" name="sex" defaultValue="female" />
<span> Nữ </span>
</label>
</td>
</tr>
<tr>
<td>Đa chỉ email</td>
<td>
<input
type="text"
className="form-control"
name="email"
size={40}
value={customer?.email}
readOnly
/>
<input
type="hidden"
name="old_email"
id="old_email"
defaultValue="ducdt@hurasoft.com"
/>
</td>
</tr>
<tr>
<td>Đa chỉ nhà</td>
<td>
<input
type="text"
className="form-control"
name="address"
id="address"
defaultValue={customer?.address || ""}
size={50}
/>
</td>
</tr>
<tr>
<td>Tỉnh / TP</td>
<td>
<select
className="form-control"
name="province"
defaultValue="Hà Nội"
>
<option value="Hà Nội"> Nội</option><option value="TP HCM">TP HCM</option><option value="Hải Phòng">Hải Phòng</option><option value="Đà Nẵng">Đà Nẵng</option><option value="An Giang">An Giang</option><option value="Bà Rịa-Vũng Tàu"> Rịa-Vũng Tàu</option><option value="Bình Dương">Bình Dương</option><option value="Bình Phước">Bình Phước</option><option value="Bình Thuận">Bình Thuận</option><option value="Bình Định">Bình Đnh</option><option value="Bạc Liêu">Bạc Liêu</option><option value="Bắc Giang">Bắc Giang</option><option value="Bắc Kạn">Bắc Kạn</option><option value="Bắc Ninh">Bắc Ninh</option><option value="Bến Tre">Bến Tre</option><option value="Cao Bằng">Cao Bằng</option><option value="Cà Mau"> Mau</option><option value="Cần Thơ">Cần Thơ</option><option value="Gia Lai">Gia Lai</option><option value="Hà Giang"> Giang</option><option value="Hà Nam"> Nam</option><option value="Hà Tĩnh"> Tĩnh</option><option value="Hòa Bình">Hòa Bình</option><option value="Hải Dương">Hải Dương</option><option value="Hậu Giang">Hậu Giang</option><option value="Hưng Yên">Hưng Yên</option><option value="Khánh Hòa">Khánh Hòa</option><option value="Kiên Giang">Kiên Giang</option><option value="Kon Tum">Kon Tum</option><option value="Lai Châu">Lai Châu</option><option value="Lào Cai">Lào Cai</option><option value="Lâm Đồng">Lâm Đng</option><option value="Lạng Sơn">Lạng Sơn</option><option value="Long An">Long An</option><option value="Nam Định">Nam Đnh</option><option value="Nghệ An">Nghệ An</option><option value="Ninh Bình">Ninh Bình</option><option value="Ninh Thuận">Ninh Thuận</option><option value="Phú Thọ">Phú Thọ</option><option value="Phú Yên">Phú Yên</option><option value="Quảng Bình">Quảng Bình</option><option value="Quảng Nam">Quảng Nam</option><option value="Quảng Ngãi">Quảng Ngãi</option><option value="Quảng Ninh">Quảng Ninh</option><option value="Quảng Trị">Quảng Trị</option><option value="Sóc Trăng">Sóc Trăng</option><option value="Sơn La">Sơn La</option><option value="Tây Ninh">Tây Ninh</option><option value="Thanh Hóa">Thanh Hóa</option><option value="Thái Bình">Thái Bình</option><option value="Thái Nguyên">Thái Nguyên</option><option value="Thừa Thiên-Huế">Thừa Thiên-Huế</option><option value="Tiền Giang">Tiền Giang</option><option value="Trà Vinh">Trà Vinh</option><option value="Tuyên Quang">Tuyên Quang</option><option value="Vĩnh Long">Vĩnh Long</option><option value="Vĩnh Phúc">Vĩnh Phúc</option><option value="Yên Bái">Yên Bái</option><option value="Đắk Lắk">Đk Lắk</option><option value="Đồng Nai">Đng Nai</option><option value="Đồng Tháp">Đng Tháp</option><option value="Điện Biên">Điện Biên</option><option value="Đăk Nông">Đăk Nông</option>
</select>
</td>
</tr>
<tr>
<td>Điện thoại di đng</td>
<td>
<input
type="text"
className="form-control"
name="mobile"
defaultValue={customer?.mobile || ""}
/>
</td>
</tr>
<tr>
<td />
<td>
<button
type="button"
className="btn btn-danger uppercase">
Thay đi
</button>
</td>
</tr>
</tbody>
</table>
<input type="hidden" name="update" defaultValue="yes" />
</form>
</div>
);
}

View File

@@ -0,0 +1,40 @@
export default function ChangePassword() {
return (
<>
<h3 className="title">Thay đi mật khẩu</h3>
<form method="post" encType="multipart/form-data" name="account_form" className="col-right-tbl">
<table cellPadding={5} border={0} style={{ borderCollapse: 'collapse' }}>
<tbody>
<tr>
<td width="150px">Mật khẩu hiện tại</td>
<td>
<input type="password" name="currentpassword" id="currentpassword" className="form-control" />
</td>
</tr>
<tr>
<td>Mật khẩu mới</td>
<td>
<input type="password" name="newpassword" id="newpassword" className="form-control" />
</td>
</tr>
<tr>
<td>Nhập lại mật khẩu</td>
<td>
<input type="password" name="renewpassword" id="renewpassword" className="form-control" />
</td>
</tr>
<tr>
<td />
<td>
<input type="submit" defaultValue="Thay đổi" className="btn btn-danger" />
</td>
</tr>
</tbody>
</table>
<input type="hidden" name="update" defaultValue="yes" />
</form>
</>
);
}

View File

@@ -0,0 +1,23 @@
export default function Comment({ customer } : any) {
return (
<>
<h3 className="title">Bình luận sản phẩm</h3>
<div className="account-review-page">
<div className="item">
<div className="item-text">
<a href="/link/product.php?id=6434" className="item-name"> HuraSoft - Sản phẩm test (Không xóa) </a>
<time className="item-time"> 21/10/2025 </time>
<p className="item-rate">
<i className="star star-4" />
<span style={{ color: '#f51f42' }}>Chưa duyệt</span>
<span style={{ color: '#1BB51B' }}>Đã duyệt</span>
</p>
<div className="item-content">account test comment</div>
</div>
</div>
<div className="account-paging"></div>
</div>
</>
);
}

View File

@@ -0,0 +1,40 @@
export default function Order() {
return (
<>
<h3 className="title">Danh sách đơn hàng</h3>
<div style={{ overflow: 'auto' }} className="account-order">
<table width="100%" border={1} style={{ borderCollapse: 'collapse' }} cellPadding={4} cellSpacing={0}>
<tbody>
<tr className="text-center" style={{ fontWeight: 'bold', background: '#0066c1', color: '#fff' }}>
<td>STT</td>
<td>Số đơn hàng</td>
<td>Giá trị</td>
<td>Thời gian</td>
<td>Thông tin</td>
</tr>
<tr className="text-center">
<td>1</td>
<td>
#12236
<a href="?view=order-detail&id=12236" className="table blue font-500 m-auto">Xem chi tiết</a>
</td>
<td className="red font-600">
1.990.000
</td>
<td>22-10-2025</td>
<td>
<span>Đang xử </span>
</td>
</tr>
</tbody>
</table>
</div >
</>
);
}

View File

View File

@@ -0,0 +1,23 @@
export default function Review() {
return (
<>
<h3 className="title">Đánh giá sản phẩm</h3>
<div className="account-review-page">
<div className="item">
<div className="item-text">
<a href="/link/product.php?id=6434" className="item-name"> HuraSoft - Sản phẩm test (Không xóa) </a>
<time className="item-time"> 21/10/2025 </time>
<p className="item-rate">
<i className="star star-4" />
<span style={{ color: '#f51f42' }}>Chưa duyệt</span>
<span style={{ color: '#1BB51B' }}>Đã duyệt</span>
</p>
<div className="item-content">account test comment</div>
</div>
</div>
<div className="account-paging"></div>
</div>
</>
);
}

View File

@@ -0,0 +1,96 @@
'use client';
import Link from "next/link";
import { CustomerInfo } from "@/data/customers"
import { useSearchParams } from 'next/navigation';
import ChangeInfo from "./ChangeInfo";
import Order from "./Order";
import ChangePass from "./ChangePassword";
import Review from "./Review";
import Comment from "./Comment";
export default function AccountPage() {
const searchParams = useSearchParams();
const view = searchParams.get('view');
const customer = CustomerInfo[0];
const viewComponent: any = {
"change-info": ChangeInfo,
"order": Order,
"product-review": Review,
"product-comment": Comment,
"change-pass": ChangePass,
};
const ActiveComponent = viewComponent[view || "change-info"];
console.log(customer)
return (
<div className="account-page">
<div className="container">
<div className="account-col-left">
<div className="box-info">
<p>
Tài khoản của,
<b> {customer.name} </b>
</p>
</div>
<div className="box-direction font-500 text-16">
<Link href="/taikhoan?view=change-info"
className={view === 'change-info' ? 'current' : ''}
>
<i className="bx bx-user text-20" />
<span>Thông tin tài khoản</span>
</Link>
<Link href="/taikhoan?view=order"
className={view === 'order' ? 'current' : ''}
>
<i className="bx bx-list-ul-square text-20" />
<span>Danh sách đơn hàng</span>
</Link>
<Link href="/taikhoan?view=product-review"
className={view === 'product-review' ? 'current' : ''}
>
<i className="bxr bx-star text-20" />
<span>Đánh giá của tôi</span>
</Link>
<Link href="/taikhoan?view=product-comment"
className={view === 'product-comment' ? 'current' : ''}
>
<i className="bxr bx-message-dots text-20" />
<span>Bình luận của tôi</span>
</Link>
<Link href="/taikhoan?view=change-pass"
className={view === 'change-pass' ? 'current' : ''}
>
<i className="bx bx-lock text-20" />
<span>Thay đi mật khẩu</span>
</Link>
<Link href="/san-pham-da-xem">
<i className="bx bx-eye text-20" />
<span>Sản phẩm đã xem</span>
</Link>
<Link href="/logout.php">
<i className="bx bx-arrow-out-right-square-half text-20" />
<span>Đăng xuất</span>
</Link>
</div>
</div>
<div className="account-col-right">
{ActiveComponent &&
<ActiveComponent customer={customer}
/>}
</div>
</div>
</div>
)
}

View File

@@ -5,7 +5,7 @@ import { useShowMore } from "@/hooks/useShowMore"
import { VideoData } from "@/data/articles/Video"; import { VideoData } from "@/data/articles/Video";
import ShowMoreButton from "@/components/shared/ButtonShowMore" import ShowMoreButton from "@/components/shared/ButtonShowMore"
export default function VideoList({ slug }: any) { export default function VideoList() {
useEffect(() => { useEffect(() => {
Fancybox.bind('[data-fancybox]', {}); Fancybox.bind('[data-fancybox]', {});

View File

@@ -0,0 +1,21 @@
export default function Buttons() {
return (
<div className="buildpc-btn-action">
<button className="item" data-action="create-image">
Tải nh cấu hình <i className="bxr bx-chevron-down" />
</button>
<button className="item" data-action="download-excel">
Tải file excel cấu hình <i className="bxr bx-chevron-down" />
</button>
<button className="item" data-action="view">
<i className="bx bx-window " /> Xem & In
</button>
<button className="item btn-cart" data-action="add-cart">
<i className="icon-cart" /> Thêm vào giỏ hàng
</button>
</div>
)
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,52 @@
export default function Popups({ onRebuild }: any) {
return (<>
{/* Rebuild */}
<div className="buildpc-popup-container buildpc-popup-rebuild text-black" id="popup-rebuild_config">
<div className="popup-content-group">
<i className="fa fa-exclamation-circle" />
<b>LÀM MỚI</b>
<p>Cảnh báo: Toàn bộ linh kiện của bộ PC hiện tại sẽ bị xóa đi</p>
<div className="popup-btn-group">
<button className="btn-cancel" data-fancybox-close> Hủy </button>
<button
className="btn-red"
style={{ background: '#FA354A', color: '#fff' }}
onClick={() => {
onRebuild();
}}>
Xác nhận
</button>
</div>
</div>
</div>
{/* error */}
<div className="buildpc-popup-container buildpc-popup-rebuild" id="fancybox-opps">
<div className="popup-content-group">
<i className="fa fa-exclamation-circle" />
<b>OPPS...</b>
<p>Bạn chưa chọn sản phẩm nào</p>
<div className="popup-btn-group">
<button className="btn-red js-close-popup" style={{ background: '#FA354A', color: '#fff' }} onClick={() => { /* Fancybox.close(); */ }}> OK </button>
</div>
</div>
</div>
{/* Popup variant */}
<div className="popup-select-variant-container" id="js-popup-select-variant-container">
<div className="popup-select-content">
<div className="popup-title">
<p className="m-0 font-600 text-20">CHỌN CẤU HÌNH</p>
<a href="javascript:void(0)"
onClick={() => { /* $('.popup-select-variant-container').hide(); $('#js-product-selected-info-holder, #js-variant-containe').html('');*/ }} className="bx bx-x font-600" />
</div>
<div id="js-product-selected-info-holder">{/* load variant item */} </div>
<div className="popup-select-holder" id="js-variant-container">{/* load variant list */} </div>
<button type="button" className="popup-select-btn">CHỌN CẤU HÌNH NÀY</button>
</div>
</div>
</>)
}

View File

@@ -0,0 +1,17 @@
export default function Promotion({ total }: any) {
return (
<div className="buildpc-info-group">
<p>
Chi phí dự tính:
<span
className="font-600"
style={{ color: '#FF4E2A' }}
>
{total.toLocaleString()} đ
</span>
</p>
<div className="buildpc-promotion-content" />
</div>
);
}

View File

@@ -0,0 +1,142 @@
'use client';
import { useEffect, useState } from "react";
import { Fancybox } from "@fancyapps/ui/dist/fancybox/";
import { categoryDetail } from "@/data/buildpc/categoryDetail";
import ModalContent from "../modal";
import SelectedItemRow from "../modal/SelectedItemRow";
export default function BuildPCCategories({
categories,
activeTab,
buildData,
setBuildData
}: any) {
const [selectedCategory, setSelectedCategory] = useState<any>(null);
const [categoryInfo, setCategoryInfo] = useState<any>(null);
const getStorageKey = () => `buildpc_tab_${activeTab}`;
useEffect(() => {
if (selectedCategory) {
const filterCategory = categoryDetail.find(
(item: any) => item.id === selectedCategory
);
setCategoryInfo(filterCategory);
}
}, [selectedCategory]);
const handleSaveProduct = (rowId: number, product: any) => {
const newData = [
...buildData.filter((b: any) => b.rowId !== rowId), // loại bỏ row cũ
{
rowId,
info: [product]
}
];
localStorage.setItem(getStorageKey(), JSON.stringify(newData));
setBuildData(newData);
window.dispatchEvent(new Event("buildpcUpdated"));
};
// ==============================
// REMOVE
// ==============================
const handleRemove = (rowId: number) => {
const newData = buildData.filter((b: any) => b.rowId !== rowId);
localStorage.setItem(getStorageKey(), JSON.stringify(newData));
setBuildData(newData);
};
// ==============================
// QUANTITY
// ==============================
const handleQuantityChange = (rowId: number, quantity: number) => {
const newData = buildData.map((b: any) => {
if (b.rowId === rowId) {
return {
...b,
info: [
{
...b.info[0],
quantity
}
]
};
}
return b;
});
localStorage.setItem(getStorageKey(), JSON.stringify(newData));
setBuildData(newData);
};
return (
<>
<div className="buildpc-holder-container">
{categories.map((item: any, index: number) => {
const selectedBuild = buildData.find((b: any) => b.rowId === item.id);
const product = selectedBuild?.info?.[0];
return (
<div className="item-drive" key={item.id}>
<p className="item-title leading-5">
<span>{index + 1}. {item.name}</span>
</p>
<div className="item-drive-info">
{ product
? (
<SelectedItemRow
product={product}
rowId={item.id}
onRemove={handleRemove}
onQuantityChange={handleQuantityChange}
onEdit={(rowId: number) => setSelectedCategory(rowId)}
/>
) : (
<button
type="button"
className="open-selection"
onClick={(e) => {
e.preventDefault();
setSelectedCategory(item.id);
Fancybox.show([
{
src: "#js-modal-popup",
type: "inline",
},
]);
}}
>
<i className="bx bx-plus" /> Chọn {item.name}
</button>
)}
</div>
</div>
);
})}
</div>
<div
className="buildpc-modal-popup-container text-black"
id="js-modal-popup"
style={{ display: 'none', padding: 0 }}
>
<ModalContent
item={categoryInfo}
onSave={handleSaveProduct}
/>
</div>
</>
);
}

View File

@@ -0,0 +1,147 @@
'use client';
import Link from "next/link";
import useFancybox from '@/hooks/useFancyBox';
import { Fancybox } from "@fancyapps/ui/dist/fancybox/";
import { useState, useEffect, useMemo } from "react";
import { buildPcData } from "@/data/buildpc";
import Content from "./Content";
import BuildPCCategories from "./categories";
import BuildPcPopups from "./Popups";
import Promotion from "./Promotion";
import Buttons from "./Buttons";
export default function BuildPc() {
const [fancyboxRef] = useFancybox({});
const [activeTab, setActiveTab] = useState(1);
const [buildData, setBuildData] = useState<any[]>([]);
const getStorageKey = (tab: number) => `buildpc_tab_${tab}`;
// Load data khi đổi tab
useEffect(() => {
const oldData = localStorage.getItem(getStorageKey(activeTab));
setBuildData(oldData ? JSON.parse(oldData) : []);
}, [activeTab]);
const handleTabChange = (tabIndex: number) => {
setActiveTab(tabIndex);
};
const handleRebuild = () => {
const storageKey = getStorageKey(activeTab);
localStorage.removeItem(storageKey);
setBuildData([]);
Fancybox.close();
};
const totalPrice = useMemo(() => {
return buildData.reduce((total, item) => {
const product = item?.info?.[0];
if (!product) return total;
const price = Number(product.price) || 0;
const quantity = Number(product.quantity) || 1;
return total + (price * quantity);
}, 0);
}, [buildData]);
return (
<>
<div ref={fancyboxRef}>
<div className="global-breadcrumb">
<div className="container">
<ol itemScope itemType="http://schema.org/BreadcrumbList" className="ul clearfix">
<li itemProp="itemListElement" itemScope itemType="http://schema.org/ListItem">
<Link href="/" itemProp="item" className="nopad-l">
<span itemProp="name">Trang chủ</span>
</Link>
<meta itemProp="position" content="1" />
</li>
<li itemProp="itemListElement" itemScope itemType="http://schema.org/ListItem">
<Link href="https://hoanghapc.vn/buildpc" itemProp="item" className="nopad-l">
<span itemProp="name"> Xây dựng máy tính - tạo máy tính </span>
</Link>
<meta itemProp="position" content="2" />
</li>
</ol>
</div>
</div>
<div className="buildpc-page">
<div className="container">
<h1 className="mb-6 font-600 text-[#004BA4] text-20 leading-6 lg:leading-10 lg:text-[32px]">
Xây Dựng Cấu Hình Máy Tính
</h1>
<div className="overflow-hidden relative mb-6">
<Link href="">
<img src="https://hoanghapccdn.com/media/banner/23_02-a0bcc210735ecfa67eccf8a434ab61b1.jpg"
alt="Banner"
width={100}
height={100}
className="block w-full h-full lazy"
/>
</Link>
</div>
<div className="btn-buildpc-group mb-6">
{
[1, 2, 3, 4, 5].map((item) => (
<button
key={item}
type="button"
className={item === activeTab ? "active" : ""}
onClick={() => handleTabChange(item)}
>
Cấu hình {item}
</button>
))
}
</div>
<div className="buildpc-detail-group gap-4">
<Promotion total={totalPrice} />
<Link
href="#popup-rebuild_config"
data-fancybox=""
className="flex items-center gap-3 bg-btn text-white rounded-[30px] leading-10 text-16 font-500 px-6"
>
LÀM MỚI <i className="bx bx-rotate-ccw" />
</Link>
</div>
<BuildPCCategories
categories={ buildPcData.category_config }
activeTab={ activeTab }
buildData={ buildData }
setBuildData={ setBuildData }
/>
<div className="flex flex-wrap items-center justify-between text-18 font-500 leading-6">
<Promotion total={totalPrice} />
<Buttons />
</div>
</div>
</div>
<Content />
<BuildPcPopups
onRebuild={handleRebuild}
/>
</div>
</>
)
}

View File

@@ -0,0 +1,73 @@
export default function Filter({
attributeFilter,
brandFilter,
priceFilter
}: any) {
return (
<div className="popup-filter-holder">
{ brandFilter && brandFilter.length > 0 &&
<div className="filter-item brand-filter">
<p className="filter-name capitalize"> Hãng sản xuất </p>
<div className="filter-list-holder">
{
brandFilter.map((item: any) => (
<label key={item.id}>
<input type="checkbox"
defaultChecked={item.is_selected === 1}
/>
<span className="value-filter">{item.name} ({item.count})</span>
</label>
))
}
</div>
</div>
}
{ priceFilter && priceFilter.length > 0 &&
<div className="filter-item">
<p className="filter-name capitalize"> Khoảng giá </p>
<div className="filter-list-holder">
{
priceFilter.map((item: any, index: number) => (
<label key={`price-${index}`}>
<input type="checkbox"
defaultChecked={item.is_selected === 1}
/>
<span className="value-filter">{item.name} ({item.count})</span>
</label>
))
}
</div>
</div>
}
{ attributeFilter && attributeFilter.length > 0 &&
attributeFilter.map((item: any, index: number) => (
<div key={index} className="filter-item" >
<p className="filter-name capitalize"> {item.name} </p>
<div className="filter-list-holder">
{
item.value_list.map((value: any) => (
<label key={value.id}>
<input type="checkbox"
defaultChecked={item.is_selected === 1}
/>
<span className="value-filter capitalize">
{value.name} ({value.count})
</span>
</label>
))
}
</div>
</div>
))
}
</div>
)
}

View File

@@ -0,0 +1,15 @@
export default function Paging({ item }: any) {
return (
<div className="popup-paging">
{
item.map((item: any) => (
<a key={item.name} href="#"
className={`${item.is_active ? 'active' : ''} capitalize`}
>
{item.name}
</a>
))
}
</div>
)
}

View File

@@ -0,0 +1,74 @@
'use client';
import Link from "next/link";
export default function ProductItem({ item, rowId, onSelect }: any) {
const handleSelect = () => {
const productData = {
id : item.productId,
name : item.productName,
url : item.productUrl,
price : item.price,
image : item.productImage.large,
quantity : 1,
sku : item.productSKU,
warranty : item.warranty || ''
};
onSelect(productData);
};
return (
<div className="p-item">
<Link href={item.productUrl} className="item-img">
<img
src={item.productImage.large}
alt={item.productName}
width={100}
height={100}
/>
</Link>
<div className="item-text">
<Link href={item.productUrl} className="item-name">
{item.productName}
</Link>
{item.productSKU != 0 &&
<p className="item-info">
<span className="font-500"> SP: </span>
<span> {item.productSKU} </span>
</p>
}
{item.warranty &&
<p className="item-info">
<span className="font-500">Bảo hành: </span>
<span> {item.warranty} </span>
</p>
}
<p className="item-info">
<span className="font-500">Kho hàng: </span>
<span>
{item.quantity > 0 ? "Còn hàng" : "Hết hàng"}
</span>
</p>
<p className="p-price">
{item.price > 0
? item.price.toLocaleString() + ' đ'
: "Liên hệ"
}
</p>
</div>
<button
onClick={handleSelect}
className="btn-buy p-btn bx bx-plus bg-btn text-white rounded-full w-9 h-9 text-20"
/>
</div>
);
}

View File

@@ -0,0 +1,101 @@
'use client';
import { Fancybox } from "@fancyapps/ui/dist/fancybox/";
interface Props {
product: any;
rowId: number;
onRemove: (rowId: number) => void;
onQuantityChange: (rowId: number, quantity: number) => void;
onEdit: (rowId: number) => void;
}
export default function SelectedItemRow({
product,
rowId,
onRemove,
onQuantityChange,
onEdit
}: Props) {
return (
<div className="contain-item-drive">
<a href={product.url} target="_blank" className="item-img">
<img src={product.image} alt={product.name} />
</a>
<div className="item-text">
<div className="item-left">
<a href={product.url} target="_blank" className="item-name">
{product.name}
</a>
<p>
<span className="font-500">- Kho hàng:</span>
{product.quantity > 0 ? "Còn hàng" : "Hết hàng"}
</p>
<p>
<span className="font-500">- Bảo hành:</span>
{product.warranty || "—"}
</p>
</div>
<div className="item-right">
<div className="item-quantity-group">
<b>{product.price.toLocaleString()}</b>
<div className="flex items-center" style={{ display: "flex", gap: "10px" }}>
<span>x</span>
<input
type="number"
className="item-quantity"
value={product.quantity}
min={1}
max={50}
onChange={(e) =>
onQuantityChange(rowId, Number(e.target.value))
}
/>
<span>=</span>
</div>
<b className="item-price">
{(product.price * product.quantity).toLocaleString()}
</b>
</div>
<div className="item-button-group">
<button
type="button"
className="btn-action_seclect show-popup_select bx bx-edit"
onClick={(e) => {
e.preventDefault();
onEdit(rowId);
Fancybox.show([
{
src: "#js-modal-popup",
type: "inline",
},
]);
}}
/>
<button
type="button"
title="Xóa"
className="btn-action_seclect delete_select bx bx-trash remove-item"
onClick={() => onRemove(rowId)}
/>
</div>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,17 @@
export default function Sort({ item }: any) {
return (
<div className="sort-block">
<span>Sắp xếp: </span>
<select id="js-sort-holder">
<option value="">Tùy chọn</option>
{
item.map((item: any) => (
<option key={item.key} value={item.url} >
{item.name}
</option>
))
}
</select>
</div>
)
}

View File

@@ -0,0 +1,99 @@
import { Fancybox } from "@fancyapps/ui/dist/fancybox/";
import Filter from "./Filter";
import ProductItem from "./Products"
import Sort from "./Sort";
import Paing from "./Paging";
export default function ModalContent({
item,
onSave
}: any) {
if (!item) return null;
const {
id,
attribute_filter_list,
brand_filter_list,
price_filter_list,
sort_by_collection,
paging_collection,
product_list
} = item;
return (
<div className="buildpc-popup">
<div className="popup-select">
<div className="popup-header">
<p>Chọn linh kiện</p>
<div className="popup-search-holder">
<input
type="text"
defaultValue=""
className="input-search"
placeholder="Nhập từ khóa cần tìm"
/>
<button className="btn-search bg-linear rounded-full" id="js-buildpc-search-btn">
<i className="block !w-full !h-full icons icon-search" />
</button>
</div>
<div className="icon-menu-filter-mobile js-mobile-filter-btn bx bx-filter">
<i className="fas fa-filter" />
<span>Lọc</span>
</div>
<button className="bx bx-x btn-close" data-fancybox-close />
</div>
<div className="popup-main">
{product_list && product_list.length > 0 ?
(
<>
<div className="popup-filter-group">
<p className="group-titlle"> Lọc sản phẩm </p>
<Filter
attributeFilter={attribute_filter_list}
brandFilter={brand_filter_list}
priceFilter={price_filter_list}
/>
</div>
<div className="popup-content-group">
<div className="sort-paging-group">
{sort_by_collection &&
<Sort item={sort_by_collection} />
}
{paging_collection &&
<Paing item={paging_collection} />
}
</div>
<div className="popup-product-list">
{product_list.map((product: any) => (
<ProductItem
key={product.id}
rowId={id}
item={product}
onSelect={(selectedProduct: any) => {
onSave(id, selectedProduct);
Fancybox.close()
}}
/>
))}
</div>
</div>
</>
) : (
<p className="capitalize font-bold mt-5 text-center w-full">Không tìm thấy sản phẩm nào</p>
)
}
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,40 @@
export default function ForgotPasswordPage() {
return (
<div className="customer-page p-10 container">
<div className="p-10" style={{ padding: '20px 0' }}>
<form action="" method="post" encType="multipart/form-data">
<h2 className="text-20 font-600">Bạn quên mật khẩu vào tài khoản?</h2>
<p>Vui lòng nhập đa chỉ email đã đăng với chúng tôi đ tạo mật khẩu mới. Chúng tôi sẽ gửi 1 email vào đa chỉ email cung cấp yêu cầu xác minh trước khi thể tạo mật khẩu mới</p>
<table>
<tbody>
<tr>
<td>Nhập đa chỉ email đăng </td>
<td>
<input
type="text"
size={40}
name="email"
className="bg-white w-full block h-9 rounded-[4px] px-3"
/>
<span className="red d-block"></span>
</td>
</tr>
<tr>
<td />
<td>
<input
type="button"
className="btn-regis text-uppercase bold px-9"
style={{ width: 'auto' }}
defaultValue="Lấy mật khẩu"
/>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
)
}

View File

@@ -0,0 +1,99 @@
'use client';
import Link from "next/link";
import { useState } from "react";
import { useRouter } from 'next/navigation';
export default function LoginPage() {
const router = useRouter();
const [ hidePass, setHidePass ] = useState(false);
const [ email, setEmail ] = useState('');
const [ password, setPassword ] = useState('');
const [ error, setError ] = useState('');
const handleLogin = () => {
console.log('email: ', email);
console.log('password: ', password);
if (
email === 'admin@mail.com' &&
password === '123456'
) {
setError('');
router.push('/taikhoan');
} else {
setError('Email hoặc mật khẩu không đúng!');
}
}
return (
<div className="customer-page container p-10">
<div className="customer-content-group">
<div className="text-center title text-18 font-600">
<Link href="/dang-ky" className="mr-5">ĐĂNG </Link>
<Link href="/dang-nhap" className="current">ĐĂNG NHẬP</Link>
</div>
<p className="text-center font-bold red my-4">
Test:
admin@mail.com / 123456
</p>
<div className="customer-form">
<div className="item">
<p>Email<span className="red">*</span></p>
<input
type="email"
name="email"
value={email}
onChange={ (e) => setEmail(e.target.value) }
required
/>
</div>
<div className="item">
<p>Mật khẩu<span className="red">*</span></p>
<div className="position-relative">
<input
type={`${hidePass ? 'text' : 'password'}`}
className="input-pass"
name="password"
value={password}
onChange={ (e) => setPassword(e.target.value) }
required
/>
<button
type="button"
onClick={ () => setHidePass(!hidePass) }
className="show-pass bx bx-eye-big"
/>
</div>
</div>
{ error &&
<span className="d-block w-100 mt-2 red">{error}</span>
}
<div className="text-right mt-2 mb-2">
<Link
href="/quen-mat-khau"
style={{ color: '#208ce8' }}
> Quên mật khẩu? </Link>
</div>
<button
type="button"
onClick={handleLogin}
className="bg-red font-600 text-18 text-white d-block btn-regis"
>
ĐĂNG NHẬP
</button>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,79 @@
'use client';
import Link from "next/link";
import { useState } from "react";
export default function RegisterPage() {
const [ hidePass, setHidePass ] = useState(false);
const [ hideConfirmPass, setHideConfirmPass ] = useState(false);
return (
<div className="customer-page container p-10">
<div className="customer-content-group">
<div className="text-center title text-18 font-600">
<Link href="/dang-ky" className="current mr-5">ĐĂNG </Link>
<Link href="/dang-nhap">ĐĂNG NHẬP</Link>
</div>
<div className="customer-form">
<form encType="multipart/form-data">
<div className="item">
<p>Họ Tên<span className="red">*</span></p>
<input type="text" name="info[full_name]" id="full_name" />
</div>
<div className="item">
<p>Số điện thoại<span className="red">*</span></p>
<input type="text" name="info[tel]" id="tel" />
</div>
<div className="item">
<p>Đa chỉ<span className="red">*</span></p>
<input type="text" name="info[address]" id="address" />
</div>
<div className="item">
<p>Email<span className="red">*</span></p>
<input type="text" name="info[email]" id="email" />
</div>
<div className="item">
<p>Mật khẩu<span className="red">*</span></p>
<div className="position-relative">
<input
type={`${hidePass ? 'text' : 'password'}`}
className="input-pass"
name="info[password]"
id="password"
/>
<button
type="button"
onClick={ () => setHidePass(!hidePass) }
className="show-pass bx bx-eye-big"
/>
</div>
</div>
<div className="item">
<p>Nhập lại mật khẩu<span className="red">*</span></p>
<div className="position-relative">
<input
type={`${hideConfirmPass ? 'text' : 'password'}`}
className="input-pass"
name="info[confirm_password]"
id="confirm_password"
/>
<button
type="button"
onClick={ () => setHideConfirmPass(!hideConfirmPass) }
className="show-pass bx bx-eye-big"
/>
</div>
<span className="d-block w-100 red" id="js-pass-alert" />
</div>
<button type="button" className="bg-red font-600 text-18 text-white d-block btn-regis mt-3">ĐĂNG </button>
</form>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,93 @@
'use client';
import Link from "next/link";
import parse from "html-react-parser";
import { formatPrice } from "@/lib/utils";
import { useDealItem } from "@/hooks/useDealItem"
import { useCart } from '@/hooks/useCart';
import { DealCountdown } from "@/lib/times"
export default function DealItem( {item}: any ) {
const deal = useDealItem(item);
if (!deal) return null;
const { addToCart, isInCart } = useCart();
const {
productInfo,
price,
marketPrice,
discount,
remain,
saleRemainPercent,
specialOffer,
} = deal;
const discountView = discount > 0 ? (<>
<del>{formatPrice(marketPrice)} đ</del>
<span className="deal-discount">-{discount}%</span>
</>
) : null;
const checkIncart = isInCart(productInfo.id);
return(
<div className="deal-item js-p-item js-deal-item p-[10px]">
<Link href={ productInfo.productUrl } className="deal-img">
<img
src={ productInfo.productImage.large }
alt={ productInfo.productName }
width={200}
height={200}
className="fit-img"
/>
</Link>
<div className="deal-text">
<Link href={ productInfo.productUrl } className="deal-name"> { item.title } </Link>
<div className="deal-price-holder">
<div>
<p className="deal-price"> {formatPrice(price)} đ </p>
{discountView}
</div>
<button className={`deal-btn bx ${checkIncart ? 'bx-check' : 'bx-plus' }`}
style={{ background: `${checkIncart ? '#ccc' : ''}` }}
disabled={checkIncart}
type="button" aria-label="Mua"
onClick={() => addToCart(productInfo.id)}
></button>
</div>
<div className="deal-count">
<i className="deal-line" style={{ width: saleRemainPercent + '%' }}></i>
<span>
{ Number(item.sale_quantity) < Number(item.quantity)
? `Còn ${remain}/${item.quantity} sản phẩm`
: 'Hết DEAL'
}
</span>
</div>
<div className="deal-time-container my-2 flex flex-wrap justify-content-between items-center text-13 gap-1">
<p className="m-0"> Kết thúc sau: </p>
<div className="deal-time-holder js-deal-time" data-time-left={item.to_time}>
<DealCountdown endTime={item.to_time} />
</div>
</div>
{specialOffer && (
<div className="deal-offer">
<span className="text-[#BE1F2D]"> Quà tặng: </span>
{parse(specialOffer)}
</div>
)}
</div>
</div>
)
}

View File

@@ -0,0 +1,46 @@
'use client';
import { dealList } from "@/data/deals"
import { useMemo } from "react";
import { usePagination } from "@/hooks/usePagination";
import ButtonShowMore from "@/components/shared/ProductShowMore";
import DealItemType2 from "@/components/deal/DealItemType2"
export default function DealPage() {
const data = useMemo(() => {
return dealList.flatMap((item: any) => item.list);
}, []);
const {
currentData,
hasMore,
loadMore,
total
} = usePagination(data);
return (
<div className="deal-page container">
<div className="text-center mb-4">
<img src="https://hoanghapccdn.com/media/lib/09-07-2024/hoanghapc-deal-hot.jpg" alt="DEAL" width={1600} height={490} className="deal-featured-image" style={{ width: '100%', borderRadius: 12 }} />
</div>
<div className="product-holder grid grid-cols-2 gap-3 lg:grid-cols-5 lg:gap-x-5 lg:gap-y-8 mb-6 relative min-h-[300px]">
{currentData.map((item: any) => (
<DealItemType2 key={item.id} item={item} />
))}
</div>
{hasMore &&
<ButtonShowMore
onClick={loadMore}
displayCount={currentData.length}
total={total}
/>
}
</div>
)
}

View File

@@ -0,0 +1,43 @@
import { formatPrice, renderSummary } from "@/lib/utils";
export default function DesignerItem({ item }: any) {
return (
<div className="p-item">
<a href={item.productUrl} className="p-img">
<img src={item.productImage.large}
alt={item.productName}
width={250}
height={250}
/>
</a>
<div className="p-text">
<a href={item.productUrl} className="p-name">
<h3> {item.productName} </h3>
</a>
<div className="p-price-group">
<p className="p-price">
{item.price > 0
? formatPrice(item.price) + 'đ'
: 'Liên hệ'
}
</p>
{Number(item.price_off) > 0 &&
<>
<del> {formatPrice(item.marketPrice)} đ </del>
<span className="p-discount"> -{item.price_off}% </span>
</>
}
</div>
{item.productSummary &&
<div className="p-summary">
{renderSummary(item.productSummary)}
</div>
}
</div>
</div>
)
}

Some files were not shown because too many files have changed in this diff Show More