From b567aef3d8b61820ac5b55803d2e8e4494b47374 Mon Sep 17 00:00:00 2001
From: Dao Duc
Date: Thu, 26 Feb 2026 17:14:40 +0700
Subject: [PATCH] 26/02
---
src/components/buildpc/Popups.tsx | 7 +-
src/components/buildpc/Promotion.tsx | 17 ++-
src/components/buildpc/categories/index.tsx | 93 ++++++++------
src/components/buildpc/index.tsx | 62 +++++++--
src/components/buildpc/modal/Products.tsx | 31 +----
.../buildpc/modal/SelectedItemRow.tsx | 120 ++++++++++--------
src/components/buildpc/modal/index.tsx | 27 ++--
src/components/search/index.tsx | 13 +-
src/styles/buildpc.css | 2 +-
9 files changed, 216 insertions(+), 156 deletions(-)
diff --git a/src/components/buildpc/Popups.tsx b/src/components/buildpc/Popups.tsx
index ea76b94..32a41cb 100644
--- a/src/components/buildpc/Popups.tsx
+++ b/src/components/buildpc/Popups.tsx
@@ -1,4 +1,5 @@
-export default function Popups() {
+export default function Popups({ onRebuild }: any) {
+
return (<>
{/* Rebuild */}
diff --git a/src/components/buildpc/Promotion.tsx b/src/components/buildpc/Promotion.tsx
index 1ea6860..b3a95a5 100644
--- a/src/components/buildpc/Promotion.tsx
+++ b/src/components/buildpc/Promotion.tsx
@@ -1,12 +1,17 @@
-export default function Promotion() {
+export default function Promotion({ total }: any) {
return (
-
- Chi phí dự tính:
- 0đ
+
+ Chi phí dự tính:
+
+ {total.toLocaleString()} đ
+
-
{/* // Khuyến mại buildpc */}
+
- )
+ );
}
\ No newline at end of file
diff --git a/src/components/buildpc/categories/index.tsx b/src/components/buildpc/categories/index.tsx
index d62cc8b..6841556 100644
--- a/src/components/buildpc/categories/index.tsx
+++ b/src/components/buildpc/categories/index.tsx
@@ -1,35 +1,22 @@
'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 }: any) {
+export default function BuildPCCategories({
+ categories,
+ activeTab,
+ buildData,
+ setBuildData
+}: any) {
const [selectedCategory, setSelectedCategory] = useState(null);
const [categoryInfo, setCategoryInfo] = useState(null);
- const [buildData, setBuildData] = useState([]);
- const storageKey = "buildpc";
-
- // Load khi mount
- useEffect(() => {
- const oldData = localStorage.getItem(storageKey);
- setBuildData(oldData ? JSON.parse(oldData) : []);
- }, []);
-
- // Nghe event update
- useEffect(() => {
- const handleUpdate = () => {
- const oldData = localStorage.getItem(storageKey);
- setBuildData(oldData ? JSON.parse(oldData) : []);
- };
-
- window.addEventListener("buildpcUpdated", handleUpdate);
- return () => window.removeEventListener("buildpcUpdated", handleUpdate);
- }, []);
-
- // Set category info khi mở modal
+ const getStorageKey = () => `buildpc_tab_${activeTab}`;
+
useEffect(() => {
if (selectedCategory) {
const filterCategory = categoryDetail.find(
@@ -39,15 +26,36 @@ export default function BuildPCCategories({ categories }: any) {
}
}, [selectedCategory]);
- // Xoá sản phẩm
+ 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(storageKey, JSON.stringify(newData));
+ localStorage.setItem(getStorageKey(), JSON.stringify(newData));
setBuildData(newData);
};
- // Đổi số lượng
+ // ==============================
+ // QUANTITY
+ // ==============================
const handleQuantityChange = (rowId: number, quantity: number) => {
+
const newData = buildData.map((b: any) => {
if (b.rowId === rowId) {
return {
@@ -63,7 +71,7 @@ export default function BuildPCCategories({ categories }: any) {
return b;
});
- localStorage.setItem(storageKey, JSON.stringify(newData));
+ localStorage.setItem(getStorageKey(), JSON.stringify(newData));
setBuildData(newData);
};
@@ -83,24 +91,34 @@ export default function BuildPCCategories({ categories }: any) {
@@ -114,7 +132,10 @@ export default function BuildPCCategories({ categories }: any) {
id="js-modal-popup"
style={{ display: 'none', padding: 0 }}
>
-
+
>
);
diff --git a/src/components/buildpc/index.tsx b/src/components/buildpc/index.tsx
index da70a5f..439962f 100644
--- a/src/components/buildpc/index.tsx
+++ b/src/components/buildpc/index.tsx
@@ -1,7 +1,8 @@
'use client';
import Link from "next/link";
import useFancybox from '@/hooks/useFancyBox';
-import { useState } from "react";
+import { Fancybox } from "@fancyapps/ui/dist/fancybox/";
+import { useState, useEffect, useMemo } from "react";
import { buildPcData } from "@/data/buildpc";
import Content from "./Content";
@@ -10,16 +11,48 @@ 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([]);
- const [activeTab, setActiveTab] = useState(1);
+ 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 (
<>
@@ -60,7 +93,7 @@ export default function BuildPc() {
-
+
{
[1, 2, 3, 4, 5].map((item) => (
>
)
diff --git a/src/components/buildpc/modal/Products.tsx b/src/components/buildpc/modal/Products.tsx
index 8f65027..b4a2ce5 100644
--- a/src/components/buildpc/modal/Products.tsx
+++ b/src/components/buildpc/modal/Products.tsx
@@ -1,15 +1,9 @@
'use client';
import Link from "next/link";
-import { Fancybox } from "@fancyapps/ui/dist/fancybox/";
-export default function ProductItem({ item, rowId }: any) {
+export default function ProductItem({ item, rowId, onSelect }: any) {
- const handleBuy = () => {
- if (typeof window === "undefined") return;
-
- const storageKey = "buildpc";
- const oldData = localStorage.getItem(storageKey);
- const parsed = oldData ? JSON.parse(oldData) : [];
+ const handleSelect = () => {
const productData = {
id : item.productId,
@@ -22,24 +16,7 @@ export default function ProductItem({ item, rowId }: any) {
warranty : item.warranty || ''
};
- const buildIndex = parsed.findIndex((b: any) => b.rowId === rowId);
-
- if (buildIndex !== -1) {
- parsed[buildIndex].info = [productData];
- } else {
- parsed.push({
- rowId: rowId,
- info: [productData]
- });
- }
-
- localStorage.setItem(storageKey, JSON.stringify(parsed));
-
- // báo cho component cha
- window.dispatchEvent(new Event("buildpcUpdated"));
-
- // đóng popup
- Fancybox.close();
+ onSelect(productData);
};
@@ -89,7 +66,7 @@ export default function ProductItem({ item, rowId }: any) {
diff --git a/src/components/buildpc/modal/SelectedItemRow.tsx b/src/components/buildpc/modal/SelectedItemRow.tsx
index 85804c0..d0a5704 100644
--- a/src/components/buildpc/modal/SelectedItemRow.tsx
+++ b/src/components/buildpc/modal/SelectedItemRow.tsx
@@ -1,5 +1,5 @@
'use client';
-
+import { Fancybox } from "@fancyapps/ui/dist/fancybox/";
interface Props {
product: any;
rowId: number;
@@ -17,75 +17,83 @@ export default function SelectedItemRow({
}: Props) {
return (
-
-
+
-
-
-
+
+
+
-
+
-
-
- {product.name}
-
+
+
+ {product.name}
+
-
- - Kho hàng:
- {product.quantity > 0 ? "Còn hàng" : "Hết hàng"}
-
+
+ - Kho hàng:
+ {product.quantity > 0 ? "Còn hàng" : "Hết hàng"}
+
-
- - Bảo hành:
- {product.warranty || "—"}
-
-
+
+ - Bảo hành:
+ {product.warranty || "—"}
+
+
-
+
-
-
{product.price.toLocaleString()}
+
+
{product.price.toLocaleString()}
-
-
x
+
+ x
-
- onQuantityChange(rowId, Number(e.target.value))
- }
- />
-
- =
-
-
-
- {(product.price * product.quantity).toLocaleString()}
-
-
-
-
+
+ {(product.price * product.quantity).toLocaleString()}
+
+
+
+
+
diff --git a/src/components/buildpc/modal/index.tsx b/src/components/buildpc/modal/index.tsx
index bf0c9d1..7a7203c 100644
--- a/src/components/buildpc/modal/index.tsx
+++ b/src/components/buildpc/modal/index.tsx
@@ -1,9 +1,13 @@
+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 }: any) {
+export default function ModalContent({
+ item,
+ onSave
+}: any) {
if (!item) return null;
const {
@@ -69,15 +73,18 @@ export default function ModalContent({ item }: any) {
- {
- product_list.map((item: any) => (
-
- ))
- }
+ {product_list.map((product: any) => (
+
{
+ onSave(id, selectedProduct);
+
+ Fancybox.close()
+ }}
+ />
+ ))}
>
diff --git a/src/components/search/index.tsx b/src/components/search/index.tsx
index cb6ce40..84f78d0 100644
--- a/src/components/search/index.tsx
+++ b/src/components/search/index.tsx
@@ -15,10 +15,6 @@ export default function ProductSearch() {
const searchParams = useSearchParams();
const search_query = searchParams.get('q') || "";
- const {
- sort_by_collection,
- } = productCategory.current_category;
-
const totalProduct = useMemo(() => {
return productList.flatMap((item: any) => item.list);
}, []);
@@ -70,7 +66,10 @@ export default function ProductSearch() {
-
+
{currentData.map((item: any) => (
@@ -89,8 +88,8 @@ export default function ProductSearch() {
- )}
-
+ )
+ }
)
}
\ No newline at end of file
diff --git a/src/styles/buildpc.css b/src/styles/buildpc.css
index aac8627..f1bac2f 100644
--- a/src/styles/buildpc.css
+++ b/src/styles/buildpc.css
@@ -38,7 +38,7 @@
.buildpc-page .contain-item-drive .item-quantity-group > span{text-align:center;padding:0 5px}
.buildpc-page .contain-item-drive .item-quantity-group > b {width: calc(50% - 65px)}
.buildpc-page .contain-item-drive .item-quantity-group .item-price{color:#f71400}
-.buildpc-page .contain-item-drive .btn-action_seclect{cursor: pointer;border: 1px solid #DFE4EC;border-radius: 50%;width: 40px;height: 40px;line-height: 39px;font-size: 20px;color: #0678DB;background: #EAF1FF;}
+.buildpc-page .contain-item-drive .btn-action_seclect{cursor: pointer;border: 1px solid #DFE4EC;border-radius: 50%;width: 40px;height: 40px;line-height: 39px;font-size: 20px;color: #0678DB;background: #EAF1FF;text-align: center;}
.buildpc-page .contain-item-drive .delete_select{border-color:#E7D9D9;background: #F8F3F3;color: #BE1F2D}
.buildpc-page .contain-item-drive input::-webkit-outer-spin-button,.buildpc-page .contain-item-drive input::-webkit-inner-spin-button{-webkit-appearance:none}
.buildpc-page .contain-item-drive input[type=number]{-moz-appearance:textfield}