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
34a66524
Commit
34a66524
authored
Nov 19, 2025
by
Văn Hoàng
Browse files
Options
Browse Files
Download
Plain Diff
[tag]0.1-vcci
parents
e7182338
b53461dd
Pipeline
#44281
passed with stages
in 6 minutes and 12 seconds
Changes
5
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
64 additions
and
21 deletions
+64
-21
page.tsx
src/app/(main)/(home)/page.tsx
+4
-7
ArticlePage.tsx
src/app/(main)/[...slug]/templates/ArticlePage.tsx
+19
-3
EventPage.tsx
src/app/(main)/[...slug]/templates/EventPage.tsx
+19
-3
header.tsx
src/app/(main)/_lib/layout/header.tsx
+1
-1
page.tsx
src/app/(main)/search/page.tsx
+21
-7
No files found.
src/app/(main)/(home)/page.tsx
View file @
34a66524
...
@@ -247,14 +247,11 @@ const Page = () => {
...
@@ -247,14 +247,11 @@ const Page = () => {
/>
/>
</
div
>
</
div
>
<
div
className=
"flex-1 p-5 pt-
0
"
>
<
div
className=
"flex-1 p-5 pt-
1
"
>
<
p
className=
"text-[#063E8E] font-bold text-xl line-clamp-2"
>
<
p
className=
"text-[#063E8E] font-bold
pb-2
text-xl line-clamp-2"
>
{
news
.
title
}
{
news
.
title
}
</
p
>
</
p
>
<
p
className=
"text-gray-500 text-sm"
>
<
p
className=
"line-clamp-4 text-justify"
>
{
stripImagesAndHtml
(
news
.
description
)
}
</
p
>
{
dayjs
(
news
.
release_at
).
format
(
"DD/MM/YYYY"
)
}
</
p
>
<
p
className=
"line-clamp-4"
>
{
stripImagesAndHtml
(
news
.
description
)
}
</
p
>
</
div
>
</
div
>
</
a
>
</
a
>
))
}
))
}
...
@@ -389,7 +386,7 @@ const Page = () => {
...
@@ -389,7 +386,7 @@ const Page = () => {
<
p
className=
"text-gray-500 text-sm my-1"
>
<
p
className=
"text-gray-500 text-sm my-1"
>
{
dayjs
(
event
.
start_time
).
format
(
"DD/MM/YYYY"
)
}
{
dayjs
(
event
.
start_time
).
format
(
"DD/MM/YYYY"
)
}
</
p
>
</
p
>
<
p
className=
"line-clamp-3"
>
{
stripImagesAndHtml
(
event
.
description
)
}
</
p
>
<
p
className=
"line-clamp-3
text-justify
"
>
{
stripImagesAndHtml
(
event
.
description
)
}
</
p
>
</
div
>
</
div
>
</
a
>
</
a
>
))
}
))
}
...
...
src/app/(main)/[...slug]/templates/ArticlePage.tsx
View file @
34a66524
...
@@ -3,14 +3,14 @@
...
@@ -3,14 +3,14 @@
import
{
GetNewsPageConfigResponseType
}
from
"@/api/types/news-page-config"
;
import
{
GetNewsPageConfigResponseType
}
from
"@/api/types/news-page-config"
;
import
{
useGetNewsPageConfigGetHierarchical
}
from
"@/api/endpoints/news-page-config"
;
import
{
useGetNewsPageConfigGetHierarchical
}
from
"@/api/endpoints/news-page-config"
;
import
ListCategory
from
"@/components/base/list-category"
;
import
ListCategory
from
"@/components/base/list-category"
;
import
{
useParams
}
from
"next/dist/client/components
/navigation"
;
import
{
useParams
,
useSearchParams
,
useRouter
,
usePathname
}
from
"next
/navigation"
;
import
{
useGetNews
}
from
"@/api/endpoints/news"
;
import
{
useGetNews
}
from
"@/api/endpoints/news"
;
import
{
GetNewsResponseType
}
from
"@/api/types/news"
;
import
{
GetNewsResponseType
}
from
"@/api/types/news"
;
import
CardNews
from
"@/components/base/card-news"
;
import
CardNews
from
"@/components/base/card-news"
;
import
{
Pagination
}
from
"@/components/base/pagination"
;
import
{
Pagination
}
from
"@/components/base/pagination"
;
import
ListFilter
from
"@/components/base/list-filter"
;
import
ListFilter
from
"@/components/base/list-filter"
;
import
EventCalendar
from
"@/components/base/event-calendar"
;
import
EventCalendar
from
"@/components/base/event-calendar"
;
import
{
useState
}
from
"react"
;
import
{
useState
,
useEffect
}
from
"react"
;
import
{
Spinner
}
from
"@/components/ui"
;
import
{
Spinner
}
from
"@/components/ui"
;
export
default
function
ArticlePage
()
{
export
default
function
ArticlePage
()
{
...
@@ -19,11 +19,27 @@ export default function ArticlePage() {
...
@@ -19,11 +19,27 @@ export default function ArticlePage() {
const
slug
=
Array
.
isArray
(
params
.
slug
)
?
params
.
slug
:
[
params
.
slug
];
const
slug
=
Array
.
isArray
(
params
.
slug
)
?
params
.
slug
:
[
params
.
slug
];
const
path
=
slug
.
join
(
"/"
);
const
path
=
slug
.
join
(
"/"
);
const
searchParams
=
useSearchParams
();
const
router
=
useRouter
();
const
pathname
=
usePathname
();
// states
// states
const
initialPage
=
Number
(
searchParams
.
get
(
"page"
)
??
"1"
);
const
[
submitSearch
,
setSubmitSearch
]
=
useState
(
""
);
const
[
submitSearch
,
setSubmitSearch
]
=
useState
(
""
);
const
[
page
,
setPage
]
=
useState
(
1
);
const
[
page
,
setPage
]
=
useState
(
initialPage
);
const
pageSize
=
5
;
const
pageSize
=
5
;
useEffect
(()
=>
{
const
params
=
new
URLSearchParams
(
searchParams
.
toString
());
if
(
page
>
1
)
{
params
.
set
(
"page"
,
String
(
page
));
}
else
{
params
.
delete
(
"page"
);
}
const
qs
=
params
.
toString
();
router
.
replace
(
qs
?
`
${
pathname
}
?
${
qs
}
`
:
pathname
,
{
scroll
:
false
});
},
[
page
]);
// query
// query
const
{
data
:
categoriesPage
}
=
useGetNewsPageConfigGetHierarchical
<
GetNewsPageConfigResponseType
>
({
const
{
data
:
categoriesPage
}
=
useGetNewsPageConfigGetHierarchical
<
GetNewsPageConfigResponseType
>
({
code
:
slug
[
0
],
code
:
slug
[
0
],
...
...
src/app/(main)/[...slug]/templates/EventPage.tsx
View file @
34a66524
'use client'
;
'use client'
;
import
{
useState
}
from
"react"
;
import
{
use
Effect
,
use
State
}
from
"react"
;
import
{
useParams
}
from
"next/navigation"
;
import
{
useParams
,
usePathname
,
useRouter
,
useSearchParams
}
from
"next/navigation"
;
import
{
useGetEvents
}
from
"@/api/endpoints/event"
;
import
{
useGetEvents
}
from
"@/api/endpoints/event"
;
import
{
EventApiResponse
}
from
"@/api/types/event"
;
import
{
EventApiResponse
}
from
"@/api/types/event"
;
...
@@ -20,11 +20,27 @@ export default function EventPage() {
...
@@ -20,11 +20,27 @@ export default function EventPage() {
const
params
=
useParams
();
const
params
=
useParams
();
const
slug
=
Array
.
isArray
(
params
.
slug
)
?
params
.
slug
:
[
params
.
slug
];
const
slug
=
Array
.
isArray
(
params
.
slug
)
?
params
.
slug
:
[
params
.
slug
];
const
searchParams
=
useSearchParams
();
const
router
=
useRouter
();
const
pathname
=
usePathname
();
// states
// states
const
initialPage
=
Number
(
searchParams
.
get
(
"page"
)
??
"1"
);
const
[
submitSearch
,
setSubmitSearch
]
=
useState
(
""
);
const
[
submitSearch
,
setSubmitSearch
]
=
useState
(
""
);
const
[
page
,
setPage
]
=
useState
(
1
);
const
[
page
,
setPage
]
=
useState
(
initialPage
);
const
pageSize
=
5
;
const
pageSize
=
5
;
useEffect
(()
=>
{
const
params
=
new
URLSearchParams
(
searchParams
.
toString
());
if
(
page
>
1
)
{
params
.
set
(
"page"
,
String
(
page
));
}
else
{
params
.
delete
(
"page"
);
}
const
qs
=
params
.
toString
();
router
.
replace
(
qs
?
`
${
pathname
}
?
${
qs
}
`
:
pathname
,
{
scroll
:
false
});
},
[
page
]);
// query
// query
const
{
data
:
categoriesPage
}
=
useGetNewsPageConfigGetHierarchical
<
GetNewsPageConfigResponseType
>
({
const
{
data
:
categoriesPage
}
=
useGetNewsPageConfigGetHierarchical
<
GetNewsPageConfigResponseType
>
({
code
:
`
${
slug
[
0
]}
`
,
code
:
`
${
slug
[
0
]}
`
,
...
...
src/app/(main)/_lib/layout/header.tsx
View file @
34a66524
...
@@ -52,7 +52,7 @@ function Header() {
...
@@ -52,7 +52,7 @@ function Header() {
const
value
=
const
value
=
(
e
.
currentTarget
as
HTMLInputElement
).
value
||
""
;
(
e
.
currentTarget
as
HTMLInputElement
).
value
||
""
;
const
encoded
=
encodeURIComponent
(
value
);
const
encoded
=
encodeURIComponent
(
value
);
router
.
push
(
`/search?q=${encoded}`
);
router
.
push
(
`/search?q=${encoded}
&page=1
`
);
}
}
}
}
}
}
/>
/>
...
...
src/app/(main)/search/page.tsx
View file @
34a66524
"use client"
;
"use client"
;
import
React
,
{
useState
,
Suspense
}
from
"react"
;
import
React
,
{
useState
,
Suspense
,
useEffect
}
from
"react"
;
import
ListCategory
from
"@/components/base/list-category"
;
import
ListCategory
from
"@/components/base/list-category"
;
import
ListFilter
from
"@/components/base/list-filter"
;
import
ListFilter
from
"@/components/base/list-filter"
;
import
CardNews
from
"@/components/base/card-news"
;
import
CardNews
from
"@/components/base/card-news"
;
...
@@ -9,12 +9,15 @@ import Image from "next/image";
...
@@ -9,12 +9,15 @@ import Image from "next/image";
import
{
useGetNews
}
from
"@api/endpoints/news"
;
import
{
useGetNews
}
from
"@api/endpoints/news"
;
import
{
GetNewsResponseType
}
from
"@api/types/news"
;
import
{
GetNewsResponseType
}
from
"@api/types/news"
;
import
{
Spinner
}
from
"@components/ui/spinner"
;
import
{
Spinner
}
from
"@components/ui/spinner"
;
import
{
useSearchParams
}
from
'next/navigation'
import
{
useSearchParams
,
useRouter
}
from
'next/navigation'
function
SearchContent
()
{
function
SearchContent
()
{
const
[
page
,
setPage
]
=
useState
(
1
);
const
router
=
useRouter
(
);
const
searchParams
=
useSearchParams
()
const
searchParams
=
useSearchParams
()
;
const
query
=
searchParams
.
get
(
'q'
)
||
''
;
const
query
=
searchParams
.
get
(
'q'
)
||
''
;
const
pageFromUrl
=
searchParams
.
get
(
'page'
);
const
[
page
,
setPage
]
=
useState
(
pageFromUrl
?
parseInt
(
pageFromUrl
)
:
1
);
const
pageSize
=
5
;
const
pageSize
=
5
;
const
{
data
:
allData
,
isLoading
}
=
useGetNews
<
GetNewsResponseType
>
({
const
{
data
:
allData
,
isLoading
}
=
useGetNews
<
GetNewsResponseType
>
({
pageSize
:
String
(
pageSize
),
pageSize
:
String
(
pageSize
),
...
@@ -22,6 +25,20 @@ function SearchContent() {
...
@@ -22,6 +25,20 @@ function SearchContent() {
filters
:
query
?
`title @=
${
query
}
`
:
undefined
,
filters
:
query
?
`title @=
${
query
}
`
:
undefined
,
});
});
// Update URL when page changes
useEffect
(()
=>
{
const
params
=
new
URLSearchParams
(
searchParams
.
toString
());
params
.
set
(
'page'
,
String
(
page
));
router
.
push
(
`/search?
${
params
.
toString
()}
`
,
{
scroll
:
false
});
},
[
page
]);
// Sync state with URL on mount/change
useEffect
(()
=>
{
if
(
pageFromUrl
)
{
setPage
(
parseInt
(
pageFromUrl
));
}
},
[
pageFromUrl
]);
return
(
return
(
<
div
className=
"min-h-screen container mx-auto p-4"
>
<
div
className=
"min-h-screen container mx-auto p-4"
>
<
div
className=
"w-full flex flex-col gap-5"
>
<
div
className=
"w-full flex flex-col gap-5"
>
...
@@ -29,7 +46,6 @@ function SearchContent() {
...
@@ -29,7 +46,6 @@ function SearchContent() {
<
div
className=
"w-full px-4 sm:px-6 lg:px-8"
>
<
div
className=
"w-full px-4 sm:px-6 lg:px-8"
>
<
div
className=
"py-3"
>
<
div
className=
"py-3"
>
<
h1
className=
"text-md md:text-lg font-semibold leading-6 text-gray-900"
>
<
h1
className=
"text-md md:text-lg font-semibold leading-6 text-gray-900"
>
{
" "
}
Search Results for:
{
query
}
Search Results for:
{
query
}
</
h1
>
</
h1
>
</
div
>
</
div
>
...
@@ -37,7 +53,6 @@ function SearchContent() {
...
@@ -37,7 +53,6 @@ function SearchContent() {
</
div
>
</
div
>
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
<
div
className=
"grid grid-cols-1 lg:grid-cols-3 gap-6"
>
{
/* Main content */
}
<
main
className=
"lg:col-span-2 bg-background "
>
<
main
className=
"lg:col-span-2 bg-background "
>
<
div
className=
"pb-5 overflow-hidden"
>
<
div
className=
"pb-5 overflow-hidden"
>
{
isLoading
?
(
{
isLoading
?
(
...
@@ -76,7 +91,6 @@ function SearchContent() {
...
@@ -76,7 +91,6 @@ function SearchContent() {
</
div
>
</
div
>
</
main
>
</
main
>
{
/* Sidebar */
}
<
aside
className=
"space-y-6 order-first lg:order-last"
>
<
aside
className=
"space-y-6 order-first lg:order-last"
>
<
div
className=
"bg-white border rounded-md overflow-hidden hidden lg:block"
>
<
div
className=
"bg-white border rounded-md overflow-hidden hidden lg:block"
>
<
div
className=
"w-full relative bg-gray-100"
>
<
div
className=
"w-full relative bg-gray-100"
>
...
...
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