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
adfed5ce
Commit
adfed5ce
authored
May 19, 2026
by
Lê Bảo Hồng Đức
☄
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix
parent
54901914
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
53 additions
and
32 deletions
+53
-32
custom-client.ts
src/api/mutator/custom-client.ts
+2
-1
index.tsx
...nts/business-opportunities/components/card-news/index.tsx
+2
-2
index.tsx
.../(home)/components/events/components/card-event/index.tsx
+3
-3
index.tsx
...in)/(home)/components/news/components/card-news/index.tsx
+2
-2
index.tsx
...)/(home)/components/policies-and-laws/card-news/index.tsx
+2
-2
use-home-posts.ts
src/app/(main)/(home)/lib/use-home-posts.ts
+2
-3
EventDetailPage.tsx
src/app/(main)/[...slug]/templates/EventDetailPage.tsx
+2
-2
data.ts
src/app/(main)/[...slug]/templates/data.ts
+2
-3
page.tsx
src/app/admin/login/page.tsx
+2
-1
index.tsx
src/components/base/card-events/index.tsx
+3
-3
index.tsx
src/components/base/card-news/index.tsx
+2
-3
cms-admin.ts
src/lib/api/cms-admin.ts
+2
-1
files.ts
src/lib/api/files.ts
+2
-4
admin-auth.ts
src/lib/auth/admin-auth.ts
+2
-1
index.d.ts
src/links/index.d.ts
+1
-0
index.ts
src/links/index.ts
+22
-1
No files found.
src/api/mutator/custom-client.ts
View file @
adfed5ce
import
Axios
,
{
AxiosError
,
AxiosHeaders
,
AxiosRequestConfig
,
InternalAxiosRequestConfig
}
from
"axios"
;
import
Axios
,
{
AxiosError
,
AxiosHeaders
,
AxiosRequestConfig
,
InternalAxiosRequestConfig
}
from
"axios"
;
import
links
from
"@/links"
;
import
{
import
{
ensureValidAdminAccessToken
,
ensureValidAdminAccessToken
,
refreshAdminAccessToken
,
refreshAdminAccessToken
,
...
@@ -10,7 +11,7 @@ interface RetriableAxiosRequestConfig extends InternalAxiosRequestConfig {
...
@@ -10,7 +11,7 @@ interface RetriableAxiosRequestConfig extends InternalAxiosRequestConfig {
const
createAxiosInstance
=
()
=>
{
const
createAxiosInstance
=
()
=>
{
const
instance
=
Axios
.
create
({
const
instance
=
Axios
.
create
({
baseURL
:
`
${
process
.
env
.
NEXT_PUBLIC_BACKEND_HOST
}
/api/v1.0`
,
baseURL
:
links
.
apiEndpoint
,
withCredentials
:
true
,
withCredentials
:
true
,
});
});
...
...
src/app/(main)/(home)/components/business-opportunities/components/card-news/index.tsx
View file @
adfed5ce
import
{
NewsItem
}
from
"@/api/types/news"
;
import
{
NewsItem
}
from
"@/api/types/news"
;
import
BASE_URL
from
"@/links"
;
import
{
resolveUploadUrl
}
from
"@/links"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
AppEditorContent
from
"@/components/shared/editor-content"
;
import
AppEditorContent
from
"@/components/shared/editor-content"
;
import
Link
from
"next/link"
;
import
Link
from
"next/link"
;
...
@@ -12,7 +12,7 @@ function CardNews({ news }: { news: NewsItem }) {
...
@@ -12,7 +12,7 @@ function CardNews({ news }: { news: NewsItem }) {
className=
"flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
className=
"flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
>
>
<
ImageNext
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
src=
{
resolveUploadUrl
(
news
.
thumbnail
)
}
alt=
{
news
.
title
}
alt=
{
news
.
title
}
className=
"aspect-3/2 object-cover"
className=
"aspect-3/2 object-cover"
width=
{
130
}
width=
{
130
}
...
...
src/app/(main)/(home)/components/events/components/card-event/index.tsx
View file @
adfed5ce
import
{
EventItem
}
from
'@/api/types/event'
import
{
EventItem
}
from
'@/api/types/event'
import
BASE_URL
from
'@/links'
import
{
resolveUploadUrl
}
from
'@/links'
import
dayjs
from
'dayjs'
;
import
dayjs
from
'dayjs'
;
import
AppEditorContent
from
'@/components/shared/editor-content'
;
import
AppEditorContent
from
'@/components/shared/editor-content'
;
import
Link
from
"next/link"
;
import
Link
from
"next/link"
;
...
@@ -12,7 +12,7 @@ function CardEvent({ event }: { event: EventItem }) {
...
@@ -12,7 +12,7 @@ function CardEvent({ event }: { event: EventItem }) {
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'
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'
>
>
<
ImageNext
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${event.image}`
}
src=
{
resolveUploadUrl
(
event
.
image
)
}
alt=
{
event
.
name
}
alt=
{
event
.
name
}
className=
'aspect-3/2 object-cover'
className=
'aspect-3/2 object-cover'
width=
{
130
}
width=
{
130
}
...
@@ -31,4 +31,4 @@ function CardEvent({ event }: { event: EventItem }) {
...
@@ -31,4 +31,4 @@ function CardEvent({ event }: { event: EventItem }) {
);
);
}
}
export
default
CardEvent
;
export
default
CardEvent
;
\ No newline at end of file
src/app/(main)/(home)/components/news/components/card-news/index.tsx
View file @
adfed5ce
import
{
NewsItem
}
from
"@/api/types/news"
;
import
{
NewsItem
}
from
"@/api/types/news"
;
import
BASE_URL
from
"@/links"
;
import
{
resolveUploadUrl
}
from
"@/links"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
AppEditorContent
from
"@/components/shared/editor-content"
;
import
AppEditorContent
from
"@/components/shared/editor-content"
;
import
Link
from
"next/link"
;
import
Link
from
"next/link"
;
...
@@ -12,7 +12,7 @@ function CardNews({ news }: { news: NewsItem }) {
...
@@ -12,7 +12,7 @@ function CardNews({ news }: { news: NewsItem }) {
className=
"flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
className=
"flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
>
>
<
ImageNext
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
src=
{
resolveUploadUrl
(
news
.
thumbnail
)
}
alt=
{
news
.
title
}
alt=
{
news
.
title
}
className=
"aspect-3/2 object-cover"
className=
"aspect-3/2 object-cover"
width=
{
130
}
width=
{
130
}
...
...
src/app/(main)/(home)/components/policies-and-laws/card-news/index.tsx
View file @
adfed5ce
import
{
NewsItem
}
from
"@/api/types/news"
;
import
{
NewsItem
}
from
"@/api/types/news"
;
import
BASE_URL
from
"@/links"
;
import
{
resolveUploadUrl
}
from
"@/links"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
Link
from
"next/link"
;
import
Link
from
"next/link"
;
import
ImageNext
from
"@/components/shared/image-next"
;
import
ImageNext
from
"@/components/shared/image-next"
;
...
@@ -11,7 +11,7 @@ function CardNews({ news }: { news: NewsItem }) {
...
@@ -11,7 +11,7 @@ function CardNews({ news }: { news: NewsItem }) {
className=
"flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
className=
"flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
>
>
<
ImageNext
<
ImageNext
src=
{
`${BASE_URL.imageEndpoint}${news.thumbnail}`
}
src=
{
resolveUploadUrl
(
news
.
thumbnail
)
}
alt=
{
news
.
title
}
alt=
{
news
.
title
}
className=
"aspect-3/2 object-cover"
className=
"aspect-3/2 object-cover"
width=
{
130
}
width=
{
130
}
...
...
src/app/(main)/(home)/lib/use-home-posts.ts
View file @
adfed5ce
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
import
*
as
React
from
"react"
;
import
*
as
React
from
"react"
;
import
{
useQuery
}
from
"@tanstack/react-query"
;
import
{
useQuery
}
from
"@tanstack/react-query"
;
import
{
useCustomClient
}
from
"@/api/mutator/custom-client"
;
import
{
useCustomClient
}
from
"@/api/mutator/custom-client"
;
import
Links
from
"@/links"
;
import
Links
,
{
resolveUploadUrl
}
from
"@/links"
;
type
RawHomeCategory
=
{
type
RawHomeCategory
=
{
id
?:
string
|
null
;
id
?:
string
|
null
;
...
@@ -153,9 +153,8 @@ const resolveAssetUrl = (value?: string | null) => {
...
@@ -153,9 +153,8 @@ const resolveAssetUrl = (value?: string | null) => {
const
trimmed
=
value
?.
trim
();
const
trimmed
=
value
?.
trim
();
if
(
!
trimmed
)
return
"/thumbnail.png"
;
if
(
!
trimmed
)
return
"/thumbnail.png"
;
if
(
trimmed
.
startsWith
(
"http://"
)
||
trimmed
.
startsWith
(
"https://"
))
return
trimmed
;
return
`
${
Links
.
imageEndpoint
}${
trimmed
.
replace
(
/^
\/
+/
,
""
)}
`
;
return
resolveUploadUrl
(
trimmed
)
;
};
};
const
sortByPublishedDesc
=
(
items
:
HomePostItem
[])
=>
const
sortByPublishedDesc
=
(
items
:
HomePostItem
[])
=>
...
...
src/app/(main)/[...slug]/templates/EventDetailPage.tsx
View file @
adfed5ce
...
@@ -6,7 +6,7 @@ import { notFound, useParams } from "next/navigation";
...
@@ -6,7 +6,7 @@ import { notFound, useParams } from "next/navigation";
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
parse
from
"html-react-parser"
;
import
parse
from
"html-react-parser"
;
import
BASE_URL
from
"@/links"
;
import
{
resolveUploadUrl
}
from
"@/links"
;
import
{
useGetEvents
}
from
"@/api/endpoints/event"
;
import
{
useGetEvents
}
from
"@/api/endpoints/event"
;
import
{
EventApiResponse
}
from
"@/api/types/event"
;
import
{
EventApiResponse
}
from
"@/api/types/event"
;
...
@@ -58,7 +58,7 @@ export default function EventDetailPage() {
...
@@ -58,7 +58,7 @@ export default function EventDetailPage() {
{
eventsDetail
?.
responseData
?.
rows
[
0
].
image
?
(
{
eventsDetail
?.
responseData
?.
rows
[
0
].
image
?
(
<
div
className=
"w-full h-52 relative "
>
<
div
className=
"w-full h-52 relative "
>
<
EventImage
<
EventImage
src=
{
`${BASE_URL.imageEndpoint}${eventsDetail?.responseData?.rows[0].image}`
}
src=
{
resolveUploadUrl
(
eventsDetail
?.
responseData
?.
rows
[
0
].
image
)
}
alt=
{
eventsDetail
?.
responseData
?.
rows
[
0
]?.
name
||
"image"
}
alt=
{
eventsDetail
?.
responseData
?.
rows
[
0
]?.
name
||
"image"
}
/>
/>
</
div
>
</
div
>
...
...
src/app/(main)/[...slug]/templates/data.ts
View file @
adfed5ce
import
type
{
Category
}
from
"@/api/models/category"
;
import
type
{
Category
}
from
"@/api/models/category"
;
import
{
useCustomClient
}
from
"@/api/mutator/custom-client"
;
import
{
useCustomClient
}
from
"@/api/mutator/custom-client"
;
import
Links
from
"@/links"
;
import
Links
,
{
resolveUploadUrl
}
from
"@/links"
;
import
{
getCategoryFallbackResponse
}
from
"@/mockdata/categories"
;
import
{
getCategoryFallbackResponse
}
from
"@/mockdata/categories"
;
import
type
{
import
type
{
DynamicCategoryMenuItem
,
DynamicCategoryMenuItem
,
...
@@ -293,9 +293,8 @@ export function resolveDynamicPostImage(thumbnail?: DynamicPostThumbnail) {
...
@@ -293,9 +293,8 @@ export function resolveDynamicPostImage(thumbnail?: DynamicPostThumbnail) {
const
value
=
thumbnail
?.
path
??
thumbnail
?.
original
??
thumbnail
?.
url
??
""
;
const
value
=
thumbnail
?.
path
??
thumbnail
?.
original
??
thumbnail
?.
url
??
""
;
if
(
!
value
)
return
"/thumbnail.png"
;
if
(
!
value
)
return
"/thumbnail.png"
;
if
(
value
.
startsWith
(
"http://"
)
||
value
.
startsWith
(
"https://"
))
return
value
;
return
`
${
Links
.
imageEndpoint
}${
value
.
replace
(
/^
\/
+/
,
""
)}
`
;
return
resolveUploadUrl
(
value
)
;
}
}
export
function
stripHtml
(
value
?:
string
|
null
)
{
export
function
stripHtml
(
value
?:
string
|
null
)
{
...
...
src/app/admin/login/page.tsx
View file @
adfed5ce
...
@@ -19,6 +19,7 @@ import { Checkbox } from "@/components/ui/checkbox";
...
@@ -19,6 +19,7 @@ import { Checkbox } from "@/components/ui/checkbox";
import
{
Input
}
from
"@/components/ui/input"
;
import
{
Input
}
from
"@/components/ui/input"
;
import
{
Label
}
from
"@/components/ui/label"
;
import
{
Label
}
from
"@/components/ui/label"
;
import
logo
from
"@/assets/VCCI-HCM-logo-VN-2025.png"
;
import
logo
from
"@/assets/VCCI-HCM-logo-VN-2025.png"
;
import
links
from
"@/links"
;
import
{
loginAdmin
}
from
"@/lib/auth/admin-auth"
;
import
{
loginAdmin
}
from
"@/lib/auth/admin-auth"
;
import
useAuthStore
from
"@/store/useAuthStore"
;
import
useAuthStore
from
"@/store/useAuthStore"
;
...
@@ -85,7 +86,7 @@ function getAuthErrorMessage(error: unknown, fallback: string) {
...
@@ -85,7 +86,7 @@ function getAuthErrorMessage(error: unknown, fallback: string) {
}
}
async
function
postAuthJson
<
TResponse
,
TBody
>
(
path
:
string
,
body
:
TBody
)
{
async
function
postAuthJson
<
TResponse
,
TBody
>
(
path
:
string
,
body
:
TBody
)
{
const
response
=
await
fetch
(
`
${
process
.
env
.
NEXT_PUBLIC_BACKEND_HOST
}
/api/v1.0
${
path
}
`
,
{
const
response
=
await
fetch
(
`
${
links
.
apiEndpoint
}
${
path
}
`
,
{
method
:
"POST"
,
method
:
"POST"
,
headers
:
{
headers
:
{
"Content-Type"
:
"application/json"
,
"Content-Type"
:
"application/json"
,
...
...
src/components/base/card-events/index.tsx
View file @
adfed5ce
import
{
EventItem
}
from
'@/api/types/event'
;
import
{
EventItem
}
from
'@/api/types/event'
;
import
Links
from
'@links/index'
import
{
resolveUploadUrl
}
from
'@links/index'
import
dayjs
from
'dayjs'
;
import
dayjs
from
'dayjs'
;
// Helper: remove <img> tags and extract plain text from HTML
// Helper: remove <img> tags and extract plain text from HTML
...
@@ -27,7 +27,7 @@ const CardEvents = ({ event, link }: { event: EventItem, link: string }) => {
...
@@ -27,7 +27,7 @@ const CardEvents = ({ event, link }: { event: EventItem, link: string }) => {
className=
"flex flex-col hover:no-underline sm:flex-row gap-2 mb-6 bg-white rounded-lg shadow-sm p-4 border items-start min-w-0"
className=
"flex flex-col hover:no-underline sm:flex-row gap-2 mb-6 bg-white rounded-lg shadow-sm p-4 border items-start min-w-0"
>
>
<
img
<
img
src=
{
`${Links.imageEndpoint}${event.image}`
}
src=
{
resolveUploadUrl
(
event
.
image
)
}
alt=
{
event
.
name
}
alt=
{
event
.
name
}
className=
"w-full sm:w-56 md:w-64 h-40 md:h-36 object-cover shrink-0"
className=
"w-full sm:w-56 md:w-64 h-40 md:h-36 object-cover shrink-0"
onError=
{
(
e
)
=>
{
onError=
{
(
e
)
=>
{
...
@@ -48,4 +48,4 @@ const CardEvents = ({ event, link }: { event: EventItem, link: string }) => {
...
@@ -48,4 +48,4 @@ const CardEvents = ({ event, link }: { event: EventItem, link: string }) => {
)
)
}
}
export
default
CardEvents
;
export
default
CardEvents
;
\ No newline at end of file
src/components/base/card-news/index.tsx
View file @
adfed5ce
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
Links
from
"@links/index"
;
import
{
resolveUploadUrl
}
from
"@links/index"
;
import
{
NewsItem
}
from
"@/api/types/news"
;
import
{
NewsItem
}
from
"@/api/types/news"
;
const
stripImagesAndHtml
=
(
html
?:
string
)
=>
{
const
stripImagesAndHtml
=
(
html
?:
string
)
=>
{
...
@@ -21,8 +21,7 @@ const stripImagesAndHtml = (html?: string) => {
...
@@ -21,8 +21,7 @@ const stripImagesAndHtml = (html?: string) => {
const
resolveThumbnail
=
(
thumbnail
?:
string
)
=>
{
const
resolveThumbnail
=
(
thumbnail
?:
string
)
=>
{
if
(
!
thumbnail
)
return
"/img-error.png"
;
if
(
!
thumbnail
)
return
"/img-error.png"
;
if
(
thumbnail
.
startsWith
(
"http://"
)
||
thumbnail
.
startsWith
(
"https://"
))
return
thumbnail
;
return
resolveUploadUrl
(
thumbnail
);
return
`
${
Links
.
imageEndpoint
}${
thumbnail
.
replace
(
/^
\/
+/
,
""
)}
`
;
};
};
const
CardNews
=
({
news
,
link
}:
{
news
:
NewsItem
;
link
:
string
})
=>
{
const
CardNews
=
({
news
,
link
}:
{
news
:
NewsItem
;
link
:
string
})
=>
{
...
...
src/lib/api/cms-admin.ts
View file @
adfed5ce
"use client"
;
"use client"
;
import
{
useCustomClient
}
from
"@/api/mutator/custom-client"
;
import
{
useCustomClient
}
from
"@/api/mutator/custom-client"
;
import
{
resolveUploadUrl
}
from
"@/links"
;
import
{
categoryFallbackRows
}
from
"@/mockdata/categories"
;
import
{
categoryFallbackRows
}
from
"@/mockdata/categories"
;
export
type
CmsHeaderCategoryType
=
"category"
|
"page"
|
"news"
;
export
type
CmsHeaderCategoryType
=
"category"
|
"page"
|
"news"
;
...
@@ -350,7 +351,7 @@ const transformPost = (
...
@@ -350,7 +351,7 @@ const transformPost = (
id
:
post
.
thumbnail
.
id
,
id
:
post
.
thumbnail
.
id
,
name
:
post
.
thumbnail
.
original
??
post
.
thumbnail
.
path
??
"thumbnail"
,
name
:
post
.
thumbnail
.
original
??
post
.
thumbnail
.
path
??
"thumbnail"
,
alt
:
post
.
thumbnail
.
original
??
post
.
thumbnail
.
path
??
"thumbnail"
,
alt
:
post
.
thumbnail
.
original
??
post
.
thumbnail
.
path
??
"thumbnail"
,
url
:
post
.
thumbnail
.
path
??
""
,
url
:
resolveUploadUrl
(
post
.
thumbnail
.
path
)
,
}
}
:
null
,
:
null
,
is_hidden
:
Boolean
(
post
.
is_hidden
),
is_hidden
:
Boolean
(
post
.
is_hidden
),
...
...
src/lib/api/files.ts
View file @
adfed5ce
"use client"
;
"use client"
;
import
{
useCustomClient
}
from
"@/api/mutator/custom-client"
;
import
{
useCustomClient
}
from
"@/api/mutator/custom-client"
;
import
Links
from
"@/links"
;
import
{
resolveUploadUrl
}
from
"@/links"
;
import
type
{
AdminMediaItem
}
from
"@/mockdata/admin-news"
;
import
type
{
AdminMediaItem
}
from
"@/mockdata/admin-news"
;
export
type
CmsFileItem
=
{
export
type
CmsFileItem
=
{
...
@@ -44,9 +44,7 @@ export const resolveCmsFileUrl = (path?: string | null) => {
...
@@ -44,9 +44,7 @@ export const resolveCmsFileUrl = (path?: string | null) => {
const
value
=
path
?.
trim
();
const
value
=
path
?.
trim
();
if
(
!
value
)
return
"/img-error.png"
;
if
(
!
value
)
return
"/img-error.png"
;
if
(
value
.
startsWith
(
"http://"
)
||
value
.
startsWith
(
"https://"
))
return
value
;
return
resolveUploadUrl
(
value
);
return
`
${
Links
.
imageEndpoint
}${
value
.
replace
(
/^
\/
+/
,
""
)}
`
;
};
};
export
const
toAdminMediaItem
=
(
item
:
CmsFileItem
):
AdminMediaItem
=>
({
export
const
toAdminMediaItem
=
(
item
:
CmsFileItem
):
AdminMediaItem
=>
({
...
...
src/lib/auth/admin-auth.ts
View file @
adfed5ce
...
@@ -5,8 +5,9 @@ import useAuthStore, {
...
@@ -5,8 +5,9 @@ import useAuthStore, {
type
AuthenticatedAdminSession
,
type
AuthenticatedAdminSession
,
type
AuthenticatedAdminUser
,
type
AuthenticatedAdminUser
,
}
from
"@/store/useAuthStore"
;
}
from
"@/store/useAuthStore"
;
import
links
from
"@/links"
;
const
AUTH_BASE_URL
=
`
${
process
.
env
.
NEXT_PUBLIC_BACKEND_HOST
}
/api/v1.0
/auth`
;
const
AUTH_BASE_URL
=
`
${
links
.
apiEndpoint
}
/auth`
;
const
SESSION_EXPIRED_MESSAGE
=
"Phiên đăng nhập đã hết hạn. Vui lòng đăng nhập lại."
;
const
SESSION_EXPIRED_MESSAGE
=
"Phiên đăng nhập đã hết hạn. Vui lòng đăng nhập lại."
;
interface
AuthEnvelope
<
T
>
{
interface
AuthEnvelope
<
T
>
{
...
...
src/links/index.d.ts
View file @
adfed5ce
...
@@ -2,6 +2,7 @@ declare const links: {
...
@@ -2,6 +2,7 @@ declare const links: {
analyticsGoogle
:
string
analyticsGoogle
:
string
apiEndpoint
:
string
apiEndpoint
:
string
imageEndpoint
:
string
imageEndpoint
:
string
resolveUploadUrl
:
(
value
?:
string
|
null
)
=>
string
backendHost
:
string
backendHost
:
string
backendProtocol
:
string
backendProtocol
:
string
backendPathname
:
string
backendPathname
:
string
...
...
src/links/index.ts
View file @
adfed5ce
const
DEFAULT_BACKEND_ORIGIN
=
"https://vietprodev.duckdns.org/gateway/vcci-news-backend"
;
const
normalizeOrigin
=
(
value
?:
string
|
null
)
=>
value
?.
trim
().
replace
(
/
\/
+$/
,
""
)
||
""
;
const
normalizeOrigin
=
(
value
?:
string
|
null
)
=>
value
?.
trim
().
replace
(
/
\/
+$/
,
""
)
||
""
;
const
readOrigin
=
(
key
:
"NEXT_PUBLIC_BACKEND_HOST"
|
"NEXT_PUBLIC_FRONTEND_HOST"
)
=>
{
const
readOrigin
=
(
key
:
"NEXT_PUBLIC_BACKEND_HOST"
|
"NEXT_PUBLIC_FRONTEND_HOST"
)
=>
{
const
envOrigin
=
normalizeOrigin
(
process
.
env
[
key
]);
const
envOrigin
=
normalizeOrigin
(
process
.
env
[
key
]);
if
(
envOrigin
)
return
envOrigin
;
if
(
envOrigin
)
return
envOrigin
;
if
(
key
===
"NEXT_PUBLIC_BACKEND_HOST"
&&
process
.
env
.
NODE_ENV
===
"production"
)
{
return
DEFAULT_BACKEND_ORIGIN
;
}
if
(
typeof
window
!==
"undefined"
&&
key
===
"NEXT_PUBLIC_FRONTEND_HOST"
)
{
if
(
typeof
window
!==
"undefined"
&&
key
===
"NEXT_PUBLIC_FRONTEND_HOST"
)
{
return
normalizeOrigin
(
window
.
location
.
origin
);
return
normalizeOrigin
(
window
.
location
.
origin
);
...
@@ -33,11 +38,27 @@ const frontendOrigin = readOrigin("NEXT_PUBLIC_FRONTEND_HOST");
...
@@ -33,11 +38,27 @@ const frontendOrigin = readOrigin("NEXT_PUBLIC_FRONTEND_HOST");
const
backendUrl
=
toUrl
(
backendOrigin
);
const
backendUrl
=
toUrl
(
backendOrigin
);
const
frontendUrl
=
toUrl
(
frontendOrigin
);
const
frontendUrl
=
toUrl
(
frontendOrigin
);
const
uploadsEndpoint
=
backendOrigin
?
`
${
backendOrigin
}
/uploads/`
:
"/uploads/"
;
export
const
resolveUploadUrl
=
(
value
?:
string
|
null
)
=>
{
const
trimmed
=
value
?.
trim
();
if
(
!
trimmed
)
return
""
;
if
(
trimmed
.
startsWith
(
"http://"
)
||
trimmed
.
startsWith
(
"https://"
))
return
trimmed
;
const
cleanPath
=
trimmed
.
replace
(
/^
\/
+/
,
""
).
replace
(
/^api
\/
uploads
\/
/
,
"uploads/"
);
if
(
cleanPath
.
startsWith
(
"uploads/"
))
{
return
backendOrigin
?
`
${
backendOrigin
}
/
${
cleanPath
}
`
:
`/
${
cleanPath
}
`
;
}
return
`
${
uploadsEndpoint
}${
cleanPath
}
`
;
};
const
links
=
{
const
links
=
{
analyticsGoogle
:
"G-C9TEK9BS4C"
,
analyticsGoogle
:
"G-C9TEK9BS4C"
,
apiEndpoint
:
backendOrigin
?
`
${
backendOrigin
}
/api/v1.0`
:
"/api/v1.0"
,
apiEndpoint
:
backendOrigin
?
`
${
backendOrigin
}
/api/v1.0`
:
"/api/v1.0"
,
imageEndpoint
:
backendOrigin
?
`
${
backendOrigin
}
/uploads/`
:
"/uploads/"
,
imageEndpoint
:
uploadsEndpoint
,
resolveUploadUrl
,
backendHost
:
backendUrl
?.
hostname
||
""
,
backendHost
:
backendUrl
?.
hostname
||
""
,
backendProtocol
:
backendUrl
?.
protocol
.
replace
(
":"
,
""
)
||
""
,
backendProtocol
:
backendUrl
?.
protocol
.
replace
(
":"
,
""
)
||
""
,
backendPathname
:
backendUrl
?.
pathname
.
replace
(
/
\/
+$/
,
""
)
||
"/"
,
backendPathname
:
backendUrl
?.
pathname
.
replace
(
/
\/
+$/
,
""
)
||
"/"
,
...
...
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