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
ec8c8834
Commit
ec8c8834
authored
Aug 10, 2026
by
Lê Bảo Hồng Đức
☄
Browse files
Options
Browse Files
Download
Plain Diff
[tag]0.1-vcci
parents
c0e482e8
379eb4cb
Pipeline
#52458
passed with stages
in 4 minutes and 19 seconds
Changes
9
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
55 additions
and
17 deletions
+55
-17
ArticlePage.tsx
src/app/(main)/[...slug]/templates/ArticlePage.tsx
+14
-2
CatalogPage.tsx
src/app/(main)/[...slug]/templates/CatalogPage.tsx
+13
-1
InformationPage.tsx
src/app/(main)/[...slug]/templates/InformationPage.tsx
+5
-3
MemberBenefitsPage.tsx
....slug]/templates/information-pages/MemberBenefitsPage.tsx
+1
-1
ServicePage.tsx
...in)/[...slug]/templates/information-pages/ServicePage.tsx
+1
-1
constants.ts
...(main)/[...slug]/templates/information-pages/constants.ts
+4
-2
Router.tsx
.../templates/information-pages/legal-trade-pages/Router.tsx
+5
-0
index.tsx
src/components/base/menu-item/index.tsx
+6
-1
categories.ts
src/mockdata/categories.ts
+6
-6
No files found.
src/app/(main)/[...slug]/templates/ArticlePage.tsx
View file @
ec8c8834
...
@@ -10,6 +10,7 @@ import ImageNext from "@/components/shared/image-next";
...
@@ -10,6 +10,7 @@ import ImageNext from "@/components/shared/image-next";
import
{
Button
}
from
"@/components/ui/button"
;
import
{
Button
}
from
"@/components/ui/button"
;
import
{
Input
}
from
"@/components/ui/input"
;
import
{
Input
}
from
"@/components/ui/input"
;
import
ListCategory
from
"@/components/base/list-category"
;
import
ListCategory
from
"@/components/base/list-category"
;
import
EventsCalendar
from
"@/app/(main)/(home)/components/events-calendar"
;
import
{
import
{
buildDynamicPostHref
,
buildDynamicPostHref
,
buildDynamicCategoryMenu
,
buildDynamicCategoryMenu
,
...
@@ -63,6 +64,15 @@ export default function ArticlePage({ category, allCategories }: ArticlePageProp
...
@@ -63,6 +64,15 @@ export default function ArticlePage({ category, allCategories }: ArticlePageProp
const
pageSize
=
10
;
const
pageSize
=
10
;
const
keyword
=
submitSearch
.
trim
();
const
keyword
=
submitSearch
.
trim
();
// Auto-search with debounce
useEffect
(()
=>
{
const
timer
=
setTimeout
(()
=>
{
setSubmitSearch
(
searchInput
);
setPage
(
1
);
},
500
);
return
()
=>
clearTimeout
(
timer
);
},
[
searchInput
]);
useEffect
(()
=>
{
useEffect
(()
=>
{
const
params
=
new
URLSearchParams
(
searchParamsString
);
const
params
=
new
URLSearchParams
(
searchParamsString
);
if
(
page
>
1
)
{
if
(
page
>
1
)
{
...
@@ -202,7 +212,7 @@ export default function ArticlePage({ category, allCategories }: ArticlePageProp
...
@@ -202,7 +212,7 @@ export default function ArticlePage({ category, allCategories }: ArticlePageProp
<
aside
className=
"contents xl:order-2 xl:block xl:w-[320px] xl:space-y-5 xl:pt-0"
>
<
aside
className=
"contents xl:order-2 xl:block xl:w-[320px] xl:space-y-5 xl:pt-0"
>
<
form
<
form
className=
"order-1 rounded-[22px] border border-[#edf1f5] bg-white p-5 shadow-[0_14px_34px_rgba(17,24,39,0.05)] xl:order-
none
"
className=
"order-1 rounded-[22px] border border-[#edf1f5] bg-white p-5 shadow-[0_14px_34px_rgba(17,24,39,0.05)] xl:order-
0
"
onSubmit=
{
(
event
)
=>
{
onSubmit=
{
(
event
)
=>
{
event
.
preventDefault
();
event
.
preventDefault
();
setPage
(
1
);
setPage
(
1
);
...
@@ -238,7 +248,9 @@ export default function ArticlePage({ category, allCategories }: ArticlePageProp
...
@@ -238,7 +248,9 @@ export default function ArticlePage({ category, allCategories }: ArticlePageProp
</
div
>
</
div
>
</
form
>
</
form
>
<
div
className=
"order-3 overflow-hidden rounded-[22px] shadow-[0_18px_42px_rgba(17,24,39,0.12)] xl:order-none"
>
<
EventsCalendar
compact
className=
"xl:w-full xl:min-w-0"
/>
<
div
className=
"order-3 overflow-hidden rounded-[22px] shadow-[0_18px_42px_rgba(17,24,39,0.12)] xl:order-0"
>
<
div
className=
"relative min-h-[390px] bg-[#1f334f]"
>
<
div
className=
"relative min-h-[390px] bg-[#1f334f]"
>
<
ImageNext
<
ImageNext
src=
"/banner.webp"
src=
"/banner.webp"
...
...
src/app/(main)/[...slug]/templates/CatalogPage.tsx
View file @
ec8c8834
...
@@ -10,6 +10,7 @@ import ImageNext from "@/components/shared/image-next";
...
@@ -10,6 +10,7 @@ import ImageNext from "@/components/shared/image-next";
import
{
Button
}
from
"@/components/ui/button"
;
import
{
Button
}
from
"@/components/ui/button"
;
import
{
Input
}
from
"@/components/ui/input"
;
import
{
Input
}
from
"@/components/ui/input"
;
import
ListCategory
from
"@/components/base/list-category"
;
import
ListCategory
from
"@/components/base/list-category"
;
import
EventsCalendar
from
"@/app/(main)/(home)/components/events-calendar"
;
import
{
import
{
buildDynamicPostHref
,
buildDynamicPostHref
,
buildDynamicCategoryMenu
,
buildDynamicCategoryMenu
,
...
@@ -37,6 +38,15 @@ export default function CatalogPage({ category, allCategories }: CatalogPageProp
...
@@ -37,6 +38,15 @@ export default function CatalogPage({ category, allCategories }: CatalogPageProp
const
pageSize
=
8
;
const
pageSize
=
8
;
const
keyword
=
submitSearch
.
trim
();
const
keyword
=
submitSearch
.
trim
();
// Auto-search with debounce
useEffect
(()
=>
{
const
timer
=
setTimeout
(()
=>
{
setSubmitSearch
(
searchInput
);
setPage
(
1
);
},
500
);
return
()
=>
clearTimeout
(
timer
);
},
[
searchInput
]);
useEffect
(()
=>
{
useEffect
(()
=>
{
const
params
=
new
URLSearchParams
(
searchParamsString
);
const
params
=
new
URLSearchParams
(
searchParamsString
);
if
(
page
>
1
)
{
if
(
page
>
1
)
{
...
@@ -140,7 +150,7 @@ export default function CatalogPage({ category, allCategories }: CatalogPageProp
...
@@ -140,7 +150,7 @@ export default function CatalogPage({ category, allCategories }: CatalogPageProp
<
aside
className=
"contents xl:order-2 xl:block xl:w-[320px] xl:space-y-5 xl:pt-0"
>
<
aside
className=
"contents xl:order-2 xl:block xl:w-[320px] xl:space-y-5 xl:pt-0"
>
<
form
<
form
className=
"order-1 rounded-[22px] border border-[#edf1f5] bg-white p-5 shadow-[0_14px_34px_rgba(17,24,39,0.05)] xl:order-
none
"
className=
"order-1 rounded-[22px] border border-[#edf1f5] bg-white p-5 shadow-[0_14px_34px_rgba(17,24,39,0.05)] xl:order-
0
"
onSubmit=
{
(
event
)
=>
{
onSubmit=
{
(
event
)
=>
{
event
.
preventDefault
();
event
.
preventDefault
();
setPage
(
1
);
setPage
(
1
);
...
@@ -176,6 +186,8 @@ export default function CatalogPage({ category, allCategories }: CatalogPageProp
...
@@ -176,6 +186,8 @@ export default function CatalogPage({ category, allCategories }: CatalogPageProp
</
div
>
</
div
>
</
form
>
</
form
>
<
EventsCalendar
compact
className=
"xl:w-full xl:min-w-0"
/>
<
div
className=
"order-3 overflow-hidden rounded-[22px] shadow-[0_18px_42px_rgba(17,24,39,0.12)] xl:order-0"
>
<
div
className=
"order-3 overflow-hidden rounded-[22px] shadow-[0_18px_42px_rgba(17,24,39,0.12)] xl:order-0"
>
<
div
className=
"relative min-h-[390px] bg-[#1f334f]"
>
<
div
className=
"relative min-h-[390px] bg-[#1f334f]"
>
<
ImageNext
<
ImageNext
...
...
src/app/(main)/[...slug]/templates/InformationPage.tsx
View file @
ec8c8834
...
@@ -7,7 +7,7 @@ import {
...
@@ -7,7 +7,7 @@ import {
ABOUT_VCCI_HCM_SLUG
,
ABOUT_VCCI_HCM_SLUG
,
AboutVcciHcmPage
,
AboutVcciHcmPage
,
DefaultInformationPage
,
DefaultInformationPage
,
LEGAL_TRADE_PAGE_SLUG
,
LEGAL_TRADE_PAGE_SLUG
S
,
LegalTradePages
,
LegalTradePages
,
MARKET_PROFILE_PAGE_SLUG
,
MARKET_PROFILE_PAGE_SLUG
,
MarketProfilePage
,
MarketProfilePage
,
...
@@ -32,6 +32,7 @@ const LEGAL_TRADE_CHILD_SLUGS = new Set([
...
@@ -32,6 +32,7 @@ const LEGAL_TRADE_CHILD_SLUGS = new Set([
"bieu-mau-co-va-cach-khai"
,
"bieu-mau-co-va-cach-khai"
,
"phi-va-le-phi-cap-co"
,
"phi-va-le-phi-cap-co"
,
"diem-cap-va-thoi-gian-cap-co"
,
"diem-cap-va-thoi-gian-cap-co"
,
"diem-cap-va-thoi-gian-cap-gcn-va-xac-nhan-cttm"
,
"thong-tin-lien-he-co"
,
"thong-tin-lien-he-co"
,
]);
]);
...
@@ -77,15 +78,16 @@ function resolveInformationVariant(post: DynamicPostItem, category: DynamicCateg
...
@@ -77,15 +78,16 @@ function resolveInformationVariant(post: DynamicPostItem, category: DynamicCateg
}
}
if
(
if
(
category
.
slug
===
LEGAL_TRADE_PAGE_SLUG
||
LEGAL_TRADE_PAGE_SLUGS
.
has
(
category
.
slug
)
||
category
.
parent_id
===
LEGAL_TRADE_CATEGORY_ID
||
category
.
parent_id
===
LEGAL_TRADE_CATEGORY_ID
||
LEGAL_TRADE_CHILD_SLUGS
.
has
(
category
.
slug
)
||
LEGAL_TRADE_CHILD_SLUGS
.
has
(
category
.
slug
)
||
post
.
slug
===
LEGAL_TRADE_PAGE_SLUG
||
LEGAL_TRADE_PAGE_SLUGS
.
has
(
post
.
slug
)
||
LEGAL_TRADE_CHILD_SLUGS
.
has
(
post
.
slug
)
||
LEGAL_TRADE_CHILD_SLUGS
.
has
(
post
.
slug
)
||
post
.
categories
.
some
((
item
)
=>
item
.
id
===
LEGAL_TRADE_CATEGORY_ID
)
||
post
.
categories
.
some
((
item
)
=>
item
.
id
===
LEGAL_TRADE_CATEGORY_ID
)
||
post
.
categories
.
some
(
post
.
categories
.
some
(
(
item
)
=>
(
item
)
=>
item
.
url
===
"/phap-che-cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai"
||
item
.
url
===
"/phap-che-cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai"
||
item
.
url
===
"/phap-che-va-cttm"
||
item
.
url
.
startsWith
(
"/xuat-xu-hang-hoa/"
),
item
.
url
.
startsWith
(
"/xuat-xu-hang-hoa/"
),
)
)
)
{
)
{
...
...
src/app/(main)/[...slug]/templates/information-pages/MemberBenefitsPage.tsx
View file @
ec8c8834
...
@@ -162,7 +162,7 @@ export default function MemberBenefitsPage() {
...
@@ -162,7 +162,7 @@ export default function MemberBenefitsPage() {
<
p
className=
"mt-1"
>
<
p
className=
"mt-1"
>
P. 306, Lầu 3, Tòa nhà VCCI, 171 Võ Thị Sáu,
P. 306, Lầu 3, Tòa nhà VCCI, 171 Võ Thị Sáu,
<
br
/>
<
br
/>
Quận 3, TP. Hồ Chí Minh
Phường Xuân Hoà, TP. HCM
</
p
>
</
p
>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
src/app/(main)/[...slug]/templates/information-pages/ServicePage.tsx
View file @
ec8c8834
...
@@ -47,7 +47,7 @@ const SERVICE_SUPPORT_ITEMS = [
...
@@ -47,7 +47,7 @@ const SERVICE_SUPPORT_ITEMS = [
},
},
{
{
key
:
"certificate"
,
key
:
"certificate"
,
title
:
"Xác nhận các chứng từ thương mại
(Bỏ cấp C/O)
"
,
title
:
"Xác nhận các chứng từ thương mại"
,
icon
:
FileBadge2
,
icon
:
FileBadge2
,
},
},
{
{
...
...
src/app/(main)/[...slug]/templates/information-pages/constants.ts
View file @
ec8c8834
...
@@ -3,5 +3,7 @@ export const SERVICE_PAGE_SLUG = "dich-vu-cung-cap";
...
@@ -3,5 +3,7 @@ export const SERVICE_PAGE_SLUG = "dich-vu-cung-cap";
export
const
MEMBER_BENEFITS_PAGE_SLUG
=
"loi-ich-hoi-vien-vcci"
;
export
const
MEMBER_BENEFITS_PAGE_SLUG
=
"loi-ich-hoi-vien-vcci"
;
export
const
MEMBER_REGISTRATION_PAGE_SLUG
=
"dang-ky-hoi-vien"
;
export
const
MEMBER_REGISTRATION_PAGE_SLUG
=
"dang-ky-hoi-vien"
;
export
const
MARKET_PROFILE_PAGE_SLUG
=
"ho-so-thi-truong"
;
export
const
MARKET_PROFILE_PAGE_SLUG
=
"ho-so-thi-truong"
;
export
const
LEGAL_TRADE_PAGE_SLUG
=
export
const
LEGAL_TRADE_PAGE_SLUGS
=
new
Set
([
"phap-che-cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai"
;
"phap-che-cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai"
,
"phap-che-va-cttm"
,
]);
src/app/(main)/[...slug]/templates/information-pages/legal-trade-pages/Router.tsx
View file @
ec8c8834
...
@@ -74,10 +74,15 @@ function resolveVariant(post: DynamicPostItem, category: DynamicCategoryRouteIte
...
@@ -74,10 +74,15 @@ function resolveVariant(post: DynamicPostItem, category: DynamicCategoryRouteIte
if
(
if
(
slug
===
"diem-cap-va-cap-gcn-va-xac-nhan-cttm"
||
slug
===
"diem-cap-va-cap-gcn-va-xac-nhan-cttm"
||
slug
===
"diem-cap-va-thoi-gian-cap-co"
||
slug
===
"diem-cap-va-thoi-gian-cap-co"
||
slug
===
"diem-cap-va-thoi-gian-cap-gcn-va-xac-nhan-cttm"
||
externalLink
===
externalLink
===
"/phap-che-cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai/diem-cap-va-cap-gcn-va-xac-nhan-cttm"
||
"/phap-che-cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai/diem-cap-va-cap-gcn-va-xac-nhan-cttm"
||
externalLink
===
"/phap-che-va-xac-nhan-chung-tu-tm/diem-cap-va-thoi-gian-cap-gcn-va-xac-nhan-cttm"
||
url
===
url
===
"/phap-che-cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai/diem-cap-va-cap-gcn-va-xac-nhan-cttm"
||
"/phap-che-cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai/diem-cap-va-cap-gcn-va-xac-nhan-cttm"
||
url
===
"/phap-che-va-xac-nhan-chung-tu-tm/diem-cap-va-thoi-gian-cap-gcn-va-xac-nhan-cttm"
||
url
===
"/xuat-xu-hang-hoa/diem-cap-va-thoi-gian-cap-co"
url
===
"/xuat-xu-hang-hoa/diem-cap-va-thoi-gian-cap-co"
)
{
)
{
return
"locations"
as
const
;
return
"locations"
as
const
;
...
...
src/components/base/menu-item/index.tsx
View file @
ec8c8834
...
@@ -19,7 +19,12 @@ const MenuItem = ({ title, link, items }: MenuItemProps) => {
...
@@ -19,7 +19,12 @@ const MenuItem = ({ title, link, items }: MenuItemProps) => {
const
normalizedLink
=
link
&&
link
!==
'#'
?
link
:
'/'
const
normalizedLink
=
link
&&
link
!==
'#'
?
link
:
'/'
const
hasChildren
=
items
.
length
>
0
const
hasChildren
=
items
.
length
>
0
const
isRoot
=
normalizedLink
===
'/'
const
isRoot
=
normalizedLink
===
'/'
const
isActive
=
isRoot
?
pathname
===
'/'
:
pathname
===
normalizedLink
||
pathname
.
startsWith
(
normalizedLink
)
const
isChildActive
=
items
.
some
((
item
)
=>
pathname
===
item
.
link
||
pathname
.
startsWith
(
item
.
link
))
const
isActive
=
isRoot
?
pathname
===
'/'
:
pathname
===
normalizedLink
||
pathname
.
startsWith
(
normalizedLink
)
||
isChildActive
const
linkId
=
useMemo
(()
=>
`header-trigger-
${
title
}
`
,
[
title
])
const
linkId
=
useMemo
(()
=>
`header-trigger-
${
title
}
`
,
[
title
])
const
hoverCardRef
=
useCallback
(
const
hoverCardRef
=
useCallback
(
...
...
src/mockdata/categories.ts
View file @
ec8c8834
...
@@ -3,9 +3,9 @@ import type { Category } from "@/api/models/category";
...
@@ -3,9 +3,9 @@ import type { Category } from "@/api/models/category";
export
const
categoryFallbackRows
:
Category
[]
=
[
export
const
categoryFallbackRows
:
Category
[]
=
[
{
{
"id"
:
"450bed53-0e17-4f0a-8a02-17fa657ab5b0"
,
"id"
:
"450bed53-0e17-4f0a-8a02-17fa657ab5b0"
,
"name"
:
"Điểm cấp và cấp GCN và xác nhận CTTM"
,
"name"
:
"Điểm cấp và
thời gian
cấp GCN và xác nhận CTTM"
,
"slug"
:
"diem-cap-va-cap-gcn-va-xac-nhan-cttm"
,
"slug"
:
"diem-cap-va-
thoi-gian-
cap-gcn-va-xac-nhan-cttm"
,
"url"
:
"/phap-che-
cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai/diem-cap-va
-cap-gcn-va-xac-nhan-cttm"
,
"url"
:
"/phap-che-
va-xac-nhan-chung-tu-tm/diem-cap-va-thoi-gian
-cap-gcn-va-xac-nhan-cttm"
,
"created_at"
:
"2026-05-19T07:10:47.564Z"
,
"created_at"
:
"2026-05-19T07:10:47.564Z"
,
"created_by"
:
"aff87dea-73a3-4076-b1be-6b0b7b59a21d"
,
"created_by"
:
"aff87dea-73a3-4076-b1be-6b0b7b59a21d"
,
"updated_at"
:
"2026-05-19T07:10:47.564Z"
,
"updated_at"
:
"2026-05-19T07:10:47.564Z"
,
...
@@ -241,9 +241,9 @@ export const categoryFallbackRows: Category[] = [
...
@@ -241,9 +241,9 @@ export const categoryFallbackRows: Category[] = [
},
},
{
{
"id"
:
"69b4c7e7-28ea-41f2-97f4-988fe702a8a3"
,
"id"
:
"69b4c7e7-28ea-41f2-97f4-988fe702a8a3"
,
"name"
:
"Pháp chế
, cấp giấy chứng nhận và xác nhận chứng từ thương mại
"
,
"name"
:
"Pháp chế
và CTTM
"
,
"slug"
:
"phap-che-
cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai
"
,
"slug"
:
"phap-che-
va-cttm
"
,
"url"
:
"/phap-che-
cap-giay-chung-nhan-va-xac-nhan-chung-tu-thuong-mai
"
,
"url"
:
"/phap-che-
va-cttm
"
,
"created_at"
:
"2026-05-14T04:54:26.127Z"
,
"created_at"
:
"2026-05-14T04:54:26.127Z"
,
"created_by"
:
null
,
"created_by"
:
null
,
"updated_at"
:
"2026-05-15T08:29:25.863Z"
,
"updated_at"
:
"2026-05-15T08:29:25.863Z"
,
...
...
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