Commit 74a04b88 authored by Vũ Đình Nguyên's avatar Vũ Đình Nguyên

update layout

parent 6c996526
import { ResponseType } from '@lib/types/common'
export type EventStatus = {
id: string;
name: string;
......@@ -22,7 +23,68 @@ export type EventOrganization = {
add_info: unknown | null;
organization: unknown | null;
};
// useGetEventsId
export type GetEventsIdQueryResponseType = ResponseType<{
accept_entries: boolean | null
counter_cost: number
counter_count: number
created_at: string
description: string
end_time: string
event_organizations: Array<{
add_info: string | null
created_at: string
guest_image: string | null
guest_name: string | null
id: string
org_counter_count: number | null
org_table_count: number | null
organization: {
address: string
avatar: string | null
club_link: string | null
club_name: string | null
id: string
name: string
org_categories: string[]
org_link: string | null
org_status_id: string | null
organization_products: Array<{
id: string
images: string[]
}>
province: string[]
tax_code: string
users: Array<{
id: string
}>
website: string
} | null
role: 'PARTAKER' | 'MAIN' | 'SUPPORT' | 'SUPPORT_1' | 'SUPPORT_2' | 'SUPPORT_3' | 'GUEST'
status: string | null
}>
host_club: string | null
id: string
image: string
introduction: string | null
location: string
name: string
org_support_titles: string[] | null
province: string
seo_text: string
seo_text_en: string | null
start_time: string
status: string
status_status: {
code: string
id: string
name: string
name_en: string
}
table_cost: number
table_count: number
updated_at: string | null
}>
export type EventItem = {
id: string;
name: string;
......@@ -71,4 +133,4 @@ export type EventApiResponse = {
status: string;
timeStamp: string;
violations: null | unknown;
};
\ No newline at end of file
};
"use client";
import React, { useState } from "react";
import { useRouter } from 'next/navigation'
import { useRouter } from "next/navigation";
import { Menu, X, Facebook, Linkedin, Twitter, Youtube } from "lucide-react";
import logo from "@/assets/VCCI-HCM-logo-VN-2025.png";
import Image from "next/image";
......@@ -8,33 +8,33 @@ import MenuItem from "./MenuItem";
import Link from "next/link";
function Header() {
const [toggleMenu, setToggleMenu] = useState<boolean>(false);
const router = useRouter()
const router = useRouter();
return (
<>
<div className="sticky top-0 w-full h-[56px] hidden lg:flex items-center justify-center bg-[#063e8e]">
<div className="sticky top-0 w-full h-14 hidden lg:flex items-center justify-center bg-[#063e8e]">
<div className="container w-full px-4 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-[130px] h-[36px] bg-[#e8c518] flex items-center justify-center border-4 rounded-sm border-[#647792]">
<a
className="font-[600] text-[14px] text-[#063E8E] hover:text-white transition"
href="#"
<div className="w-[130px] h-9 bg-[#e8c518] flex items-center justify-center border-4 rounded-sm border-[#647792]">
<Link
className="font-semibold text-[14px] text-primary hover:text-white transition"
href="https://vccihcm.vn/dang-ky"
>
Đăng Ký Hội Viên
</a>
</Link>
</div>
<a
<Link
className="px-3 py-2 text-[14px] text-white hover:opacity-80"
href="#"
href="/site-map"
>
Sitemap
</a>
<a
</Link>
<Link
className="px-3 py-2 text-[14px] text-white hover:opacity-80"
href="#"
href="https://vccihcm.vn/lien-he"
>
Liên hệ
</a>
</Link>
</div>
<div className="flex items-center gap-8">
......@@ -43,10 +43,11 @@ function Header() {
type="text"
placeholder="Tìm kiếm"
onKeyDown={(e) => {
if (e.key === 'Enter') {
const value = (e.currentTarget as HTMLInputElement).value || ''
const encoded = encodeURIComponent(value)
router.push(`/search?q=${encoded}`)
if (e.key === "Enter") {
const value =
(e.currentTarget as HTMLInputElement).value || "";
const encoded = encodeURIComponent(value);
router.push(`/search?q=${encoded}`);
}
}}
/>
......@@ -92,12 +93,11 @@ function Header() {
{ title: "Sơ Đồ Tổ Chức", link: "so-do-to-chuc" },
{ title: "Dịch Vụ Cung Cấp", link: "dich-vu-cung-cap" },
]}
/>
<MenuItem
title="Hội viên"
link="hoi-vien"
items={[
items={[
{
title: "Lợi Ích Của Hội Viên VCCI",
link: "",
......@@ -106,16 +106,15 @@ function Header() {
{ title: "Kết Nối Hội Viên", link: "ket-noi-hoi-vien" },
{ title: "Tin Hội Viên", link: "tin-hoi-vien" },
]}
/>
<MenuItem
title="Hoạt động"
link="hoat-dong"
items={[
items={[
{ title: "Sự Kiện", link: "" },
{ title: "Đào Tạo", link: "dao-tao" },
]}
/>
/>
<MenuItem
title="Xuất Xứ Hàng Hóa"
link="xuat-xu-hang-hoa"
......@@ -198,7 +197,7 @@ function Header() {
<MenuItem
title="Xúc tiến thương mại"
link="xuc-tien-thuong-mai"
items={[
items={[
{ title: "Hồ Sơ Thị Trường", link: "ho-so-thi-truong" },
{
title: "Môi Trường Kinh Doanh",
......@@ -207,12 +206,11 @@ function Header() {
{ title: "Cơ Hội Kinh Doanh", link: "co-hoi-kinh-doanh" },
{ title: "Hỗ Trợ Kinh Doanh", link: "ho-tro-kinh-doanh" },
]}
/>
<MenuItem
title="Thông tin truyền thông"
link="thong-tin-truyen-thong"
items={[
items={[
{ title: "Tin VCCI", link: "tin-vcci" },
{ title: "Tin Kinh Tế", link: "tin-kinh-te" },
{ title: "Tin Doanh Nghiệp", link: "tin-doanh-nghiep" },
......@@ -224,7 +222,6 @@ function Header() {
{ title: "Ấn Phẩm", link: "an-pham" },
{ title: "Thư Viện Tài Liệu", link: "thu-vien-tai-lieu" },
]}
/>
</nav>
......@@ -240,8 +237,9 @@ function Header() {
{/* Mobile Menu */}
<div
className={`lg:hidden bg-white shadow-lg transition-all duration-300 overflow-hidden ${toggleMenu ? "max-h-96 opacity-100" : "max-h-0 opacity-0"
}`}
className={`lg:hidden bg-white shadow-lg transition-all duration-300 overflow-hidden ${
toggleMenu ? "max-h-96 opacity-100" : "max-h-0 opacity-0"
}`}
>
{[
"Giới thiệu",
......
......@@ -9,12 +9,13 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData,isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
// filters: submitSearch ? `title @=${submitSearch}` : undefined,
......@@ -29,26 +30,35 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/chu-de/${news.id}`}/>
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải dữ liệu...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/chu-de/${news.id}`}/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -2,7 +2,7 @@
import { NewsItem } from '@app/dai-dien-gioi-chu/lib/types/NewsPage.type';
import Links from '@links/index'
import dayjs from 'dayjs';
import {EventItem} from "@api/types/event";
// Helper: remove <img> tags and extract plain text from HTML
const stripImagesAndHtml = (html?: string) => {
if (!html) return ''
......@@ -19,7 +19,7 @@ const stripImagesAndHtml = (html?: string) => {
}
return withoutImgs.replace(/<[^>]*>/g, '')
}
function NewsContent({ news ,link}: { news: NewsItem ,link:string}) {
function NewsContent({ news ,link,event}: { news?: NewsItem ,link:string,event?:EventItem}) {
return (
<a
......@@ -27,8 +27,8 @@ function NewsContent({ news ,link}: { news: NewsItem ,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"
>
<img
src={`${Links.imageEndpoint}${news.thumbnail}`}
alt={news.title}
src={`${Links.imageEndpoint}${news?news.thumbnail:event?.image}`}
alt={news?news.title:event?.name}
className="w-full sm:w-56 md:w-64 h-40 md:h-36 object-cover shrink-0"
onError={(e) => {
e.currentTarget.src = "/img-error.png"
......@@ -38,13 +38,13 @@ function NewsContent({ news ,link}: { news: NewsItem ,link:string}) {
<div className="flex-1 min-w-0 pl-0 sm:pl-4">
<p className="text-primary font-semibold text-base md:text-lg hover:underline line-clamp-2 wrap-break-word">
{news.title}
{news?.title}{event?.name}
</p>
<div className="text-sm my-2 text-[#00AED5]">{dayjs(news.release_at).format('DD/MM/YYYY')}</div>
<div className="text-sm my-2 text-[#00AED5]">{dayjs(news?news?.created_at:event?.created_at).format('DD/MM/YYYY')}</div>
<div className="text-sm text-[#777] line-clamp-3">
<div className="text-sm prose tiptap">{stripImagesAndHtml(news.description)}</div>
<div className="text-sm prose tiptap">{stripImagesAndHtml(news?news.description:event?.description)}</div>
</div>
</div>
</a>
......
......@@ -9,12 +9,13 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : undefined,
......@@ -28,26 +29,35 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/tap-huan-nsdld/${news.id}`} />
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải tập huấn NSDLĐ...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/tap-huan-nsdld/${news.id}`} />
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -9,12 +9,13 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch,setsubmitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch},category@=Tin liên quan` : 'category@=Tin liên quan',
......@@ -28,19 +29,28 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/tin-lien-quan/${news.id}`} />
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải tin liên quan...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/tin-lien-quan/${news.id}`} />
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -9,12 +9,13 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : 'category @=Đào tạo',
......@@ -28,19 +29,28 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.event}/dao-tao/${news.id}`} />
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải khóa đào tạo...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.event}/dao-tao/${news.id}`} />
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -4,14 +4,16 @@ import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { EVENT_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
import { useGetNewsId } from '@/api/endpoints/news';
import {useGetEventsId} from '@/api/endpoints/event';
import parse from "html-react-parser";
import { useParams } from 'next/navigation'
import { GetNewsDetailResponseType } from '@lib/types/news-detail-response-data';
import {GetEventsIdQueryResponseType} from '@api/types/event';
import { Spinner } from "@components/ui/spinner";
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(id as string)
const { data, isLoading } = useGetEventsId<GetEventsIdQueryResponseType>(id as string)
return (
<div className="min-h-screen w-full container mx-auto p-4">
<div className="w-full flex flex-col gap-5">
......@@ -20,11 +22,20 @@ const Page: React.FC = () => {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */}
<main className="lg:col-span-2 bg-white border rounded-md p-6">
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{data?.responseData?.title}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải chi tiết sự kiện...</span>
</div>
) : (
<>
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{data?.responseData?.name}
</div>
<hr className="py-2"/>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</>
)}
</main>
{/* Sidebar */}
......
......@@ -7,18 +7,23 @@ import NewsContent from "@app/dai-dien-gioi-chu/components/card-news";
// ...existing code...
import { Pagination } from "@components/base/pagination";
import Image from "next/image";
import { useGetEvents } from '@api/endpoints/event'
import { EventApiResponse } from '@api/types/event'
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetEvents<EventApiResponse>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : 'category @=Sự kiện',
sortField: 'start_time',
sortOrder: 'ASC',
filters: submitSearch ? `title @=${submitSearch},start_time>${new Date()}` : `start_time>${new Date()}`,
});
return (
<div className="min-h-screen container mx-auto p-4">
......@@ -29,19 +34,28 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.event}/su-kien/${news.id}`} />
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải sự kiện...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((event) => (
<NewsContent key={event.id} event={event} link={`${PATHS.event}/su-kien/${event.id}`} />
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -7,6 +7,7 @@ import { Pagination } from "@components/base/pagination";
import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
......@@ -26,26 +27,35 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<CardNews key={news.id} news={news} />
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải dữ liệu kết nối hội viên...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((news) => (
<CardNews key={news.id} news={news} />
))}
<div className='w-full flex justify-center mt-4'>
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
<div className='w-full flex justify-center mt-4'>
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -7,6 +7,7 @@ import { Pagination } from '@components/base/pagination'
import Image from "next/image";
import { useGetNews } from '@api/endpoints/news'
import { GetNewsResponseType } from '@api/types/NewsPage.type'
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState('')
......@@ -26,26 +27,35 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background">
<div className='pb-5 overflow-hidden'>
{allData?.responseData.rows.map((news) => (
<CardNews key={news.id} news={news} />
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải tin hội viên...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((news) => (
<CardNews key={news.id} news={news} />
))}
<div className='w-full flex justify-center mt-4'>
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
<div className='w-full flex justify-center mt-4'>
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -8,6 +8,7 @@ import { Pagination } from "@components/base/pagination";
import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { Spinner } from "@components/ui/spinner";
import { PATHS } from "@constants/paths";
import { useSearchParams } from 'next/navigation'
......@@ -16,7 +17,7 @@ function SearchContent() {
const searchParams = useSearchParams()
const query = searchParams.get('q') //
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: query ? `title @=${query}` : undefined,
......@@ -40,30 +41,39 @@ function SearchContent() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-vcci/${news.id}`}
/>
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tìm kiếm...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-vcci/${news.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -10,14 +10,15 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : 'category @=Chuyên đề',
filters: submitSearch ? `title @=${submitSearch},category @=Chuyên đề` : 'category @=Chuyên đề',
});
return (
<div className="min-h-screen container mx-auto p-4">
......@@ -28,26 +29,34 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.length === 0 ? (
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải chuyên đề...</span>
</div>
) : allData?.responseData.rows.length === 0 ? (
<p className="text-center py-4">Không có dữ liệu</p>
) : (
allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/chuyen-de/${news.id}`}
/>
)))}
<>
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/chuyen-de/${news.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -15,10 +15,10 @@ export default function Page() {
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData,isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : 'category @=Thông tin chính sách và pháp luật',
filters: submitSearch ? `title @=${submitSearch},category @=Thông tin chính sách và pháp luật` : 'category @=Thông tin chính sách và pháp luật',
});
return (
<div className="min-h-screen container mx-auto p-4">
......
......@@ -10,15 +10,16 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : 'category @=Thư viện tài liệu',
filters: submitSearch ? `title @=${submitSearch},category @=Thư viện tài liệu'` : 'category @=Thư viện tài liệu',
});
return (
<div className="min-h-screen container mx-auto p-4">
......@@ -29,26 +30,34 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.length === 0 ? (
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải thư viện tài liệu...</span>
</div>
) : allData?.responseData.rows.length === 0 ? (
<p className="text-center py-4">Không có dữ liệu</p>
) : (
allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/thu-vien-tai-lieu/${news.id}`}
/>
)))}
<>
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/thu-vien-tai-lieu/${news.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -10,15 +10,16 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : 'category @=Tin doanh nghiệp',
filters: submitSearch ? `title @=${submitSearch},category @=Tin doanh nghiệp` : 'category @=Tin doanh nghiệp',
});
return (
<div className="min-h-screen container mx-auto p-4">
......@@ -29,26 +30,34 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.length === 0 ? (
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải tin doanh nghiệp...</span>
</div>
) : allData?.responseData.rows.length === 0 ? (
<p className="text-center py-4">Không có dữ liệu</p>
) : (
allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-doanh-nghiep/${news.id}`}
/>
)))}
<>
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-doanh-nghiep/${news.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -9,15 +9,16 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : 'category @=Tin kinh tế',
filters: submitSearch ? `title @=${submitSearch},category @=Tin kinh tế` : 'category @=Tin kinh tế',
});
return (
<div className="min-h-screen container mx-auto p-4">
......@@ -28,26 +29,34 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.length === 0 ? (
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải tin kinh tế...</span>
</div>
) : allData?.responseData.rows.length === 0 ? (
<p className="text-center py-4">Không có dữ liệu</p>
) : (
allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-kinh-te/${news.id}`}
/>
)))}
<>
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-kinh-te/${news.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -11,12 +11,13 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { PATHS } from "@constants/paths";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch, setSubmitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : undefined,
......@@ -30,27 +31,34 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.length === 0 ? (
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải tin VCCI...</span>
</div>
) : allData?.responseData.rows.length === 0 ? (
<p className="text-center py-4">Không có dữ liệu</p>
) : (
allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-vcci/${news.id}`}
/>
)))
}
<>
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-vcci/${news.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() => setPage(Math.min(Number(allData?.responseData.totalPages ?? 1), page + 1))}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -8,6 +8,7 @@ import { useGetNewsId } from '@/api/endpoints/news';
import parse from "html-react-parser";
import { useParams } from 'next/navigation'
import { GetNewsDetailResponseType } from '@lib/types/news-detail-response-data';
import { Spinner } from "@components/ui/spinner";
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
......@@ -20,11 +21,20 @@ const Page: React.FC = () => {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */}
<main className="lg:col-span-2 bg-white border rounded-md p-6">
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải nội dung...</span>
</div>
) : (
<>
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{data?.responseData?.title}
</div>
<hr className="py-2"/>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</>
)}
</main>
{/* Sidebar */}
......
......@@ -8,6 +8,7 @@ import { useGetNewsId } from '@/api/endpoints/news';
import parse from "html-react-parser";
import { useParams } from 'next/navigation'
import { GetNewsDetailResponseType } from '@lib/types/news-detail-response-data';
import { Spinner } from "@components/ui/spinner";
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
......@@ -20,11 +21,22 @@ const Page: React.FC = () => {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */}
<main className="lg:col-span-2 bg-white border rounded-md p-6">
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải chi tiết cơ hội kinh doanh...</span>
</div>
) : data?.responseData ? (
<>
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{data?.responseData?.title}
</div>
<hr className="py-2"/>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</>
) : (
<p className="text-center py-4">Không có dữ liệu</p>
)}
</main>
{/* Sidebar */}
......
......@@ -9,12 +9,13 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
// filters: submitSearch ? `title @=${submitSearch}` : undefined,
......@@ -29,26 +30,37 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.tradePromotion}/${news.id}`} />
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải cơ hội kinh doanh...</span>
</div>
) : allData?.responseData.rows.length === 0 ? (
<p className="text-center py-4">Không có dữ liệu</p>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.tradePromotion}/${news.id}`} />
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -8,6 +8,7 @@ import { useGetNewsId } from '@/api/endpoints/news';
import parse from "html-react-parser";
import { useParams } from 'next/navigation'
import { GetNewsDetailResponseType } from '@lib/types/news-detail-response-data';
import { Spinner } from "@components/ui/spinner";
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
......@@ -20,11 +21,22 @@ const Page: React.FC = () => {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */}
<main className="lg:col-span-2 bg-white border rounded-md p-6">
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải chi tiết hỗ trợ kinh doanh...</span>
</div>
) : data?.responseData ? (
<>
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{data?.responseData?.title}
</div>
<hr className="py-2"/>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</>
) : (
<p className="text-center py-4">Không có dữ liệu</p>
)}
</main>
{/* Sidebar */}
......
......@@ -8,12 +8,13 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
// filters: submitSearch ? `title @=${submitSearch}` : undefined,
......@@ -28,30 +29,41 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.tradePromotion}/${news.id}`}
/>
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải hỗ trợ kinh doanh...</span>
</div>
) : allData?.responseData.rows.length === 0 ? (
<p className="text-center py-4">Không có dữ liệu</p>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.tradePromotion}/${news.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -8,6 +8,7 @@ import { useGetNewsId } from '@/api/endpoints/news';
import parse from "html-react-parser";
import { useParams } from 'next/navigation'
import { GetNewsDetailResponseType } from '@lib/types/news-detail-response-data';
import { Spinner } from "@components/ui/spinner";
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
......@@ -20,11 +21,22 @@ const Page: React.FC = () => {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */}
<main className="lg:col-span-2 bg-white border rounded-md p-6">
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải chi tiết môi trường kinh doanh...</span>
</div>
) : data?.responseData ? (
<>
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{data?.responseData?.title}
</div>
<hr className="py-2"/>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
<div className="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</>
) : (
<p className="text-center py-4">Không có dữ liệu</p>
)}
</main>
{/* Sidebar */}
......
......@@ -9,12 +9,13 @@ import EventCalendar from "@app/dai-dien-gioi-chu/components/event-calendar";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
// filters: submitSearch ? `title @=${submitSearch}` : undefined,
......@@ -29,30 +30,41 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.tradePromotion}/${news.id}`}
/>
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải môi trường kinh doanh...</span>
</div>
) : allData?.responseData.rows.length === 0 ? (
<p className="text-center py-4">Không có dữ liệu</p>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent
key={news.id}
news={news}
link={`${PATHS.tradePromotion}/${news.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
</>
)}
</div>
</main>
......
......@@ -8,12 +8,13 @@ import Image from "next/image";
import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
import { Spinner } from "@components/ui/spinner";
export default function Page() {
const [submitSearch] = useState("");
const [page, setPage] = useState(1);
const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({
const { data: allData, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: submitSearch ? `title @=${submitSearch}` : undefined,
......@@ -27,26 +28,35 @@ export default function Page() {
{/* Main content */}
<main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.tradePromotion}/${news.id}`} />
))}
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spinner className="size-8" />
<span className="ml-2 text-gray-600">Đang tải tin xúc tiến thương mại...</span>
</div>
) : (
<>
{allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} link={`${PATHS.tradePromotion}/${news.id}`} />
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(allData?.responseData.totalPages ?? 1)}
page={Number(allData?.responseData.currentPage ?? page)}
onChangePage={(p) => setPage(p)}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(
Math.min(
Number(allData?.responseData.totalPages ?? 1),
page + 1
)
)
}
/>
</div>
)
}
/>
</div>
</>
)}
</div>
</main>
......
import { Spinner } from "@/components/ui/spinner";
import { cn } from "@/lib/utils";
interface LoadingStateProps {
message?: string;
size?: "sm" | "md" | "lg";
className?: string;
showMessage?: boolean;
}
export function LoadingState({
message = "Đang tải dữ liệu...",
size = "md",
className,
showMessage = true
}: LoadingStateProps) {
const sizeClasses = {
sm: "size-4",
md: "size-6",
lg: "size-8"
};
const paddingClasses = {
sm: "py-6",
md: "py-8",
lg: "py-12"
};
return (
<div className={cn("flex justify-center items-center", paddingClasses[size], className)}>
<Spinner className={sizeClasses[size]} />
{showMessage && (
<span className="ml-2 text-gray-600">{message}</span>
)}
</div>
);
}
// Các preset thường dùng
export const LoadingPresets = {
News: () => <LoadingState message="Đang tải tin tức..." />,
Search: () => <LoadingState message="Đang tìm kiếm..." />,
Content: () => <LoadingState message="Đang tải nội dung..." />,
Data: () => <LoadingState message="Đang tải dữ liệu..." />,
Members: () => <LoadingState message="Đang tải thông tin hội viên..." />,
Events: () => <LoadingState message="Đang tải sự kiện..." />,
Small: (message?: string) => <LoadingState size="sm" message={message} />,
Large: (message?: string) => <LoadingState size="lg" message={message} />,
};
\ No newline at end of file
// Query response type
interface ResponseType<T = any> {
data: any
message: string | null
message_en: string | null
responseData: T
status: 'fail' | 'success'
statusCode: number
timeStamp: string
violations: Array<{
code: number
message: string
action: Array<{
location: string
msg: {
en: string
vi: string
}
path: string
value: string
}>
}> | null
}
// Infinite query statuses type
interface InfiniteQueryStatusesType {
isFetchingInitialPage: boolean
isFetchingNextPage: boolean
isEmptyData: boolean
isError?: boolean
}
export type { ResponseType, InfiniteQueryStatusesType }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment