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
dff8066d
Commit
dff8066d
authored
Jan 06, 2026
by
Phạm Quang Bảo
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feat/loading' into 'develop'
update/feature loading content See merge request
!47
parents
1242be99
724f942d
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
95 additions
and
72 deletions
+95
-72
index.tsx
src/app/(main)/(home)/components/events/index.tsx
+1
-1
index.tsx
src/app/(main)/(home)/components/featured-news/index.tsx
+42
-36
index.tsx
src/app/(main)/(home)/components/news/index.tsx
+44
-32
index.tsx
src/components/shared/image-next/index.tsx
+8
-3
No files found.
src/app/(main)/(home)/components/events/index.tsx
View file @
dff8066d
...
@@ -26,7 +26,7 @@ function Events() {
...
@@ -26,7 +26,7 @@ function Events() {
<
div
className=
"flex flex-col md:flex-row gap-5"
>
<
div
className=
"flex flex-col md:flex-row gap-5"
>
{
isLoading
?
(
{
isLoading
?
(
<
div
className=
"
container w-full h-[80vh] flex justify-center items-center
"
>
<
div
className=
"
flex flex-col justify-center items-center w-full min-h-[180px] sm:min-h-[220px] p-3
"
>
<
Spinner
/>
<
Spinner
/>
</
div
>
</
div
>
)
:
(
)
:
(
...
...
src/app/(main)/(home)/components/featured-news/index.tsx
View file @
dff8066d
...
@@ -7,9 +7,10 @@ import Link from "next/link";
...
@@ -7,9 +7,10 @@ import Link from "next/link";
import
{
Swiper
,
SwiperSlide
}
from
"swiper/react"
;
import
{
Swiper
,
SwiperSlide
}
from
"swiper/react"
;
import
{
Autoplay
,
Grid
}
from
"swiper/modules"
;
import
{
Autoplay
,
Grid
}
from
"swiper/modules"
;
import
BASE_URL
from
"@/links/index"
;
import
BASE_URL
from
"@/links/index"
;
import
{
Spinner
}
from
"@/components/ui/spinner"
;
function
FeaturedNews
()
{
function
FeaturedNews
()
{
const
{
data
}
=
useGetNews
<
GetNewsResponseType
>
(
const
{
data
,
isLoading
}
=
useGetNews
<
GetNewsResponseType
>
(
{
{
pageSize
:
'10'
,
pageSize
:
'10'
,
}
}
...
@@ -26,41 +27,46 @@ function FeaturedNews() {
...
@@ -26,41 +27,46 @@ function FeaturedNews() {
<
div
className=
"flex-1 h-px bg-linear-to-l from-transparent via-gray-300 to-gray-400"
></
div
>
<
div
className=
"flex-1 h-px bg-linear-to-l from-transparent via-gray-300 to-gray-400"
></
div
>
</
div
>
</
div
>
</
div
>
</
div
>
{
isLoading
?
(
<
Swiper
<
div
className=
"flex justify-center items-center w-full h-64"
>
modules=
{
[
Autoplay
]
}
<
Spinner
/>
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
</
div
>
loop
)
:
(
breakpoints=
{
{
<
Swiper
0
:
{
slidesPerView
:
1.1
,
spaceBetween
:
10
},
modules=
{
[
Autoplay
]
}
640
:
{
slidesPerView
:
2
,
spaceBetween
:
16
},
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
loop
}
}
breakpoints=
{
{
className=
"pb-5"
0
:
{
slidesPerView
:
1.1
,
spaceBetween
:
10
},
>
640
:
{
slidesPerView
:
2
,
spaceBetween
:
16
},
{
data
?.
responseData
?.
rows
.
map
((
news
)
=>
(
1024
:
{
slidesPerView
:
3
,
spaceBetween
:
24
},
<
SwiperSlide
key=
{
news
.
id
}
>
}
}
<
Link
className=
"pb-5"
href=
{
`${news.external_link}`
}
>
className=
"relative block bg-white shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"
{
data
?.
responseData
?.
rows
.
map
((
news
)
=>
(
>
<
SwiperSlide
key=
{
news
.
id
}
>
<
ImageNext
<
Link
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
href=
{
`${news.external_link}`
}
alt=
{
news
.
title
}
className=
"relative block bg-white shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"
width=
{
600
}
>
height=
{
400
}
<
ImageNext
sizes=
"(max-width:640px) 100vw,(max-width:1024px) 50vw,33vw"
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
className=
"w-full aspect-3/2 sm:h-56 md:h-64 object-cover"
alt=
{
news
.
title
}
/>
width=
{
600
}
<
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"
>
height=
{
400
}
<
p
className=
"text-white text-center font-semibold line-clamp-2 text-sm sm:text-base leading-snug"
>
sizes=
"(max-width:640px) 100vw,(max-width:1024px) 50vw,33vw"
{
news
.
title
}
className=
"w-full aspect-3/2 sm:h-56 md:h-64 object-cover"
</
p
>
/>
</
div
>
<
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"
>
</
Link
>
<
p
className=
"text-white text-center font-semibold line-clamp-2 text-sm sm:text-base leading-snug"
>
</
SwiperSlide
>
{
news
.
title
}
))
}
</
p
>
</
Swiper
>
</
div
>
</
Link
>
</
SwiperSlide
>
))
}
</
Swiper
>
)
}
</
section
>
</
section
>
);
);
}
}
...
...
src/app/(main)/(home)/components/news/index.tsx
View file @
dff8066d
...
@@ -7,12 +7,13 @@ import { ChevronsRight } from "lucide-react";
...
@@ -7,12 +7,13 @@ import { ChevronsRight } from "lucide-react";
import
{
useState
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
stripImagesAndHtml
from
"@/helpers/stripImageAndHtml"
;
import
stripImagesAndHtml
from
"@/helpers/stripImageAndHtml"
;
import
CardNews
from
"./components/card-news"
;
import
CardNews
from
"./components/card-news"
;
import
{
Spinner
}
from
"@/components/ui/spinner"
;
const
News
=
()
=>
{
const
News
=
()
=>
{
const
[
tab
,
setTab
]
=
useState
(
"all"
);
const
[
tab
,
setTab
]
=
useState
(
"all"
);
const
{
data
:
newsSpecial
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
'1'
});
const
{
data
:
newsSpecial
,
isLoading
:
isLoadingSpecial
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
'1'
});
const
{
data
:
newsFilters
}
=
useGetNews
<
GetNewsResponseType
>
(
const
{
data
:
newsFilters
,
isLoading
:
isLoadingFilters
}
=
useGetNews
<
GetNewsResponseType
>
(
{
{
pageSize
:
'5'
,
pageSize
:
'5'
,
filters
:
tab
===
"all"
?
``
:
`page_config.code @=
${
tab
}
`
,
filters
:
tab
===
"all"
?
``
:
`page_config.code @=
${
tab
}
`
,
...
@@ -38,34 +39,39 @@ const News = () => {
...
@@ -38,34 +39,39 @@ const News = () => {
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
hr
className=
"border-[#063e8e] mb-4"
/>
<
div
className=
"flex flex-col md:flex-row gap-5"
>
<
div
className=
"flex flex-col md:flex-row gap-5"
>
{
newsSpecial
?.
responseData
.
rows
{
isLoadingSpecial
?
(
.
slice
(
0
,
1
)
<
div
className=
"flex justify-center items-center flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3"
>
.
map
((
news
:
NewsItem
)
=>
(
<
Spinner
/>
<
Link
</
div
>
key=
{
news
.
id
}
)
:
(
href=
{
`${news.external_link}`
}
newsSpecial
?.
responseData
.
rows
className=
"flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 bg-white"
.
slice
(
0
,
1
)
>
.
map
((
news
:
NewsItem
)
=>
(
<
div
className=
"w-full aspect-3/2 overflow-hidden"
>
<
Link
<
ImageNext
key=
{
news
.
id
}
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
href=
{
`${news.external_link}`
}
alt=
{
news
.
title
}
className=
"flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 bg-white"
width=
{
600
}
>
height=
{
400
}
<
div
className=
"w-full aspect-3/2 overflow-hidden"
>
sizes=
"(max-width:768px) 100vw,50vw"
<
ImageNext
className=
"w-full h-full object-cover"
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
/>
alt=
{
news
.
title
}
</
div
>
width=
{
600
}
height=
{
400
}
<
div
className=
"flex-1 p-5 pt-1"
>
sizes=
"(max-width:768px) 100vw,50vw"
<
p
className=
"text-[#063E8E] font-bold pb-2 text-xl line-clamp-2"
>
className=
"w-full h-full object-cover"
{
news
.
title
}
/>
</
p
>
</
div
>
<
p
className=
"line-clamp-4 text-justify"
>
{
stripImagesAndHtml
(
news
.
description
)
}
</
p
>
</
div
>
</
Link
>
))
}
<
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
>
</
Link
>
))
)
}
<
div
className=
"w-full md:w-1/2"
>
<
div
className=
"w-full md:w-1/2"
>
<
div
className=
"flex flex-wrap gap-2 sm:gap-3 mb-5"
>
<
div
className=
"flex flex-wrap gap-2 sm:gap-3 mb-5"
>
<
button
<
button
...
@@ -105,9 +111,15 @@ const News = () => {
...
@@ -105,9 +111,15 @@ const News = () => {
</
button
>
</
button
>
</
div
>
</
div
>
{
newsFilters
?.
responseData
?.
rows
.
slice
(
0
,
4
).
map
((
news
)
=>
(
{
isLoadingFilters
?
(
<
CardNews
key=
{
news
.
id
}
news=
{
news
}
/>
<
div
className=
"flex justify-center py-10"
>
))
}
<
Spinner
/>
</
div
>
)
:
(
newsFilters
?.
responseData
?.
rows
.
slice
(
0
,
4
).
map
((
news
)
=>
(
<
CardNews
key=
{
news
.
id
}
news=
{
news
}
/>
))
)
}
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
src/components/shared/image-next/index.tsx
View file @
dff8066d
import
Image
from
"next/image"
;
import
Image
from
"next/image"
;
import
{
useState
}
from
"react"
;
import
{
use
Effect
,
use
State
}
from
"react"
;
const
ImageNext
=
({
src
,
alt
,
width
,
height
,
className
,
onError
}:
any
)
=>
{
const
ImageNext
=
({
src
,
alt
,
width
,
height
,
className
,
fallback
=
"/img-error.png"
}:
any
)
=>
{
const
[
imgSrc
,
setImgSrc
]
=
useState
(
src
);
const
[
imgSrc
,
setImgSrc
]
=
useState
(
src
);
useEffect
(()
=>
{
setImgSrc
(
src
);
},
[
src
]);
return
(
return
(
<
Image
<
Image
src=
{
imgSrc
}
src=
{
imgSrc
}
...
@@ -11,7 +15,8 @@ const ImageNext = ({ src, alt, width, height, className, onError }: any) => {
...
@@ -11,7 +15,8 @@ const ImageNext = ({ src, alt, width, height, className, onError }: any) => {
width=
{
width
}
width=
{
width
}
height=
{
height
}
height=
{
height
}
className=
{
className
}
className=
{
className
}
onError=
{
()
=>
setImgSrc
(
onError
||
"/img-error.png"
)
}
onError=
{
()
=>
setImgSrc
(
fallback
)
}
unoptimized
/>
/>
);
);
};
};
...
...
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