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
9f9abbe5
You need to sign in or sign up before continuing.
Commit
9f9abbe5
authored
Nov 25, 2025
by
Phạm Quang Bảo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update/change to components nextjs
parent
3d0df67f
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
668 additions
and
616 deletions
+668
-616
next.config.ts
next.config.ts
+7
-1
index.tsx
src/app/(main)/(home)/components/card-event/index.tsx
+8
-8
index.tsx
src/app/(main)/(home)/components/card-news/index.tsx
+8
-8
page.tsx
src/app/(main)/(home)/page.tsx
+577
-599
index.tsx
src/components/base/image/index.tsx
+19
-0
memberImages.ts
src/constants/memberImages.ts
+10
-0
partnerImages.ts
src/constants/partnerImages.ts
+22
-0
stripImageAndHtml.ts
src/helpers/stripImageAndHtml.ts
+17
-0
No files found.
next.config.ts
View file @
9f9abbe5
...
...
@@ -2,7 +2,7 @@ import type { NextConfig } from "next";
import
links
from
"./src/links/index"
;
const
nextConfig
:
NextConfig
=
{
/* config options here */
images
:
{
images
:
{
remotePatterns
:
[
{
protocol
:
"https"
,
...
...
@@ -10,6 +10,12 @@ const nextConfig: NextConfig = {
port
:
""
,
pathname
:
"/vcci/images/**"
,
},
{
protocol
:
"https"
,
hostname
:
"vcci-hcm.org.vn"
,
// WordPress / media host
port
:
""
,
pathname
:
"/wp-content/uploads/**"
,
},
],
},
};
...
...
src/app/(main)/(home)/components/card-event/index.tsx
View file @
9f9abbe5
...
...
@@ -2,21 +2,21 @@ import { EventItem } from '@/api/types/event'
import
BASE_URL
from
'@/links'
import
dayjs
from
'dayjs'
;
import
AppEditorContent
from
'@/components/shared/editor-content'
;
import
Link
from
"next/link"
;
import
ImageNext
from
"@/components/base/image"
;
function
CardEvent
({
event
}:
{
event
:
EventItem
})
{
return
(
<
a
<
Link
href=
{
`hoat-dong/su-kien/${event.id}`
}
className=
'flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3 p-2 sm:p-3 border border-gray-200 bg-white rounded-md'
>
<
img
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${event.image}`
}
alt=
{
event
.
name
}
className=
'w-[100px] md:w-[130px] aspect-3/2 object-cover'
onError=
{
(
e
)
=>
{
e
.
currentTarget
.
onerror
=
null
e
.
currentTarget
.
src
=
"/img-error.png"
}
}
className=
'aspect-3/2 object-cover'
width=
{
130
}
height=
{
86
}
/>
<
div
className=
'flex-1'
>
<
p
className=
'text-[#0056b3] font-bold text-sm line-clamp-2'
>
...
...
@@ -27,7 +27,7 @@ function CardEvent({ event }: { event: EventItem }) {
</
p
>
{
/* <AppEditorContent className='line-clamp-2' value={event.description} /> */
}
</
div
>
</
a
>
</
Link
>
);
}
...
...
src/app/(main)/(home)/components/card-news/index.tsx
View file @
9f9abbe5
...
...
@@ -2,21 +2,21 @@ import { NewsItem } from "@/api/types/news";
import
BASE_URL
from
"@/links"
;
import
dayjs
from
"dayjs"
;
import
AppEditorContent
from
"@/components/shared/editor-content"
;
import
Link
from
"next/link"
;
import
ImageNext
from
"@/components/base/image"
;
function
CardNews
({
news
}:
{
news
:
NewsItem
})
{
return
(
<
a
<
Link
href=
{
`${news.external_link}`
}
className=
"flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
>
<
img
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
className=
"w-[100px] md:w-[130px] aspect-3/2 object-cover"
onError=
{
(
e
)
=>
{
e
.
currentTarget
.
onerror
=
null
e
.
currentTarget
.
src
=
"/img-error.png"
}
}
className=
"aspect-3/2 object-cover"
width=
{
130
}
height=
{
86
}
/>
<
div
className=
"flex-1"
>
<
p
className=
"text-[#363636] font-bold text-sm line-clamp-2"
>
...
...
@@ -27,7 +27,7 @@ function CardNews({ news }: { news: NewsItem }) {
</
p
>
{
/* <AppEditorContent className='line-clamp-2' value={news.description} /> */
}
</
div
>
</
a
>
</
Link
>
);
}
...
...
src/app/(main)/(home)/page.tsx
View file @
9f9abbe5
"use client"
;
import
Image
from
"next/image"
;
import
{
useEffect
,
useRef
,
useState
}
from
"react"
;
// core
import
{
useRef
,
useState
}
from
"react"
;
import
Link
from
'next/link'
// app
import
{
Autoplay
,
Grid
}
from
"swiper/modules"
;
import
{
Swiper
,
SwiperSlide
}
from
"swiper/react"
;
import
{
Swiper
as
SwiperType
}
from
"swiper/types"
;
...
...
@@ -9,42 +12,40 @@ import "swiper/css";
import
"swiper/css/navigation"
;
import
"swiper/css/pagination"
;
import
BASE_URL
from
"@/links/index"
;
import
dayjs
from
"dayjs"
;
import
ImageNext
from
'@/components/base/image'
;
import
{
Spinner
}
from
"@/components/ui"
;
import
CardNews
from
"./components/card-news"
;
import
CardEvent
from
"./components/card-event"
;
import
EventCalendar
from
"@components/base/event-calendar"
;
import
dayjs
from
"dayjs"
;
import
stripImagesAndHtml
from
'@/helpers/stripImageAndHtml'
;
import
partnerImages
from
'@/constants/partnerImages'
;
import
memberImages
from
'@/constants/memberImages'
;
// server
import
{
useGetEvents
}
from
"@/api/endpoints/event"
;
import
{
useGetCategory
}
from
"@/api/endpoints/category"
;
import
{
useGetNews
}
from
"@/api/endpoints/news"
;
import
{
GetCategoryAdminResponseType
}
from
"@/api/types/category"
;
import
{
GetNewsResponseType
,
NewsItem
}
from
"@/api/types/news"
;
import
{
EventApiResponse
,
EventItem
}
from
"@/api/types/event"
;
import
{
ChevronsRight
,
Link
}
from
"lucide-react"
;
import
{
useParams
}
from
"next/navigation"
;
import
{
ChevronsRight
}
from
"lucide-react"
;
const
Page
=
()
=>
{
// state
const
[
tab
,
setTab
]
=
useState
(
"all"
);
const
[
currentIndex
,
setCurrentIndex
]
=
useState
(
0
);
const
swiperRef
=
useRef
<
SwiperType
|
null
>
(
null
);
// query
const
{
data
:
news
Data
,
isLoading
:
isLoadingNews
}
=
useGetNews
<
GetNewsResponseType
>
(
const
{
data
:
news
All
}
=
useGetNews
<
GetNewsResponseType
>
(
{
pageSize
:
'5'
,
filters
:
tab
===
"all"
?
``
:
`page_config.code @=
${
tab
}
`
,
pageSize
:
'10'
,
}
);
const
{
data
:
newsAll
,
isLoading
:
isLoadingNewsAll
}
=
useGetNews
<
GetNewsResponseType
>
(
const
{
data
:
newsData
}
=
useGetNews
<
GetNewsResponseType
>
(
{
pageSize
:
'10'
,
pageSize
:
'5'
,
filters
:
tab
===
"all"
?
``
:
`page_config.code @=
${
tab
}
`
,
}
);
const
{
data
:
eventData
,
isLoading
:
isLoadingEvent
}
=
useGetEvents
<
EventApiResponse
>
();
const
{
data
:
businessOpportunities
,
isLoading
:
isLoadingBusinessOpportunities
}
=
useGetNews
<
GetNewsResponseType
>
(
{
pageSize
:
'5'
,
...
...
@@ -58,642 +59,619 @@ const Page = () => {
}
);
const
{
data
:
eventData
,
isLoading
:
isLoadingEvent
}
=
useGetEvents
<
EventApiResponse
>
();
const
now
=
new
Date
();
const
eventDataFiltered
=
eventData
?.
responseData
.
rows
.
filter
(
event
=>
{
const
eventTime
=
new
Date
(
event
.
start_time
);
return
eventTime
>
now
;
});
// helpers
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
,
''
)
}
const
images
=
[
"/home/doi-tac/AMFORI-1.png.webp"
,
"/home/doi-tac/AUS4SKILLS-1.png.webp"
,
"/home/doi-tac/BetterWork-1.png.webp"
,
"/home/doi-tac/BOI-LOGO.jpg.webp"
,
"/home/doi-tac/DNV-logo-1-1.png.webp"
,
"/home/doi-tac/GERMAN-COOPERATION-1.png.webp"
,
"/home/doi-tac/GIZ.png.webp"
,
"/home/doi-tac/HBA.png.webp"
,
"/home/doi-tac/ILO-1.png.webp"
,
"/home/doi-tac/InvestHK.png.webp"
,
"/home/doi-tac/IOM-1.png.webp"
,
"/home/doi-tac/JICA-134x100-1-1.jpg.webp"
,
"/home/doi-tac/KIRBY.png.webp"
,
"/home/doi-tac/NHO-1.png.webp"
,
"/home/doi-tac/OXFAM-1.png.webp"
,
"/home/doi-tac/RECOTVET-1.png.webp"
,
"/home/doi-tac/SC-1.png.webp"
,
"/home/doi-tac/UNDP.png.webp"
,
];
const
hoivien
=
[
"/home/hoi-vien-tieu-bieu/logo-GTD-768x768.png.webp"
,
"/home/hoi-vien-tieu-bieu/Nhua-Long-Thanh_Logo.jpg.webp"
,
"/home/hoi-vien-tieu-bieu/Nova_Group_logo-1.png.webp"
,
"/home/hoi-vien-tieu-bieu/samngoclinh-1-768x768.png.webp"
,
"/home/hoi-vien-tieu-bieu/Screenshot-2022-12-26-144136-768x768.png.webp"
,
"/home/hoi-vien-tieu-bieu/UOB-logo_Vuong.jpeg.webp"
,
];
// template
return
(
(
isLoadingBusinessOpportunities
||
isLoadingPolicyAndLegalInformation
||
isLoadingEvent
)
?
(
<
div
className=
"container w-full h-[80vh] flex justify-center items-center"
>
<
Spinner
/>
</
div
>
)
:
(
<>
{
/* Banner */
}
<
Swiper
modules=
{
[
Autoplay
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
slidesPerView=
{
1
}
onSwiper=
{
(
s
)
=>
(
swiperRef
.
current
=
s
)
}
onSlideChange=
{
(
s
)
=>
setCurrentIndex
(
typeof
s
.
realIndex
===
"number"
?
s
.
realIndex
:
s
.
activeIndex
)
}
>
<
SwiperSlide
>
<
img
src=
"https://vcci-hcm.org.vn/wp-content/uploads/2025/10/1.1.-Hero-Banner-CEO-2025-Bi-Sai-Nam-2025-Nhe-2560x720-Px.jpg"
alt=
"Banner"
className=
"w-full h-[200px] sm:h-[300px] md:h-[400px] lg:h-[500px] object-cover"
/>
</
SwiperSlide
>
<
SwiperSlide
>
<
img
src=
"https://vcci-hcm.org.vn/wp-content/uploads/2022/07/Landscape-HCM_3-01.png"
alt=
"Banner"
className=
"w-full h-[200px] sm:h-[300px] md:h-[400px] lg:h-[500px] object-cover"
/>
</
SwiperSlide
>
</
Swiper
>
<
div
className=
"container mx-auto px-3 sm:px-6 lg:px-10 space-y-12"
>
{
/* Featured News */
}
<
section
>
<
div
className=
"flex items-center justify-center py-8 px-4"
>
<
div
className=
"flex items-center w-full max-w-4xl"
>
<
div
className=
"flex-1 h-px bg-linear-to-r from-transparent via-gray-300 to-gray-400"
></
div
>
<
h1
className=
"px-6 text-[20px] sm:text-[24px] md:text-[28px] uppercase font-bold text-[#063e8e] whitespace-nowrap"
>
Tin Nổi Bật
</
h1
>
<
div
className=
"flex-1 h-px bg-linear-to-l from-transparent via-gray-300 to-gray-400"
></
div
>
</
div
>
<>
{
/* Banner */
}
<
Swiper
modules=
{
[
Autoplay
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
slidesPerView=
{
1
}
onSwiper=
{
(
s
)
=>
(
swiperRef
.
current
=
s
)
}
>
<
SwiperSlide
>
<
ImageNext
src=
"https://vcci-hcm.org.vn/wp-content/uploads/2025/10/1.1.-Hero-Banner-CEO-2025-Bi-Sai-Nam-2025-Nhe-2560x720-Px.jpg.webp"
alt=
"Banner"
width=
{
2560
}
height=
{
720
}
priority
sizes=
"100vw"
className=
"w-full h-[200px] sm:h-[300px] md:h-[400px] lg:h-[500px] object-cover"
/>
</
SwiperSlide
>
<
SwiperSlide
>
<
ImageNext
src=
"https://vcci-hcm.org.vn/wp-content/uploads/2022/07/Landscape-HCM_3-01.png"
alt=
"Banner"
width=
{
2560
}
height=
{
720
}
sizes=
"100vw"
className=
"w-full h-[200px] sm:h-[300px] md:h-[400px] lg:h-[500px] object-cover"
/>
</
SwiperSlide
>
</
Swiper
>
<
div
className=
"container mx-auto px-3 sm:px-6 lg:px-10 space-y-12"
>
{
/* Featured News */
}
<
section
>
<
div
className=
"flex items-center justify-center py-8 px-4"
>
<
div
className=
"flex items-center w-full max-w-4xl"
>
<
div
className=
"flex-1 h-px bg-linear-to-r from-transparent via-gray-300 to-gray-400"
></
div
>
<
h1
className=
"px-6 text-[20px] sm:text-[24px] md:text-[28px] uppercase font-bold text-[#063e8e] whitespace-nowrap"
>
Tin Nổi Bật
</
h1
>
<
div
className=
"flex-1 h-px bg-linear-to-l from-transparent via-gray-300 to-gray-400"
></
div
>
</
div
>
</
div
>
<
Swiper
modules=
{
[
Autoplay
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
breakpoints=
{
{
0
:
{
slidesPerView
:
1.1
,
spaceBetween
:
10
},
640
:
{
slidesPerView
:
2
,
spaceBetween
:
16
},
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
}
}
className=
"pb-5"
>
{
newsAll
?.
responseData
?.
rows
.
map
((
news
)
=>
(
<
SwiperSlide
key=
{
news
.
id
}
>
<
a
<
Swiper
modules=
{
[
Autoplay
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
breakpoints=
{
{
0
:
{
slidesPerView
:
1.1
,
spaceBetween
:
10
},
640
:
{
slidesPerView
:
2
,
spaceBetween
:
16
},
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
}
}
className=
"pb-5"
>
{
newsAll
?.
responseData
?.
rows
.
map
((
news
)
=>
(
<
SwiperSlide
key=
{
news
.
id
}
>
<
Link
href=
{
`${news.external_link}`
}
className=
"relative block bg-white shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"
>
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
width=
{
600
}
height=
{
400
}
sizes=
"(max-width:640px) 100vw,(max-width:1024px) 50vw,33vw"
className=
"w-full aspect-3/2 sm:h-56 md:h-64 object-cover"
/>
<
div
className=
"absolute bottom-0 left-0 right-0 h-20 md:h-24 bg-linear-to-t from-black/80 to-transparent flex items-center justify-center p-3"
>
<
p
className=
"text-white text-center font-semibold line-clamp-2 text-sm sm:text-base leading-snug"
>
{
news
.
title
}
</
p
>
</
div
>
</
Link
>
</
SwiperSlide
>
))
}
</
Swiper
>
</
section
>
<
div
>
<
Link
href=
"https://hardwaretools.com.vn/"
>
<
ImageNext
src=
"/home/Standard-Banner-1-2024.png.webp"
alt=
"banner"
width=
{
2560
}
height=
{
720
}
/>
</
Link
>
</
div
>
{
/* Tin tức + Liên kết nhanh */
}
<
section
className=
"flex flex-col lg:flex-row gap-5 pb-10 mb-0"
>
{
/* Left */
}
<
div
className=
"flex-1"
>
<
div
className=
"flex justify-between items-center"
>
<
Link
href=
"/thong-tin-truyen-thong/tin-vcci/"
className=
"text-[18px] sm:text-[20px] font-semibold uppercase text-[#063e8e]"
>
Tin tức
</
Link
>
<
Link
href=
"/thong-tin-truyen-thong/tin-vcci/"
className=
"text-[#063e8e] text-sm sm:text-base"
>
<
ChevronsRight
/>
</
Link
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
div
className=
"flex flex-col md:flex-row gap-5"
>
{
newsAll
?.
responseData
.
rows
.
slice
(
0
,
1
)
.
map
((
news
:
NewsItem
)
=>
(
<
Link
key=
{
news
.
id
}
href=
{
`${news.external_link}`
}
className=
"
relative block bg-white shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300
"
className=
"
flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 bg-white
"
>
<
img
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
className=
"w-full aspect-3/2 sm:h-56 md:h-64 object-cover"
onError=
{
(
e
)
=>
{
e
.
currentTarget
.
onerror
=
null
e
.
currentTarget
.
src
=
"/img-error.png"
}
}
/>
<
div
className=
"absolute bottom-0 left-0 right-0 h-20 md:h-24 bg-linear-to-t from-black/80 to-transparent flex items-center justify-center p-3"
>
<
p
className=
"text-white text-center font-semibold line-clamp-2 text-sm sm:text-base leading-snug"
>
<
div
className=
"w-full aspect-3/2 overflow-hidden"
>
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
width=
{
600
}
height=
{
400
}
sizes=
"(max-width:768px) 100vw,50vw"
className=
"w-full h-full object-cover"
/>
</
div
>
<
div
className=
"flex-1 p-5 pt-1"
>
<
p
className=
"text-[#063E8E] font-bold pb-2 text-xl line-clamp-2"
>
{
news
.
title
}
</
p
>
<
p
className=
"line-clamp-4 text-justify"
>
{
stripImagesAndHtml
(
news
.
description
)
}
</
p
>
</
div
>
</
a
>
</
SwiperSlide
>
))
}
</
Swiper
>
</
section
>
</
Link
>
))
}
<
div
>
<
a
href=
"https://hardwaretools.com.vn/"
>
<
img
src=
"/home/Standard-Banner-1-2024.png.webp"
alt=
"banner"
/>
</
a
>
<
div
className=
"w-full md:w-1/2"
>
<
div
className=
"flex flex-wrap gap-2 sm:gap-3 mb-5"
>
<
button
className=
{
`flex-1 py-[3px] text-sm transition-colors cursor-pointer ${tab === "all"
? " bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`
}
onClick=
{
()
=>
setTab
(
"all"
)
}
>
Tất cả
</
button
>
<
button
className=
{
`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`
tin
-
vcci
` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`
}
onClick=
{
()
=>
setTab
(
"tin-vcci"
)
}
>
Tin VCCI
</
button
>
<
button
className=
{
`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`
tin
-
kinh
-
te
` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`
}
onClick=
{
()
=>
setTab
(
"tin-kinh-te"
)
}
>
Tin Kinh Tế
</
button
>
<
button
className=
{
`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`
chuyen
-
de
` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`
}
onClick=
{
()
=>
setTab
(
"chuyen-de"
)
}
>
Chuyên Đề
</
button
>
</
div
>
{
newsData
?.
responseData
?.
rows
.
slice
(
0
,
4
).
map
((
news
)
=>
(
<
CardNews
key=
{
news
.
id
}
news=
{
news
}
/>
))
}
</
div
>
</
div
>
</
div
>
{
/* Tin tức + Liên kết nhanh */
}
<
section
className=
"flex flex-col lg:flex-row gap-5 pb-10 mb-0"
>
{
/* Left */
}
<
div
className=
"flex-1"
>
<
div
className=
"flex justify-between items-center"
>
<
a
href=
"/thong-tin-truyen-thong/tin-vcci/"
className=
"text-[18px] sm:text-[20px] font-semibold uppercase text-[#063e8e]"
{
/* Right */
}
<
aside
className=
"w-full lg:w-[30%]"
>
<
div
className=
"flex justify-between items-center"
>
<
h2
className=
"text-[18px] sm:text-[20px] font-semibold uppercase text-[#063e8e]"
>
Liên kết nhanh
</
h2
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
div
className=
"space-y-2 text-[#063e8e] text-sm md:text-base pb-10"
>
<
div
>
<
Link
className=
"text-[#363636]"
href=
"https://vcci-hcm.org.vn/lien-ket-nhanh/cam-nang-huong-dan-dau-tu-kinh-doanh-tai-viet-nam-2023/"
>
Tin tức
</
a
>
<
a
href=
"/thong-tin-truyen-thong/tin-vcci/"
className=
"text-[#063e8e] text-sm sm:text-base"
🔗 Cẩm nang hướng dẫn đầu tư kinh doanh tại Việt Nam
</
Link
>
</
div
>
<
div
>
<
Link
className=
"text-[#363636]"
href=
"https://vcci-hcm.org.vn/lien-ket-nhanh/doanh-nghiep-kien-nghi-ve-chinh-sach-va-phap-luat/"
>
<
ChevronsRight
/>
</
a
>
🔗 Doanh nghiệp kiến nghị về chính sách và pháp luật
</
Link
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-4"
/>
</
div
>
<
div
>
<
Link
href=
"https://hardwaretools.com.vn/"
>
<
ImageNext
src=
"/home/20-2048x1365.webp"
alt=
"banner"
width=
{
2048
}
height=
{
1365
}
/>
</
Link
>
</
div
>
</
aside
>
</
section
>
{
/* Sự kiện */
}
<
section
className=
"flex flex-col lg:flex-row gap-5 pb-10 mb-0"
>
<
div
className=
"flex-1 bg-[#063e8e] p-5"
>
<
div
className=
"flex justify-between items-center"
>
<
h2
className=
"text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]"
>
Sự kiện sắp diễn ra
</
h2
>
<
Link
href=
"/hoat-dong/su-kien"
className=
"text-[#e8c518] text-sm sm:text-base"
>
<
ChevronsRight
/>
</
Link
>
</
div
>
<
hr
className=
"border-[#e8c518] mb-4"
/>
<
div
className=
"flex flex-col md:flex-row gap-5"
>
{
newsAll
?.
responseData
.
rows
.
slice
(
0
,
1
)
.
map
((
news
:
NewsItem
)
=>
(
<
a
key=
{
news
.
id
}
href=
{
`${news.external_link}`
}
className=
"flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 bg-white"
<
div
className=
"flex flex-col md:flex-row gap-5"
>
{
isLoadingEvent
?
(
<
div
className=
"container w-full h-[80vh] flex justify-center items-center"
>
<
Spinner
/>
</
div
>
)
:
(
<>
{
eventData
?.
responseData
.
rows
.
slice
(
0
,
1
).
map
((
event
:
EventItem
)
=>
(
<
Link
key=
{
event
.
id
}
href=
{
`hoat-dong/su-kien/${event.id}`
}
className=
"flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 border border-gray-200 bg-white rounded-md p-3"
>
<
div
className=
"w-full aspect-3/2 overflow-hidden"
>
<
img
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${event.image}`
}
alt=
{
event
.
name
}
width=
{
600
}
height=
{
400
}
sizes=
"(max-width:768px) 100vw,50vw"
className=
"w-full h-full object-cover"
onError=
{
(
e
)
=>
{
e
.
currentTarget
.
onerror
=
null
e
.
currentTarget
.
src
=
"/img-error.png"
}
}
/>
</
div
>
<
div
className=
"flex-1
p-5 pt-1
"
>
<
p
className=
"text-[#0
63E8E] font-bold pb-2
text-xl line-clamp-2"
>
{
news
.
titl
e
}
<
div
className=
"flex-1"
>
<
p
className=
"text-[#0
056b3] font-bold
text-xl line-clamp-2"
>
{
event
.
nam
e
}
</
p
>
<
p
className=
"line-clamp-4 text-justify"
>
{
stripImagesAndHtml
(
news
.
description
)
}
</
p
>
<
p
className=
"text-gray-500 text-sm my-1"
>
{
dayjs
(
event
.
start_time
).
format
(
"DD/MM/YYYY"
)
}
</
p
>
<
p
className=
"line-clamp-3 text-justify"
>
{
stripImagesAndHtml
(
event
.
description
)
}
</
p
>
</
div
>
</
a
>
</
Link
>
))
}
<
div
className=
"w-full md:w-1/2"
>
<
div
className=
"flex flex-wrap gap-2 sm:gap-3 mb-5"
>
<
button
className=
{
`flex-1 py-[3px] text-sm transition-colors cursor-pointer ${tab === "all"
? " bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`
}
onClick=
{
()
=>
setTab
(
"all"
)
}
>
Tất cả
</
button
>
<
button
className=
{
`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`
tin
-
vcci
` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`
}
onClick=
{
()
=>
setTab
(
`tin-vcci`
)
}
>
Tin VCCI
</
button
>
<
button
className=
{
`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`
tin
-
kinh
-
te
` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`
}
onClick=
{
()
=>
setTab
(
`tin-kinh-te`
)
}
>
Tin Kinh Tế
</
button
>
<
button
className=
{
`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`
chuyen
-
de
` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`
}
onClick=
{
()
=>
setTab
(
`chuyen-de`
)
}
>
Chuyên Đề
</
button
>
<
div
className=
"w-full md:w-1/2"
>
{
eventData
?.
responseData
.
rows
.
slice
(
0
,
4
).
map
((
event
)
=>
(
<
CardEvent
key=
{
event
.
id
}
event=
{
event
}
/>
))
}
</
div
>
{
newsData
?.
responseData
?.
rows
.
slice
(
0
,
4
).
map
((
news
)
=>
(
<
CardNews
key=
{
news
.
id
}
news=
{
news
}
/>
))
}
</
div
>
</
div
>
</>
)
}
</
div
>
{
/* Right */
}
<
aside
className=
"w-full lg:w-[30%]"
>
<
div
className=
"flex justify-between items-center"
>
<
h2
className=
"text-[18px] sm:text-[20px] font-semibold uppercase text-[#063e8e]"
>
Liên kết nhanh
</
h2
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
div
className=
"space-y-2 text-[#063e8e] text-sm md:text-base pb-10"
>
<
div
>
<
a
className=
"text-[#363636]"
href=
"https://vcci-hcm.org.vn/lien-ket-nhanh/cam-nang-huong-dan-dau-tu-kinh-doanh-tai-viet-nam-2023/"
>
<
Link
size=
{
16
}
className=
"inline mr-2 font-semibold text-[#063e8e]"
style=
{
{
verticalAlign
:
"middle"
,
marginTop
:
"-2px"
}
}
/>
Cẩm nang hướng dẫn đầu tư kinh doanh tại Việt Nam
</
a
>
</
div
>
<
div
>
<
a
className=
"text-[#363636]"
href=
"https://vcci-hcm.org.vn/lien-ket-nhanh/doanh-nghiep-kien-nghi-ve-chinh-sach-va-phap-luat/"
>
<
Link
size=
{
16
}
className=
"inline mr-2 font-semibold text-[#063e8e]"
style=
{
{
verticalAlign
:
"middle"
,
marginTop
:
"-2px"
}
}
/>
Doanh nghiệp kiến nghị về chính sách và pháp luật
</
a
>
</
div
>
</
div
>
<
div
>
<
a
href=
"https://hardwaretools.com.vn/"
>
<
img
src=
"/home/20-2048x1365.webp"
alt=
"banner"
/>
</
a
>
</
div
>
</
aside
>
</
section
>
{
/* Sự kiện */
}
<
section
className=
"flex flex-col lg:flex-row gap-5 pb-10 mb-0"
>
<
div
className=
"flex-1 bg-[#063e8e] p-5"
>
</
div
>
<
div
className=
"bg-[#063e8e] w-full lg:w-[30%] p-5"
>
<
aside
>
<
div
className=
"flex justify-between items-center"
>
<
h2
className=
"text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]"
>
Sự kiện sắp diễn ra
Lịch sự kiện
</
h2
>
<
a
href=
"/hoat-dong/su-kien"
className=
"text-[#e8c518] text-sm sm:text-base"
>
<
Link
href=
"/hoat-dong/su-kien"
className=
"text-[#e8c518] hover:underline text-sm sm:text-base"
>
<
ChevronsRight
/>
</
a
>
</
Link
>
</
div
>
<
hr
className=
"border-[#e8c518] mb-4"
/>
<
div
className=
"flex flex-col md:flex-row gap-5"
>
{
eventDataFiltered
?.
slice
(
0
,
1
).
map
((
event
:
EventItem
)
=>
(
<
a
key=
{
event
.
id
}
href=
{
`hoat-dong/su-kien/${event.id}`
}
className=
"flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 border border-gray-200 bg-white rounded-md p-3"
<
EventCalendar
/>
</
aside
>
</
div
>
</
section
>
{
/* Cơ hội kinh doanh + Chính sách */
}
<
div
className=
"flex flex-col lg:flex-row gap-5 pb-10 mb-0"
>
<
div
className=
"flex flex-col flex-1"
>
<
div
>
<
Link
href=
"https://vcci-hcm.org.vn/wp-content/uploads/2022/11/MEDIA-KIT_VCCI-HCM-2022-Final.pdf"
>
<
ImageNext
src=
"/home/Standard-Banner-1-2024.png.webp"
alt=
"banner"
width=
{
2560
}
height=
{
720
}
/>
</
Link
>
</
div
>
<
section
className=
"flex flex-col md:flex-row gap-5 pt-8"
>
<
div
className=
"flex-1"
>
<
div
className=
"flex justify-between items-center"
>
<
Link
href=
"/xuc-tien-thuong-mai/co-hoi/"
className=
"text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
>
<
div
className=
"w-full aspect-3/2 overflow-hidden"
>
<
img
src=
{
`${BASE_URL.imageEndpoint}${event.image}`
}
alt=
{
event
.
name
}
className=
"w-full h-full object-cover"
onError=
{
(
e
)
=>
{
(
e
.
target
as
HTMLImageElement
).
src
=
"/img-error.png"
;
}
}
/>
Cơ hội kinh doanh
</
Link
>
<
Link
href=
"/xuc-tien-thuong-mai/co-hoi/"
className=
"text-[#063e8e] text-sm sm:text-base"
>
<
ChevronsRight
/>
</
Link
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
div
className=
"pt-2"
>
{
isLoadingBusinessOpportunities
?
(
<
div
className=
"container w-full h-[80vh] flex justify-center items-center"
>
<
Spinner
/>
</
div
>
)
:
(
<>
{
businessOpportunities
?.
responseData
.
rows
.
slice
(
0
,
1
)
.
map
((
news
:
NewsItem
)
=>
(
<
Link
key=
{
news
.
id
}
href=
{
`${news.external_link}`
}
>
<
div
className=
"w-full aspect-3/2 relative overflow-hidden mb-5"
>
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
width=
{
600
}
height=
{
400
}
sizes=
"(max-width:768px) 100vw,50vw"
className=
"w-full h-full object-cover"
/>
<
div
className=
"absolute bg-white opacity-80 bottom-5 left-5 right-5 p-5"
>
<
p
className=
"text-[#063e8e] font-semibold text-sm sm:text-base z-10 line-clamp-3"
>
{
news
.
title
}
</
p
>
</
div
>
</
div
>
</
Link
>
))
}
<
div
className=
"flex-1"
>
<
p
className=
"text-[#0056b3] font-bold text-xl line-clamp-2"
>
{
event
.
name
}
</
p
>
<
p
className=
"text-gray-500 text-sm my-1"
>
{
dayjs
(
event
.
start_time
).
format
(
"DD/MM/YYYY"
)
}
</
p
>
<
p
className=
"line-clamp-3 text-justify"
>
{
stripImagesAndHtml
(
event
.
description
)
}
</
p
>
</
div
>
</
a
>
))
}
<
div
className=
"w-full md:w-1/2"
>
{
eventDataFiltered
?.
slice
(
0
,
4
).
map
((
event
)
=>
(
<
CardEvent
key=
{
event
.
id
}
event=
{
event
}
/>
))
}
{
businessOpportunities
?.
responseData
.
rows
.
slice
(
0
,
3
).
map
((
news
)
=>
(
<
CardNews
key=
{
news
.
id
}
news=
{
news
}
/>
))
}
</>
)
}
</
div
>
</
div
>
</
div
>
<
div
className=
"bg-[#063e8e] w-full lg:w-[30%] p-5"
>
<
aside
>
<
div
className=
"flex-1"
>
<
div
className=
"flex justify-between items-center"
>
<
h2
className=
"text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]"
>
Lịch sự kiện
</
h2
>
<
a
href=
"/hoat-dong/su-kien"
className=
"text-[#e8c518] hover:underline text-sm sm:text-base"
<
Link
href=
"/thong-tin-truyen-thong/phap-luat"
className=
"text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
>
Chính sách
&
pháp luật
</
Link
>
<
Link
href=
"/thong-tin-truyen-thong/phap-luat"
className=
"text-[#063e8e] text-sm sm:text-base"
>
<
ChevronsRight
/>
</
a
>
</
Link
>
</
div
>
<
hr
className=
"border-[#e8c518] mb-4"
/>
<
EventCalendar
/>
</
aside
>
</
div
>
</
section
>
{
/* Cơ hội kinh doanh + Chính sách */
}
<
div
className=
"flex flex-col lg:flex-row gap-5 pb-10 mb-0"
>
<
div
className=
"flex flex-col flex-1"
>
<
div
>
<
a
href=
"https://vcci-hcm.org.vn/wp-content/uploads/2022/11/MEDIA-KIT_VCCI-HCM-2022-Final.pdf"
>
<
img
src=
"/home/Standard-Banner-1-2024.png.webp"
alt=
"banner"
/>
</
a
>
</
div
>
<
section
className=
"flex flex-col md:flex-row gap-5 pt-8"
>
<
div
className=
"flex-1"
>
<
div
className=
"flex justify-between items-center"
>
<
a
href=
"/xuc-tien-thuong-mai/co-hoi/"
className=
"text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
>
Cơ hội kinh doanh
</
a
>
<
a
href=
"/xuc-tien-thuong-mai/co-hoi/"
className=
"text-[#063e8e] text-sm sm:text-base"
>
<
ChevronsRight
/>
</
a
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
div
className=
"pt-2"
>
{
businessOpportunities
?.
responseData
.
rows
.
slice
(
0
,
1
)
.
map
((
news
:
NewsItem
)
=>
(
<
a
key=
{
news
.
id
}
href=
{
`${news.external_link}`
}
>
<
div
className=
"w-full aspect-3/2 relative overflow-hidden mb-5"
>
<
img
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
className=
"w-full h-full object-cover"
onError=
{
(
e
)
=>
{
e
.
currentTarget
.
onerror
=
null
e
.
currentTarget
.
src
=
"/img-error.png"
}
}
/>
<
div
className=
"absolute bg-white opacity-80 bottom-5 left-5 right-5 p-5"
>
<
p
className=
"text-[#063e8e] font-semibold text-sm sm:text-base z-10 line-clamp-3"
>
{
news
.
title
}
</
p
>
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
div
className=
"pt-2"
>
{
isLoadingPolicyAndLegalInformation
?
(
<
div
className=
"container w-full h-[80vh] flex justify-center items-center"
>
<
Spinner
/>
</
div
>
)
:
(
<>
{
policyAndLegalInformation
?.
responseData
.
rows
.
slice
(
0
,
1
)
.
map
((
news
:
NewsItem
)
=>
(
<
Link
key=
{
news
.
id
}
href=
{
`${news.external_link}`
}
>
<
div
className=
"w-full aspect-3/2 relative overflow-hidden mb-5"
>
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
width=
{
600
}
height=
{
400
}
sizes=
"(max-width:768px) 100vw,50vw"
className=
"w-full h-full object-cover"
/>
<
div
className=
"absolute bg-white opacity-80 bottom-5 left-5 right-5 p-5"
>
<
p
className=
"text-[#063e8e] font-semibold text-sm sm:text-base z-10 line-clamp-3"
>
{
news
.
title
}
</
p
>
</
div
>
</
div
>
</
div
>
</
a
>
</
Link
>
))
}
{
policyAndLegalInformation
?.
responseData
.
rows
.
slice
(
0
,
3
).
map
((
news
)
=>
(
<
CardNews
key=
{
news
.
id
}
news=
{
news
}
/>
))
}
{
businessOpportunities
?.
responseData
.
rows
.
slice
(
0
,
3
).
map
((
news
)
=>
(
<
CardNews
key=
{
news
.
id
}
news=
{
news
}
/>
))
}
</
div
>
</>
)
}
</
div
>
<
div
className=
"flex-1"
>
<
div
className=
"flex justify-between items-center"
>
<
a
href=
"/thong-tin-truyen-thong/phap-luat"
className=
"text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
>
Chính sách
&
pháp luật
</
a
>
<
a
href=
"/thong-tin-truyen-thong/phap-luat"
className=
"text-[#063e8e] text-sm sm:text-base"
>
<
ChevronsRight
/>
</
a
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
div
className=
"pt-2"
>
{
policyAndLegalInformation
?.
responseData
.
rows
.
slice
(
0
,
1
)
.
map
((
news
:
NewsItem
)
=>
(
<
a
key=
{
news
.
id
}
href=
{
`${news.external_link}`
}
>
<
div
className=
"w-full aspect-3/2 relative overflow-hidden mb-5"
>
<
img
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
alt=
{
news
.
title
}
className=
"w-full h-full object-cover"
onError=
{
(
e
)
=>
{
e
.
currentTarget
.
onerror
=
null
e
.
currentTarget
.
src
=
"/img-error.png"
}
}
/>
<
div
className=
"absolute bg-white opacity-80 bottom-5 left-5 right-5 p-5"
>
<
p
className=
"text-[#063e8e] font-semibold text-sm sm:text-base z-10 line-clamp-3"
>
{
news
.
title
}
</
p
>
</
div
>
</
div
>
</
a
>
))
}
</
div
>
</
section
>
</
div
>
<
div
className=
"w-full lg:w-[30%] justify-center items-start flex"
>
<
Link
href=
"https://smartgara.ecaraid.com/"
>
<
ImageNext
src=
"/home/eCarAid_web_banner_600x400.webp"
alt=
"banner"
width=
{
600
}
height=
{
400
}
/>
</
Link
>
</
div
>
</
div
>
{
policyAndLegalInformation
?.
responseData
.
rows
.
slice
(
0
,
3
).
map
((
news
)
=>
(
<
CardNews
key=
{
news
.
id
}
news=
{
news
}
/>
))
}
{
/* Hội viên tiêu biểu */
}
<
section
className=
"flex flex-col lg:flex-row gap-5 pb-10 mb-0"
>
{
/* left */
}
<
aside
className=
"w-full lg:w-1/3 flex-1 bg-[#e8c518] p-5"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
h2
className=
"text-xl font-bold uppercase text-[#063e8e]"
>
Hội viên tiêu biểu
</
h2
>
<
Link
href=
"/danh-ba-hoi-vien"
className=
"text-[#063e8e] hover:underline text-sm font-medium"
>
<
ChevronsRight
/>
</
Link
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-5"
/>
<
div
>
<
Swiper
modules=
{
[
Autoplay
,
Grid
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
grid=
{
{
rows
:
1
,
fill
:
"row"
}
}
slidesPerGroup=
{
3
}
breakpoints=
{
{
0
:
{
slidesPerView
:
2
,
spaceBetween
:
10
},
640
:
{
slidesPerView
:
3
,
spaceBetween
:
16
},
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
}
}
className=
"partner-swiper"
>
{
memberImages
.
map
((
src
,
i
)
=>
(
<
SwiperSlide
key=
{
i
}
>
<
div
className=
"aspect-square flex justify-center items-center bg-white rounded-lg shadow"
>
<
ImageNext
src=
{
src
}
alt=
{
`partner-${i}`
}
width=
{
160
}
height=
{
160
}
sizes=
"(max-width:640px) 25vw,(max-width:1024px) 15vw,10vw"
className=
"w-3/4 h-3/4 object-contain"
/>
</
div
>
</
SwiperSlide
>
))
}
</
Swiper
>
</
div
>
</
aside
>
{
/* right */
}
<
aside
className=
"w-full lg:w-[30%] py-5"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
h2
className=
"text-xl font-bold uppercase text-[#063e8e]"
>
Kết nối hội viên
</
h2
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-5"
/>
<
div
className=
"pb-10"
>
<
Swiper
modules=
{
[
Autoplay
,
Grid
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
grid=
{
{
rows
:
2
,
fill
:
"row"
}
}
slidesPerGroup=
{
3
}
breakpoints=
{
{
0
:
{
slidesPerView
:
2
,
spaceBetween
:
10
},
640
:
{
slidesPerView
:
3
,
spaceBetween
:
16
},
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
}
}
className=
"partner-swiper"
>
{
partnerImages
.
map
((
src
,
i
)
=>
(
<
SwiperSlide
key=
{
i
}
>
<
div
className=
"aspect-square flex justify-center items-center bg-white rounded-lg shadow"
>
<
ImageNext
src=
{
src
}
alt=
{
`partner-${i}`
}
width=
{
160
}
height=
{
160
}
sizes=
"(max-width:640px) 25vw,(max-width:1024px) 15vw,10vw"
className=
"w-3/4 h-3/4 object-contain"
/>
</
div
>
</
SwiperSlide
>
))
}
</
Swiper
>
</
div
>
</
aside
>
</
section
>
{
/* Video + đối tác */
}
<
section
className=
"flex flex-col lg:flex-row gap-5 pb-10"
>
{
/* left */
}
<
div
className=
"flex flex-col flex-1"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
h2
className=
"text-xl font-bold uppercase text-[#063e8e]"
>
Video
</
h2
>
<
Link
href=
"/video"
className=
"text-[#063e8e] hover:underline text-sm font-medium"
>
<
ChevronsRight
/>
</
Link
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-5"
/>
<
div
className=
"flex flex-col md:flex-row gap-4 md:gap-6"
>
{
[
{
src
:
"https://www.youtube.com/embed/J0Iz0iGuAXY"
,
title
:
"VCCI-HCM 2024 IN REVIEW (ENGLISH VERSION)"
,
},
{
src
:
"https://www.youtube.com/embed/_OnnGWv2ehM"
,
title
:
"Hội nghị Hội viên VCCI - Gala Mừng Xuân Ất Tỵ 2025"
,
},
].
map
((
video
,
i
)
=>
(
<
div
key=
{
i
}
className=
"w-full md:w-1/2"
>
<
div
className=
"aspect-video rounded-lg overflow-hidden shadow"
>
<
iframe
className=
"w-full h-full font-bold"
src=
{
video
.
src
}
title=
{
video
.
title
}
frameBorder=
"0"
allow=
"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy=
"strict-origin-when-cross-origin"
allowFullScreen
/>
</
div
>
<
p
className=
"mt-2 text-sm text-gray-700 font-medium"
>
{
video
.
title
}
</
p
>
</
div
>
</
section
>
</
div
>
<
div
className=
"w-full lg:w-[30%] justify-center items-start flex"
>
<
a
href=
"https://smartgara.ecaraid.com/"
>
<
img
src=
"/home/eCarAid_web_banner_600x400.webp"
alt=
"banner"
/>
</
a
>
))
}
</
div
>
</
div
>
{
/* Hội viên tiêu biểu */
}
<
section
className=
"flex flex-col lg:flex-row gap-5 pb-10 mb-0"
>
{
/* left */
}
<
aside
className=
"w-full lg:w-1/3 flex-1 bg-[#e8c518] p-5"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
h2
className=
"text-xl font-bold uppercase text-[#063e8e]"
>
Hội viên tiêu biểu
</
h2
>
<
a
href=
"/danh-ba-hoi-vien"
className=
"text-[#063e8e] hover:underline text-sm font-medium"
>
<
ChevronsRight
/>
</
a
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-5"
/>
<
div
>
<
Swiper
modules=
{
[
Autoplay
,
Grid
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
grid=
{
{
rows
:
1
,
fill
:
"row"
}
}
slidesPerGroup=
{
3
}
breakpoints=
{
{
0
:
{
slidesPerView
:
2
,
spaceBetween
:
10
},
640
:
{
slidesPerView
:
3
,
spaceBetween
:
16
},
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
}
}
className=
"partner-swiper"
>
{
hoivien
.
map
((
src
,
i
)
=>
(
<
SwiperSlide
key=
{
i
}
>
<
div
className=
"aspect-square flex justify-center items-center bg-white rounded-lg shadow"
>
<
img
src=
{
src
}
alt=
{
`partner-${i}`
}
className=
"w-3/4 h-3/4 object-contain"
/>
</
div
>
</
SwiperSlide
>
))
}
</
Swiper
>
</
div
>
</
aside
>
{
/* right */
}
<
aside
className=
"w-full lg:w-[30%] py-5"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
h2
className=
"text-xl font-bold uppercase text-[#063e8e]"
>
Kết nối hội viên
</
h2
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-5"
/>
<
div
className=
"pb-10"
>
<
Swiper
modules=
{
[
Autoplay
,
Grid
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
grid=
{
{
rows
:
2
,
fill
:
"row"
}
}
slidesPerGroup=
{
3
}
breakpoints=
{
{
0
:
{
slidesPerView
:
2
,
spaceBetween
:
10
},
640
:
{
slidesPerView
:
3
,
spaceBetween
:
16
},
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
}
}
className=
"partner-swiper"
>
{
images
.
map
((
src
,
i
)
=>
(
<
SwiperSlide
key=
{
i
}
>
<
div
className=
"aspect-square flex justify-center items-center bg-white rounded-lg shadow"
>
<
img
src=
{
src
}
alt=
{
`partner-${i}`
}
className=
"w-3/4 h-3/4 object-contain"
/>
</
div
>
</
SwiperSlide
>
))
}
</
Swiper
>
</
div
>
</
aside
>
</
section
>
{
/* Video + đối tác */
}
<
section
className=
"flex flex-col lg:flex-row gap-5 pb-10"
>
{
/* left */
}
<
div
className=
"flex flex-col flex-1"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
h2
className=
"text-xl font-bold uppercase text-[#063e8e]"
>
Video
</
h2
>
<
a
href=
"/video"
className=
"text-[#063e8e] hover:underline text-sm font-medium"
>
<
ChevronsRight
/>
</
a
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-5"
/>
<
div
className=
"flex flex-col md:flex-row gap-4 md:gap-6"
>
{
[
{
src
:
"https://www.youtube.com/embed/J0Iz0iGuAXY"
,
title
:
"VCCI-HCM 2024 IN REVIEW (ENGLISH VERSION)"
,
},
{
src
:
"https://www.youtube.com/embed/_OnnGWv2ehM"
,
title
:
"Hội nghị Hội viên VCCI - Gala Mừng Xuân Ất Tỵ 2025"
,
},
].
map
((
video
,
i
)
=>
(
<
div
key=
{
i
}
className=
"w-full md:w-1/2"
>
<
div
className=
"aspect-video rounded-lg overflow-hidden shadow"
>
<
iframe
className=
"w-full h-full font-bold"
src=
{
video
.
src
}
title=
{
video
.
title
}
frameBorder=
"0"
allow=
"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy=
"strict-origin-when-cross-origin"
allowFullScreen
{
/* right */
}
<
aside
className=
"w-full lg:w-[30%]"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
h2
className=
"text-xl font-bold uppercase text-[#063e8e]"
>
Đối tác
</
h2
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-5"
/>
<
div
className=
"pb-10"
>
<
Swiper
modules=
{
[
Autoplay
,
Grid
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
grid=
{
{
rows
:
2
,
fill
:
"row"
}
}
slidesPerGroup=
{
3
}
breakpoints=
{
{
0
:
{
slidesPerView
:
2
,
spaceBetween
:
10
},
640
:
{
slidesPerView
:
3
,
spaceBetween
:
16
},
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
}
}
className=
"partner-swiper"
>
{
partnerImages
.
map
((
src
,
i
)
=>
(
<
SwiperSlide
key=
{
i
}
>
<
div
className=
"aspect-square flex justify-center items-center bg-white rounded-lg shadow"
>
<
ImageNext
src=
{
src
}
alt=
{
`partner-${i}`
}
width=
{
160
}
height=
{
160
}
sizes=
"(max-width:640px) 25vw,(max-width:1024px) 15vw,10vw"
className=
"w-3/4 h-3/4 object-contain"
/>
</
div
>
<
p
className=
"mt-2 text-sm text-gray-700 font-medium"
>
{
video
.
title
}
</
p
>
</
div
>
</
SwiperSlide
>
))
}
</
div
>
</
div
>
{
/* right */
}
<
aside
className=
"w-full lg:w-[30%]"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
h2
className=
"text-xl font-bold uppercase text-[#063e8e]"
>
Đối tác
</
h2
>
</
div
>
<
hr
className=
"border-[#063e8e] mb-5"
/>
<
div
className=
"pb-10"
>
<
Swiper
modules=
{
[
Autoplay
,
Grid
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop
grid=
{
{
rows
:
2
,
fill
:
"row"
}
}
slidesPerGroup=
{
3
}
breakpoints=
{
{
0
:
{
slidesPerView
:
2
,
spaceBetween
:
10
},
640
:
{
slidesPerView
:
3
,
spaceBetween
:
16
},
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
}
}
className=
"partner-swiper"
>
{
images
.
map
((
src
,
i
)
=>
(
<
SwiperSlide
key=
{
i
}
>
<
div
className=
"aspect-square flex justify-center items-center bg-white rounded-lg shadow"
>
<
img
src=
{
src
}
alt=
{
`partner-${i}`
}
className=
"w-3/4 h-3/4 object-contain"
/>
</
div
>
</
SwiperSlide
>
))
}
</
Swiper
>
</
div
>
</
aside
>
</
section
>
</
div
>
</>
)
</
Swiper
>
</
div
>
</
aside
>
</
section
>
</
div
>
</>
);
};
...
...
src/components/base/image/index.tsx
0 → 100644
View file @
9f9abbe5
import
Image
from
"next/image"
;
import
{
useState
}
from
"react"
;
const
ImageNext
=
({
src
,
alt
,
width
,
height
,
className
,
onError
}:
any
)
=>
{
const
[
imgSrc
,
setImgSrc
]
=
useState
(
src
);
return
(
<
Image
src=
{
imgSrc
}
alt=
{
alt
}
width=
{
width
}
height=
{
height
}
className=
{
className
}
onError=
{
()
=>
setImgSrc
(
onError
||
"/img-error.png"
)
}
/>
);
};
export
default
ImageNext
;
src/constants/memberImages.ts
0 → 100644
View file @
9f9abbe5
const
memberImages
=
[
"/home/hoi-vien-tieu-bieu/logo-GTD-768x768.png.webp"
,
"/home/hoi-vien-tieu-bieu/Nhua-Long-Thanh_Logo.jpg.webp"
,
"/home/hoi-vien-tieu-bieu/Nova_Group_logo-1.png.webp"
,
"/home/hoi-vien-tieu-bieu/samngoclinh-1-768x768.png.webp"
,
"/home/hoi-vien-tieu-bieu/Screenshot-2022-12-26-144136-768x768.png.webp"
,
"/home/hoi-vien-tieu-bieu/UOB-logo_Vuong.jpeg.webp"
,
];
export
default
memberImages
;
\ No newline at end of file
src/constants/partnerImages.ts
0 → 100644
View file @
9f9abbe5
const
partnerImages
=
[
"/home/doi-tac/AMFORI-1.png.webp"
,
"/home/doi-tac/AUS4SKILLS-1.png.webp"
,
"/home/doi-tac/BetterWork-1.png.webp"
,
"/home/doi-tac/BOI-LOGO.jpg.webp"
,
"/home/doi-tac/DNV-logo-1-1.png.webp"
,
"/home/doi-tac/GERMAN-COOPERATION-1.png.webp"
,
"/home/doi-tac/GIZ.png.webp"
,
"/home/doi-tac/HBA.png.webp"
,
"/home/doi-tac/ILO-1.png.webp"
,
"/home/doi-tac/InvestHK.png.webp"
,
"/home/doi-tac/IOM-1.png.webp"
,
"/home/doi-tac/JICA-134x100-1-1.jpg.webp"
,
"/home/doi-tac/KIRBY.png.webp"
,
"/home/doi-tac/NHO-1.png.webp"
,
"/home/doi-tac/OXFAM-1.png.webp"
,
"/home/doi-tac/RECOTVET-1.png.webp"
,
"/home/doi-tac/SC-1.png.webp"
,
"/home/doi-tac/UNDP.png.webp"
,
];
export
default
partnerImages
;
\ No newline at end of file
src/helpers/stripImageAndHtml.ts
0 → 100644
View file @
9f9abbe5
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
,
''
)
}
export
default
stripImagesAndHtml
\ No newline at end of file
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