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

update/events page

parent 32cb6417
......@@ -10,12 +10,12 @@ const EventsCalendar = () => {
<h2 className="text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]">
Lịch sự kiện
</h2>
<Link
{/* <Link
href="#"
className="text-[#e8c518] hover:underline text-sm sm:text-base"
>
<ChevronsRight />
</Link>
</Link> */}
</div>
<hr className="border-[#e8c518] mb-4" />
<EventCalendar />
......
......@@ -8,8 +8,7 @@ import ImageNext from "@/components/shared/image-next";
function CardEvent({ event }: { event: EventItem }) {
return (
<Link
// href={`hoat-dong/su-kien/${event.id}`}
href={`#`}
href={`/hoat-dong/su-kien/${event.id}`}
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
......
......@@ -18,7 +18,7 @@ function Events() {
<h2 className="text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]">
Sự kiện sắp diễn ra
</h2>
<Link href="#" className="text-[#e8c518] text-sm sm:text-base">
<Link href="/hoat-dong/su-kien" className="text-[#e8c518] text-sm sm:text-base">
<ChevronsRight />
</Link>
</div>
......@@ -34,7 +34,7 @@ function Events() {
{data?.responseData.rows.slice(0, 1).map((event: EventItem) => (
<Link
key={event.id}
href={`#`}
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">
......
......@@ -28,12 +28,12 @@ const News = () => {
>
Tin tức
</Link>
<Link
{/* <Link
href="/thong-tin-truyen-thong/tin-vcci/"
className="text-[#063e8e] text-sm sm:text-base"
>
<ChevronsRight />
</Link>
</Link> */}
</div>
<hr className="border-[#063e8e] mb-4" />
......
......@@ -11,6 +11,8 @@ import ArticlePage from "./templates/ArticlePage";
import { Spinner } from "@/components/ui";
import { useGetNews } from "@/api/endpoints/news";
import ArticleDetailPage from "./templates/ArticleDetailPage";
import EventPage from "./templates/EventPage";
import EventDetailPage from "./templates/EventDetailPage";
export default function DynamicPage() {
const params = useParams();
......@@ -38,6 +40,11 @@ export default function DynamicPage() {
// }, [slug, category, children, router]);
//template
if (slug[0] === "hoat-dong" && slug[1] === "su-kien") {
if (slug.length === 2) return <EventPage />;
if (slug.length === 3) return <EventDetailPage />;
}
if (news?.responseData?.count == 0 && categoryLoading) {
return (
<div className="flex justify-center items-center w-full h-64">
......
'use client';
import { useState } from "react";
import Image from "next/image";
import { notFound, useParams } from "next/navigation";
import dayjs from "dayjs";
import parse from "html-react-parser";
import BASE_URL from "@/links";
import { useGetEvents } from "@/api/endpoints/event";
import { EventApiResponse } from "@/api/types/event";
import { GetNewsPageConfigResponseType } from "@/api/types/news-page-config";
import { useGetNewsPageConfigGetHierarchical } from "@/api/endpoints/news-page-config";
import { Spinner } from "@/components/ui/spinner";
import ListCategory from "@/components/base/list-category";
import EventCalendar from "@/components/base/event-calendar";
import { CreditCard, MapPin, Clock } from "lucide-react";
export default function EventDetailPage() {
// get url
const params = useParams();
const slug = Array.isArray(params.slug) ? params.slug : [params.slug];
const lastpath = slug[slug.length - 1];
// query
const { data: categoriesPage } = useGetNewsPageConfigGetHierarchical<GetNewsPageConfigResponseType>({
code: `${slug[0]}`,
});
const { data: eventsDetail, isLoading } = useGetEvents<EventApiResponse>({
filters: `id==${lastpath}`,
});
// template
if (!isLoading && (!eventsDetail?.responseData?.rows || eventsDetail.responseData.rows.length === 0)) {
return notFound();
}
return (
<div className='container w-full flex justify-center items-center pb-10'>
{isLoading ? (
<div className="flex justify-center items-center w-full h-64">
<Spinner />
</div>
) : (
<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 py-10 px-5 md:px-20">
<div className='pb-5 text-primary text-2xl leading-normal font-medium'>
{eventsDetail?.responseData?.rows[0]?.name}
</div>
<hr className="py-2" />
{/* Top summary with image + details */}
<div className="flex flex-col md:flex-row gap-6 my-6">
<div className="w-full lg:w-1/2 bg-gray-50 rounded-md overflow-hidden">
{eventsDetail?.responseData?.rows[0].image ? (
<div className="w-full h-52 relative ">
<EventImage
src={`${BASE_URL.imageEndpoint}${eventsDetail?.responseData?.rows[0].image}`}
alt={eventsDetail?.responseData?.rows[0]?.name || "image"}
/>
</div>
) : (
<div className="w-full h-52 bg-gray-200" />
)}
</div>
<div className="w-full lg:w-1/2 bg-white border rounded-md p-3 md:p-6">
<div className="flex flex-col gap-3">
<div className="text-sm text-gray-500 flex flex-row items-center gap-2">
<Clock className="h-5 w-5 text-yellow-500" />
<div>
<div className="text-sm font-medium text-gray-800">
Bắt đầu: {eventsDetail?.responseData?.rows[0].start_time
? dayjs(
eventsDetail.responseData.rows[0].start_time
).format('HH:mm DD/MM/YYYY')
: "-"}
</div>
<div className="text-sm font-medium text-gray-800">
Kết thúc: {eventsDetail?.responseData?.rows[0].end_time
? dayjs(
eventsDetail.responseData.rows[0].end_time
).format('HH:mm DD/MM/YYYY')
: "-"}
</div>
</div>
</div>
<div className="text-sm text-gray-500 flex items-center gap-2">
<MapPin className="h-5 w-5 text-blue-600" />
<div className="text-sm font-medium text-gray-800">
Địa điểm: {eventsDetail?.responseData?.rows[0]?.location ??
eventsDetail?.responseData?.rows[0]?.province ??
"-"}
</div>
</div>
<div className="text-sm text-gray-500 flex items-center gap-2">
<CreditCard className="h-5 w-5 text-yellow-400" />
<div className="text-sm font-medium text-gray-800">
Phí tham dự: {eventsDetail?.responseData?.rows[0]?.table_cost
? `${eventsDetail?.responseData?.rows[0]?.table_count
} Bàn : ${eventsDetail?.responseData?.rows[0]?.table_cost.toLocaleString()} đ`
: "Vui lòng xem chi tiết trong bài"}
</div>
</div>
</div>
</div>
</div>
{/* Full description */}
<div className="prose tiptap overflow-hidden">
{parse(eventsDetail?.responseData?.rows[0]?.description ?? "")}
</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<EventCalendar />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-75 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-contain"
/>
</div>
</div>
</aside>
</div>
</div>
)}
</div >
);
}
// Local small component to safely handle Image src fallback without mutating DOM
type EventImageProps = {
src: string;
alt?: string;
};
function EventImage({ src, alt }: EventImageProps) {
const [imgSrc, setImgSrc] = useState<string>(src);
return (
<Image
src={imgSrc}
alt={alt ?? "image"}
fill
className="object-cover"
onError={() => {
// swap to local fallback file when Next/Image fails to load the provided URL
if (imgSrc !== "/img-error.png") setImgSrc("/img-error.png");
}}
/>
);
}
\ No newline at end of file
'use client';
import { useEffect, useState } from "react";
import { notFound, useParams, usePathname, useRouter, useSearchParams } from "next/navigation";
import { useGetEvents } from "@/api/endpoints/event";
import { EventApiResponse } from "@/api/types/event";
import { GetNewsPageConfigResponseType } from "@/api/types/news-page-config";
import { useGetNewsPageConfigGetHierarchical } from "@/api/endpoints/news-page-config";
import { Spinner } from "@/components/ui/spinner";
import ListCategory from "@/components/base/list-category";
import CardEvents from "@/components/base/card-events";
import { Pagination } from "@/components/base/pagination";
import ListFilter from "@/components/base/list-filter";
import EventCalendar from "@/components/base/event-calendar";
export default function EventPage() {
// get url
const params = useParams();
const slug = Array.isArray(params.slug) ? params.slug : [params.slug];
const searchParams = useSearchParams();
const router = useRouter();
const pathname = usePathname();
// states
const initialPage = Number(searchParams.get("page") ?? "1");
const [submitSearch, setSubmitSearch] = useState("");
const [page, setPage] = useState(initialPage);
const pageSize = 5;
useEffect(() => {
const params = new URLSearchParams(searchParams.toString());
if (page > 1) {
params.set("page", String(page));
} else {
params.delete("page");
}
const qs = params.toString();
router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false });
}, [page]);
// query
const { data: categoriesPage } = useGetNewsPageConfigGetHierarchical<GetNewsPageConfigResponseType>({
code: `${slug[0]}`,
});
const { data: events, isLoading: eventsLoading } = useGetEvents<EventApiResponse>({
filters: `name@=${submitSearch ? `title@=${submitSearch}` : ""}`,
pageSize: String(pageSize),
currentPage: String(page),
});
//template
return (
<>
<div className="min-h-screen container mx-auto">
{eventsLoading ? (
<div className="flex justify-center items-center w-full h-64">
<Spinner />
</div>
) : (
<div className="w-full flex flex-col gap-5">
<ListCategory categories={categoriesPage?.responseData?.children} />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<main className="lg:col-span-2 bg-background">
<div className="pb-5 overflow-hidden">
{events?.responseData?.rows?.map((item) => (
<CardEvents
key={item.id}
event={item}
link={`su-kien/${item.id}`}
/>
))}
<div className="w-full flex justify-center mt-4">
<Pagination
pageCount={Number(events?.responseData?.totalPages ?? 1)}
page={Number(events?.responseData?.currentPage ?? page)}
onChangePage={setPage}
onGoToPreviousPage={() => setPage(Math.max(1, page - 1))}
onGoToNextPage={() =>
setPage(Math.min(Number(events?.responseData?.totalPages ?? 1), page + 1))
}
/>
</div>
</div>
</main>
<aside className="space-y-6">
<ListFilter onSearch={setSubmitSearch} />
<EventCalendar />
</aside>
</div>
</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