ifixkart-storefront/sections/BrandsSection.tsx

141 lines
4.5 KiB
TypeScript

"use client";
import React, { useState, useEffect } from 'react';
import Link from 'next/link';
import { catalogService, BrandResponse } from '../services/api/catalogService';
import { getImageUrl } from '../lib/utils';
import { BrandTileSkeleton } from '../components/ui/Skeleton';
import { getSectionTitle } from '../lib/homepageDefaults';
interface BrandItem {
id: string;
name: string;
slug: string;
logo?: string;
fontClass?: string;
}
/** Real brands from catalog / CMS only — no fake filler brands */
const FALLBACK_FONT = 'font-bold tracking-wide text-[15px]';
interface BrandsSectionProps {
config?: any;
initialBrands?: BrandResponse[];
}
function toBrandItem(b: any, idx: number): BrandItem {
return {
id: String(b.brand_id || b.id || b.slug || idx),
name: b.name || 'Brand',
slug: b.slug || String(b.brand_id || b.id || idx),
logo: getImageUrl(b.logo_url || b.logo || b.image) || undefined,
fontClass: FALLBACK_FONT,
};
}
export const BrandsSection: React.FC<BrandsSectionProps> = ({
config,
initialBrands,
}) => {
const [brands, setBrands] = useState<BrandItem[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const rawConfig =
config?.metadata_json?.brands || config?.metadata?.brands;
const applyList = (list: any[]) => {
if (list && list.length > 0) {
setBrands(list.slice(0, 10).map(toBrandItem));
} else {
setBrands([]);
}
setLoading(false);
};
if (rawConfig && Array.isArray(rawConfig) && rawConfig.length > 0) {
applyList(rawConfig);
return;
}
if (initialBrands && initialBrands.length > 0) {
applyList(initialBrands);
return;
}
catalogService
.getBrands()
.then((res) => applyList(res || []))
.catch(() => applyList([]));
}, [config, initialBrands]);
const title = getSectionTitle(config, 'official_brands', 'Official Tech Brands');
if (!loading && brands.length === 0) {
return (
<section className="py-8 bg-white font-sans">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-[1400px]">
<div className="flex items-center justify-between gap-4 pb-3.5 mb-6 border-b border-[#e5e5e5]">
<h2 className="text-[18px] md:text-[20px] font-bold text-[#222] tracking-tight">
{title}
</h2>
</div>
<div className="border border-[#e5e5e5] rounded-lg p-10 text-center text-[13px] text-[#777]">
Brand partners will appear here once logos are configured.
</div>
</div>
</section>
);
}
return (
<section className="py-8 bg-white font-sans">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-[1400px]">
{/* Header + full-width divider */}
<div className="pb-3.5 border-b border-[#e5e5e5] mb-5">
<h2 className="text-[18px] md:text-[20px] font-bold text-[#333] tracking-tight text-left">
{title}
</h2>
</div>
{loading ? (
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-3 md:gap-4">
{Array.from({ length: 10 }).map((_, i) => (
<BrandTileSkeleton key={i} />
))}
</div>
) : (
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-3 md:gap-4">
{brands.map((brand) => (
<Link
key={brand.id}
href={`/shop?brand=${encodeURIComponent(brand.slug)}`}
className="group flex items-center justify-center h-[72px] md:h-[80px] px-4 rounded-lg bg-[#F3F3F3] hover:bg-[#ebebeb] transition-colors"
>
{brand.logo ? (
<img
src={brand.logo}
alt={brand.name}
className="max-h-[36px] md:max-h-[40px] max-w-[70%] object-contain opacity-70 group-hover:opacity-100 transition-opacity"
style={{
filter: 'grayscale(1) contrast(0.85) brightness(0.55)',
}}
/>
) : (
<span
className={`select-none text-[#555] group-hover:text-[#222] transition-colors ${
brand.fontClass || 'font-bold text-[15px]'
}`}
>
{brand.name}
</span>
)}
</Link>
))}
</div>
)}
</div>
</section>
);
};