Commit e57f97aa authored by Văn Hoàng's avatar Văn Hoàng

[tag]0.1-vcci

parents ea03e458 bae5e371
Pipeline #43899 passed with stages
in 4 minutes and 30 seconds
...@@ -17,6 +17,7 @@ export interface NewsItem { ...@@ -17,6 +17,7 @@ export interface NewsItem {
name: string name: string
static_link: string static_link: string
static_link_en: string static_link_en: string
code: string
} }
} }
......
...@@ -6,7 +6,7 @@ import AppEditorContent from "@/components/shared/editor-content"; ...@@ -6,7 +6,7 @@ import AppEditorContent from "@/components/shared/editor-content";
function CardNews({ news }: { news: NewsItem }) { function CardNews({ news }: { news: NewsItem }) {
return ( return (
<a <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" className="flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
> >
<img <img
......
...@@ -33,11 +33,10 @@ const Page = () => { ...@@ -33,11 +33,10 @@ const Page = () => {
const swiperRef = useRef<SwiperType | null>(null); const swiperRef = useRef<SwiperType | null>(null);
// query // query
const { data: categoryData, isLoading: isLoadingCategory } = useGetCategory<GetCategoryAdminResponseType>();
const { data: newsData, isLoading: isLoadingNews } = useGetNews<GetNewsResponseType>( const { data: newsData, isLoading: isLoadingNews } = useGetNews<GetNewsResponseType>(
{ {
pageSize: '5', pageSize: '5',
filters: tab === "all" ? `` : `category @=${tab}`, filters: tab === "all" ? `` : `page_config.code @=${tab}`,
} }
); );
...@@ -49,17 +48,25 @@ const Page = () => { ...@@ -49,17 +48,25 @@ const Page = () => {
const { data: businessOpportunities, isLoading: isLoadingBusinessOpportunities } = useGetNews<GetNewsResponseType>( const { data: businessOpportunities, isLoading: isLoadingBusinessOpportunities } = useGetNews<GetNewsResponseType>(
{ {
pageSize: '5', pageSize: '5',
filters: `category @=Cơ hội kinh doanh`, filters: `page_config.code @=co-hoi-kinh-doanh`,
} }
); );
const { data: policyAndLegalInformation, isLoading: isLoadingPolicyAndLegalInformation } = useGetNews<GetNewsResponseType>( const { data: policyAndLegalInformation, isLoading: isLoadingPolicyAndLegalInformation } = useGetNews<GetNewsResponseType>(
{ {
pageSize: '5', 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 { 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 // helpers
const stripImagesAndHtml = (html?: string) => { const stripImagesAndHtml = (html?: string) => {
if (!html) return '' if (!html) return ''
...@@ -108,7 +115,7 @@ const Page = () => { ...@@ -108,7 +115,7 @@ const Page = () => {
]; ];
return ( return (
(isLoadingBusinessOpportunities || isLoadingPolicyAndLegalInformation || isLoadingCategory || isLoadingEvent) ? ( (isLoadingBusinessOpportunities || isLoadingPolicyAndLegalInformation || isLoadingEvent) ? (
<div className="container w-full h-[80vh] flex justify-center items-center"> <div className="container w-full h-[80vh] flex justify-center items-center">
<Spinner /> <Spinner />
</div> </div>
...@@ -170,7 +177,7 @@ const Page = () => { ...@@ -170,7 +177,7 @@ const Page = () => {
{newsAll?.responseData?.rows.map((news) => ( {newsAll?.responseData?.rows.map((news) => (
<SwiperSlide key={news.id}> <SwiperSlide key={news.id}>
<a <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" className="relative block bg-white shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"
> >
<img <img
...@@ -225,7 +232,7 @@ const Page = () => { ...@@ -225,7 +232,7 @@ const Page = () => {
.map((news: NewsItem) => ( .map((news: NewsItem) => (
<a <a
key={news.id} 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" 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"> <div className="w-full aspect-3/2 overflow-hidden">
...@@ -263,20 +270,33 @@ const Page = () => { ...@@ -263,20 +270,33 @@ const Page = () => {
> >
Tất cả Tất cả
</button> </button>
{categoryData?.responseData.rows
.slice(0, 3)
.map((category) => (
<button <button
key={category.id} className={`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${`tin-vcci` === tab
className={`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${category.name === tab
? "bg-[#d3d3d3] text-[#063e8e] font-semibold" ? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold" : "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`} }`}
onClick={() => setTab(category.name)} onClick={() => setTab(`tin-vcci`)}
> >
{category.name} 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> </button>
))}
</div> </div>
{newsData?.responseData?.rows.slice(0, 4).map((news) => ( {newsData?.responseData?.rows.slice(0, 4).map((news) => (
...@@ -347,9 +367,7 @@ const Page = () => { ...@@ -347,9 +367,7 @@ const Page = () => {
<hr className="border-[#e8c518] mb-4" /> <hr className="border-[#e8c518] mb-4" />
<div className="flex flex-col md:flex-row gap-5"> <div className="flex flex-col md:flex-row gap-5">
{eventData?.responseData.rows {eventDataFiltered?.slice(0, 1).map((event: EventItem) => (
.slice(0, 1)
.map((event: EventItem) => (
<a <a
key={event.id} key={event.id}
href={`hoat-dong/su-kien/${event.id}`} href={`hoat-dong/su-kien/${event.id}`}
...@@ -379,7 +397,7 @@ const Page = () => { ...@@ -379,7 +397,7 @@ const Page = () => {
</a> </a>
))} ))}
<div className="w-full md:w-1/2"> <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} /> <CardEvent key={event.id} event={event} />
))} ))}
</div> </div>
...@@ -416,13 +434,13 @@ const Page = () => { ...@@ -416,13 +434,13 @@ const Page = () => {
<div className="flex-1"> <div className="flex-1">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<a <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]" className="text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
> >
Cơ hội kinh doanh Cơ hội kinh doanh
</a> </a>
<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" className="text-[#063e8e] text-sm sm:text-base"
> >
<ChevronsRight /> <ChevronsRight />
...@@ -433,7 +451,7 @@ const Page = () => { ...@@ -433,7 +451,7 @@ const Page = () => {
{businessOpportunities?.responseData.rows {businessOpportunities?.responseData.rows
.slice(0, 1) .slice(0, 1)
.map((news: NewsItem) => ( .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"> <div className="w-full aspect-3/2 relative overflow-hidden mb-5">
<img <img
src={`${BASE_URL.imageEndpoint}${news.thumbnail}`} src={`${BASE_URL.imageEndpoint}${news.thumbnail}`}
...@@ -461,13 +479,13 @@ const Page = () => { ...@@ -461,13 +479,13 @@ const Page = () => {
<div className="flex-1"> <div className="flex-1">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<a <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]" className="text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
> >
Chính sách & pháp luật Chính sách & pháp luật
</a> </a>
<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" className="text-[#063e8e] text-sm sm:text-base"
> >
<ChevronsRight /> <ChevronsRight />
...@@ -478,7 +496,7 @@ const Page = () => { ...@@ -478,7 +496,7 @@ const Page = () => {
{policyAndLegalInformation?.responseData.rows {policyAndLegalInformation?.responseData.rows
.slice(0, 1) .slice(0, 1)
.map((news: NewsItem) => ( .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"> <div className="w-full aspect-3/2 relative overflow-hidden mb-5">
<img <img
src={`${BASE_URL.imageEndpoint}${news.thumbnail}`} 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"; ...@@ -8,17 +8,17 @@ import { ListFilter } from "@/components/base/list-filter";
import EventCalendar from "@/components/base/event-calendar"; import EventCalendar from "@/components/base/event-calendar";
import ListCategory from "@/components/base/list-category"; import ListCategory from "@/components/base/list-category";
import CardNews from "@/components/base/card-news"; import CardNews from "@/components/base/card-news";
import Image from "next/image";
import parse from "html-react-parser";
import dayjs from "dayjs";
// API hooks // API hooks
import { useGetNews, useGetNewsId } from "@/api/endpoints/news"; import { useGetNews } from "@/api/endpoints/news";
import { GetNewsResponseType } from "@/api/types/news"; import { GetNewsResponseType } from "@/api/types/news";
import { GetNewsDetailResponseType } from "./page.type";
import { useGetNewsPageConfigGetHierarchical } from "@/api/endpoints/news-page-config"; import { useGetNewsPageConfigGetHierarchical } from "@/api/endpoints/news-page-config";
import { GetNewsPageConfigResponseType } from "@/api/types/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() { export default function DynamicPage() {
const params = useParams(); const params = useParams();
const slugArray = Array.isArray(params.slug) ? params.slug : [params.slug]; const slugArray = Array.isArray(params.slug) ? params.slug : [params.slug];
...@@ -30,19 +30,19 @@ export default function DynamicPage() { ...@@ -30,19 +30,19 @@ export default function DynamicPage() {
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const pageSize = 5; const pageSize = 5;
// query // queries
const { data: categoriesPage } = useGetNewsPageConfigGetHierarchical<GetNewsPageConfigResponseType>({ const { data: categoriesPage } = useGetNewsPageConfigGetHierarchical<GetNewsPageConfigResponseType>({
code: `${slugArray[0]}`, code: slugArray[0],
}); });
const { data: newsDetail, isLoading: isLoadingDetail } = useGetNews<GetNewsResponseType>({ 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>({ const { data: news, isLoading } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize), pageSize: String(pageSize),
currentPage: String(page), currentPage: String(page),
filters: `page_config.static_link==/${url}` + (submitSearch ? `,title@=${submitSearch}` : ""), filters: `page_config.static_link==/${url}${submitSearch ? `,title@=${submitSearch}` : ""}`,
}); });
if (isLoadingDetail) { if (isLoadingDetail) {
...@@ -53,29 +53,23 @@ export default function DynamicPage() { ...@@ -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; const isDetailPage = newsDetail?.responseData?.rows?.length === 1;
if (isDetailPage) {
if (isDetailPage || id) {
return ( return (
<div className='container w-full flex justify-center items-center pb-10'> <div className="container w-full flex justify-center items-center pb-10">
<div className='flex flex-col gap-5 w-full'> <div className="flex flex-col gap-5 w-full">
<ListCategory categories={categoriesPage?.responseData?.children} /> <ListCategory categories={categoriesPage?.responseData?.children} />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-5"> <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"> <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'> {isDetailPage ? <NewsDetail data={newsDetail} /> : <EventDetail id={id} />}
{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>
</main> </main>
<aside className="space-y-6"> <aside className="space-y-6">
<EventCalendar /> <EventCalendar />
...@@ -104,11 +98,7 @@ export default function DynamicPage() { ...@@ -104,11 +98,7 @@ export default function DynamicPage() {
) : ( ) : (
<> <>
{news?.responseData.rows.map((item) => ( {news?.responseData.rows.map((item) => (
<CardNews <CardNews key={item.id} news={item} link={`${item.external_link}`} />
key={item.id}
news={item}
link={`${item.external_link}`}
/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
<Pagination <Pagination
......
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