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

add: partner

parent 6596db21
"use client";
import { getOrganizations } from "@/api/vcci-hcm/endpoints/organizations";
import type { Organization } from "@/api/vcci-hcm/models";
import partnerImages from "@/constants/partnerImages";
import { MOCK_PARTNERS_RESPONSE } from "@/mockdata/bff-fallback";
import Image from "next/image"; import Image from "next/image";
import { useQuery } from "@tanstack/react-query";
import { Autoplay } from "swiper/modules";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";
const VCCI_HCM_SITE_URL = "https://vccihcm.vn";
const resolvePartnerImage = (avatar: string | null | undefined, index: number) => {
if (avatar?.startsWith("http://") || avatar?.startsWith("https://")) {
return avatar;
}
if (avatar?.startsWith("/")) {
return `${VCCI_HCM_SITE_URL}${avatar}`;
}
return partnerImages[index % partnerImages.length] ?? "/img-error.png";
};
const MOCK_PARTNER_ROWS = const PARTNERS_IMAGE = "/home/doi-tac/meu-partner.jpg";
MOCK_PARTNERS_RESPONSE.responseData.rows as unknown as Organization[];
export function Partners() { export function Partners() {
const { data: partnersResponse } = useQuery<Organization[] | undefined>({
queryKey: ["home-partners", "type-sponsor"] as const,
queryFn: async () => {
const response = await getOrganizations({
filters: "type==SPONSOR",
pageSize: "12",
sortField: "sort_order",
sortOrder: "ASC",
});
const rows = ((response as any)?.responseData?.rows ?? []) as Organization[];
return rows.length > 0 ? rows : MOCK_PARTNER_ROWS;
},
staleTime: 60 * 1000,
});
const partners = (partnersResponse ?? MOCK_PARTNER_ROWS).slice(0, 12);
return ( return (
<aside className="flex w-full flex-col xl:w-[43%]"> <aside className="flex w-full flex-col xl:contents">
<div className="mb-5 flex items-start justify-between gap-3"> <div className="mb-5 flex items-start justify-between gap-3 xl:col-start-2 xl:row-start-1 xl:mb-0">
<div> <div>
<h2 className="client-section-title uppercase text-[#24469c]"> <h2 className="client-section-title uppercase text-[#24469c]">
Đối tác Đối tác
...@@ -56,58 +14,16 @@ export function Partners() { ...@@ -56,58 +14,16 @@ export function Partners() {
</div> </div>
</div> </div>
{partners.length > 0 ? ( <div className="relative aspect-[16/9] w-full overflow-hidden rounded-[16px] border border-[#edf1f7] bg-white shadow-[0_8px_20px_rgba(31,59,124,0.05)] xl:col-start-2 xl:row-start-2 xl:h-full xl:w-auto xl:justify-self-start">
<Swiper <Image
modules={[Autoplay]} src={PARTNERS_IMAGE}
autoplay={{ delay: 4200, disableOnInteraction: false }} alt="Đối tác"
observer fill
observeParents priority
updateOnWindowResize sizes="(min-width: 1280px) 43vw, 100vw"
slidesPerView="auto" className="object-contain object-left"
spaceBetween={16} />
className="w-full" </div>
>
{partners.map((partner, index) => (
<SwiperSlide
key={partner.id}
className="!h-auto !w-full sm:!w-[calc(50%-8px)] xl:!w-[calc(33.333%-10.67px)]"
>
{partner.website ? (
<a
href={partner.website}
target="_blank"
rel="noreferrer"
className="block"
>
<div className="flex h-[96px] items-center justify-center rounded-[16px] border border-[#edf1f7] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(31,59,124,0.05)] transition-all hover:-translate-y-0.5 hover:shadow-[0_14px_24px_rgba(31,59,124,0.1)] xl:h-[151px]">
<Image
src={resolvePartnerImage(partner.avatar, index)}
alt={partner.name ?? ""}
width={140}
height={72}
className="max-h-full w-full object-contain"
/>
</div>
</a>
) : (
<div className="flex h-[96px] items-center justify-center rounded-[16px] border border-[#edf1f7] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(31,59,124,0.05)] xl:h-[151px]">
<Image
src={resolvePartnerImage(partner.avatar, index)}
alt={partner.name ?? ""}
width={140}
height={72}
className="max-h-full w-full object-contain"
/>
</div>
)}
</SwiperSlide>
))}
</Swiper>
) : (
<div className="rounded-2xl border border-[#edf1f7] bg-white px-5 py-10 text-center text-sm text-gray-500">
Chưa có thông tin.
</div>
)}
</aside> </aside>
); );
} }
\ No newline at end of file
...@@ -45,8 +45,8 @@ const fetchVideos = async (): Promise<VideoItem[]> => { ...@@ -45,8 +45,8 @@ const fetchVideos = async (): Promise<VideoItem[]> => {
export function VideosSkeleton() { export function VideosSkeleton() {
return ( return (
<div className="flex-1"> <div className="flex-1 xl:contents">
<div className="mb-5 flex items-center justify-between gap-3"> <div className="mb-5 flex items-center justify-between gap-3 xl:col-start-1 xl:row-start-1 xl:mb-0">
<div> <div>
<h2 className="client-section-title uppercase text-[#24469c]"> <h2 className="client-section-title uppercase text-[#24469c]">
Video Video
...@@ -62,7 +62,7 @@ export function VideosSkeleton() { ...@@ -62,7 +62,7 @@ export function VideosSkeleton() {
</Link> </Link>
</div> </div>
<div className="grid gap-4 md:grid-cols-2"> <div className="grid gap-4 md:grid-cols-2 xl:col-start-1 xl:row-start-2">
{Array.from({ length: 2 }, (_, index) => ( {Array.from({ length: 2 }, (_, index) => (
<div <div
key={`video-skeleton-${index}`} key={`video-skeleton-${index}`}
...@@ -78,8 +78,8 @@ export async function Videos() { ...@@ -78,8 +78,8 @@ export async function Videos() {
const videos = await fetchVideos(); const videos = await fetchVideos();
return ( return (
<div className="flex-1"> <div className="flex-1 xl:contents">
<div className="mb-5 flex items-center justify-between gap-3"> <div className="mb-5 flex items-center justify-between gap-3 xl:col-start-1 xl:row-start-1 xl:mb-0">
<div> <div>
<h2 className="client-section-title uppercase text-[#24469c]"> <h2 className="client-section-title uppercase text-[#24469c]">
Video Video
...@@ -95,7 +95,7 @@ export async function Videos() { ...@@ -95,7 +95,7 @@ export async function Videos() {
</Link> </Link>
</div> </div>
<div className="grid gap-4 md:grid-cols-2"> <div className="grid gap-4 md:grid-cols-2 xl:col-start-1 xl:row-start-2">
{videos.length ? ( {videos.length ? (
videos.map((video) => ( videos.map((video) => (
<a <a
......
...@@ -62,7 +62,7 @@ export default function HomePage() { ...@@ -62,7 +62,7 @@ export default function HomePage() {
<MemberConnection /> <MemberConnection />
</Suspense> </Suspense>
</section> </section>
<section className="flex flex-col gap-6 pb-10 xl:flex-row xl:items-stretch"> <section className="flex flex-col gap-6 pb-10 xl:grid xl:grid-cols-[minmax(0,1fr)_43%] xl:grid-rows-[auto_1fr] xl:gap-x-6 xl:gap-y-5">
<Suspense fallback={<VideosSkeleton />}> <Suspense fallback={<VideosSkeleton />}>
<Videos /> <Videos />
</Suspense> </Suspense>
......
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