diff --git a/src/components/product/detail/offer/index.tsx b/src/components/product/detail/offer/index.tsx
index c71a6f0..c85406d 100644
--- a/src/components/product/detail/offer/index.tsx
+++ b/src/components/product/detail/offer/index.tsx
@@ -4,7 +4,7 @@ import parse from 'html-react-parser';
export default function ProductOffer({ item }: any) {
return (
<>
- {item.specialOffer.all.length > 0 &&
+ {item.specialOffer?.all.length > 0 &&
diff --git a/src/components/shared/ArticleItem.tsx b/src/components/shared/ArticleItem.tsx
index 0eff8a4..8d6d677 100644
--- a/src/components/shared/ArticleItem.tsx
+++ b/src/components/shared/ArticleItem.tsx
@@ -2,8 +2,11 @@ import Link from "next/link";
import { formatArticleTime } from "@/lib/utils";
export default function ArticleItem({ item }: any) {
- const url = item.external_url ? item.external_url : item.url;
- const time = item.article_time ? item.article_time : item.lastUpdate;
+
+ if (!item) return null;
+
+ const url = item.external_url || item.url;
+ const time = item.article_time || item.lastUpdate;
return (
<>
diff --git a/src/components/shared/FixedButtons.tsx b/src/components/shared/FixedButtons.tsx
index d663a6f..9dd714c 100644
--- a/src/components/shared/FixedButtons.tsx
+++ b/src/components/shared/FixedButtons.tsx
@@ -11,16 +11,19 @@ export default function FixedButtons() {
};
window.addEventListener('scroll', onScroll);
- return () => window.removeEventListener('scroll', onScroll);
- }, []);
-
- useEffect(() => {
+
const timer = setTimeout(() => setAnimate(true), 800);
- return () => clearTimeout(timer);
+ return () => {
+ clearTimeout(timer);
+ window.removeEventListener('scroll', onScroll);
+ }
}, []);
const goTop = () => {
- window.scrollTo({ top: 0, behavior: 'smooth' });
+ window.scrollTo({
+ top: 0,
+ behavior: 'smooth'
+ });
};
return (
diff --git a/src/data/articles/Job.tsx b/src/data/articles/Job.tsx
new file mode 100644
index 0000000..bce03e2
--- /dev/null
+++ b/src/data/articles/Job.tsx
@@ -0,0 +1,206 @@
+export const JobData = {
+ "total": 3,
+ "list": [
+ {
+ "id": 1185,
+ "type": "job",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": "36",
+ "title": "Tuy\u1ec3n D\u1ee5ng Nh\u00e2n Vi\u00ean Nam K\u1ef9 Thu\u1eadt Ph\u1ea7n C\u1ee9ng M\u00e1y T\u00ednh",
+ "video_code": "",
+ "external_url": "",
+ "url": "\/tuyen-dung-nhan-vien-nam-ky-thuat-phan-cung-may-tinh",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": {
+ "salary": "12 Tri\u1ec7u \u0110\u1ebfn 15 Tri\u1ec7u ",
+ "vacancy_num": "5",
+ "end_date": "30-11-2025",
+ "location": "K8bis B\u1eedu Long, Ph\u01b0\u1eddng Ho\u00e0 H\u01b0ng, Th\u00e0nh ph\u1ed1 H\u1ed3 Ch\u00ed Minh"
+ },
+ "summary": "",
+ "tags": "",
+ "createDate": "31-10-2022, 1:42 pm",
+ "createBy": 22,
+ "create_by_name": "Mai V\u0103n H\u1ecdc",
+ "lastUpdate": "12-11-2025, 8:45 am",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 10743,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "Tuy\u1ec3n D\u1ee5ng Nh\u00e2n Vi\u00ean Nam K\u1ef9 Thu\u1eadt Ph\u1ea7n C\u1ee9ng M\u00e1y T\u00ednh",
+ "meta_keywords": "",
+ "meta_description": "Ho\u00e0ng H\u00e0 PC tuy\u1ec3n d\u1ee5ng k\u1ef9 thu\u1eadt ph\u1ea7n c\u1ee9ng m\u00e1y t\u00ednh: Ch\u1ecbu tr\u00e1ch nhi\u1ec7m tr\u1ef1c ti\u1ebfp thi c\u00f4ng vi\u1ec7c l\u1eafp \u0111\u1eb7t c\u00e1c s\u1ea3n ph\u1ea9m theo y\u00eau c\u1ea7u c\u1ee7a c\u1ea5p tr\u00ean.",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 1,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 1,
+ "image": {
+ "thum": "https:\/\/hoanghapccdn.com\/media\/news\/120_1185_tuyen_dung_ky_thuat.jpg",
+ "original": "https:\/\/hoanghapccdn.com\/media\/news\/1185_tuyen_dung_ky_thuat.jpg"
+ },
+ "categories": [
+ {
+ "id": 36,
+ "type": "job",
+ "name": "K\u1ef9 thu\u1eadt m\u00e1y t\u00ednh",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 345,
+ "item_count": 3,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/ky-thuat-may-tinh",
+ "relate_product": null
+ }
+ ]
+ },
+ {
+ "id": 1497,
+ "type": "job",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": "36",
+ "title": "Tuy\u1ec3n D\u1ee5ng Nh\u00e2n Vi\u00ean K\u1ef9 Thu\u1eadt Tri\u1ec3n Khai H\u1ea1 T\u1ea7ng M\u1ea1ng",
+ "video_code": "",
+ "external_url": "",
+ "url": "\/tuyen-dung-nhan-vien-ky-thuat-trien-khai-ha-tang-mang",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": {
+ "salary": "12 Tri\u1ec7u - 15 Tri\u1ec7u ",
+ "vacancy_num": "1",
+ "end_date": "30-11-2024",
+ "location": "41 Kh\u00fac Th\u1eeba D\u1ee5, Ph\u01b0\u1eddng D\u1ecbch V\u1ecdng, Qu\u1eadn C\u1ea7u Gi\u1ea5y, H\u00e0 N\u1ed9i"
+ },
+ "summary": "",
+ "tags": "",
+ "createDate": "16-10-2024, 11:30 am",
+ "createBy": 22,
+ "create_by_name": "Mai V\u0103n H\u1ecdc",
+ "lastUpdate": "16-10-2024, 11:32 am",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 695,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "",
+ "meta_keywords": "",
+ "meta_description": "",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 1,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 2,
+ "image": {
+ "thum": "",
+ "original": ""
+ },
+ "categories": [
+ {
+ "id": 36,
+ "type": "job",
+ "name": "K\u1ef9 thu\u1eadt m\u00e1y t\u00ednh",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 345,
+ "item_count": 3,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/ky-thuat-may-tinh",
+ "relate_product": null
+ }
+ ]
+ },
+ {
+ "id": 1178,
+ "type": "job",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": "34",
+ "title": "Nh\u00e2n vi\u00ean Quay D\u1ef1ng Cameraman\/ Editor",
+ "video_code": "",
+ "external_url": "",
+ "url": "\/nhan-vien-quay-dung-cameraman-editor",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": {
+ "salary": "10 - 15 Tri\u1ec7u",
+ "vacancy_num": "1",
+ "end_date": "31-07-2025",
+ "location": "41 Kh\u00fac Th\u1eeba D\u1ee5, C\u1ea7u Gi\u1ea5y"
+ },
+ "summary": "",
+ "tags": "",
+ "createDate": "18-10-2022, 2:52 pm",
+ "createBy": 22,
+ "create_by_name": "Mai V\u0103n H\u1ecdc",
+ "lastUpdate": "30-06-2025, 4:15 pm",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 620,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "Nh\u00e2n vi\u00ean Quay D\u1ef1ng Cameraman\/ Editor",
+ "meta_keywords": "",
+ "meta_description": "V\u1ecb tr\u00ed Quay d\u1ef1ng Cameraman\/ Editor gi\u00fap n\u00e2ng t\u1ea7m h\u00ecnh \u1ea3nh cho c\u00f4ng ty, t\u1ea1o n\u00ean nh\u1eefng video viral c\u0169ng nh\u01b0 l\u00e0 b\u1ed9 m\u1eb7t c\u1ee7a c\u00f4ng ty trong truy\u1ec1n th\u00f4ng.",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 1,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 3,
+ "image": {
+ "thum": "",
+ "original": ""
+ },
+ "categories": [
+ {
+ "id": 34,
+ "type": "job",
+ "name": "Marketing",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 0,
+ "item_count": 3,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/marketing",
+ "relate_product": null
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/articles/Video.tsx b/src/data/articles/Video.tsx
new file mode 100644
index 0000000..a7dc9e0
--- /dev/null
+++ b/src/data/articles/Video.tsx
@@ -0,0 +1,377 @@
+export const VideoData = {
+ "total": 6,
+ "list": [
+ {
+ "id": 1241,
+ "type": "video",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": ",31,",
+ "title": "PC \u0110\u1ed3 H\u1ecda Si\u00eau Kh\u1ecfe - \u0110\u1eb9p 13900K + VGA RTX 4070",
+ "video_code": "https:\/\/www.youtube.com\/watch?v=kGSYaCyNPvg",
+ "external_url": "",
+ "url": "\/unbox-pc-do-hoa-sieu-khoe-dep",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": false,
+ "summary": "",
+ "tags": "",
+ "createDate": "27-07-2023, 3:04 pm",
+ "createBy": 22,
+ "create_by_name": "Mai V\u0103n H\u1ecdc",
+ "lastUpdate": "27-07-2023, 3:13 pm",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 337,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "PC \u0110\u1ed3 H\u1ecda Si\u00eau Kh\u1ecfe - \u0110\u1eb9p 13900K + VGA RTX 4070",
+ "meta_keywords": "",
+ "meta_description": "Unbox PC \u0110\u1ed3 H\u1ecda Si\u00eau Kh\u1ecfe - \u0110\u1eb9p T\u1ed1i \u01afu Ph\u1ea7n C\u1ee9ng i9-13900K, Card \u0111\u1ed3 h\u1ecda RTX 4070 12GB, Bo m\u1ea1ch ch\u1ee7 Z790 c\u1ef1c kh\u1ecfe cho anh em.\r\n",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 0,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 1,
+ "image": {
+ "thum": "https:\/\/hoanghapccdn.com\/media\/news\/120_1241_pc_do_hoa_13900k_4070.jpg",
+ "original": "https:\/\/hoanghapccdn.com\/media\/news\/1241_pc_do_hoa_13900k_4070.jpg"
+ },
+ "categories": [
+ {
+ "id": 31,
+ "type": "video",
+ "name": "Trending video",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 413,
+ "item_count": 6,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/trending-video",
+ "relate_product": null
+ }
+ ]
+ },
+ {
+ "id": 1181,
+ "type": "video",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": ",31,",
+ "title": "Mini PC White Nh\u1ecf G\u1ecdn - Tinh T\u1ebf - Hi\u1ec7u N\u0103ng Cao",
+ "video_code": "https:\/\/www.youtube.com\/watch?v=nwkc_lvEJMA",
+ "external_url": "",
+ "url": "\/pc-may-ao-gia-lap-xeon-e5-2676v3-64gb-rx-580-8gb",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": false,
+ "summary": "",
+ "tags": "",
+ "createDate": "18-10-2022, 3:03 pm",
+ "createBy": 22,
+ "create_by_name": "Mai V\u0103n H\u1ecdc",
+ "lastUpdate": "27-07-2023, 3:15 pm",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 366,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "Mini PC White Nh\u1ecf G\u1ecdn - Tinh T\u1ebf - Hi\u1ec7u N\u0103ng Cao",
+ "meta_keywords": "",
+ "meta_description": "HHPC MINI WHITE i5 13600K l\u00e0 b\u1ed9 PC gaming s\u1edf h\u1eefu s\u1eafc tr\u1eafng, hi\u1ec7n \u0111\u1ea1i v\u00e0 si\u00eau nh\u1ecf g\u1ecdn. T\u1ed1i \u01b0u v\u1ec1 c\u1ea5u h\u00ecnh mang t\u1edbi cho game th\u1ee7 tr\u1ea3i nghi\u1ec7m ch\u01a1i game m\u00e3n nh\u00e3n",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 0,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 2,
+ "image": {
+ "thum": "https:\/\/hoanghapccdn.com\/media\/news\/120_1181_pc_mini_white_13600k.jpg",
+ "original": "https:\/\/hoanghapccdn.com\/media\/news\/1181_pc_mini_white_13600k.jpg"
+ },
+ "categories": [
+ {
+ "id": 31,
+ "type": "video",
+ "name": "Trending video",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 413,
+ "item_count": 6,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/trending-video",
+ "relate_product": null
+ }
+ ]
+ },
+ {
+ "id": 1180,
+ "type": "video",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": ",31,",
+ "title": "PC Full Tr\u1eafng 5x Tri\u1ec7u Linh Ki\u1ec7n Th\u1ebf H\u1ec7 M\u1edbi Hi\u1ec7u N\u0103ng Kh\u1ee7ng",
+ "video_code": "https:\/\/www.youtube.com\/watch?v=08varEBPXwc",
+ "external_url": "",
+ "url": "\/build-pc-do-hoa-40-trieu-full-trang-intel-i9-12900k-ram-32gb-rtx-3060",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": false,
+ "summary": "",
+ "tags": "",
+ "createDate": "18-10-2022, 2:57 pm",
+ "createBy": 22,
+ "create_by_name": "Mai V\u0103n H\u1ecdc",
+ "lastUpdate": "27-07-2023, 3:17 pm",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 827,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "PC Full Tr\u1eafng 5x Tri\u1ec7u Linh Ki\u1ec7n Th\u1ebf H\u1ec7 M\u1edbi Hi\u1ec7u N\u0103ng Kh\u1ee7ng",
+ "meta_keywords": "",
+ "meta_description": "HHPC WHITE CORE i9 13900K n\u1eb1m trong b\u1ed9 s\u01b0u t\u1eadp nh\u1eefng c\u1ea5u h\u00ecnh m\u00e1y t\u00ednh si\u00eau \u0111\u1eb9p t\u1ea1i Ho\u00e0ng H\u00e0 PC, kh\u00f4ng ch\u1ec9 t\u1ed1i \u01b0u v\u1ec1 ph\u1ea7n c\u1ee9ng v\u00e0 t\u1ed1t nh\u1ea5t trong t\u1ea7m gi\u00e1. ",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 0,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 3,
+ "image": {
+ "thum": "https:\/\/hoanghapccdn.com\/media\/news\/120_1180_pc_do_hoa_13900k_4070_1.jpg",
+ "original": "https:\/\/hoanghapccdn.com\/media\/news\/1180_pc_do_hoa_13900k_4070_1.jpg"
+ },
+ "categories": [
+ {
+ "id": 31,
+ "type": "video",
+ "name": "Trending video",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 413,
+ "item_count": 6,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/trending-video",
+ "relate_product": null
+ }
+ ]
+ },
+ {
+ "id": 1179,
+ "type": "video",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": ",31,",
+ "title": "C\u1ea5u H\u00ecnh \"Ch\u1ea5t Ch\u01a1i\" V\u1edbi i9-13900K - RTX 3070 Si\u00eau Kh\u1ecfe!",
+ "video_code": "https:\/\/www.youtube.com\/watch?v=QAwiNtcYi3M",
+ "external_url": "build-pc-do-hoa-da-nang-i7-12700f-rtx-3060",
+ "url": "\/build-pc-do-hoa-da-nang-intel-core-i7-12700f-va-rtx-3060-12gb",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": false,
+ "summary": "",
+ "tags": "",
+ "createDate": "18-10-2022, 2:57 pm",
+ "createBy": 22,
+ "create_by_name": "Mai V\u0103n H\u1ecdc",
+ "lastUpdate": "27-07-2023, 3:19 pm",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 393,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "C\u1ea5u H\u00ecnh \"Ch\u1ea5t Ch\u01a1i\" V\u1edbi i9-13900K - RTX 3070 Si\u00eau Kh\u1ecfe!",
+ "meta_keywords": "",
+ "meta_description": "Build pc \u0111\u1ed3 h\u1ecda \u0111a n\u0103ng Intel Core i9-13900K v\u00e0 RTX 3070 t\u1ea1i Ho\u00e0ng H\u00e0 PC gi\u00e1 c\u1ef1c \u01b0u \u0111\u00e3i, b\u1ea3o h\u00e0nh t\u1eadn nh\u00e0. H\u1ed7 tr\u1ee3 tr\u1ea3 g\u00f3p.\r\n",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 0,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 4,
+ "image": {
+ "thum": "https:\/\/hoanghapccdn.com\/media\/news\/120_1179_pc_do_hoa_13900k_3070.jpg",
+ "original": "https:\/\/hoanghapccdn.com\/media\/news\/1179_pc_do_hoa_13900k_3070.jpg"
+ },
+ "categories": [
+ {
+ "id": 31,
+ "type": "video",
+ "name": "Trending video",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 413,
+ "item_count": 6,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/trending-video",
+ "relate_product": null
+ }
+ ]
+ },
+ {
+ "id": 1170,
+ "type": "video",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": ",31,",
+ "title": "PC Gaming Full Tr\u1eafng Si\u00eau \u0110\u1eb9p V\u1edbi i7-13700K vs RTX 4070",
+ "video_code": "https:\/\/www.youtube.com\/watch?v=TvJQnov_Wjs",
+ "external_url": "",
+ "url": "\/build-pc-da-nang-12900k-va-rtx-3060",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": false,
+ "summary": "",
+ "tags": "",
+ "createDate": "04-10-2022, 8:38 pm",
+ "createBy": 27,
+ "create_by_name": "",
+ "lastUpdate": "27-07-2023, 3:22 pm",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 440,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "PC Gaming Full Tr\u1eafng Si\u00eau \u0110\u1eb9p V\u1edbi i7-13700K vs RTX 4070",
+ "meta_keywords": "",
+ "meta_description": "Build PC \u0110a n\u0103ng i7-13700K v\u00e0 RTX 4070 l\u00e0m vi\u1ec7c t\u1ea1i Ho\u00e0ng H\u00e0 PC gi\u00e1 c\u1ef1c \u01b0u \u0111\u00e3i, b\u1ea3o h\u00e0nh t\u1eadn nh\u00e0. H\u1ed7 tr\u1ee3 tr\u1ea3 g\u00f3p. Mi\u1ec5n ph\u00ed v\u1eadn chuy\u1ec3n.\r\n",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 0,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 5,
+ "image": {
+ "thum": "https:\/\/hoanghapccdn.com\/media\/news\/120_1170_pc_do_hoa_13700k_4070ti.jpg",
+ "original": "https:\/\/hoanghapccdn.com\/media\/news\/1170_pc_do_hoa_13700k_4070ti.jpg"
+ },
+ "categories": [
+ {
+ "id": 31,
+ "type": "video",
+ "name": "Trending video",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 413,
+ "item_count": 6,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/trending-video",
+ "relate_product": null
+ }
+ ]
+ },
+ {
+ "id": 1169,
+ "type": "video",
+ "changeCount": 0,
+ "sellerId": 0,
+ "article_category": ",31,",
+ "title": "Review PC H\u01a1n 50 Tri\u1ec7u C\u1ef1c Ng\u1ea7u Full \u0110en",
+ "video_code": "https:\/\/www.youtube.com\/watch?v=kOAs-q4Qp6k",
+ "external_url": "",
+ "url": "\/buid-pc-do-hoa-cao-cap-intel-12900k-rtx-3070",
+ "redirect_url": "",
+ "url_hash": "0",
+ "image_background": "",
+ "extend": false,
+ "summary": "",
+ "tags": "",
+ "createDate": "04-10-2022, 7:41 pm",
+ "createBy": 27,
+ "create_by_name": "",
+ "lastUpdate": "27-07-2023, 3:24 pm",
+ "lastUpdateBy": 22,
+ "lastUpdateByUser": "Mai V\u0103n H\u1ecdc",
+ "review_rate": 0,
+ "review_count": 0,
+ "visit": 447,
+ "like_count": 0,
+ "is_featured": 0,
+ "album_id": 0,
+ "search_fulltext": null,
+ "meta_title": "Review PC H\u01a1n 50 Tri\u1ec7u C\u1ef1c Ng\u1ea7u Full \u0110en",
+ "meta_keywords": "",
+ "meta_description": "Build PC \u0111\u1ed3 h\u1ecda cao c\u1ea5p Intel Core i9 13900K, RTX 4070 t\u1ea1i Ho\u00e0ng H\u00e0 PC gi\u00e1 c\u1ef1c r\u1ebb, b\u1ea3o h\u00e0nh t\u1eadn nh\u00e0. H\u1ed7 tr\u1ee3 tr\u1ea3 g\u00f3p. Mi\u1ec5n ph\u00ed v\u1eadn chuy\u1ec3n.\r\n",
+ "url_canonical": "",
+ "article_time": "",
+ "allow_se_index": 0,
+ "comment_count": 0,
+ "comment_rate": 0,
+ "counter": 6,
+ "image": {
+ "thum": "https:\/\/hoanghapccdn.com\/media\/news\/120_1169_pc_do_hoa_13900k_4070ti.jpg",
+ "original": "https:\/\/hoanghapccdn.com\/media\/news\/1169_pc_do_hoa_13900k_4070ti.jpg"
+ },
+ "categories": [
+ {
+ "id": 31,
+ "type": "video",
+ "name": "Trending video",
+ "summary": "",
+ "description": "",
+ "isParent": 0,
+ "imgUrl": "",
+ "parentId": 0,
+ "extend": null,
+ "visit": 413,
+ "item_count": 6,
+ "display_option": "child_article",
+ "lastUpdateBy": 27,
+ "request_path": "\/trending-video",
+ "relate_product": null
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/data/articles/index.tsx b/src/data/articles/index.tsx
index 8e7cb14..8b475d5 100644
--- a/src/data/articles/index.tsx
+++ b/src/data/articles/index.tsx
@@ -215,7 +215,7 @@ export const articleList = [
"review_count": 0,
"visit": 214588,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "7 C\u1ea5u H\u00ecnh M\u00e1y T\u00ednh Cho Streamer Livestream\u2714\ufe0fChuy\u00ean Nghi\u1ec7p",
@@ -655,7 +655,7 @@ export const articleList = [
"review_count": 0,
"visit": 2333,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "RAM v\u00e0 SSD \u0111ang t\u0103ng gi\u00e1 phi m\u00e3 t\u1ea1i Vi\u1ec7t Nam: Chuy\u1ec7n g\u00ec \u0111ang x\u1ea3y ra?",
@@ -717,7 +717,7 @@ export const articleList = [
"review_count": 0,
"visit": 802,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "",
@@ -903,7 +903,7 @@ export const articleList = [
"review_count": 0,
"visit": 15176,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "Build 1 B\u1ed9 PC C\u1ea7n Nh\u1eefng G\u00ec? C\u00e1c B\u01b0\u1edbc L\u1eafp R\u00e1p 1 B\u1ed9 M\u00e1y T\u00ednh",
@@ -965,7 +965,7 @@ export const articleList = [
"review_count": 0,
"visit": 663,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "ZADAK ra m\u1eaft RAM DDR4 2 t\u1ea7ng, dung l\u01b0\u1ee3ng 32 GB\/thanh",
@@ -1298,7 +1298,7 @@ export const articleList = [
"review_count": 0,
"visit": 11822,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "",
@@ -1360,7 +1360,7 @@ export const articleList = [
"review_count": 0,
"visit": 1567,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "",
@@ -1484,7 +1484,7 @@ export const articleList = [
"review_count": 0,
"visit": 879,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "",
@@ -1608,7 +1608,7 @@ export const articleList = [
"review_count": 0,
"visit": 604,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "",
@@ -1670,7 +1670,7 @@ export const articleList = [
"review_count": 0,
"visit": 182444,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "Khuy\u1ebfn M\u1ea1i Si\u00eau H\u1ea5p D\u1eabn D\u00e0nh Cho H\u1ecdc Sinh, Sinh Vi\u00ean - HHPC",
@@ -1856,7 +1856,7 @@ export const articleList = [
"review_count": 0,
"visit": 923,
"like_count": 0,
- "is_featured": 0,
+ "is_featured": 1,
"album_id": 0,
"search_fulltext": null,
"meta_title": "",
diff --git a/src/data/cart/index.tsx b/src/data/cart/index.tsx
index 133f2fe..bbca192 100644
--- a/src/data/cart/index.tsx
+++ b/src/data/cart/index.tsx
@@ -493,7 +493,7 @@ export const CartData = {
}
],
"cart_summary" : {
- "total_value": 28990000,
+ "total_value": 717240000,
"total_quantity": 4,
"total_item": 6,
"total_weight": 0,
diff --git a/src/hooks/useCart.ts b/src/hooks/useCart.ts
index f46c539..69925b2 100644
--- a/src/hooks/useCart.ts
+++ b/src/hooks/useCart.ts
@@ -9,8 +9,6 @@ import {
increaseQuantity,
decreaseQuantity,
updateQuantity,
- getProductQuantity,
- isProductInCart,
CART_CHANGE_EVENT,
type CartItem,
} from '../services/cart';
@@ -77,13 +75,13 @@ export function useCart() {
removeProductFromCart(productId);
}, []);
- const increase = useCallback((productId: number, amount: number = 1) => {
- const success = increaseQuantity(productId, amount);
+ const increase = useCallback((productId: number) => {
+ const success = increaseQuantity(productId);
return success;
}, []);
- const decrease = useCallback((productId: number, amount: number = 1) => {
- const success = decreaseQuantity(productId, amount);
+ const decrease = useCallback((productId: number) => {
+ const success = decreaseQuantity(productId);
if (!success) {
console.log('Số lượng tối thiểu: 1');
}
@@ -106,18 +104,18 @@ export function useCart() {
}, []);
const isInCart = useCallback(
- (productId: number) => cartItems?.some(item => item.id === productId) ?? false,
+ (productId: number) => cartItems?.some(item => item.item_info.id === productId) ?? false,
[cartItems]
);
const getQuantity = useCallback(
(productId: number) => {
- return cartItems?.find(item => item.id === productId)?.cartQuantity ?? 0;
+ return cartItems?.find(item => item.item_info.id === productId)?.in_cart.quantity ?? 0;
},
[cartItems]
);
- const totalItems = cartItems?.reduce((sum, item) => sum + item.cartQuantity, 0) ?? 0;
+ const totalItems = cartItems?.reduce((sum, item) => sum + item.in_cart.quantity, 0) ?? 0;
return {
cartItems: cartItems ?? [],
diff --git a/src/hooks/useScrollSpy.ts b/src/hooks/useScrollSpy.ts
new file mode 100644
index 0000000..df6d562
--- /dev/null
+++ b/src/hooks/useScrollSpy.ts
@@ -0,0 +1,61 @@
+'use client';
+import { useEffect } from 'react';
+
+export default function useScrollSpy({
+ menuSelector = '.js-category-tab',
+ offsetTop = 250,
+ scrollOffset = 120,
+} = {}) {
+ useEffect(() => {
+ const menuItems = document.querySelectorAll(menuSelector);
+ if (!menuItems.length) return;
+
+ const sections = Array.from(menuItems)
+ .map(item => {
+ const id = item.getAttribute('href');
+ if (!id) return null;
+ return document.querySelector(id);
+ })
+ .filter(Boolean);
+
+ const onScroll = () => {
+ const scrollPos = window.scrollY + offsetTop;
+ let currentId = '';
+
+ sections.forEach(section => {
+ if (section.offsetTop <= scrollPos) {
+ currentId = section.id;
+ }
+ });
+
+ menuItems.forEach(item => item.classList.remove('active'));
+
+ if (currentId) {
+ document
+ .querySelector(`${menuSelector}[href="#${currentId}"]`)
+ ?.classList.add('active');
+ }
+ };
+
+ window.addEventListener('scroll', onScroll);
+
+ menuItems.forEach(item => {
+ item.addEventListener('click', e => {
+ e.preventDefault();
+
+ const targetId = item.getAttribute('href');
+ const target = targetId && document.querySelector(targetId);
+ if (!target) return;
+
+ window.scrollTo({
+ top: target.offsetTop - scrollOffset,
+ behavior: 'smooth',
+ });
+ });
+ });
+
+ return () => {
+ window.removeEventListener('scroll', onScroll);
+ };
+ }, [menuSelector, offsetTop, scrollOffset]);
+}
diff --git a/src/services/cart.ts b/src/services/cart.ts
index 2c9ac96..c822a36 100644
--- a/src/services/cart.ts
+++ b/src/services/cart.ts
@@ -1,147 +1,171 @@
'use client';
+import { CartData } from '@/data/cart';
+
+/* ================= TYPES ================= */
export interface CartItem {
- id: number;
- cartQuantity: number;
+ id: string;
+ item_id: string;
+ item_type: 'product';
+ item_info: {
+ id: number; // productId thật
+ priceUnit: string;
+ marketPrice: number;
+ hasVAt: number;
+ weight: number;
+ };
+ in_cart: {
+ quantity: number;
+ buyer_note: string;
+ price: number;
+ total_price: number;
+ weight: number;
+ };
}
-const CART_KEY = 'cart_products';
const CART_CHANGE_EVENT = 'cart-changed';
-// Helper để dispatch event khi cart thay đổi
+/* ================= HELPERS ================= */
+
function notifyCartChange() {
if (typeof window !== 'undefined') {
window.dispatchEvent(new Event(CART_CHANGE_EVENT));
}
}
-// 1. Lấy danh sách sản phẩm trong giỏ
+/* ================= CORE ================= */
+
+/**
+ * 1. Lấy danh sách sản phẩm trong giỏ
+ */
export function getCartItems(): CartItem[] {
- if (typeof window === 'undefined') return [];
- try {
- const raw = localStorage.getItem(CART_KEY);
- return raw ? (JSON.parse(raw) as CartItem[]) : [];
- } catch (error) {
- console.error('Invalid cart data', error);
- return [];
- }
+ return Array.isArray((CartData as any)?.data)
+ ? (CartData as any).data
+ : [];
}
-// 2. Thêm sản phẩm vào giỏ
-export function addProductToCart(productId: number, quantity: number = 1): { success: boolean; message: string; isNew: boolean } {
- if (typeof window === 'undefined') {
- return { success: false, message: 'Window is undefined', isNew: false };
- }
-
- const items = getCartItems();
- const existingItem = items.find(item => item.id === productId);
-
- if (existingItem) {
- existingItem.cartQuantity += quantity;
- localStorage.setItem(CART_KEY, JSON.stringify(items));
- notifyCartChange(); // Notify change
- return {
- success: true,
- message: `Đã cập nhật số lượng thành ${existingItem.cartQuantity}`,
- isNew: false
+
+/**
+ * 2. Kiểm tra sản phẩm đã có trong giỏ hay chưa
+ */
+export function isProductInCart(productId: number): boolean {
+ return getCartItems().some(
+ item => item.item_info?.id === productId
+ );
+}
+
+/**
+ * 3. Add sản phẩm vào giỏ (CHỈ CHECK – KHÔNG LƯU)
+ */
+export function addProductToCart(
+ productId: number,
+ quantity: number = 1
+): { success: boolean; message: string; isNew: boolean } {
+
+ if (isProductInCart(productId)) {
+ return {
+ success: false,
+ message: 'Sản phẩm đã tồn tại trong giỏ hàng',
+ isNew: false
};
}
-
- items.push({ id: productId, cartQuantity: quantity });
- localStorage.setItem(CART_KEY, JSON.stringify(items));
- notifyCartChange(); // Notify change
- return {
- success: true,
- message: 'Đã thêm sản phẩm vào giỏ hàng',
- isNew: true
+
+ /**
+ * 👉 await cartApi.add({ productId, quantity })
+ */
+
+ notifyCartChange();
+
+ return {
+ success: true,
+ message: 'Đã thêm sản phẩm vào giỏ hàng',
+ isNew: true
};
}
-// 3. Tăng số lượng sản phẩm
-export function increaseQuantity(productId: number, amount: number = 1): boolean {
- if (typeof window === 'undefined') return false;
-
- const items = getCartItems();
- const item = items.find(item => item.id === productId);
-
- if (item) {
- item.cartQuantity += amount;
- localStorage.setItem(CART_KEY, JSON.stringify(items));
- notifyCartChange(); // Notify change
- return true;
- }
- return false;
+/**
+ * 4. Tăng số lượng
+ */
+export function increaseQuantity(productId: number): boolean {
+ if (!isProductInCart(productId)) return false;
+
+ /**
+ * await cartApi.increase(productId)
+ */
+ notifyCartChange();
+ return true;
}
-// 4. Giảm số lượng sản phẩm
-export function decreaseQuantity(productId: number, amount: number = 1): boolean {
- if (typeof window === 'undefined') return false;
-
- const items = getCartItems();
- const item = items.find(item => item.id === productId);
-
- if (item) {
- const newQuantity = item.cartQuantity - amount;
- if (newQuantity < 1) {
- return false;
- }
- item.cartQuantity = newQuantity;
- localStorage.setItem(CART_KEY, JSON.stringify(items));
- notifyCartChange(); // Notify change
- return true;
- }
- return false;
+/**
+ * 5. Giảm số lượng
+ */
+export function decreaseQuantity(productId: number): boolean {
+ const item = getCartItems().find(
+ i => i.item_info.id === productId
+ );
+
+ if (!item || item.in_cart.quantity <= 1) return false;
+
+ /**
+ * await cartApi.decrease(productId)
+ */
+ notifyCartChange();
+ return true;
}
-// 5. Update số lượng trực tiếp
-export function updateQuantity(productId: number, cartQuantity: number): boolean {
- if (typeof window === 'undefined') return false;
-
- if (cartQuantity < 1) {
- return false;
- }
-
- const items = getCartItems();
- const item = items.find(item => item.id === productId);
-
- if (item) {
- item.cartQuantity = cartQuantity;
- localStorage.setItem(CART_KEY, JSON.stringify(items));
- notifyCartChange(); // Notify change
- return true;
- }
- return false;
+/**
+ * 6. Update số lượng trực tiếp
+ */
+export function updateQuantity(
+ productId: number,
+ quantity: number
+): boolean {
+ if (quantity < 1 || !isProductInCart(productId)) return false;
+
+ /**
+ * await cartApi.update(productId, quantity)
+ */
+ notifyCartChange();
+ return true;
}
-// 6. Xóa 1 sản phẩm
-export function removeProductFromCart(productId: number) {
- if (typeof window === 'undefined') return;
-
- const items = getCartItems();
- const newItems = items.filter(item => item.id !== productId);
- localStorage.setItem(CART_KEY, JSON.stringify(newItems));
- notifyCartChange(); // Notify change
+/**
+ * 7. Xóa 1 sản phẩm khỏi giỏ
+ */
+export function removeProductFromCart(productId: number): boolean {
+ if (!isProductInCart(productId)) return false;
+
+ /**
+ * await cartApi.remove(productId)
+ */
+ notifyCartChange();
+ return true;
}
-// 7. Xóa toàn bộ giỏ hàng
-export function clearCart() {
- if (typeof window === 'undefined') return;
- localStorage.removeItem(CART_KEY);
- notifyCartChange(); // Notify change
+/**
+ * 8. Xóa toàn bộ giỏ hàng
+ */
+export function clearCart(): boolean {
+ if (!getCartItems().length) return false;
+
+ /**
+ * await cartApi.clear()
+ */
+ notifyCartChange();
+ return true;
}
-// 8. Lấy cartQuantity của 1 sản phẩm
+/**
+ * 9. Lấy số lượng sản phẩm trong giỏ
+ */
export function getProductQuantity(productId: number): number {
- const items = getCartItems();
- const item = items.find(item => item.id === productId);
- return item?.cartQuantity ?? 0;
+ return (
+ getCartItems().find(
+ item => item.item_info.id === productId
+ )?.in_cart.quantity ?? 0
+ );
}
-// 9. Kiểm tra sản phẩm có trong giỏ hàng không
-export function isProductInCart(productId: number): boolean {
- const items = getCartItems();
- return items.some(item => item.id === productId);
-}
+/* ================= EXPORT ================= */
-// 10. Export event name để hooks sử dụng
-export { CART_CHANGE_EVENT };
\ No newline at end of file
+export { CART_CHANGE_EVENT };
diff --git a/src/styles/pc_style.css b/src/styles/pc_style.css
index b19dc0e..25991dd 100644
--- a/src/styles/pc_style.css
+++ b/src/styles/pc_style.css
@@ -322,10 +322,12 @@ body{min-width:1248px;background:#E8ECF6}
.top-article-container .art-item .art-img{margin:0;width:192px;padding-bottom:130px}
.top-article-container .art-item .art-text{width:calc(100% - 204px)}
.article-categories-group {z-index: 12}
-.article-categories-group a{text-align:center;flex:1;padding-bottom:20px;position:relative}
-.article-categories-group a::after{content:"";position:absolute;left:0;bottom:0;right:0;max-width:100%;height:3px;background:transparent;transition:.25s all;width:0}
-.article-categories-group a:hover,.article-categories-group a.active{color:#0678DB}
-.article-categories-group a:hover::after,.article-categories-group a.active::after{background:#0678DB;width:100%}
+.article-categories-group a, .article-categories-group button{text-align:center;flex:1;padding-bottom:20px;position:relative;cursor: pointer;}
+.article-categories-group a::after, .article-categories-group button::after{content:"";position:absolute;left:0;bottom:0;right:0;max-width:100%;height:3px;background:transparent;transition:.25s all;width:0}
+.article-categories-group a:hover,.article-categories-group a.active,
+.article-categories-group button:hover,.article-categories-group button.active{color:#0678DB}
+.article-categories-group a:hover::after,.article-categories-group a.active::after,
+.article-categories-group button:hover::after,.article-categories-group button.active::after{background:#0678DB;width:100%}
.article-category-container{padding:64px 0}
.article-category-container:nth-child(even){background:#E8ECF6}
.article-category-container .art-summary{display:none}