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 { 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 =
MOCK_PARTNERS_RESPONSE.responseData.rows as unknown as Organization[];
const PARTNERS_IMAGE = "/home/doi-tac/meu-partner.jpg";
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 (
<aside className="flex w-full flex-col xl:w-[43%]">
<div className="mb-5 flex items-start justify-between gap-3">
<aside className="flex w-full flex-col xl:contents">
<div className="mb-5 flex items-start justify-between gap-3 xl:col-start-2 xl:row-start-1 xl:mb-0">
<div>
<h2 className="client-section-title uppercase text-[#24469c]">
Đối tác
......@@ -56,58 +14,16 @@ export function Partners() {
</div>
</div>
{partners.length > 0 ? (
<Swiper
modules={[Autoplay]}
autoplay={{ delay: 4200, disableOnInteraction: false }}
observer
observeParents
updateOnWindowResize
slidesPerView="auto"
spaceBetween={16}
className="w-full"
>
{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]">
<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">
<Image
src={resolvePartnerImage(partner.avatar, index)}
alt={partner.name ?? ""}
width={140}
height={72}
className="max-h-full w-full object-contain"
src={PARTNERS_IMAGE}
alt="Đối tác"
fill
priority
sizes="(min-width: 1280px) 43vw, 100vw"
className="object-contain object-left"
/>
</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>
);
}
......@@ -45,8 +45,8 @@ const fetchVideos = async (): Promise<VideoItem[]> => {
export function VideosSkeleton() {
return (
<div className="flex-1">
<div className="mb-5 flex items-center justify-between gap-3">
<div className="flex-1 xl:contents">
<div className="mb-5 flex items-center justify-between gap-3 xl:col-start-1 xl:row-start-1 xl:mb-0">
<div>
<h2 className="client-section-title uppercase text-[#24469c]">
Video
......@@ -62,7 +62,7 @@ export function VideosSkeleton() {
</Link>
</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) => (
<div
key={`video-skeleton-${index}`}
......@@ -78,8 +78,8 @@ export async function Videos() {
const videos = await fetchVideos();
return (
<div className="flex-1">
<div className="mb-5 flex items-center justify-between gap-3">
<div className="flex-1 xl:contents">
<div className="mb-5 flex items-center justify-between gap-3 xl:col-start-1 xl:row-start-1 xl:mb-0">
<div>
<h2 className="client-section-title uppercase text-[#24469c]">
Video
......@@ -95,7 +95,7 @@ export async function Videos() {
</Link>
</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.map((video) => (
<a
......
......@@ -62,7 +62,7 @@ export default function HomePage() {
<MemberConnection />
</Suspense>
</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 />}>
<Videos />
</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