Commit bae5e371 authored by Phạm Quang Bảo's avatar Phạm Quang Bảo

update/add events detail

parent b98d8d29
......@@ -17,6 +17,7 @@ export interface NewsItem {
name: string
static_link: string
static_link_en: string
code: string
}
}
......
......@@ -6,7 +6,7 @@ import AppEditorContent from "@/components/shared/editor-content";
function CardNews({ news }: { news: NewsItem }) {
return (
<a
href={`${news.page_config.static_link}/${news.id}`}
href={`${news.external_link}`}
className="flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
>
<img
......
......@@ -33,11 +33,10 @@ const Page = () => {
const swiperRef = useRef<SwiperType | null>(null);
// query
const { data: categoryData, isLoading: isLoadingCategory } = useGetCategory<GetCategoryAdminResponseType>();
const { data: newsData, isLoading: isLoadingNews } = useGetNews<GetNewsResponseType>(
{
pageSize: '5',
filters: tab === "all" ? `` : `category @=${tab}`,
filters: tab === "all" ? `` : `page_config.code @=${tab}`,
}
);
......@@ -49,17 +48,25 @@ const Page = () => {
const { data: businessOpportunities, isLoading: isLoadingBusinessOpportunities } = useGetNews<GetNewsResponseType>(
{
pageSize: '5',
filters: `category @=Cơ hội kinh doanh`,
filters: `page_config.code @=co-hoi-kinh-doanh`,
}
);
const { data: policyAndLegalInformation, isLoading: isLoadingPolicyAndLegalInformation } = useGetNews<GetNewsResponseType>(
{
pageSize: '5',
filters: `category @=Thông tin chính sách và pháp luật`,
filters: `page_config.code @=phap-luat`,
}
);
const { data: eventData, isLoading: isLoadingEvent } = useGetEvents<EventApiResponse>();
const now = new Date();
const eventDataFiltered = eventData?.responseData.rows.filter(event => {
const eventTime = new Date(event.start_time);
return eventTime > now;
});
// helpers
const stripImagesAndHtml = (html?: string) => {
if (!html) return ''
......@@ -108,7 +115,7 @@ const Page = () => {
];
return (
(isLoadingBusinessOpportunities || isLoadingPolicyAndLegalInformation || isLoadingCategory || isLoadingEvent) ? (
(isLoadingBusinessOpportunities || isLoadingPolicyAndLegalInformation || isLoadingEvent) ? (
<div className="container w-full h-[80vh] flex justify-center items-center">
<Spinner />
</div>
......@@ -170,7 +177,7 @@ const Page = () => {
{newsAll?.responseData?.rows.map((news) => (
<SwiperSlide key={news.id}>
<a
href={`${news.page_config.static_link}/${news.id}`}
href={`${news.external_link}`}
className="relative block bg-white shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"
>
<img
......@@ -225,7 +232,7 @@ const Page = () => {
.map((news: NewsItem) => (
<a
key={news.id}
href={`${news.page_config.static_link}/${news.id}`}
href={`${news.external_link}`}
className="flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 bg-white"
>
<div className="w-full aspect-3/2 overflow-hidden">
......@@ -263,20 +270,33 @@ const Page = () => {
>
Tất cả
</button>
{categoryData?.responseData.rows
.slice(0, 3)
.map((category) => (
<button
key={category.id}
className={`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${category.name === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`}
onClick={() => setTab(category.name)}
>
{category.name}
</button>
))}
<button
className={`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`tin-vcci` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`}
onClick={() => setTab(`tin-vcci`)}
>
Tin VCCI
</button>
<button
className={`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`tin-kinh-te` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`}
onClick={() => setTab(`tin-kinh-te`)}
>
Tin Kinh Tế
</button>
<button
className={`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`chuyen-de` === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`}
onClick={() => setTab(`chuyen-de`)}
>
Chuyên Đề
</button>
</div>
{newsData?.responseData?.rows.slice(0, 4).map((news) => (
......@@ -347,39 +367,37 @@ const Page = () => {
<hr className="border-[#e8c518] mb-4" />
<div className="flex flex-col md:flex-row gap-5">
{eventData?.responseData.rows
.slice(0, 1)
.map((event: EventItem) => (
<a
key={event.id}
href={`hoat-dong/su-kien/${event.id}`}
className="flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 border border-gray-200 bg-white rounded-md p-3"
>
<div className="w-full aspect-3/2 overflow-hidden">
<img
src={`${BASE_URL.imageEndpoint}${event.image}`}
alt={event.name}
className="w-full h-full object-cover"
onError={(e) => {
(e.target as HTMLImageElement).src =
"/img-error.png";
}}
/>
</div>
{eventDataFiltered?.slice(0, 1).map((event: EventItem) => (
<a
key={event.id}
href={`hoat-dong/su-kien/${event.id}`}
className="flex flex-col w-full md:w-1/2 min-h-[180px] sm:min-h-[220px] gap-3 mb-3 border border-gray-200 bg-white rounded-md p-3"
>
<div className="w-full aspect-3/2 overflow-hidden">
<img
src={`${BASE_URL.imageEndpoint}${event.image}`}
alt={event.name}
className="w-full h-full object-cover"
onError={(e) => {
(e.target as HTMLImageElement).src =
"/img-error.png";
}}
/>
</div>
<div className="flex-1">
<p className="text-[#0056b3] font-bold text-xl line-clamp-2">
{event.name}
</p>
<p className="text-gray-500 text-sm my-1">
{dayjs(event.start_time).format("DD/MM/YYYY")}
</p>
<p className="line-clamp-3">{stripImagesAndHtml(event.description)}</p>
</div>
</a>
))}
<div className="flex-1">
<p className="text-[#0056b3] font-bold text-xl line-clamp-2">
{event.name}
</p>
<p className="text-gray-500 text-sm my-1">
{dayjs(event.start_time).format("DD/MM/YYYY")}
</p>
<p className="line-clamp-3">{stripImagesAndHtml(event.description)}</p>
</div>
</a>
))}
<div className="w-full md:w-1/2">
{eventData?.responseData.rows.slice(0, 4).map((event) => (
{eventDataFiltered?.slice(0, 4).map((event) => (
<CardEvent key={event.id} event={event} />
))}
</div>
......@@ -416,13 +434,13 @@ const Page = () => {
<div className="flex-1">
<div className="flex justify-between items-center">
<a
href="/xuc-tien-thuong-mai/co-hoi-kinh-doanh/"
href="/xuc-tien-thuong-mai/co-hoi/"
className="text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
>
Cơ hội kinh doanh
</a>
<a
href="/xuc-tien-thuong-mai/co-hoi-kinh-doanh/"
href="/xuc-tien-thuong-mai/co-hoi/"
className="text-[#063e8e] text-sm sm:text-base"
>
<ChevronsRight />
......@@ -433,7 +451,7 @@ const Page = () => {
{businessOpportunities?.responseData.rows
.slice(0, 1)
.map((news: NewsItem) => (
<a key={news.id} href={`${news.page_config.static_link}/${news.id}`}>
<a key={news.id} href={`${news.external_link}`}>
<div className="w-full aspect-3/2 relative overflow-hidden mb-5">
<img
src={`${BASE_URL.imageEndpoint}${news.thumbnail}`}
......@@ -461,13 +479,13 @@ const Page = () => {
<div className="flex-1">
<div className="flex justify-between items-center">
<a
href="/thong-tin-truyen-thong/thong-tin-chinh-sach-va-phap-luat"
href="/thong-tin-truyen-thong/phap-luat"
className="text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
>
Chính sách & pháp luật
</a>
<a
href="/thong-tin-truyen-thong/thong-tin-chinh-sach-va-phap-luat"
href="/thong-tin-truyen-thong/phap-luat"
className="text-[#063e8e] text-sm sm:text-base"
>
<ChevronsRight />
......@@ -478,7 +496,7 @@ const Page = () => {
{policyAndLegalInformation?.responseData.rows
.slice(0, 1)
.map((news: NewsItem) => (
<a key={news.id} href={`${news.page_config.static_link}/${news.id}`}>
<a key={news.id} href={`${news.external_link}`}>
<div className="w-full aspect-3/2 relative overflow-hidden mb-5">
<img
src={`${BASE_URL.imageEndpoint}${news.thumbnail}`}
......
"use client";
import parse from "html-react-parser";
import dayjs from "dayjs";
import { Spinner } from "@/components/ui";
import { useGetNewsId } from "@/api/endpoints/news";
import { GetNewsDetailResponseType } from "./../../page.type";
interface EventDetailProps {
id?: string;
}
export default function EventDetail({ id }: EventDetailProps) {
if (!id) return null;
const { data: eventDetail, isLoading } = useGetNewsId<GetNewsDetailResponseType>(id);
if (isLoading) {
return (
<div className="flex justify-center py-6">
<Spinner />
</div>
);
}
const event = eventDetail?.responseData;
if (!event) return null;
return (
<div>
<h1 className="text-2xl font-medium text-primary">{event.title}</h1>
<div className="text-sm text-blue-700 mb-4">
{dayjs(event.created_at).format("DD/MM/YYYY")}
</div>
<div className="prose tiptap">{parse(event.description ?? "")}</div>
</div>
);
}
"use client";
import parse from "html-react-parser";
import dayjs from "dayjs";
import { GetNewsResponseType } from "@/api/types/news";
interface NewsDetailProps {
data: GetNewsResponseType;
}
export default function NewsDetail({ data }: NewsDetailProps) {
const news = data?.responseData?.rows?.[0];
if (!news) return null;
return (
<div>
<h1 className="text-2xl font-medium text-primary">{news.title}</h1>
<div className="text-sm text-blue-700 mb-4">
{dayjs(news.created_at).format("DD/MM/YYYY")}
</div>
<div className="prose tiptap">{parse(news.description ?? "")}</div>
</div>
);
}
......@@ -8,17 +8,17 @@ import { ListFilter } from "@/components/base/list-filter";
import EventCalendar from "@/components/base/event-calendar";
import ListCategory from "@/components/base/list-category";
import CardNews from "@/components/base/card-news";
import Image from "next/image";
import parse from "html-react-parser";
import dayjs from "dayjs";
// API hooks
import { useGetNews, useGetNewsId } from "@/api/endpoints/news";
import { useGetNews } from "@/api/endpoints/news";
import { GetNewsResponseType } from "@/api/types/news";
import { GetNewsDetailResponseType } from "./page.type";
import { useGetNewsPageConfigGetHierarchical } from "@/api/endpoints/news-page-config";
import { GetNewsPageConfigResponseType } from "@/api/types/news-page-config";
// Component con
import NewsDetail from "./components/news-detail";
import EventDetail from "./components/event-detail";
export default function DynamicPage() {
const params = useParams();
const slugArray = Array.isArray(params.slug) ? params.slug : [params.slug];
......@@ -30,19 +30,19 @@ export default function DynamicPage() {
const [page, setPage] = useState(1);
const pageSize = 5;
// query
// queries
const { data: categoriesPage } = useGetNewsPageConfigGetHierarchical<GetNewsPageConfigResponseType>({
code: `${slugArray[0]}`,
code: slugArray[0],
});
const { data: newsDetail, isLoading: isLoadingDetail } = useGetNews<GetNewsResponseType>({
filters: `page_config.static_link==/${url}` + `,external_link@=${lastPart}`,
filters: `page_config.static_link==/${url},external_link@=${lastPart}`,
});
const { data: news, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize),
currentPage: String(page),
filters: `page_config.static_link==/${url}` + (submitSearch ? `,title@=${submitSearch}` : ""),
filters: `page_config.static_link==/${url}${submitSearch ? `,title@=${submitSearch}` : ""}`,
});
if (isLoadingDetail) {
......@@ -53,29 +53,23 @@ export default function DynamicPage() {
);
}
// detail news page
// check UUID
const isUUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(
lastPart as string
);
const id = isUUID ? lastPart : undefined;
// detail page condition
const isDetailPage = newsDetail?.responseData?.rows?.length === 1;
if (isDetailPage) {
if (isDetailPage || id) {
return (
<div className='container w-full flex justify-center items-center pb-10'>
<div className='flex flex-col gap-5 w-full'>
<div className="container w-full flex justify-center items-center pb-10">
<div className="flex flex-col gap-5 w-full">
<ListCategory categories={categoriesPage?.responseData?.children} />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-5">
<main className="lg:col-span-2 bg-white border rounded-md p-8">
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{newsDetail?.responseData?.rows[0].title}
</div>
<div className='flex items-center gap-2 text-sm mb-4'>
<span className='text-base text-blue-700'>
{dayjs(newsDetail?.responseData?.rows[0].created_at).format('DD/MM/YYYY')}
</span>
</div>
<hr className="my-5" />
<div className='flex-1 text-app-grey text-base overflow-hidden'>
<div className="prose tiptap overflow-hidden">
{parse(newsDetail?.responseData?.rows[0].description ?? '')}
</div>
</div>
{isDetailPage ? <NewsDetail data={newsDetail} /> : <EventDetail id={id} />}
</main>
<aside className="space-y-6">
<EventCalendar />
......@@ -104,11 +98,7 @@ export default function DynamicPage() {
) : (
<>
{news?.responseData.rows.map((item) => (
<CardNews
key={item.id}
news={item}
link={`${item.external_link}`}
/>
<CardNews key={item.id} news={item} link={`${item.external_link}`} />
))}
<div className="w-full flex justify-center mt-4">
<Pagination
......@@ -138,4 +128,4 @@ export default function DynamicPage() {
</div>
</div>
);
}
\ No newline at end of file
}
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