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

Merge branch 'fix/home_page' into 'develop'

fix/home_page-and-fix-footer

See merge request !12
parents 75098072 4b74d1b8
import { NewsAdminItem } from '@/api/types/news' import { NewsAdminItem } from "@/api/types/news";
import BASE_URL from '@/links' import BASE_URL from "@/links";
import dayjs from 'dayjs'; import dayjs from "dayjs";
import AppEditorContent from '@/components/shared/editor-content'; import AppEditorContent from "@/components/shared/editor-content";
function CardNews({ news }: { news: NewsAdminItem }) { function CardNews({ news }: { news: NewsAdminItem }) {
return ( return (
<a <a
href={`${news.id}`} href={`${news.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' className="flex flex-row gap-2 mb-2 sm:gap-3 sm:mb-3"
> >
<img <img
src={`${BASE_URL.imageEndpoint}${news.thumbnail}`} src={`${BASE_URL.imageEndpoint}${news.thumbnail}`}
...@@ -18,13 +18,12 @@ function CardNews({ news }: { news: NewsAdminItem }) { ...@@ -18,13 +18,12 @@ function CardNews({ news }: { news: NewsAdminItem }) {
e.currentTarget.src = "/fallback.png" e.currentTarget.src = "/fallback.png"
}} }}
/> />
<div className="flex-1">
<div className='flex-1'> <p className="text-[#363636] font-bold text-sm line-clamp-2">
<p className='text-[#0056b3] font-bold text-sm line-clamp-2'>
{news.title} {news.title}
</p> </p>
<p className='text-gray-500 text-sm my-1'> <p className="text-gray-500 text-sm my-1">
{dayjs(news.release_at).format('DD/MM/YYYY')} {dayjs(news.release_at).format("DD/MM/YYYY")}
</p> </p>
{/* <AppEditorContent className='line-clamp-2' value={news.description} /> */} {/* <AppEditorContent className='line-clamp-2' value={news.description} /> */}
</div> </div>
......
'use client' "use client";
import Image from 'next/image' import Image from "next/image";
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from "react";
import { Autoplay, Grid } from 'swiper/modules' import { Autoplay, Grid } from "swiper/modules";
import { Swiper, SwiperSlide } from 'swiper/react' import { Swiper, SwiperSlide } from "swiper/react";
import { Swiper as SwiperType } from 'swiper/types' import { Swiper as SwiperType } from "swiper/types";
import 'swiper/css' import "swiper/css";
import 'swiper/css/navigation' import "swiper/css/navigation";
import 'swiper/css/pagination' import "swiper/css/pagination";
import BASE_URL from '@/links/index' import BASE_URL from "@/links/index";
import { Spinner } from '@/components/ui' import { Spinner } from "@/components/ui";
import CardNews from './components/card-news' import CardNews from "./components/card-news";
import CardEvent from './components/card-event' import CardEvent from "./components/card-event";
import EventCalendar from '@components/base/event-calendar' import EventCalendar from "@components/base/event-calendar";
import dayjs from 'dayjs' import dayjs from "dayjs";
import AppEditorContent from '@/components/shared/editor-content' import AppEditorContent from "@/components/shared/editor-content";
// server // server
import { useGetEvents } from '@/api/endpoints/event' import { useGetEvents } from "@/api/endpoints/event";
import { useGetCategory } from '@/api/endpoints/category' import { useGetCategory } from "@/api/endpoints/category";
import { useGetNews } from '@/api/endpoints/news' import { useGetNews } from "@/api/endpoints/news";
import { GetCategoryAdminResponseType } from '@/api/types/category' import { GetCategoryAdminResponseType } from "@/api/types/category";
import { GetNewsAdminResponseType, NewsAdminItem } from '@/api/types/news' import { GetNewsAdminResponseType, NewsAdminItem } from "@/api/types/news";
import { EventApiResponse, EventItem } from '@/api/types/event' import { EventApiResponse, EventItem } from "@/api/types/event";
import { ChevronsRight, Link } from "lucide-react";
const Page = () => { const Page = () => {
const [tab, setTab] = useState('all') const [tab, setTab] = useState("all");
const [currentIndex, setCurrentIndex] = useState(0) const [currentIndex, setCurrentIndex] = useState(0);
const swiperRef = useRef<SwiperType | null>(null) const swiperRef = useRef<SwiperType | null>(null);
const { data: categoryData, isLoading: isLoadingCategory } = useGetCategory<GetCategoryAdminResponseType>() const { data: categoryData, isLoading: isLoadingCategory } = useGetCategory<GetCategoryAdminResponseType>();
const { data: newsData, isLoading: isLoadingNews } = useGetNews<GetNewsAdminResponseType>( const { data: newsData, isLoading: isLoadingNews } = useGetNews<GetNewsAdminResponseType>(
{ pageSize: '999' }, { pageSize: '999' }
) );
const { data: eventData, isLoading: isLoadingEvent } = useGetEvents<EventApiResponse>() const { data: eventData, isLoading: isLoadingEvent } = useGetEvents<EventApiResponse>();
// filter category // filter category
const rows = newsData?.responseData?.rows ?? [] const rows = newsData?.responseData?.rows ?? [];
const filteredRows = tab === 'all' ? rows : rows.filter((n) => n.category === tab) const filteredRows =
tab === "all" ? rows : rows.filter((n) => n.category === tab);
const images = [ const images = [
'/home/doi-tac/AMFORI-1.png.webp', "/home/doi-tac/AMFORI-1.png.webp",
'/home/doi-tac/AUS4SKILLS-1.png.webp', "/home/doi-tac/AUS4SKILLS-1.png.webp",
'/home/doi-tac/BetterWork-1.png.webp', "/home/doi-tac/BetterWork-1.png.webp",
'/home/doi-tac/BOI-LOGO.jpg.webp', "/home/doi-tac/BOI-LOGO.jpg.webp",
'/home/doi-tac/DNV-logo-1-1.png.webp', "/home/doi-tac/DNV-logo-1-1.png.webp",
'/home/doi-tac/GERMAN-COOPERATION-1.png.webp', "/home/doi-tac/GERMAN-COOPERATION-1.png.webp",
'/home/doi-tac/GIZ.png.webp', "/home/doi-tac/GIZ.png.webp",
'/home/doi-tac/HBA.png.webp', "/home/doi-tac/HBA.png.webp",
'/home/doi-tac/ILO-1.png.webp', "/home/doi-tac/ILO-1.png.webp",
'/home/doi-tac/InvestHK.png.webp', "/home/doi-tac/InvestHK.png.webp",
'/home/doi-tac/IOM-1.png.webp', "/home/doi-tac/IOM-1.png.webp",
'/home/doi-tac/JICA-134x100-1-1.jpg.webp', "/home/doi-tac/JICA-134x100-1-1.jpg.webp",
'/home/doi-tac/KIRBY.png.webp', "/home/doi-tac/KIRBY.png.webp",
'/home/doi-tac/NHO-1.png.webp', "/home/doi-tac/NHO-1.png.webp",
'/home/doi-tac/OXFAM-1.png.webp', "/home/doi-tac/OXFAM-1.png.webp",
'/home/doi-tac/RECOTVET-1.png.webp', "/home/doi-tac/RECOTVET-1.png.webp",
'/home/doi-tac/SC-1.png.webp', "/home/doi-tac/SC-1.png.webp",
'/home/doi-tac/UNDP.png.webp', "/home/doi-tac/UNDP.png.webp",
] ];
const hoivien = [ const hoivien = [
'/home/hoi-vien-tieu-bieu/logo-GTD-768x768.png.webp', "/home/hoi-vien-tieu-bieu/logo-GTD-768x768.png.webp",
'/home/hoi-vien-tieu-bieu/Nhua-Long-Thanh_Logo.jpg.webp', "/home/hoi-vien-tieu-bieu/Nhua-Long-Thanh_Logo.jpg.webp",
'/home/hoi-vien-tieu-bieu/Nova_Group_logo-1.png.webp', "/home/hoi-vien-tieu-bieu/Nova_Group_logo-1.png.webp",
'/home/hoi-vien-tieu-bieu/samngoclinh-1-768x768.png.webp', "/home/hoi-vien-tieu-bieu/samngoclinh-1-768x768.png.webp",
'/home/hoi-vien-tieu-bieu/Screenshot-2022-12-26-144136-768x768.png.webp', "/home/hoi-vien-tieu-bieu/Screenshot-2022-12-26-144136-768x768.png.webp",
'/home/hoi-vien-tieu-bieu/UOB-logo_Vuong.jpeg.webp', "/home/hoi-vien-tieu-bieu/UOB-logo_Vuong.jpeg.webp",
] ];
return ( return (
isLoadingNews || isLoadingCategory || isLoadingEvent ? ( (isLoadingNews || isLoadingCategory || 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>
...@@ -84,7 +86,9 @@ const Page = () => { ...@@ -84,7 +86,9 @@ const Page = () => {
slidesPerView={1} slidesPerView={1}
onSwiper={(s) => (swiperRef.current = s)} onSwiper={(s) => (swiperRef.current = s)}
onSlideChange={(s) => onSlideChange={(s) =>
setCurrentIndex(typeof s.realIndex === 'number' ? s.realIndex : s.activeIndex) setCurrentIndex(
typeof s.realIndex === "number" ? s.realIndex : s.activeIndex
)
} }
> >
<SwiperSlide> <SwiperSlide>
...@@ -106,11 +110,14 @@ const Page = () => { ...@@ -106,11 +110,14 @@ const Page = () => {
<div className="container mx-auto px-3 sm:px-6 lg:px-10 space-y-12"> <div className="container mx-auto px-3 sm:px-6 lg:px-10 space-y-12">
{/* Featured News */} {/* Featured News */}
<section> <section>
<div className="flex flex-col items-center py-8 text-center"> <div className="flex items-center justify-center py-8 px-4">
<h1 className="text-app-blue text-[20px] sm:text-[24px] md:text-[28px] uppercase font-bold text-blue-900"> <div className="flex items-center w-full max-w-4xl">
<div className="flex-1 h-[1px] bg-gradient-to-r from-transparent via-gray-300 to-gray-400"></div>
<h1 className="px-6 text-[20px] sm:text-[24px] md:text-[28px] uppercase font-bold text-[#063e8e] whitespace-nowrap">
Tin Nổi Bật Tin Nổi Bật
</h1> </h1>
<div className="w-16 h-[3px] bg-blue-900 mt-2 rounded-full"></div> <div className="flex-1 h-[1px] bg-gradient-to-l from-transparent via-gray-300 to-gray-400"></div>
</div>
</div> </div>
<Swiper <Swiper
...@@ -128,7 +135,7 @@ const Page = () => { ...@@ -128,7 +135,7 @@ const Page = () => {
<SwiperSlide key={news.id}> <SwiperSlide key={news.id}>
<a <a
href={`/${news.id}`} href={`/${news.id}`}
className="relative block bg-white rounded-xl 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
src={`${BASE_URL.imageEndpoint}${news.thumbnail}`} src={`${BASE_URL.imageEndpoint}${news.thumbnail}`}
...@@ -157,63 +164,72 @@ const Page = () => { ...@@ -157,63 +164,72 @@ const Page = () => {
{/* Left */} {/* Left */}
<div className="flex-1"> <div className="flex-1">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<a href="/thong-tin-truyen-thong/tin-vcci/" className="text-[18px] sm:text-[20px] font-bold uppercase text-blue-900"> <a
href="/thong-tin-truyen-thong/tin-vcci/"
className="text-[18px] sm:text-[20px] font-semibold uppercase text-[#063e8e]"
>
Tin tức Tin tức
</a> </a>
<a href="/thong-tin-truyen-thong/tin-vcci/" className="text-blue-900 text-sm sm:text-base"> <a
{'>>'} href="/thong-tin-truyen-thong/tin-vcci/"
className="text-[#063e8e] text-sm sm:text-base"
>
<ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-blue-900 mb-4" /> <hr className="border-[#063e8e] mb-4" />
<div className="flex flex-col md:flex-row gap-5"> <div className="flex flex-col md:flex-row gap-5">
{newsData?.responseData.rows.slice(0, 1).map((news: NewsAdminItem) => ( {newsData?.responseData.rows
.slice(0, 1)
.map((news: NewsAdminItem) => (
<a <a
key={news.id} key={news.id}
href={`${news.id}`} href={`${news.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" 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">
<img <img
src={`${BASE_URL.imageEndpoint}${news.thumbnail}`} src={`${BASE_URL.imageEndpoint}${news.thumbnail}`}
alt={news.title} alt={news.title}
className="w-full h-full object-cover" className="w-full h-full object-cover"
onError={(e) => {
e.currentTarget.onerror = null
e.currentTarget.src = "/fallback.png"
}}
/> />
</div> </div>
<div className="flex-1"> <div className="flex-1 p-5">
<p className="text-[#0056b3] font-bold text-xl line-clamp-2"> <p className="text-[#063E8E] font-bold text-xl line-clamp-2">
{news.title} {news.title}
</p> </p>
<p className="text-gray-500 text-sm my-1"> <p className="text-gray-500 text-sm my-1">
{dayjs(news.release_at).format('DD/MM/YYYY')} {dayjs(news.release_at).format("DD/MM/YYYY")}
</p> </p>
<AppEditorContent className="line-clamp-4" value={news.description} /> <AppEditorContent
className="line-clamp-4"
value={news.description}
/>
</div> </div>
</a> </a>
))} ))}
<div className="w-full md:w-1/2"> <div className="w-full md:w-1/2">
<div className="flex flex-wrap gap-2 sm:gap-3 mb-3"> <div className="flex flex-wrap gap-2 sm:gap-3 mb-5">
<button <button
className={`flex-1 px-3 sm:px-4 py-2 rounded-md border text-sm transition-colors ${tab === 'all' className={`flex-1 py-[3px] text-sm transition-colors cursor-pointer ${tab === "all"
? 'border-blue-700 bg-blue-50 text-blue-800 font-semibold' ? " bg-[#d3d3d3] text-[#063e8e] font-semibold"
: 'border-gray-300 bg-white hover:bg-gray-50' : "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`} }`}
onClick={() => setTab('all')} onClick={() => setTab("all")}
> >
Tất cả Tất cả
</button> </button>
{categoryData?.responseData.rows.slice(0, 3).map((category) => ( {categoryData?.responseData.rows
.slice(0, 3)
.map((category) => (
<button <button
key={category.id} key={category.id}
className={`flex-1 px-3 sm:px-4 py-2 rounded-md border text-sm transition-colors ${category.name === tab className={`flex-1 py-[3px] text-[14px] transition-colors cursor-pointer ${category.name === tab
? 'border-blue-700 bg-blue-50 text-blue-800 font-semibold' ? "bg-[#d3d3d3] text-[#063e8e] font-semibold"
: 'border-gray-300 bg-white hover:bg-gray-50' : "border-gray-300 text-[#363636] bg-[#e8e8e8] hover:bg-[#e8e8e8] hover:text-[#063e8e] font-semibold"
}`} }`}
onClick={() => setTab(category.name)} onClick={() => setTab(category.name)}
> >
...@@ -232,23 +248,39 @@ const Page = () => { ...@@ -232,23 +248,39 @@ const Page = () => {
{/* Right */} {/* Right */}
<aside className="w-full lg:w-[30%]"> <aside className="w-full lg:w-[30%]">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h2 className="text-[18px] sm:text-[20px] font-bold uppercase text-blue-900"> <h2 className="text-[18px] sm:text-[20px] font-semibold uppercase text-[#063e8e]">
Liên kết nhanh Liên kết nhanh
</h2> </h2>
<a href="#" className="text-blue-900 text-sm sm:text-base"> <a href="#" className="text-[#063e8e] text-sm sm:text-base">
{'>>'} <ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-blue-900 mb-4" /> <hr className="border-[#063e8e] mb-4" />
<div className="space-y-2 text-blue-900 text-sm md:text-base pb-10"> <div className="space-y-2 text-[#063e8e] text-sm md:text-base pb-10">
<div> <div>
<a href="https://vcci-hcm.org.vn/lien-ket-nhanh/cam-nang-huong-dan-dau-tu-kinh-doanh-tai-viet-nam-2023/"> <a
🔗 Cẩm nang hướng dẫn đầu tư kinh doanh tại Việt Nam className="text-[#363636]"
href="https://vcci-hcm.org.vn/lien-ket-nhanh/cam-nang-huong-dan-dau-tu-kinh-doanh-tai-viet-nam-2023/"
>
<Link
size={16}
className="inline mr-2 font-semibold text-[#063e8e]"
style={{ verticalAlign: "middle", marginTop: "-2px" }}
/>
Cẩm nang hướng dẫn đầu tư kinh doanh tại Việt Nam
</a> </a>
</div> </div>
<div> <div>
<a href='https://vcci-hcm.org.vn/lien-ket-nhanh/doanh-nghiep-kien-nghi-ve-chinh-sach-va-phap-luat/'> <a
🔗 Doanh nghiệp kiến nghị về chính sách và pháp luật className="text-[#363636]"
href="https://vcci-hcm.org.vn/lien-ket-nhanh/doanh-nghiep-kien-nghi-ve-chinh-sach-va-phap-luat/"
>
<Link
size={16}
className="inline mr-2 font-semibold text-[#063e8e]"
style={{ verticalAlign: "middle", marginTop: "-2px" }}
/>
Doanh nghiệp kiến nghị về chính sách và pháp luật
</a> </a>
</div> </div>
</div> </div>
...@@ -258,23 +290,25 @@ const Page = () => { ...@@ -258,23 +290,25 @@ const Page = () => {
</a> </a>
</div> </div>
</aside> </aside>
</section> </section >
{/* Sự kiện */} {/* Sự kiện */}
<section className="flex flex-col lg:flex-row gap-5 pb-10 mb-0"> < section className="flex flex-col lg:flex-row gap-5 pb-10 mb-0" >
<div className="flex-1 bg-blue-900 p-5"> <div className="flex-1 bg-[#063e8e] p-5">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h2 className="text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]"> <h2 className="text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]">
Sự kiện sắp diễn ra Sự kiện sắp diễn ra
</h2> </h2>
<a href="#" className="text-[#e8c518] text-sm sm:text-base"> <a href="#" className="text-[#e8c518] text-sm sm:text-base">
{'>>'} <ChevronsRight />
</a> </a>
</div> </div>
<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.slice(0, 1).map((event: EventItem) => ( {eventData?.responseData.rows
.slice(0, 1)
.map((event: EventItem) => (
<a <a
key={event.id} key={event.id}
href={`${event.id}`} href={`${event.id}`}
...@@ -285,10 +319,7 @@ const Page = () => { ...@@ -285,10 +319,7 @@ const Page = () => {
src={`${BASE_URL.imageEndpoint}${event.image}`} src={`${BASE_URL.imageEndpoint}${event.image}`}
alt={event.name} alt={event.name}
className="w-full h-full object-cover" className="w-full h-full object-cover"
onError={(e) => { />
e.currentTarget.onerror = null
e.currentTarget.src = "/fallback.png"
}} />
</div> </div>
<div className="flex-1"> <div className="flex-1">
...@@ -296,9 +327,12 @@ const Page = () => { ...@@ -296,9 +327,12 @@ const Page = () => {
{event.name} {event.name}
</p> </p>
<p className="text-gray-500 text-sm my-1"> <p className="text-gray-500 text-sm my-1">
{dayjs(event.start_time).format('DD/MM/YYYY')} {dayjs(event.start_time).format("DD/MM/YYYY")}
</p> </p>
<AppEditorContent className="line-clamp-3" value={event.description} /> <AppEditorContent
className="line-clamp-3"
value={event.description}
/>
</div> </div>
</a> </a>
))} ))}
...@@ -309,25 +343,28 @@ const Page = () => { ...@@ -309,25 +343,28 @@ const Page = () => {
</div> </div>
</div> </div>
</div> </div>
<div className='bg-blue-900 w-full lg:w-[30%] p-5'> <div className="bg-[#063e8e] w-full lg:w-[30%] p-5">
<aside> <aside>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h2 className="text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]"> <h2 className="text-[18px] sm:text-[20px] font-bold uppercase text-[#e8c518]">
Lịch sự kiện Lịch sự kiện
</h2> </h2>
<a href="#" className="text-[#e8c518] hover:underline text-sm sm:text-base"> <a
{'>>'} href="#"
className="text-[#e8c518] hover:underline text-sm sm:text-base"
>
<ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-[#e8c518] mb-4" /> <hr className="border-[#e8c518] mb-4" />
<EventCalendar /> <EventCalendar />
</aside> </aside>
</div> </div>
</section> </section >
{/* Cơ hội kinh doanh + Chính sách */} {/* Cơ hội kinh doanh + Chính sách */}
<div className='flex flex-col lg:flex-row gap-5 pb-10 mb-0'> < div className="flex flex-col lg:flex-row gap-5 pb-10 mb-0" >
<div className='flex flex-col flex-1'> <div className="flex flex-col flex-1">
<div> <div>
<a href="https://vcci-hcm.org.vn/wp-content/uploads/2022/11/MEDIA-KIT_VCCI-HCM-2022-Final.pdf"> <a href="https://vcci-hcm.org.vn/wp-content/uploads/2022/11/MEDIA-KIT_VCCI-HCM-2022-Final.pdf">
<img src="/home/Standard-Banner-1-2024.png.webp" alt="banner" /> <img src="/home/Standard-Banner-1-2024.png.webp" alt="banner" />
...@@ -336,20 +373,25 @@ const Page = () => { ...@@ -336,20 +373,25 @@ const Page = () => {
<section className="flex flex-col md:flex-row gap-5 pt-8"> <section className="flex flex-col md:flex-row gap-5 pt-8">
<div className="flex-1"> <div className="flex-1">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<a href="/xuc-tien-thuong-mai/co-hoi-kinh-doanh/" className="text-[18px] sm:text-[20px] font-bold uppercase text-blue-900"> <a
href="/xuc-tien-thuong-mai/co-hoi-kinh-doanh/"
className="text-[18px] sm:text-[20px] font-bold uppercase text-[#063e8e]"
>
Cơ hội kinh doanh Cơ hội kinh doanh
</a> </a>
<a href="/xuc-tien-thuong-mai/co-hoi-kinh-doanh/" className="text-blue-900 text-sm sm:text-base"> <a
{'>>'} href="/xuc-tien-thuong-mai/co-hoi-kinh-doanh/"
className="text-[#063e8e] text-sm sm:text-base"
>
<ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-blue-900 mb-4" /> <hr className="border-[#063e8e] mb-4" />
<div className="pt-2"> <div className="pt-2">
{newsData?.responseData.rows.slice(0, 1).map((news: NewsAdminItem) => ( {newsData?.responseData.rows
<a .slice(0, 1)
key={news.id} .map((news: NewsAdminItem) => (
href={`${news.id}`} <a key={news.id} href={`${news.id}`}>
>
<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}`}
...@@ -357,7 +399,7 @@ const Page = () => { ...@@ -357,7 +399,7 @@ const Page = () => {
className="w-full h-full object-cover" className="w-full h-full object-cover"
/> />
<div className="absolute bg-white opacity-80 bottom-5 left-5 right-5 p-5"> <div className="absolute bg-white opacity-80 bottom-5 left-5 right-5 p-5">
<p className="text-blue-900 font-semibold text-sm sm:text-base z-10 line-clamp-3"> <p className="text-[#063e8e] font-semibold text-sm sm:text-base z-10 line-clamp-3">
{news.title} {news.title}
</p> </p>
</div> </div>
...@@ -372,20 +414,25 @@ const Page = () => { ...@@ -372,20 +414,25 @@ const Page = () => {
</div> </div>
<div className="flex-1"> <div className="flex-1">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<a href="/thong-tin-truyen-thong/thong-tin-chinh-sach-va-phap-luat" className="text-[18px] sm:text-[20px] font-bold uppercase text-blue-900"> <a
href="/thong-tin-truyen-thong/thong-tin-chinh-sach-va-phap-luat"
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 href="/thong-tin-truyen-thong/thong-tin-chinh-sach-va-phap-luat" className="text-blue-900 text-sm sm:text-base"> <a
{'>>'} href="/thong-tin-truyen-thong/thong-tin-chinh-sach-va-phap-luat"
className="text-[#063e8e] text-sm sm:text-base"
>
<ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-blue-900 mb-4" /> <hr className="border-[#063e8e] mb-4" />
<div className="pt-2"> <div className="pt-2">
{newsData?.responseData.rows.slice(0, 1).map((news: NewsAdminItem) => ( {newsData?.responseData.rows
<a .slice(0, 1)
key={news.id} .map((news: NewsAdminItem) => (
href={`${news.id}`} <a key={news.id} href={`${news.id}`}>
>
<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}`}
...@@ -393,7 +440,7 @@ const Page = () => { ...@@ -393,7 +440,7 @@ const Page = () => {
className="w-full h-full object-cover" className="w-full h-full object-cover"
/> />
<div className="absolute bg-white opacity-80 bottom-5 left-5 right-5 p-5"> <div className="absolute bg-white opacity-80 bottom-5 left-5 right-5 p-5">
<p className="text-blue-900 font-semibold text-sm sm:text-base z-10 line-clamp-3"> <p className="text-[#063e8e] font-semibold text-sm sm:text-base z-10 line-clamp-3">
{news.title} {news.title}
</p> </p>
</div> </div>
...@@ -408,7 +455,7 @@ const Page = () => { ...@@ -408,7 +455,7 @@ const Page = () => {
</div> </div>
</section> </section>
</div> </div>
<div className='w-full lg:w-[30%] justify-center items-start flex'> <div className="w-full lg:w-[30%] justify-center items-start flex">
<a href="https://smartgara.ecaraid.com/"> <a href="https://smartgara.ecaraid.com/">
<img src="/home/eCarAid_web_banner_600x400.webp" alt="banner" /> <img src="/home/eCarAid_web_banner_600x400.webp" alt="banner" />
</a> </a>
...@@ -420,21 +467,23 @@ const Page = () => { ...@@ -420,21 +467,23 @@ const Page = () => {
{/* left */} {/* left */}
< aside className="w-full lg:w-1/3 flex-1 bg-[#e8c518] p-5" > < aside className="w-full lg:w-1/3 flex-1 bg-[#e8c518] p-5" >
<div className="flex justify-between items-center mb-3"> <div className="flex justify-between items-center mb-3">
<h2 className="text-xl font-bold uppercase text-blue-900">Hội viên tiêu biểu</h2> <h2 className="text-xl font-bold uppercase text-[#063e8e]">
Hội viên tiêu biểu
</h2>
<a <a
href="#" href="#"
className="text-blue-900 hover:underline text-sm font-medium" className="text-[#063e8e] hover:underline text-sm font-medium"
> >
{'>>'} <ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-blue-900 mb-5" /> <hr className="border-[#063e8e] mb-5" />
<div> <div>
<Swiper <Swiper
modules={[Autoplay, Grid]} modules={[Autoplay, Grid]}
autoplay={{ delay: 4000, disableOnInteraction: false }} autoplay={{ delay: 4000, disableOnInteraction: false }}
loop loop
grid={{ rows: 1, fill: 'row' }} grid={{ rows: 1, fill: "row" }}
slidesPerGroup={3} slidesPerGroup={3}
breakpoints={{ breakpoints={{
0: { slidesPerView: 2, spaceBetween: 10 }, 0: { slidesPerView: 2, spaceBetween: 10 },
...@@ -461,21 +510,23 @@ const Page = () => { ...@@ -461,21 +510,23 @@ const Page = () => {
{/* right */} {/* right */}
< aside className="w-full lg:w-[30%] py-5" > < aside className="w-full lg:w-[30%] py-5" >
<div className="flex justify-between items-center mb-3"> <div className="flex justify-between items-center mb-3">
<h2 className="text-xl font-bold uppercase text-blue-900">Kết nối hội viên</h2> <h2 className="text-xl font-bold uppercase text-[#063e8e]">
Kết nối hội viên
</h2>
<a <a
href="#" href="#"
className="text-blue-900 hover:underline text-sm font-medium" className="text-[#063e8e] hover:underline text-sm font-medium"
> >
{'>>'} <ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-blue-900 mb-5" /> <hr className="border-[#063e8e] mb-5" />
<div className="pb-10"> <div className="pb-10">
<Swiper <Swiper
modules={[Autoplay, Grid]} modules={[Autoplay, Grid]}
autoplay={{ delay: 4000, disableOnInteraction: false }} autoplay={{ delay: 4000, disableOnInteraction: false }}
loop loop
grid={{ rows: 2, fill: 'row' }} grid={{ rows: 2, fill: "row" }}
slidesPerGroup={3} slidesPerGroup={3}
breakpoints={{ breakpoints={{
0: { slidesPerView: 2, spaceBetween: 10 }, 0: { slidesPerView: 2, spaceBetween: 10 },
...@@ -505,24 +556,26 @@ const Page = () => { ...@@ -505,24 +556,26 @@ const Page = () => {
{/* left */} {/* left */}
< div className="flex flex-col flex-1" > < div className="flex flex-col flex-1" >
<div className="flex justify-between items-center mb-3"> <div className="flex justify-between items-center mb-3">
<h2 className="text-xl font-bold uppercase text-blue-900">Video</h2> <h2 className="text-xl font-bold uppercase text-[#063e8e]">
Video
</h2>
<a <a
href="#" href="#"
className="text-blue-900 hover:underline text-sm font-medium" className="text-[#063e8e] hover:underline text-sm font-medium"
> >
{'>>'} <ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-blue-900 mb-5" /> <hr className="border-[#063e8e] mb-5" />
<div className="flex flex-col md:flex-row gap-4 md:gap-6"> <div className="flex flex-col md:flex-row gap-4 md:gap-6">
{[ {[
{ {
src: 'https://www.youtube.com/embed/J0Iz0iGuAXY', src: "https://www.youtube.com/embed/J0Iz0iGuAXY",
title: 'VCCI-HCM 2024 IN REVIEW (ENGLISH VERSION)', title: "VCCI-HCM 2024 IN REVIEW (ENGLISH VERSION)",
}, },
{ {
src: 'https://www.youtube.com/embed/_OnnGWv2ehM', src: "https://www.youtube.com/embed/_OnnGWv2ehM",
title: 'Hội nghị Hội viên VCCI - Gala Mừng Xuân Ất Tỵ 2025', title: "Hội nghị Hội viên VCCI - Gala Mừng Xuân Ất Tỵ 2025",
}, },
].map((video, i) => ( ].map((video, i) => (
<div key={i} className="w-full md:w-1/2"> <div key={i} className="w-full md:w-1/2">
...@@ -537,7 +590,9 @@ const Page = () => { ...@@ -537,7 +590,9 @@ const Page = () => {
allowFullScreen allowFullScreen
/> />
</div> </div>
<p className="mt-2 text-sm text-gray-700 font-medium">{video.title}</p> <p className="mt-2 text-sm text-gray-700 font-medium">
{video.title}
</p>
</div> </div>
))} ))}
</div> </div>
...@@ -546,21 +601,23 @@ const Page = () => { ...@@ -546,21 +601,23 @@ const Page = () => {
{/* right */} {/* right */}
< aside className="w-full lg:w-[30%]" > < aside className="w-full lg:w-[30%]" >
<div className="flex justify-between items-center mb-3"> <div className="flex justify-between items-center mb-3">
<h2 className="text-xl font-bold uppercase text-blue-900">Đối tác</h2> <h2 className="text-xl font-bold uppercase text-[#063e8e]">
Đối tác
</h2>
<a <a
href="#" href="#"
className="text-blue-900 hover:underline text-sm font-medium" className="text-[#063e8e] hover:underline text-sm font-medium"
> >
{'>>'} <ChevronsRight />
</a> </a>
</div> </div>
<hr className="border-blue-900 mb-5" /> <hr className="border-[#063e8e] mb-5" />
<div className="pb-10"> <div className="pb-10">
<Swiper <Swiper
modules={[Autoplay, Grid]} modules={[Autoplay, Grid]}
autoplay={{ delay: 4000, disableOnInteraction: false }} autoplay={{ delay: 4000, disableOnInteraction: false }}
loop loop
grid={{ rows: 2, fill: 'row' }} grid={{ rows: 2, fill: "row" }}
slidesPerGroup={3} slidesPerGroup={3}
breakpoints={{ breakpoints={{
0: { slidesPerView: 2, spaceBetween: 10 }, 0: { slidesPerView: 2, spaceBetween: 10 },
...@@ -587,7 +644,7 @@ const Page = () => { ...@@ -587,7 +644,7 @@ const Page = () => {
</div > </div >
</> </>
) )
) );
} };
export default Page export default Page;
"use client";
import { useState, useEffect } from "react";
import { ChevronsUp } from "lucide-react";
export default function ScrollToTopButton() {
const [visible, setVisible] = useState(false);
useEffect(() => {
const toggleVisibility = () => {
setVisible(window.scrollY > 300);
};
window.addEventListener("scroll", toggleVisibility);
return () => window.removeEventListener("scroll", toggleVisibility);
}, []);
const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: "smooth" });
};
return (
<button
onClick={scrollToTop}
className={`fixed bottom-25 right-6 bg-[#e8c518] hover:text-[#063e8e] text-white p-3 rounded-lg shadow-lg transition-all duration-500 cursor-pointer ${
visible
? "opacity-100 translate-y-0"
: "opacity-0 translate-y-3 pointer-events-none"
}`}
>
<ChevronsUp size={24} />
</button>
);
}
...@@ -170,7 +170,7 @@ function Footer() { ...@@ -170,7 +170,7 @@ function Footer() {
</div> </div>
</div> </div>
<div className="bg-[#032248] h-[80px] flex items-center justify-center"> <div className="bg-[#032248] h-[80px] flex items-center justify-center">
<div className="max-w-[1200px] w-full p-5"> <div className="container w-full p-5">
<p className="text-[14px] text-white"> <p className="text-[14px] text-white">
© Bản quyền VCCI-HCM | All rights reserved © Bản quyền VCCI-HCM | All rights reserved
</p> </p>
......
import Header from "@/app/(main)/_lib/layout/header" import Header from "@/app/(main)/_lib/layout/header";
import Footer from "@/app/(main)/_lib/layout/footer" import Footer from "@/app/(main)/_lib/layout/footer";
import React from "react"; import React from "react";
import ScrollToTopButton from "./_lib/layout/ScrollToTopButton";
export default function Layout({ export default function Layout({
children, children,
...@@ -10,9 +9,10 @@ export default function Layout({ ...@@ -10,9 +9,10 @@ export default function Layout({
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
return ( return (
<main className="bg-background"> <main className="flex flex-col min-h-screen bg-background">
<Header /> <Header />
{children} <div className="flex-1">{children}</div>
<ScrollToTopButton />
<Footer /> <Footer />
</main> </main>
); );
......
...@@ -68,7 +68,7 @@ export default function PublicationDetail() { ...@@ -68,7 +68,7 @@ export default function PublicationDetail() {
return ( return (
<div className="bg-[#f6f6f6] min-h-screen"> <div className="bg-[#f6f6f6] min-h-screen">
<div className="max-w-[1200px] mx-auto flex flex-col gap-5 mb-[50px]"> <div className="container mx-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory categories={MEDIA_INFORMATION_CATEGORIES} /> <ListCategory categories={MEDIA_INFORMATION_CATEGORIES} />
</div> </div>
......
...@@ -7,7 +7,7 @@ import PublicationList from "./components/publicationList"; ...@@ -7,7 +7,7 @@ import PublicationList from "./components/publicationList";
export default function Page() { export default function Page() {
return ( return (
<div className="bg-[#f6f6f6]"> <div className="bg-[#f6f6f6]">
<div className="max-w-[1200px] m-auto flex flex-col gap-5 mb-[50px]"> <div className="container m-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory categories={MEDIA_INFORMATION_CATEGORIES} /> <ListCategory categories={MEDIA_INFORMATION_CATEGORIES} />
</div> </div>
......
...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar"; ...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar";
export default function page() { export default function page() {
return ( return (
<div className="bg-[#f6f6f6]"> <div className="bg-[#f6f6f6]">
<div className="max-w-[1200px] m-auto flex flex-col gap-5 mb-[50px]"> <div className="container m-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory /> <ListCategory />
</div> </div>
......
...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar"; ...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar";
export default function page() { export default function page() {
return ( return (
<div className="bg-[#f6f6f6]"> <div className="bg-[#f6f6f6]">
<div className="max-w-[1200px] m-auto flex flex-col gap-5 mb-[50px]"> <div className="container m-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory /> <ListCategory />
</div> </div>
......
...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar"; ...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar";
export default function page() { export default function page() {
return ( return (
<div className="bg-[#f6f6f6]"> <div className="bg-[#f6f6f6]">
<div className="max-w-[1200px] m-auto flex flex-col gap-5 mb-[50px]"> <div className="container m-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory /> <ListCategory />
</div> </div>
......
...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar"; ...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar";
export default function page() { export default function page() {
return ( return (
<div className="bg-[#f6f6f6]"> <div className="bg-[#f6f6f6]">
<div className="max-w-[1200px] m-auto flex flex-col gap-5 mb-[50px]"> <div className="container m-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory /> <ListCategory />
</div> </div>
......
...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar"; ...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar";
export default function page() { export default function page() {
return ( return (
<div className="bg-[#f6f6f6]"> <div className="bg-[#f6f6f6]">
<div className="max-w-[1200px] m-auto flex flex-col gap-5 mb-[50px]"> <div className="container m-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory /> <ListCategory />
</div> </div>
......
...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar"; ...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar";
export default function page() { export default function page() {
return ( return (
<div className="bg-[#f6f6f6]"> <div className="bg-[#f6f6f6]">
<div className="max-w-[1200px] m-auto flex flex-col gap-5 mb-[50px]"> <div className="container m-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory /> <ListCategory />
</div> </div>
......
...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar"; ...@@ -6,7 +6,7 @@ import EventCalendar from "@/components/base/event-calendar";
export default function page() { export default function page() {
return ( return (
<div className="bg-[#f6f6f6]"> <div className="bg-[#f6f6f6]">
<div className="max-w-[1200px] m-auto flex flex-col gap-5 mb-[50px]"> <div className="container m-auto flex flex-col gap-5 mb-[50px]">
<div className="border-[#e5e7f2] border-[1px]"> <div className="border-[#e5e7f2] border-[1px]">
<ListCategory /> <ListCategory />
</div> </div>
......
import { FC, JSX } from 'react'; import { FC, JSX } from "react";
import htmlParse, { DOMNode, Element, Text } from 'html-react-parser'; import htmlParse, { DOMNode, Element, Text } from "html-react-parser";
import { AppEditorContentProps } from './AppEditorContent.type'; import { AppEditorContentProps } from "./AppEditorContent.type";
import './AppEditorContent.css'; import "./AppEditorContent.css";
const AppEditorContent: FC<AppEditorContentProps> = ({ value = '', className = '' }) => { const AppEditorContent: FC<AppEditorContentProps> = ({ value = '', className = '' }) => {
const transform = (node: DOMNode): JSX.Element | string | undefined | null => { const transform = (node: DOMNode): JSX.Element | string | undefined | null => {
...@@ -49,7 +49,9 @@ const AppEditorContent: FC<AppEditorContentProps> = ({ value = '', className = ' ...@@ -49,7 +49,9 @@ const AppEditorContent: FC<AppEditorContentProps> = ({ value = '', className = '
return ( return (
<div className="jodit-container app-editor-container"> <div className="jodit-container app-editor-container">
<div className={`jodit-wysiwyg ${className}`}>{htmlParse(value, { replace: transform })}</div> <div className={`jodit-wysiwyg ${className}`}>
{htmlParse(value, { replace: transform })}
</div>
</div> </div>
); );
}; };
......
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