Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
VCCI-News
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Văn Hoàng
VCCI-News
Commits
6c996526
Commit
6c996526
authored
Nov 04, 2025
by
Vũ Đình Nguyên
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update api
parent
fd08a77c
Changes
31
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
552 additions
and
85 deletions
+552
-85
page.tsx
src/app/(main)/(home)/[id]/page.tsx
+1
-1
MenuItem.tsx
src/app/(main)/_lib/layout/MenuItem.tsx
+32
-19
footer.tsx
src/app/(main)/_lib/layout/footer.tsx
+2
-2
header.tsx
src/app/(main)/_lib/layout/header.tsx
+90
-37
page.tsx
src/app/(main)/dai-dien-gioi-chu/chu-de/[id]/page.tsx
+4
-0
page.tsx
src/app/(main)/dai-dien-gioi-chu/chu-de/page.tsx
+2
-1
index.tsx
...p/(main)/dai-dien-gioi-chu/components/card-news/index.tsx
+19
-3
sampleHtml.ts
src/app/(main)/dai-dien-gioi-chu/lib/sampleHtml.ts
+1
-1
page.tsx
...app/(main)/dai-dien-gioi-chu/tap-huan-nsdld/[id]/page.tsx
+4
-0
page.tsx
src/app/(main)/dai-dien-gioi-chu/tin-lien-quan/[id]/page.tsx
+15
-7
page.tsx
src/app/(main)/dai-dien-gioi-chu/tin-lien-quan/page.tsx
+4
-3
page.tsx
src/app/(main)/hoat-dong/dao-tao/[id]/page.tsx
+4
-0
page.tsx
src/app/(main)/hoat-dong/su-kien/[id]/page.tsx
+4
-0
page.tsx
src/app/(main)/search/page.tsx
+102
-0
mock-data.ts
src/app/(main)/site-map/_lib/mock-data.ts
+94
-0
page.tsx
src/app/(main)/site-map/page.tsx
+103
-0
page.tsx
...app/(main)/thong-tin-truyen-thong/chuyen-de/[id]/page.tsx
+4
-0
page.tsx
...yen-thong/thong-tin-chinh-sach-va-phap-luat/[id]/page.tsx
+4
-0
page.tsx
...n)/thong-tin-truyen-thong/thu-vien-tai-lieu/[id]/page.tsx
+4
-0
page.tsx
...in)/thong-tin-truyen-thong/tin-doanh-nghiep/[id]/page.tsx
+4
-0
page.tsx
...p/(main)/thong-tin-truyen-thong/tin-kinh-te/[id]/page.tsx
+4
-0
page.tsx
src/app/(main)/thong-tin-truyen-thong/tin-vcci/[id]/page.tsx
+4
-0
page.tsx
src/app/(main)/xuat-xu-hang-hoa/page.tsx
+1
-1
page.tsx
src/app/(main)/xuc-tien-thuong-mai/[id]/page.tsx
+4
-0
page.tsx
...main)/xuc-tien-thuong-mai/co-hoi-kinh-doanh/[id]/page.tsx
+4
-0
page.tsx
...app/(main)/xuc-tien-thuong-mai/co-hoi-kinh-doanh/page.tsx
+2
-1
page.tsx
...main)/xuc-tien-thuong-mai/ho-tro-kinh-doanh/[id]/page.tsx
+4
-0
page.tsx
...app/(main)/xuc-tien-thuong-mai/ho-tro-kinh-doanh/page.tsx
+2
-1
page.tsx
...)/xuc-tien-thuong-mai/moi-truong-kinh-doanh/[id]/page.tsx
+4
-0
page.tsx
...(main)/xuc-tien-thuong-mai/moi-truong-kinh-doanh/page.tsx
+2
-1
index.tsx
src/components/base/card-news/index.tsx
+24
-7
No files found.
src/app/(main)/(home)/[id]/page.tsx
View file @
6c996526
...
...
@@ -41,7 +41,7 @@ const NewsDetailPage = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-5"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-7"
>
<
div
className=
'pb-5 text-
blue-900
text-2xl leading-normal font-medium'
>
<
div
className=
'pb-5 text-
primary
text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
div
className=
'flex items-center gap-2 text-sm mb-4'
>
...
...
src/app/(main)/_lib/layout/MenuItem.tsx
View file @
6c996526
const
MenuItem
=
({
title
,
items
,
link
}:
{
title
:
string
;
items
:
string
[];
link
?:
string
})
=>
(
<
div
className=
"group relative"
>
<
a
className=
"px-3 py-5 text-[16px] font-[600] text-[#124588] hover:text-[#E8C518] transition block"
href=
{
`/${link}`
}
>
{
title
}
</
a
>
<
div
className=
"absolute left-0 top-full hidden group-hover:block bg-[#124588]/98 text-white text-[14px] font-[500] min-w-[220px] shadow-lg"
>
{
items
.
map
((
item
,
i
)
=>
(
<
div
key=
{
i
}
className=
"px-5 py-3 hover:bg-[#e8c518]/80 cursor-pointer whitespace-nowrap"
>
{
item
}
</
div
>
))
}
import
Link
from
"next/link"
;
type
MenuItemProps
=
{
title
:
string
;
link
?:
string
;
items
:
{
title
:
string
;
link
:
string
}[];
};
const
MenuItem
=
({
title
,
link
,
items
}:
MenuItemProps
)
=>
{
return
(
<
div
className=
"group relative"
>
<
Link
href=
{
`/${link || ""}`
}
className=
"px-3 py-5 text-[16px] font-[600] text-[#124588] hover:text-[#E8C518] transition block"
>
{
title
}
</
Link
>
{
/* Dropdown */
}
<
div
className=
"absolute left-0 top-full hidden group-hover:block bg-[#124588]/98 text-white text-[14px] font-[500] min-w-[220px] shadow-lg"
>
{
items
.
map
((
item
,
i
)
=>
(
<
Link
key=
{
i
}
href=
{
`/${link}/${item.link}`
}
className=
"block px-5 py-3 hover:bg-[#e8c518]/80 cursor-pointer whitespace-nowrap transition"
>
{
item
.
title
}
</
Link
>
))
}
</
div
>
</
div
>
</
div
>
)
;
);
}
;
export
default
MenuItem
;
src/app/(main)/_lib/layout/footer.tsx
View file @
6c996526
...
...
@@ -14,7 +14,7 @@ import {
import
Image
from
"next/image"
;
import
vietnamMap
from
"@/assets/vietnam-map-white.png.webp"
;
function
f
ooter
()
{
function
F
ooter
()
{
const
emailRef
=
useRef
<
HTMLInputElement
>
(
null
);
const
checkBoxRef
=
useRef
<
HTMLInputElement
>
(
null
);
const
[
emailError
,
setEmailError
]
=
useState
(
false
);
...
...
@@ -212,4 +212,4 @@ function footer() {
);
}
export
default
f
ooter
;
export
default
F
ooter
;
src/app/(main)/_lib/layout/header.tsx
View file @
6c996526
"use client"
;
import
React
,
{
useState
}
from
"react"
;
import
{
useRouter
}
from
'next/navigation'
import
{
Menu
,
X
,
Facebook
,
Linkedin
,
Twitter
,
Youtube
}
from
"lucide-react"
;
import
logo
from
"@/assets/VCCI-HCM-logo-VN-2025.png"
;
import
Image
from
"next/image"
;
import
MenuItem
from
"./MenuItem"
;
import
Link
from
"next/link"
;
function
Header
()
{
const
[
toggleMenu
,
setToggleMenu
]
=
useState
<
boolean
>
(
false
);
const
router
=
useRouter
()
return
(
<>
...
...
@@ -25,7 +27,7 @@ function Header() {
className=
"px-3 py-2 text-[14px] text-white hover:opacity-80"
href=
"#"
>
s
itemap
S
itemap
</
a
>
<
a
className=
"px-3 py-2 text-[14px] text-white hover:opacity-80"
...
...
@@ -40,6 +42,13 @@ function Header() {
className=
"bg-white h-12 rounded-sm outline-none px-4 w-64 placeholder:text-sm"
type=
"text"
placeholder=
"Tìm kiếm"
onKeyDown=
{
(
e
)
=>
{
if
(
e
.
key
===
'Enter'
)
{
const
value
=
(
e
.
currentTarget
as
HTMLInputElement
).
value
||
''
const
encoded
=
encodeURIComponent
(
value
)
router
.
push
(
`/search?q=${encoded}`
)
}
}
}
/>
<
div
className=
"flex gap-2"
>
{
[
Facebook
,
Twitter
,
Youtube
,
Linkedin
].
map
((
Icon
,
i
)
=>
(
...
...
@@ -56,17 +65,17 @@ function Header() {
</
div
>
</
div
>
<
div
className=
"sticky top-0 z-50 bg-[#ededed] shadow-md"
>
<
div
className=
"sticky top-0 z-50 bg-[#ededed] shadow-md
py-4
"
>
<
div
className=
"container m-auto"
>
<
div
className=
"w-full flex justify-between items-center"
>
{
/* Logo */
}
<
a
href=
"/"
className=
"flex items-center
"
>
<
Link
href=
"/
"
>
<
Image
className=
"w-[140px] object-contain
lg:ml-0 ml-10
"
className=
"w-[140px] object-contain"
src=
{
logo
}
alt=
"VCCI HCM"
/>
</
a
>
</
Link
>
{
/* Desktop Menu */
}
<
nav
className=
"hidden lg:flex items-center"
>
...
...
@@ -75,38 +84,74 @@ function Header() {
title=
"Giới thiệu"
link=
"gioi-thieu"
items=
{
[
"Về VCCI-HCM"
,
"Chức Năng Và Nhiệm Vụ"
,
"Sơ Đồ Tổ Chức"
,
"Dịch Vụ Cung Cấp"
,
{
title
:
"Về VCCI-HCM"
,
link
:
"ve-vcci-hcm"
},
{
title
:
"Chức Năng Và Nhiệm Vụ"
,
link
:
"chuc-nang-va-nhiem-vu"
,
},
{
title
:
"Sơ Đồ Tổ Chức"
,
link
:
"so-do-to-chuc"
},
{
title
:
"Dịch Vụ Cung Cấp"
,
link
:
"dich-vu-cung-cap"
},
]
}
/>
<
MenuItem
title=
"Hội viên"
link=
"hoi-vien"
items=
{
[
"Lợi Ích Của Hội Viên VCCI"
,
"Đăng Ký Hội Viên"
,
"Kết Nối Hội Viên"
,
"Tin Hội Viên"
,
items=
{
[
{
title
:
"Lợi Ích Của Hội Viên VCCI"
,
link
:
""
,
},
{
title
:
"Đăng Ký Hội Viên"
,
link
:
"dang-ky-hoi-vien"
},
{
title
:
"Kết Nối Hội Viên"
,
link
:
"ket-noi-hoi-vien"
},
{
title
:
"Tin Hội Viên"
,
link
:
"tin-hoi-vien"
},
]
}
/>
<
MenuItem
title=
"Hoạt động"
link=
"hoat-dong"
items=
{
[
"Sự Kiện"
,
"Đào Tạo"
]
}
/>
items=
{
[
{
title
:
"Sự Kiện"
,
link
:
""
},
{
title
:
"Đào Tạo"
,
link
:
"dao-tao"
},
]
}
/>
<
MenuItem
title=
"Xuất Xứ Hàng Hóa"
link=
"xuat-xu-hang-hoa"
items=
{
[
"Định Nghĩa Chung"
,
"Mục Đích Của C/O"
,
"Luật Áp Dụng Về C/O"
,
"Thủ Tục Cấp C/O"
,
"Biểu Mẫu C/O Và Cách Khai"
,
"Phí Và Lệ Phí Cấp C/O"
,
"Điểm Cấp Và Thời Gian Cấp C/O"
,
"Thông Tin Liên Hệ"
,
{
title
:
"Định Nghĩa Chung"
,
link
:
""
,
},
{
title
:
"Mục Đích Của C/O"
,
link
:
"muc-dich"
,
},
{
title
:
"Luật Áp Dụng Về C/O"
,
link
:
"luat-ap-dung"
,
},
{
title
:
"Thủ Tục Cấp C/O"
,
link
:
"thu-tuc-cap"
,
},
{
title
:
"Biểu Mẫu C/O Và Cách Khai"
,
link
:
"bieu-mau-c-o-va-cach-khai"
,
},
{
title
:
"Phí Và Lệ Phí Cấp C/O"
,
link
:
"phi-va-le-phi-cap"
,
},
{
title
:
"Điểm Cấp Và Thời Gian Cấp C/O"
,
link
:
"diem-cap-va-thoi-gian-cap"
,
},
{
title
:
"Thông Tin Liên Hệ"
,
link
:
"thong-tin-lien-he"
,
},
]
}
/>
...
...
@@ -153,25 +198,33 @@ function Header() {
<
MenuItem
title=
"Xúc tiến thương mại"
link=
"xuc-tien-thuong-mai"
items=
{
[
"Hồ Sơ Thị Trường"
,
"Môi Trường Kinh Doanh"
,
"Cơ Hội Kinh Doanh"
,
"Hỗ Trợ Kinh Doanh"
,
items=
{
[
{
title
:
"Hồ Sơ Thị Trường"
,
link
:
"ho-so-thi-truong"
},
{
title
:
"Môi Trường Kinh Doanh"
,
link
:
"moi-truong-kinh-doanh"
,
},
{
title
:
"Cơ Hội Kinh Doanh"
,
link
:
"co-hoi-kinh-doanh"
},
{
title
:
"Hỗ Trợ Kinh Doanh"
,
link
:
"ho-tro-kinh-doanh"
},
]
}
/>
<
MenuItem
title=
"Thông tin truyền thông"
link=
"thong-tin-truyen-thong"
items=
{
[
"Tin VCCI"
,
"Tin Kinh Tế"
,
"Tin Doanh Nghiệp"
,
"Chuyên Đề"
,
"Thông Tin Chính Sách Và Pháp Luật"
,
"Ấn Phẩm"
,
"Thư Viện Tài Liệu"
,
items=
{
[
{
title
:
"Tin VCCI"
,
link
:
"tin-vcci"
},
{
title
:
"Tin Kinh Tế"
,
link
:
"tin-kinh-te"
},
{
title
:
"Tin Doanh Nghiệp"
,
link
:
"tin-doanh-nghiep"
},
{
title
:
"Chuyên Đề"
,
link
:
"chuyen-de"
},
{
title
:
"Thông Tin Chính Sách Và Pháp Luật"
,
link
:
"thong-tin-chinh-sach-va-phap-luat"
,
},
{
title
:
"Ấn Phẩm"
,
link
:
"an-pham"
},
{
title
:
"Thư Viện Tài Liệu"
,
link
:
"thu-vien-tai-lieu"
},
]
}
/>
</
nav
>
...
...
src/app/(main)/dai-dien-gioi-chu/chu-de/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/dai-dien-gioi-chu/chu-de/page.tsx
View file @
6c996526
...
...
@@ -17,7 +17,8 @@ export default function Page() {
const
{
data
:
allData
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
String
(
pageSize
),
currentPage
:
String
(
page
),
filters
:
submitSearch
?
`title @=
${
submitSearch
}
`
:
undefined
,
// filters: submitSearch ? `title @=${submitSearch}` : undefined,
filters
:
'category@=Chủ đề'
});
return
(
<
div
className=
"min-h-screen container mx-auto p-4"
>
...
...
src/app/(main)/dai-dien-gioi-chu/components/card-news/index.tsx
View file @
6c996526
...
...
@@ -2,7 +2,23 @@
import
{
NewsItem
}
from
'@app/dai-dien-gioi-chu/lib/types/NewsPage.type'
;
import
Links
from
'@links/index'
import
dayjs
from
'dayjs'
;
import
parse
from
'html-react-parser'
// Helper: remove <img> tags and extract plain text from HTML
const
stripImagesAndHtml
=
(
html
?:
string
)
=>
{
if
(
!
html
)
return
''
// remove img tags first
const
withoutImgs
=
html
.
replace
(
/<img
[^
>
]
*>/gi
,
''
)
// use DOMParser on client for robust extraction
if
(
typeof
window
!==
'undefined'
&&
typeof
DOMParser
!==
'undefined'
)
{
try
{
const
doc
=
new
DOMParser
().
parseFromString
(
withoutImgs
,
'text/html'
)
return
doc
.
body
.
textContent
||
''
}
catch
{
// fallback to regex
}
}
return
withoutImgs
.
replace
(
/<
[^
>
]
*>/g
,
''
)
}
function
NewsContent
({
news
,
link
}:
{
news
:
NewsItem
,
link
:
string
})
{
return
(
...
...
@@ -21,14 +37,14 @@ function NewsContent({ news ,link}: { news: NewsItem ,link:string}) {
/>
<
div
className=
"flex-1 min-w-0 pl-0 sm:pl-4"
>
<
p
className=
"text-primary font-semibold text-base md:text-lg hover:underline line-clamp-2 wrap-break-word hover:no-underline
"
>
<
p
className=
"text-primary font-semibold text-base md:text-lg hover:underline line-clamp-2 wrap-break-word
"
>
{
news
.
title
}
</
p
>
<
div
className=
"text-sm my-2 text-[#00AED5]"
>
{
dayjs
(
news
.
release_at
).
format
(
'DD/MM/YYYY'
)
}
</
div
>
<
div
className=
"text-sm text-[#777] line-clamp-3"
>
<
div
className=
"text-sm prose tiptap"
>
{
parse
(
news
.
description
)
}
</
div
>
<
div
className=
"text-sm prose tiptap"
>
{
stripImagesAndHtml
(
news
.
description
)
}
</
div
>
</
div
>
</
div
>
</
a
>
...
...
src/app/(main)/dai-dien-gioi-chu/lib/sampleHtml.ts
View file @
6c996526
export
const
SAMPLE_HTML
=
`
<div class="document">
<h1
style="font-size:18px; font-weight:700; margin-bottom:8
px;">Chức năng Đại diện Người sử dụng lao động</h1>
<h1
class="text-primary" style="font-size:20px; font-weight:700; margin-bottom:12
px;">Chức năng Đại diện Người sử dụng lao động</h1>
<p>Chức năng Đại diện Người sử dụng lao động (NSDLĐ):</p>
...
...
src/app/(main)/dai-dien-gioi-chu/tap-huan-nsdld/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/dai-dien-gioi-chu/tin-lien-quan/[id]/page.tsx
View file @
6c996526
...
...
@@ -4,23 +4,31 @@ import Image from "next/image";
import
ListCategory
from
"../../components/list-category"
;
import
{
OWNER_REPRESENTATIVES_CATEGORIES
}
from
"@constants/categories"
;
import
ListFilter
from
"../../components/list-filter"
;
import
{
useGetNewsId
}
from
'@/api/endpoints/news'
;
import
{
useGetNewsId
}
from
"@/api/endpoints/news"
;
import
parse
from
"html-react-parser"
;
import
{
useParams
}
from
'next/navigation'
import
{
GetNewsDetailResponseType
}
from
'@lib/types/news-detail-response-data'
;
import
{
useParams
}
from
"next/navigation"
;
import
{
GetNewsDetailResponseType
}
from
"@lib/types/news-detail-response-data"
;
// ...existing code...
const
Page
:
React
.
FC
=
()
=>
{
const
{
id
}
=
useParams
()
const
{
data
,
isLoading
}
=
useGetNewsId
<
GetNewsDetailResponseType
>
(
id
as
string
)
const
{
id
}
=
useParams
();
const
{
data
,
isLoading
}
=
useGetNewsId
<
GetNewsDetailResponseType
>
(
id
as
string
);
return
(
<
div
className=
"min-h-screen w-full container mx-auto p-4"
>
<
div
className=
"w-full flex flex-col gap-5"
>
<
ListCategory
categories=
{
OWNER_REPRESENTATIVES_CATEGORIES
}
/>
<
ListCategory
categories=
{
OWNER_REPRESENTATIVES_CATEGORIES
}
/>
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
<
div
className=
"pb-5 text-primary text-2xl leading-normal font-medium"
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
""
)
}
</
div
>
</
main
>
{
/* Sidebar */
}
...
...
src/app/(main)/dai-dien-gioi-chu/tin-lien-quan/page.tsx
View file @
6c996526
...
...
@@ -10,13 +10,14 @@ import { useGetNews } from "@api/endpoints/news";
import
{
GetNewsResponseType
}
from
"@api/types/NewsPage.type"
;
import
{
PATHS
}
from
"@constants/paths"
;
export
default
function
Page
()
{
const
[
submitSearch
]
=
useState
(
""
);
const
[
submitSearch
,
setsubmitSearch
]
=
useState
(
""
);
const
[
page
,
setPage
]
=
useState
(
1
);
const
pageSize
=
5
;
const
{
data
:
allData
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
String
(
pageSize
),
currentPage
:
String
(
page
),
filters
:
submitSearch
?
`title @=
${
submitSearch
}
`
:
undefined
,
filters
:
submitSearch
?
`title @=
${
submitSearch
}
,category@=Tin liên quan`
:
'category@=Tin liên quan'
,
});
return
(
<
div
className=
"min-h-screen container mx-auto p-4"
>
...
...
@@ -45,7 +46,7 @@ export default function Page() {
{
/* Sidebar */
}
<
aside
className=
"space-y-6 order-first lg:order-last"
>
<
ListFilter
/>
<
ListFilter
onSearch=
{
setsubmitSearch
}
/>
<
div
className=
"bg-white border rounded-md overflow-hidden hidden lg:block"
>
<
div
className=
"w-full h-56 relative bg-gray-100"
>
...
...
src/app/(main)/hoat-dong/dao-tao/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/hoat-dong/su-kien/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/search/page.tsx
0 → 100644
View file @
6c996526
"use client"
;
import
React
,
{
useState
,
Suspense
}
from
"react"
;
import
ListCategory
from
"@app/dai-dien-gioi-chu/components/list-category"
;
import
{
OWNER_REPRESENTATIVES_CATEGORIES
}
from
"@constants/categories"
;
import
ListFilter
from
"@app/dai-dien-gioi-chu/components/list-filter"
;
import
NewsContent
from
"@app/dai-dien-gioi-chu/components/card-news"
;
import
{
Pagination
}
from
"@components/base/pagination"
;
import
Image
from
"next/image"
;
import
{
useGetNews
}
from
"@api/endpoints/news"
;
import
{
GetNewsResponseType
}
from
"@api/types/NewsPage.type"
;
import
{
PATHS
}
from
"@constants/paths"
;
import
{
useSearchParams
}
from
'next/navigation'
function
SearchContent
()
{
const
[
page
,
setPage
]
=
useState
(
1
);
const
searchParams
=
useSearchParams
()
const
query
=
searchParams
.
get
(
'q'
)
//
const
pageSize
=
5
;
const
{
data
:
allData
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
String
(
pageSize
),
currentPage
:
String
(
page
),
filters
:
query
?
`title @=
${
query
}
`
:
undefined
,
});
return
(
<
div
className=
"min-h-screen container mx-auto p-4"
>
<
div
className=
"w-full flex flex-col gap-5"
>
<
div
className=
"border-t border-gray-200 bg-white p-2.5"
>
<
div
className=
"w-full px-4 sm:px-6 lg:px-8"
>
<
div
className=
"py-3"
>
<
h1
className=
"text-md md:text-lg font-semibold leading-6 text-gray-900"
>
{
" "
}
Search Results for:
{
query
}
</
h1
>
</
div
>
</
div
>
</
div
>
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-background "
>
<
div
className=
"pb-5 overflow-hidden"
>
{
allData
?.
responseData
.
rows
.
map
((
news
)
=>
(
<
NewsContent
key=
{
news
.
id
}
news=
{
news
}
link=
{
`${PATHS.mediaInformation}/tin-vcci/${news.id}`
}
/>
))
}
<
div
className=
"w-full flex justify-center mt-4"
>
<
Pagination
pageCount=
{
Number
(
allData
?.
responseData
.
totalPages
??
1
)
}
page=
{
Number
(
allData
?.
responseData
.
currentPage
??
page
)
}
onChangePage=
{
(
p
)
=>
setPage
(
p
)
}
onGoToPreviousPage=
{
()
=>
setPage
(
Math
.
max
(
1
,
page
-
1
))
}
onGoToNextPage=
{
()
=>
setPage
(
Math
.
min
(
Number
(
allData
?.
responseData
.
totalPages
??
1
),
page
+
1
)
)
}
/>
</
div
>
</
div
>
</
main
>
{
/* Sidebar */
}
<
aside
className=
"space-y-6 order-first lg:order-last"
>
<
div
className=
"bg-white border rounded-md overflow-hidden hidden lg:block"
>
<
div
className=
"w-full h-62 relative bg-gray-100"
>
<
Image
src=
"/banner.webp"
alt=
"Quảng cáo"
fill
className=
"object-cover"
/>
</
div
>
</
div
>
</
aside
>
</
div
>
</
div
>
</
div
>
);
}
export
default
function
Page
()
{
return
(
<
Suspense
fallback=
{
<
div
className=
"min-h-screen container mx-auto p-4 flex items-center justify-center"
>
<
div
className=
"text-center"
>
<
div
className=
"animate-spin rounded-full h-12 w-12 border-b-2 border-[#063e8e] mx-auto"
></
div
>
<
p
className=
"mt-4 text-gray-600"
>
Loading search results...
</
p
>
</
div
>
</
div
>
}
>
<
SearchContent
/>
</
Suspense
>
);
}
src/app/(main)/site-map/_lib/mock-data.ts
0 → 100644
View file @
6c996526
export
type
SiteMapItem
=
{
label
:
string
;
url
:
string
;
children
?:
SiteMapItem
[];
};
export
const
MOCK_SITEMAP
:
SiteMapItem
[]
=
[
{
label
:
"Trang chủ"
,
url
:
"/homepage"
,
children
:
[]
},
{
label
:
"Giới thiệu"
,
url
:
"/gioi-thieu"
,
children
:
[
{
label
:
"Về VCCI-HCM"
,
url
:
"/gioi-thieu/ve-vcci-hcm"
,
children
:
[]
},
{
label
:
"Chức năng và nhiệm vụ"
,
url
:
"/gioi-thieu/chuc-nang-nhiem-vu"
,
children
:
[]
},
{
label
:
"Sơ đồ tổ chức"
,
url
:
"/gioi-thieu/so-do-to-chuc"
,
children
:
[]
},
{
label
:
"Dịch vụ cung cấp"
,
url
:
"/gioi-thieu/dich-vu-cung-cap"
,
children
:
[]
},
],
},
{
label
:
"Hội viên"
,
url
:
"/hoi-vien"
,
children
:
[
{
label
:
"Lợi ích của hội viên VCCI"
,
url
:
"/hoi-vien/loi-ich-hoi-vien"
,
children
:
[]
},
{
label
:
"Đăng ký hội viên"
,
url
:
"/hoi-vien/dang-ky-hoi-vien"
,
children
:
[]
},
{
label
:
"Kết nối hội viên"
,
url
:
"/hoi-vien/ket-noi-hoi-vien"
,
children
:
[]
},
{
label
:
"Tin hội viên"
,
url
:
"/hoi-vien/tin-hoi-vien"
,
children
:
[]
},
],
},
{
label
:
"Hoạt động"
,
url
:
"/hoat-dong"
,
children
:
[
{
label
:
"Sự kiện"
,
url
:
"/hoat-dong/su-kien"
,
children
:
[]
},
{
label
:
"Đào tạo"
,
url
:
"/hoat-dong/dao-tao"
,
children
:
[]
},
],
},
{
label
:
"Xuất xứ hàng hóa"
,
url
:
"/xuat-xu-hang-hoa"
,
children
:
[
{
label
:
"Định nghĩa chung"
,
url
:
"/xuat-xu-hang-hoa"
,
children
:
[]
},
{
label
:
"Mục đích của C/O"
,
url
:
"/xuat-xu-hang-hoa/muc-dich-co"
,
children
:
[]
},
{
label
:
"Luật áp dụng về C/O"
,
url
:
"/xuat-xu-hang-hoa/luat-ap-dung-co"
,
children
:
[]
},
{
label
:
"Thủ tục cấp C/O"
,
url
:
"/xuat-xu-hang-hoa/thu-tuc-cap-co"
,
children
:
[]
},
{
label
:
"Biểu mẫu C/O và cách khai"
,
url
:
"/xuat-xu-hang-hoa/bieu-mau-co"
,
children
:
[]
},
{
label
:
"Phí và lệ phí cấp C/O"
,
url
:
"/xuat-xu-hang-hoa/phi-le-phi-cap-co"
,
children
:
[]
},
{
label
:
"Điểm cấp và thời gian cấp C/O"
,
url
:
"/xuat-xu-hang-hoa/diem-cap-thoi-gian"
,
children
:
[]
},
{
label
:
"Thông tin liên hệ"
,
url
:
"/xuat-xu-hang-hoa/lien-he"
,
children
:
[]
},
],
},
{
label
:
"Đại diện giới chủ"
,
url
:
"/dai-dien-gioi-chu"
,
children
:
[
{
label
:
"Chức năng đại diện người sử dụng lao động"
,
url
:
"/dai-dien-gioi-chu/chuc-nang"
,
children
:
[]
},
{
label
:
"Sự kiện - tập huấn NSDLĐ"
,
url
:
"/dai-dien-gioi-chu/su-kien-tap-huan"
,
children
:
[]
},
{
label
:
"Tin liên quan"
,
url
:
"/dai-dien-gioi-chu/tin-lien-quan"
,
children
:
[]
},
{
label
:
"Chủ đề"
,
url
:
"/dai-dien-gioi-chu/chu-de"
,
children
:
[]
},
],
},
{
label
:
"Xúc tiến thương mại"
,
url
:
"/xuc-tien-thuong-mai"
,
children
:
[
{
label
:
"Hồ sơ thị trường"
,
url
:
"/xuc-tien-thuong-mai/ho-so-thi-truong"
,
children
:
[]
},
{
label
:
"Môi trường kinh doanh"
,
url
:
"/xuc-tien-thuong-mai/doi-song-kinh-doanh"
,
children
:
[]
},
{
label
:
"Cơ hội kinh doanh"
,
url
:
"/xuc-tien-thuong-mai/co-hoi-kinh-doanh"
,
children
:
[]
},
{
label
:
"Hỗ trợ kinh doanh"
,
url
:
"/xuc-tien-thuong-mai/ho-tro-kinh-doanh"
,
children
:
[]
},
],
},
{
label
:
"Thông tin truyền thông"
,
url
:
"/thong-tin-truyen-thong"
,
children
:
[
{
label
:
"Tin VCCI"
,
url
:
"/thong-tin-truyen-thong/tin-vcci"
,
children
:
[]
},
{
label
:
"Tin kinh tế"
,
url
:
"/thong-tin-truyen-thong/tin-kinh-te"
,
children
:
[]
},
{
label
:
"Tin doanh nghiệp"
,
url
:
"/thong-tin-truyen-thong/tin-doanh-nghiep"
,
children
:
[]
},
{
label
:
"Chuyên đề"
,
url
:
"/thong-tin-truyen-thong/chuyen-de"
,
children
:
[]
},
{
label
:
"Thông tin chính sách và pháp luật"
,
url
:
"/thong-tin-truyen-thong/chinh-sach-phap-luat"
,
children
:
[]
},
{
label
:
"Ấn phẩm"
,
url
:
"/thong-tin-truyen-thong/an-pham"
,
children
:
[]
},
{
label
:
"Thư viện tài liệu"
,
url
:
"/thong-tin-truyen-thong/thu-vien-tai-lieu"
,
children
:
[]
},
],
},
];
export
default
MOCK_SITEMAP
;
src/app/(main)/site-map/page.tsx
0 → 100644
View file @
6c996526
"use client"
;
import
React
from
"react"
;
import
{
MOCK_SITEMAP
}
from
"./_lib/mock-data"
;
import
Link
from
"next/link"
;
function
SiteMapPage
()
{
const
homepage
=
MOCK_SITEMAP
[
0
];
const
sections
=
MOCK_SITEMAP
.
slice
(
1
);
return
(
<
div
className=
"min-h-screen bg-gray-50 py-12"
>
<
div
className=
"container mx-auto px-4"
>
<
h1
className=
"text-3xl font-bold text-center mb-12 text-[#063e8e]"
>
SƠ ĐỒ TRANG WEB
</
h1
>
{
/* Sitemap Structure */
}
<
div
className=
"relative flex flex-col items-center"
>
{
/* Homepage - Top Level */
}
<
div
className=
"relative mb-20"
>
<
Link
href=
{
homepage
.
url
}
className=
"block bg-[#063e8e] text-white px-8 py-4 rounded-lg font-semibold text-center hover:bg-[#0a4fb5] transition shadow-lg min-w-[200px]"
>
{
homepage
.
label
.
toUpperCase
()
}
</
Link
>
{
/* Vertical line from homepage down */
}
<
div
className=
"absolute left-1/2 -translate-x-1/2 top-full h-16 w-0.5 bg-gray-600"
></
div
>
</
div
>
{
/* Main Sections - Second Level */
}
<
div
className=
"relative w-full max-w-[1400px]"
>
{
/* Horizontal line connecting all sections */
}
<
div
className=
"absolute top-0 left-[7%] right-[7%] h-0.5 bg-gray-600 z-0"
></
div
>
<
div
className=
"grid grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-6 relative pt-4"
>
{
sections
.
map
((
section
,
idx
)
=>
(
<
div
key=
{
idx
}
className=
"relative flex flex-col items-center"
>
{
/* Vertical line from horizontal bar down to section */
}
<
div
className=
"absolute -top-4 left-1/2 -translate-x-1/2 h-4 w-0.5 bg-gray-600 z-10"
></
div
>
{
/* Section Box */
}
<
div
className=
"relative z-20"
>
<
Link
href=
{
section
.
url
}
className=
"flex bg-[#063e8e] text-white px-4 py-3 rounded-md font-medium text-center hover:bg-[#0a4fb5] transition shadow-md w-full text-sm min-h-20 items-center justify-center"
>
<
span
className=
"leading-tight"
>
{
section
.
label
.
toUpperCase
()
}
</
span
>
</
Link
>
{
/* Vertical line from section down to children */
}
{
section
.
children
&&
section
.
children
.
length
>
0
&&
(
<
div
className=
"absolute left-1/2 -translate-x-1/2 top-full h-6 w-0.5 bg-gray-600 z-10"
></
div
>
)
}
</
div
>
{
/* Children - Third Level */
}
{
section
.
children
&&
section
.
children
.
length
>
0
&&
(
<
div
className=
"mt-6 flex flex-col gap-3 w-full relative z-20"
>
{
section
.
children
.
map
((
child
,
childIdx
)
=>
(
<
div
key=
{
childIdx
}
className=
"relative"
>
{
/* Vertical line connecting child to parent */
}
{
childIdx
===
0
?
(
// First child connects to the line from parent
<
div
className=
"absolute left-1/2 -translate-x-1/2 -top-6 h-6 w-0.5 bg-gray-600"
></
div
>
)
:
(
// Other children connect to the vertical spine
<
div
className=
"absolute left-1/2 -translate-x-1/2 -top-[calc(1.5rem+0.375rem)] bottom-1/2 w-0.5 bg-gray-600"
></
div
>
)
}
{
/* Horizontal line from spine to child box */
}
<
div
className=
"absolute left-1/2 top-1/2 -translate-y-1/2 w-1/2 h-0.5 bg-gray-600 -translate-x-full"
></
div
>
<
Link
href=
{
child
.
url
}
className=
"block bg-gray-400 text-white px-3 py-2.5 rounded text-xs font-medium text-center hover:bg-gray-500 transition shadow-sm leading-tight relative z-10"
>
{
child
.
label
.
toUpperCase
()
}
</
Link
>
</
div
>
))
}
</
div
>
)
}
</
div
>
))
}
</
div
>
</
div
>
</
div
>
</
div
>
<
style
jsx
>
{
`
@media (max-width: 768px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
`
}
</
style
>
</
div
>
);
}
export
default
SiteMapPage
;
src/app/(main)/thong-tin-truyen-thong/chuyen-de/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/thong-tin-truyen-thong/thong-tin-chinh-sach-va-phap-luat/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/thong-tin-truyen-thong/thu-vien-tai-lieu/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/thong-tin-truyen-thong/tin-doanh-nghiep/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/thong-tin-truyen-thong/tin-kinh-te/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/thong-tin-truyen-thong/tin-vcci/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/xuat-xu-hang-hoa/page.tsx
View file @
6c996526
...
...
@@ -6,7 +6,7 @@ import Image from "next/image";
export
default
function
page
()
{
return
(
<
div
className=
"bg-[#f6f6f6]"
>
<
div
className=
"
max-w-[1200px]
m-auto flex flex-col gap-5 mb-[50px]"
>
<
div
className=
"
container
m-auto flex flex-col gap-5 mb-[50px]"
>
<
div
className=
"border-[#e5e7f2] border-[1px]"
>
<
ListCategory
/>
</
div
>
...
...
src/app/(main)/xuc-tien-thuong-mai/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/xuc-tien-thuong-mai/co-hoi-kinh-doanh/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/xuc-tien-thuong-mai/co-hoi-kinh-doanh/page.tsx
View file @
6c996526
...
...
@@ -17,7 +17,8 @@ export default function Page() {
const
{
data
:
allData
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
String
(
pageSize
),
currentPage
:
String
(
page
),
filters
:
submitSearch
?
`title @=
${
submitSearch
}
`
:
undefined
,
// filters: submitSearch ? `title @=${submitSearch}` : undefined,
filters
:
'category@=Cơ hội kinh doanh'
});
return
(
<
div
className=
"min-h-screen container mx-auto p-4"
>
...
...
src/app/(main)/xuc-tien-thuong-mai/ho-tro-kinh-doanh/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/xuc-tien-thuong-mai/ho-tro-kinh-doanh/page.tsx
View file @
6c996526
...
...
@@ -16,7 +16,8 @@ export default function Page() {
const
{
data
:
allData
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
String
(
pageSize
),
currentPage
:
String
(
page
),
filters
:
submitSearch
?
`title @=
${
submitSearch
}
`
:
undefined
,
// filters: submitSearch ? `title @=${submitSearch}` : undefined,
filters
:
'category@=Hỗ trợ kinh doanh'
});
return
(
<
div
className=
"min-h-screen container mx-auto p-4"
>
...
...
src/app/(main)/xuc-tien-thuong-mai/moi-truong-kinh-doanh/[id]/page.tsx
View file @
6c996526
...
...
@@ -20,6 +20,10 @@ const Page: React.FC = () => {
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-white border rounded-md p-6"
>
<
div
className=
'pb-5 text-primary text-2xl leading-normal font-medium'
>
{
data
?.
responseData
?.
title
}
</
div
>
<
hr
className=
"py-2"
/>
<
div
className=
"p-7.5 prose tiptap overflow-hidden"
>
{
parse
(
data
?.
responseData
?.
description
??
''
)
}
</
div
>
</
main
>
...
...
src/app/(main)/xuc-tien-thuong-mai/moi-truong-kinh-doanh/page.tsx
View file @
6c996526
...
...
@@ -17,7 +17,8 @@ export default function Page() {
const
{
data
:
allData
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
String
(
pageSize
),
currentPage
:
String
(
page
),
filters
:
submitSearch
?
`title @=
${
submitSearch
}
`
:
undefined
,
// filters: submitSearch ? `title @=${submitSearch}` : undefined,
filters
:
'category@=Môi trường kinh doanh'
});
return
(
<
div
className=
"min-h-screen container mx-auto p-4"
>
...
...
src/components/base/card-news/index.tsx
View file @
6c996526
...
...
@@ -2,8 +2,24 @@
import
{
NewsItem
}
from
'@app/dai-dien-gioi-chu/lib/types/NewsPage.type'
;
import
Links
from
'@links/index'
import
dayjs
from
'dayjs'
;
import
parse
from
'html-react-parser'
function
NewsContent
({
news
,
link
}:
{
news
:
NewsItem
,
link
:
string
})
{
// Helper: remove <img> tags and extract plain text from HTML
const
stripImagesAndHtml
=
(
html
?:
string
)
=>
{
if
(
!
html
)
return
''
// remove img tags first
const
withoutImgs
=
html
.
replace
(
/<img
[^
>
]
*>/gi
,
''
)
// use DOMParser on client for robust extraction
if
(
typeof
window
!==
'undefined'
&&
typeof
DOMParser
!==
'undefined'
)
{
try
{
const
doc
=
new
DOMParser
().
parseFromString
(
withoutImgs
,
'text/html'
)
return
doc
.
body
.
textContent
||
''
}
catch
{
// fallback to regex
}
}
return
withoutImgs
.
replace
(
/<
[^
>
]
*>/g
,
''
)
}
function
NewsContent
({
news
,
link
}:
{
news
:
NewsItem
,
link
:
string
})
{
return
(
<
a
...
...
@@ -14,20 +30,21 @@ function NewsContent({ news, link }: { news: NewsItem, link: string }) {
src=
{
`${Links.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
className=
"w-full sm:w-56 md:w-64 h-40 md:h-36 object-cover shrink-0"
onError=
{
(
e
)
=>
{
e
.
currentTarget
.
src
=
"/img-error.png"
}
}
onError=
{
(
e
)
=>
{
e
.
currentTarget
.
src
=
"/img-error.png"
}
}
/>
<
div
className=
"flex-1 min-w-0 pl-0 sm:pl-4"
>
<
p
className=
"text-primary font-semibold text-base md:text-lg line-clamp-2 wrap-break-word hover:no-underline
"
>
<
p
className=
"text-primary font-semibold text-base md:text-lg hover:underline line-clamp-2 wrap-break-word
"
>
{
news
.
title
}
</
p
>
<
div
className=
"text-sm my-2 text-[#00AED5]"
>
{
dayjs
(
news
.
release_at
).
format
(
'DD/MM/YYYY'
)
}
</
div
>
<
div
className=
"text-sm text-[#777] line-clamp-3"
>
<
div
className=
"text-sm prose tiptap"
>
{
parse
(
news
.
description
)
}
</
div
>
<
div
className=
"text-sm prose tiptap"
>
{
stripImagesAndHtml
(
news
.
description
)
}
</
div
>
</
div
>
</
div
>
</
a
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment