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

fix(layout-all-page): fix layout all page

parent eabc5f4d
...@@ -134,6 +134,9 @@ importers: ...@@ -134,6 +134,9 @@ importers:
react: react:
specifier: 19.2.0 specifier: 19.2.0
version: 19.2.0 version: 19.2.0
react-country-flag:
specifier: ^3.1.0
version: 3.1.0(react@19.2.0)
react-day-picker: react-day-picker:
specifier: ^9.11.1 specifier: ^9.11.1
version: 9.11.1(react@19.2.0) version: 9.11.1(react@19.2.0)
...@@ -3270,6 +3273,12 @@ packages: ...@@ -3270,6 +3273,12 @@ packages:
queue-microtask@1.2.3: queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
react-country-flag@3.1.0:
resolution: {integrity: sha512-JWQFw1efdv9sTC+TGQvTKXQg1NKbDU2mBiAiRWcKM9F1sK+/zjhP2yGmm8YDddWyZdXVkR8Md47rPMJmo4YO5g==}
engines: {node: '>=12'}
peerDependencies:
react: '>=16'
react-day-picker@9.11.1: react-day-picker@9.11.1:
resolution: {integrity: sha512-l3ub6o8NlchqIjPKrRFUCkTUEq6KwemQlfv3XZzzwpUeGwmDJ+0u0Upmt38hJyd7D/vn2dQoOoLV/qAp0o3uUw==} resolution: {integrity: sha512-l3ub6o8NlchqIjPKrRFUCkTUEq6KwemQlfv3XZzzwpUeGwmDJ+0u0Upmt38hJyd7D/vn2dQoOoLV/qAp0o3uUw==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -7246,6 +7255,10 @@ snapshots: ...@@ -7246,6 +7255,10 @@ snapshots:
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}
react-country-flag@3.1.0(react@19.2.0):
dependencies:
react: 19.2.0
react-day-picker@9.11.1(react@19.2.0): react-day-picker@9.11.1(react@19.2.0):
dependencies: dependencies:
'@date-fns/tz': 1.4.1 '@date-fns/tz': 1.4.1
......
...@@ -2,7 +2,7 @@ const MenuItem = ({ title, items, link }: { title: string; items: string[]; link ...@@ -2,7 +2,7 @@ const MenuItem = ({ title, items, link }: { title: string; items: string[]; link
<div className="group relative"> <div className="group relative">
<a <a
className="px-3 py-5 text-[16px] font-[600] text-[#124588] hover:text-[#E8C518] transition block" className="px-3 py-5 text-[16px] font-[600] text-[#124588] hover:text-[#E8C518] transition block"
href={`${link}`} href={`/${link}`}
> >
{title} {title}
</a> </a>
......
...@@ -11,7 +11,7 @@ function Header() { ...@@ -11,7 +11,7 @@ function Header() {
return ( 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-[56px] hidden lg:flex items-center justify-center bg-[#063e8e]">
<div className="max-w-[1215px] w-full px-4 flex items-center justify-between"> <div className="container w-full px-4 flex items-center justify-between">
<div className="flex items-center gap-3"> <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]"> <div className="w-[130px] h-[36px] bg-[#e8c518] flex items-center justify-center border-4 rounded-sm border-[#647792]">
<a <a
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "../../components/list-category";
import { OWNER_REPRESENTATIVES_CATEGORIES } from "@constants/categories";
import ListFilter from "../../components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={OWNER_REPRESENTATIVES_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -8,6 +8,7 @@ import { Pagination } from "@components/base/pagination"; ...@@ -8,6 +8,7 @@ import { Pagination } from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -28,7 +29,7 @@ export default function Page() { ...@@ -28,7 +29,7 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/chu-de/${news.id}`}/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
...@@ -3,11 +3,11 @@ import { NewsItem } from '@app/dai-dien-gioi-chu/lib/types/NewsPage.type'; ...@@ -3,11 +3,11 @@ import { NewsItem } from '@app/dai-dien-gioi-chu/lib/types/NewsPage.type';
import Links from '@links/index' import Links from '@links/index'
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import parse from 'html-react-parser' import parse from 'html-react-parser'
function NewsContent({ news }: { news: NewsItem }) { function NewsContent({ news ,link}: { news: NewsItem ,link:string}) {
return ( return (
<a <a
href={`/tin-tuc/${news.id}`} href={`${link}`}
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" 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 <img
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "../../components/list-category";
import { OWNER_REPRESENTATIVES_CATEGORIES } from "@constants/categories";
import ListFilter from "../../components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={OWNER_REPRESENTATIVES_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -8,6 +8,7 @@ import { Pagination } from "@components/base/pagination"; ...@@ -8,6 +8,7 @@ import { Pagination } from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -21,14 +22,14 @@ export default function Page() { ...@@ -21,14 +22,14 @@ export default function Page() {
return ( return (
<div className="min-h-screen container mx-auto p-4"> <div className="min-h-screen container mx-auto p-4">
<div className="w-full flex flex-col gap-5"> <div className="w-full flex flex-col gap-5">
<ListCategory categories={OWNER_REPRESENTATIVES_CATEGORIES} /> <ListCategory categories={OWNER_REPRESENTATIVES_CATEGORIES} />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */} {/* Main content */}
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/tap-huan-nsdld/${news.id}`} />
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "../../components/list-category";
import { OWNER_REPRESENTATIVES_CATEGORIES } from "@constants/categories";
import ListFilter from "../../components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={OWNER_REPRESENTATIVES_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -8,10 +8,10 @@ import { Pagination} from "@components/base/pagination"; ...@@ -8,10 +8,10 @@ import { Pagination} from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const pageSize = 5; const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({ const { data: allData } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize), pageSize: String(pageSize),
...@@ -28,7 +28,7 @@ export default function Page() { ...@@ -28,7 +28,7 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent key={news.id} news={news} link={`${PATHS.ownerRepresentatives}/tin-lien-quan/${news.id}`} />
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
"use client"; "use client";
import React from "react"; import React from "react";
import ReactCountryFlag from "react-country-flag";
type Region = { id: string; name: string; image?: string }; type Region = { id: string; name: string; image?: string };
export const DEFAULT_REGIONS: Region[] = [ export const DEFAULT_REGIONS: Region[] = [
...@@ -40,17 +40,258 @@ export default function MapRegion({ ...@@ -40,17 +40,258 @@ export default function MapRegion({
<div className="bg-white shadow-sm rounded-md overflow-hidden p-6"> <div className="bg-white shadow-sm rounded-md overflow-hidden p-6">
<div className="flex flex-col gap-6"> <div className="flex flex-col gap-6">
<div> <div>
<h3 className="text-2xl font-semibold text-primary mb-0">{activeRegion?.name ?? ""}</h3> <h3 className="text-2xl font-semibold text-primary mb-0">
{activeRegion?.name ?? ""}
</h3>
</div> </div>
<div className="w-full flex items-center justify-center"> <div className="w-full flex items-center justify-center">
<div className="w-full max-w-3xl"> <div className="w-full max-w-3xl">
<div className="bg-gray-50 p-4 flex items-center justify-center"> <div className="bg-gray-50 p-4 flex items-center justify-center">
<img <div className="relative">
src={displayedImage} <img
alt={activeRegion?.name ?? "Map"} src={displayedImage}
className="w-full h-auto object-contain block mx-auto" alt={activeRegion?.name ?? "Map"}
style={{ maxHeight: 520 }} className="w-full h-auto object-contain block mx-auto"
/> style={{ maxHeight: 520 }}
/>
{/* Country Flags*/}
{active == "dong-nam-a" && (
<>
<div className="absolute top-[17%] left-[29%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="MM"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[23%] left-[40%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="LA"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[20%] left-[43%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="VN"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[38%] left-[43%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="KH"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[27%] left-[68%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="PH"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[55%] left-[40%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="MY"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[55%] left-[57%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="BN"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[62%] left-[47%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="SG"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[65%] left-[57%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="ID"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[32%] left-[36%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="TH"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
</>
)}
{active == "dong-bac-a" && (
<>
<div className="absolute top-[40%] left-[60%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="CN"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[37%] left-[77%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="KR"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[34%] left-[87%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="JP"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[60%] left-[73%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="TW"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
</>
)}
{active == "nam-a" && (
<>
<div className="absolute top-[40%] left-[60%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="IN"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
</>
)}
{active == "bac-my" && (
<>
<div className="absolute top-[60%] left-[40%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="US"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
<div className="absolute top-[40%] left-[40%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="CA"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
</>
)}
{active == "chau-uc" && (
<>
<div className="absolute top-[30%] left-[40%] w-4 h-4 md:w-6 md:h-6 rounded-full">
<ReactCountryFlag
countryCode="AU"
svg
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
className="rounded-full"
/>
</div>
</>
)}
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -11,7 +11,7 @@ export default function Page() { ...@@ -11,7 +11,7 @@ export default function Page() {
return ( return (
<div className="min-h-screen container mx-auto p-4"> <div className="min-h-screen container mx-auto p-4">
<div className="w-full flex flex-col gap-5"> <div className="w-full flex flex-col gap-5">
<ListCategory categories={TRADE_PROMOTION_CATEGORIES} /> <ListCategory categories={TRADE_PROMOTION_CATEGORIES} />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */} {/* Main content */}
......
// Core
"use client";
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 parse from "html-react-parser";
import { useParams } from 'next/navigation'
import { GetNewsDetailResponseType } from '@lib/types/news-detail-response-data';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={EVENT_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -8,6 +8,7 @@ import { Pagination} from "@components/base/pagination"; ...@@ -8,6 +8,7 @@ import { Pagination} from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -28,7 +29,7 @@ export default function Page() { ...@@ -28,7 +29,7 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent key={news.id} news={news} link={`${PATHS.event}/dao-tao/${news.id}`}/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
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 parse from "html-react-parser";
import { useParams } from 'next/navigation'
import { GetNewsDetailResponseType } from '@lib/types/news-detail-response-data';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={EVENT_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -9,7 +9,7 @@ import { Pagination} from "@components/base/pagination"; ...@@ -9,7 +9,7 @@ import { Pagination} from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -30,7 +30,7 @@ export default function Page() { ...@@ -30,7 +30,7 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent key={news.id} news={news} link={`${PATHS.event}/su-kien/${news.id}`}/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
...@@ -27,9 +27,9 @@ export default function Page() { ...@@ -27,9 +27,9 @@ export default function Page() {
{/* Main content */} {/* Main content */}
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {/* {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent key={news.id} news={news} />
))} ))} */}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
<Pagination <Pagination
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { MEDIA_INFORMATION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={MEDIA_INFORMATION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -9,10 +9,10 @@ import { Pagination} from "@components/base/pagination"; ...@@ -9,10 +9,10 @@ import { Pagination} from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const pageSize = 5; const pageSize = 5;
const { data: allData } = useGetNews<GetNewsResponseType>({ const { data: allData } = useGetNews<GetNewsResponseType>({
pageSize: String(pageSize), pageSize: String(pageSize),
...@@ -29,7 +29,11 @@ export default function Page() { ...@@ -29,7 +29,11 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/chuyen-de/${news.id}`}
/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { MEDIA_INFORMATION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={MEDIA_INFORMATION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -9,6 +9,7 @@ import { Pagination} from "@components/base/pagination"; ...@@ -9,6 +9,7 @@ import { Pagination} from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -29,7 +30,11 @@ export default function Page() { ...@@ -29,7 +30,11 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/thong-tin-chinh-sach-va-phap-luat/${news.id}`}
/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { MEDIA_INFORMATION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={MEDIA_INFORMATION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -9,6 +9,7 @@ import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter"; ...@@ -9,6 +9,7 @@ import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -29,7 +30,11 @@ export default function Page() { ...@@ -29,7 +30,11 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={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"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { MEDIA_INFORMATION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={MEDIA_INFORMATION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -9,6 +9,7 @@ import { Pagination} from "@components/base/pagination"; ...@@ -9,6 +9,7 @@ import { Pagination} from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -29,7 +30,11 @@ export default function Page() { ...@@ -29,7 +30,11 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-doanh-nghiep/${news.id}`}
/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { MEDIA_INFORMATION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={MEDIA_INFORMATION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -8,6 +8,7 @@ import { Pagination} from "@components/base/pagination"; ...@@ -8,6 +8,7 @@ import { Pagination} from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -28,7 +29,11 @@ export default function Page() { ...@@ -28,7 +29,11 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-kinh-te/${news.id}`}
/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { MEDIA_INFORMATION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={MEDIA_INFORMATION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -9,6 +9,7 @@ import EventCalendar from "@app/dai-dien-gioi-chu/components/event-calendar"; ...@@ -9,6 +9,7 @@ import EventCalendar from "@app/dai-dien-gioi-chu/components/event-calendar";
import { Pagination} from "@components/base/pagination"; import { Pagination} from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { PATHS } from "@constants/paths";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
...@@ -30,7 +31,11 @@ export default function Page() { ...@@ -30,7 +31,11 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent
key={news.id}
news={news}
link={`${PATHS.mediaInformation}/tin-vcci/${news.id}`}
/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { TRADE_PROMOTION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={TRADE_PROMOTION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { TRADE_PROMOTION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={TRADE_PROMOTION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -8,6 +8,7 @@ import { Pagination } from "@components/base/pagination"; ...@@ -8,6 +8,7 @@ import { Pagination } from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -28,7 +29,7 @@ export default function Page() { ...@@ -28,7 +29,7 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent key={news.id} news={news} link={`${PATHS.tradePromotion}/${news.id}`} />
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { TRADE_PROMOTION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={TRADE_PROMOTION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -7,6 +7,7 @@ import { Pagination } from "@components/base/pagination"; ...@@ -7,6 +7,7 @@ import { Pagination } from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -20,14 +21,18 @@ export default function Page() { ...@@ -20,14 +21,18 @@ export default function Page() {
return ( return (
<div className="min-h-screen container mx-auto p-4"> <div className="min-h-screen container mx-auto p-4">
<div className="w-full flex flex-col gap-5"> <div className="w-full flex flex-col gap-5">
<ListCategory categories={TRADE_PROMOTION_CATEGORIES} /> <ListCategory categories={TRADE_PROMOTION_CATEGORIES} />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */} {/* Main content */}
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent
key={news.id}
news={news}
link={`${PATHS.tradePromotion}/${news.id}`}
/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
// Core
"use client";
import Image from "next/image";
import ListCategory from "@app/dai-dien-gioi-chu/components/list-category";
import { TRADE_PROMOTION_CATEGORIES } from "@constants/categories";
import ListFilter from "@app/dai-dien-gioi-chu/components/list-filter";
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';
// ...existing code...
const Page: React.FC = () => {
const { id } = useParams()
const { data, isLoading } = useGetNewsId<GetNewsDetailResponseType>(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">
<ListCategory categories={TRADE_PROMOTION_CATEGORIES} />
<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="p-7.5 prose tiptap overflow-hidden">{parse(data?.responseData?.description ?? '')}</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<ListFilter />
<div className="bg-white border rounded-md overflow-hidden">
<div className="w-full h-56 relative bg-gray-100">
<Image
src="/banner.webp"
alt="Quảng cáo"
fill
className="object-cover"
/>
</div>
</div>
</aside>
</div>
</div>
</div>
);
};
export default Page;
...@@ -8,6 +8,7 @@ import Image from "next/image"; ...@@ -8,6 +8,7 @@ import Image from "next/image";
import EventCalendar from "@app/dai-dien-gioi-chu/components/event-calendar"; import EventCalendar from "@app/dai-dien-gioi-chu/components/event-calendar";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -21,14 +22,18 @@ export default function Page() { ...@@ -21,14 +22,18 @@ export default function Page() {
return ( return (
<div className="min-h-screen container mx-auto p-4"> <div className="min-h-screen container mx-auto p-4">
<div className="w-full flex flex-col gap-5"> <div className="w-full flex flex-col gap-5">
<ListCategory categories={TRADE_PROMOTION_CATEGORIES} /> <ListCategory categories={TRADE_PROMOTION_CATEGORIES} />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */} {/* Main content */}
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent
key={news.id}
news={news}
link={`${PATHS.tradePromotion}/${news.id}`}
/>
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
...@@ -7,6 +7,7 @@ import { Pagination } from "@components/base/pagination"; ...@@ -7,6 +7,7 @@ import { Pagination } from "@components/base/pagination";
import Image from "next/image"; import Image from "next/image";
import { useGetNews } from "@api/endpoints/news"; import { useGetNews } from "@api/endpoints/news";
import { GetNewsResponseType } from "@api/types/NewsPage.type"; import { GetNewsResponseType } from "@api/types/NewsPage.type";
import { PATHS } from "@constants/paths";
export default function Page() { export default function Page() {
const [submitSearch] = useState(""); const [submitSearch] = useState("");
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
...@@ -27,7 +28,7 @@ export default function Page() { ...@@ -27,7 +28,7 @@ export default function Page() {
<main className="lg:col-span-2 bg-background "> <main className="lg:col-span-2 bg-background ">
<div className="pb-5 overflow-hidden"> <div className="pb-5 overflow-hidden">
{allData?.responseData.rows.map((news) => ( {allData?.responseData.rows.map((news) => (
<NewsContent key={news.id} news={news} /> <NewsContent key={news.id} news={news} link={`${PATHS.tradePromotion}/${news.id}`} />
))} ))}
<div className="w-full flex justify-center mt-4"> <div className="w-full flex justify-center mt-4">
......
import { NewsItem } from '@app/dai-dien-gioi-chu/lib/types/NewsPage.type';
import Links from '@links/index'
import dayjs from 'dayjs';
import parse from 'html-react-parser'
function NewsContent({ news ,link}: { news: NewsItem ,link:string}) {
return (
<a
href={`${link}`}
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}
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"
}}
/>
<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 hover:no-underline">
{news.title}
</p>
<div className="text-sm my-2 text-[#00AED5]">{dayjs(news.release_at).format('DD/MM/YYYY')}</div>
<div className="text-sm text-[#777] line-clamp-3">
<div className="text-sm prose tiptap">{parse(news.description)}</div>
</div>
</div>
</a>
)
}
export default NewsContent;
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { ArrowRight, ArrowLeft } from "lucide-react"; import { ArrowRight, ArrowLeft } from "lucide-react";
export default function EventCalendar() { export default function EventCalendar() {
const mockCalendar = { const mockCalendar = {
month: 10, month: 10,
year: 2025, year: 2025,
highlighted: [6, 9, 12], highlighted: [6, 9, 12],
......
...@@ -81,6 +81,7 @@ export const EventFilter: React.FC<{ onFilter?: (payload: FilterPayload) => void ...@@ -81,6 +81,7 @@ export const EventFilter: React.FC<{ onFilter?: (payload: FilterPayload) => void
placeholder="Tên sự kiện ..." placeholder="Tên sự kiện ..."
value={query} value={query}
onChange={(e) => setQuery(e.target.value)} onChange={(e) => setQuery(e.target.value)}
className='text-black placeholder:text-gray-400 rounded-none py-2.5 px-2'
/> />
</div> </div>
...@@ -104,8 +105,8 @@ export const EventFilter: React.FC<{ onFilter?: (payload: FilterPayload) => void ...@@ -104,8 +105,8 @@ export const EventFilter: React.FC<{ onFilter?: (payload: FilterPayload) => void
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Button onClick={handleFilter} className="flex-1">Lọc sự kiện</Button> <Button onClick={handleFilter} className="flex-1 rounded-none font-medium text-lg text-white hover:bg-muted-foreground hover:outline-1 outline-primary hover:text-primary">Lọc sự kiện</Button>
<Button variant="outline" onClick={handleReset} className="flex-1">Bỏ lọc</Button> <Button onClick={handleReset} className="flex-1 rounded-none font-medium text-lg text-white hover:bg-muted-foreground hover:outline-1 outline-primary hover:text-primary">Bỏ lọc</Button>
</div> </div>
</aside> </aside>
) )
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import React from "react" import React from "react"
import { MenuItem } from '../menu-category' import { MenuItem } from '../menu-category'
// Local Menu shape compatible with MenuItem // Local Menu shape compatible with MenuItem
type Menu = { type Menu = {
id: string | number id: string | number
...@@ -16,19 +15,9 @@ type Category = { ...@@ -16,19 +15,9 @@ type Category = {
href: string href: string
} }
const CATEGORIES: Category[] = [ // Default categories removed — component now accepts `categories` via props.
{ title: "Về VCCI-HCM", href: "/dai-dien-gioi-chu" },
{ title: "Chức năng và Nhiệm vụ", href: "/gioi-thieu/chuc-nang" },
{ title: "Sơ đồ Tổ chức", href: "/gioi-thieu/so-do" },
{ title: "Dịch vụ cung cấp", href: "/gioi-thieu/dich-vu" },
{ title: "Dịch vụ cung cấp", href: "/gioi-thieu/dich-vu" },
{ title: "Dịch vụ cung cấp", href: "/gioi-thieu/dich-vu" },
{ title: "Dịch vụ cung cấp", href: "/gioi-thieu/dich-vu" },
{ title: "Dịch vụ cung cấp", href: "/gioi-thieu/dich-vu" },
]
const ListCategory: React.FC = () => { const ListCategory: React.FC<{ categories?: Category[] }> = ({ categories = [] }) => {
const pathname = usePathname() || "" const pathname = usePathname() || ""
const isActive = (href: string) => { const isActive = (href: string) => {
...@@ -40,19 +29,19 @@ const ListCategory: React.FC = () => { ...@@ -40,19 +29,19 @@ const ListCategory: React.FC = () => {
return ( return (
<div className="border-t border-gray-200 bg-white p-2.5"> <div className="border-t border-gray-200 bg-white p-2.5">
<div className="w-full px-4 sm:px-6 lg:px-8"> <div className="w-full px-4 sm:px-6 lg:px-8">
<nav aria-label="Danh mục" className="py-3"> <div className="py-3">
<ul className="flex flex-wrap gap-4 sm:gap-8 items-center max-w-full overflow-x-auto"> <div className="flex flex-wrap items-center max-w-full overflow-x-auto">
{CATEGORIES.map((c) => { {categories.map((c) => {
const menu: Menu = { id: c.href, name: c.title, link: c.href } const menu: Menu = { id: c.href, name: c.title, link: c.href }
const active = isActive(c.href) const active = isActive(c.href)
return ( return (
<li key={c.href} className="shrink-0"> <div key={c.href} className="shrink-0">
<MenuItem menu={menu} active={active} /> <MenuItem menu={menu} active={active} />
</li> </div>
) )
})} })}
</ul> </div>
</nav> </div>
</div> </div>
</div> </div>
) )
......
"use client" "use client"
import React, { useState } from 'react' import React, { useState, useEffect } from 'react'
import { Checkbox } from '@/components/ui/checkbox' import { Checkbox } from '@/components/ui/checkbox'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
type Category = { id: string; title: string; count: number } type Category = { id: string; title: string; count: number }
const DEFAULT_CATEGORIES: Category[] = [
{ id: 'ceo', title: 'CEO', count: 4 },
{ id: 'policy', title: 'Hỏi đáp về chính sách', count: 0 },
{ id: 'biz', title: 'Tin Doanh Nghiệp', count: 9 },
{ id: 'member', title: 'Tin Hội Viên', count: 17 },
{ id: 'law', title: 'Văn bản Pháp luật sắp có hiệu lực', count: 30 }
]
export const ListFilter: React.FC<{ export const ListFilter: React.FC<{
categories?: Category[] categories?: Category[]
onSearch?: (q: string) => void onSearch?: (q: string) => void
onReset?: () => void onReset?: () => void
}> = ({ categories = DEFAULT_CATEGORIES, onSearch, onReset }) => { }> = ({ categories, onSearch, onReset }) => {
const [query, setQuery] = useState('') const [query, setQuery] = useState('')
const [visibleCount, setVisibleCount] = useState(5)
const [selected, setSelected] = useState<Record<string, boolean>>(() => { const [selected, setSelected] = useState<Record<string, boolean>>(() => {
const map: Record<string, boolean> = {} const map: Record<string, boolean> = {}
categories.forEach((c) => (map[c.id] = false)) if (categories && categories.length) {
categories.forEach((c: Category) => (map[c.id] = false))
}
return map return map
}) })
// Keep selected map in sync when categories prop changes.
// Defer setSelected to avoid calling setState synchronously inside the effect.
useEffect(() => {
const timer = setTimeout(() => {
setSelected((prev) => {
const map: Record<string, boolean> = {}
if (categories && categories.length) {
categories.forEach((c: Category) => (map[c.id] = !!prev[c.id]))
}
return map
})
}, 0)
return () => clearTimeout(timer)
}, [categories])
const toggle = (id: string) => setSelected((s) => ({ ...s, [id]: !s[id] })) const toggle = (id: string) => setSelected((s) => ({ ...s, [id]: !s[id] }))
return ( return (
...@@ -36,7 +46,7 @@ export const ListFilter: React.FC<{ ...@@ -36,7 +46,7 @@ export const ListFilter: React.FC<{
<Input <Input
placeholder="Tên văn bản ..." placeholder="Tên văn bản ..."
value={query} value={query}
className='text-black placeholder:text-gray-400' className='text-black placeholder:text-gray-400 rounded-none py-2.5 px-2'
onChange={(e) => setQuery(e.target.value)} onChange={(e) => setQuery(e.target.value)}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
...@@ -46,16 +56,37 @@ export const ListFilter: React.FC<{ ...@@ -46,16 +56,37 @@ export const ListFilter: React.FC<{
/> />
</div> </div>
<div className="flex flex-col gap-3 mb-6"> <div className="flex flex-col gap-3">
{categories.map((c) => ( {categories && categories.length > 0 ? (
<label key={c.id} className="flex items-center gap-3"> categories.slice(0, visibleCount).map((c) => (
<Checkbox checked={!!selected[c.id]} onCheckedChange={() => toggle(c.id)} /> <label key={c.id} className="flex items-center gap-3">
<div className="flex justify-between w-full items-center"> <Checkbox checked={!!selected[c.id]} onCheckedChange={() => toggle(c.id)} />
<span className="text-sm">{c.title}</span> <div className="flex justify-between w-full items-center">
<span className="text-sm text-gray-400">({c.count})</span> <span className="text-sm">{c.title}</span>
</div> <span className="text-sm text-gray-400">({c.count})</span>
</label> </div>
))} </label>
))
) : null}
<div className="mt-2 flex items-center gap-3">
{(categories?.length ?? 0) > visibleCount && (
<button
className="text-sm text-primary self-start"
onClick={() => setVisibleCount((v) => v + 5)}
>
Xem thêm
</button>
)}
{visibleCount > 5 && (
<button
className="text-sm text-gray-500 self-start"
onClick={() => setVisibleCount(5)}
>
Thu gọn
</button>
)}
</div>
</div> </div>
<div className="flex gap-3"> <div className="flex gap-3">
...@@ -64,14 +95,17 @@ export const ListFilter: React.FC<{ ...@@ -64,14 +95,17 @@ export const ListFilter: React.FC<{
</Button> </Button>
<Button <Button
className="flex-1 rounded-none font-medium text-lg text-white hover:bg-muted-foreground hover:outline-1 outline-primary hover:text-primary" className="flex-1 rounded-none font-medium text-lg text-white hover:bg-muted-foreground hover:outline-1 outline-primary hover:text-primary"
onClick={() => { onClick={() => {
setQuery('') setQuery('')
// restore initial map // restore initial map
const map: Record<string, boolean> = {} const map: Record<string, boolean> = {}
categories.forEach((c) => (map[c.id] = false)) if (categories && categories.length) {
setSelected(map) categories.forEach((c) => (map[c.id] = false))
onReset?.() }
}} setSelected(map)
setVisibleCount(5)
onReset?.()
}}
> >
Bỏ tìm Bỏ tìm
</Button> </Button>
......
'use client' 'use client'
// Local simplified menu type instead of importing HeaderMenu
type Menu = { type Menu = {
id: string | number id: string | number
name: string name: string
......
...@@ -3,7 +3,7 @@ import { PATHS } from "@constants/paths"; ...@@ -3,7 +3,7 @@ import { PATHS } from "@constants/paths";
export const TRADE_PROMOTION_CATEGORIES = [ export const TRADE_PROMOTION_CATEGORIES = [
{ {
title: "Hồ sơ thị trường", title: "Hồ sơ thị trường",
href: `${PATHS.marketProfile}/`, href: `${PATHS.marketProfile}`,
}, },
{ {
title: "Môi trường kinh doanh", title: "Môi trường kinh doanh",
......
...@@ -7,16 +7,6 @@ export const PATHS = { ...@@ -7,16 +7,6 @@ export const PATHS = {
marketProfile: '/ho-so-thi-truong', marketProfile: '/ho-so-thi-truong',
tradePromotion: '/xuc-tien-thuong-mai', tradePromotion: '/xuc-tien-thuong-mai',
mediaInformation:'/thong-tin-truyen-thong', mediaInformation:'/thong-tin-truyen-thong',
recruitmentDetail: '/tuyen-dung/[id]',
newsPage: '/tin-tuc',
newsDetail: '/tin-tuc/[id]',
contact: '/lien-he',
lookup: '/tra-cuu',
training: '/dao-tao',
login: '/dang-nhap',
logout: '/dang-xuat',
students: '/sinh-vien',
studentLife: '/cuoc-song-sinh-vien',
search: '/tim-kiem', search: '/tim-kiem',
originOfGoods: '/xuat-xu-hang-hoa', originOfGoods: '/xuat-xu-hang-hoa',
......
export interface NewsDetailItem {
id: string
title: string
thumbnail: string
external_link: string
description: string
release_at: string
is_active: boolean
created_at: string
created_by: string | null
updated_at: string
updated_by: string | null
mode: 'NOW' | string
category: string
}
export interface NewsDetailResponseData {
count: number
rows: NewsDetailItem[]
totalPages: number
currentPage: number
}
export interface GetNewsDetailResponseType {
message: string
message_en: string
responseData: NewsDetailItem
status: 'success' | 'error'
timeStamp: string
violations: any | null
}
\ 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