ifixkart-storefront/sections/FeaturesSection.tsx

256 lines
7.1 KiB
TypeScript

'use client';
import React from 'react';
import { getSectionTitle } from '@/lib/homepageDefaults';
interface FeatureItem {
id: string;
title: string;
desc: string;
icon: 'shipping' | 'return' | 'support' | 'payment' | 'wrench' | 'clock' | string;
}
interface FeaturesSectionProps {
config?: any;
}
/** TechShop reference strip — matches admin Homepage Layout defaults */
const REFERENCE_FEATURES: FeatureItem[] = [
{
id: 'shipping',
icon: 'shipping',
title: 'Free Shipping',
desc: 'On order over $100',
},
{
id: 'return',
icon: 'return',
title: 'Flexible & Easy Return',
desc: 'Return within 14 days',
},
{
id: 'support',
icon: 'support',
title: '24/7 Support Services',
desc: 'Any Time Customer Support',
},
{
id: 'payment',
icon: 'payment',
title: 'Secure payment',
desc: '100% Fast & Secure Payment',
},
];
const ICON_ALIAS: Record<string, FeatureItem['icon']> = {
Truck: 'shipping',
shipping: 'shipping',
RefreshCcw: 'return',
RefreshCw: 'return',
RotateCcw: 'return',
return: 'return',
Headphones: 'support',
Headset: 'support',
support: 'support',
CreditCard: 'payment',
ShieldCheck: 'payment',
payment: 'payment',
Wrench: 'wrench',
wrench: 'wrench',
Clock: 'clock',
clock: 'clock',
ThumbsUp: 'payment',
};
/** Custom line icons matching TechShop reference artwork */
function FeatureIcon({
type,
className = '',
}: {
type: string;
className?: string;
}) {
const kind = ICON_ALIAS[type] || type;
const common = {
fill: 'none',
stroke: 'currentColor',
strokeWidth: 1.7,
strokeLinecap: 'round' as const,
strokeLinejoin: 'round' as const,
};
if (kind === 'shipping') {
return (
<svg viewBox="0 0 40 32" className={className} aria-hidden>
{/* motion lines */}
<path d="M2 10h6M2 16h5M2 22h6" {...common} />
{/* truck body */}
<path d="M10 20V9.5a1.5 1.5 0 0 1 1.5-1.5H24v12" {...common} />
<path d="M24 12h5.2l3.8 5.2V20H24V12z" {...common} />
<circle cx="15" cy="22.5" r="2.4" {...common} />
<circle cx="29" cy="22.5" r="2.4" {...common} />
<path d="M17.4 22.5h9.2" {...common} />
</svg>
);
}
if (kind === 'return') {
return (
<svg viewBox="0 0 32 32" className={className} aria-hidden>
<path d="M25.5 12.5A9.5 9.5 0 1 0 22 23.2" {...common} />
<path d="M25.5 7.5v5h-5" {...common} />
<circle cx="16" cy="16" r="5.2" {...common} />
<text
x="16"
y="19.2"
textAnchor="middle"
fontSize="9"
fontWeight="700"
fill="currentColor"
stroke="none"
fontFamily="system-ui,sans-serif"
>
$
</text>
</svg>
);
}
if (kind === 'support') {
return (
<svg viewBox="0 0 32 32" className={className} aria-hidden>
<path
d="M8 18v-3.5a8 8 0 0 1 16 0V18"
{...common}
/>
<path
d="M8 18.5a2.2 2.2 0 0 0-2.2 2.2V23a2.2 2.2 0 0 0 2.2 2.2h1.2V18.5H8z"
{...common}
/>
<path
d="M24 18.5h1.2a2.2 2.2 0 0 1 2.2 2.2V23a2.2 2.2 0 0 1-2.2 2.2H24V18.5z"
{...common}
/>
<path d="M12 25.2h5.5a2 2 0 0 0 2-2v-.6" {...common} />
{/* speech bubble */}
<rect x="13.2" y="12.2" width="7.2" height="5.2" rx="1.2" {...common} />
<path d="M15 14.8h.1M16.8 14.8h.1M18.6 14.8h.1" {...common} />
</svg>
);
}
if (kind === 'wrench') {
return (
<svg viewBox="0 0 32 32" className={className} aria-hidden>
<path
d="M20.5 6.5a6 6 0 0 0-7.8 7.2L6.2 20.2a2.2 2.2 0 0 0 3.1 3.1l6.5-6.5a6 6 0 0 0 7.2-7.8l-3.2 3.2-2.6-2.6 3.3-3.1z"
{...common}
/>
</svg>
);
}
if (kind === 'clock') {
return (
<svg viewBox="0 0 32 32" className={className} aria-hidden>
<circle cx="16" cy="16" r="10" {...common} />
<path d="M16 10v6.5l4 2.5" {...common} />
</svg>
);
}
// payment — card + shield
return (
<svg viewBox="0 0 36 28" className={className} aria-hidden>
<rect x="2" y="5" width="26" height="18" rx="2.2" {...common} />
<path d="M2 11h26" {...common} />
<path d="M7 17h7" {...common} />
<path
d="M27 4.5l4.5 1.6v4.2c0 3.1-2 5.2-4.5 6.2-2.5-1-4.5-3.1-4.5-6.2V6.1L27 4.5z"
{...common}
/>
<path d="M25.2 10.2l1.5 1.5 3-3" {...common} />
</svg>
);
}
function resolveIconKey(raw: string | undefined, idx: number): string {
if (raw && ICON_ALIAS[raw]) return ICON_ALIAS[raw] as string;
if (
raw === 'shipping' ||
raw === 'return' ||
raw === 'support' ||
raw === 'payment' ||
raw === 'wrench' ||
raw === 'clock'
) {
return raw;
}
return REFERENCE_FEATURES[idx]?.icon || 'shipping';
}
/**
* Prefer CMS features from admin Homepage Layout.
* Fall back to TechShop reference badges when CMS has none.
*/
function buildTiles(config?: any): FeatureItem[] {
const fromConfig =
config?.metadata_json?.features || config?.metadata?.features;
if (!Array.isArray(fromConfig) || fromConfig.length === 0) {
return REFERENCE_FEATURES;
}
return fromConfig.slice(0, 8).map((item: any, idx: number) => {
const ref = REFERENCE_FEATURES[idx] || REFERENCE_FEATURES[0];
return {
id: String(item.id || `feature-${idx + 1}`),
title: String(item.title || ref.title),
desc: String(item.desc || item.description || item.subtitle || ref.desc),
icon: resolveIconKey(item.icon, idx),
};
});
}
export const FeaturesSection: React.FC<FeaturesSectionProps> = ({ config }) => {
const tiles = buildTiles(config);
const title = getSectionTitle(config, 'trust_badges', '');
return (
<section className="py-8 md:py-10 bg-white font-sans">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-[1400px]">
{title ? (
<div className="text-left mb-6 pb-3.5 border-b border-[#e5e5e5]">
<h2 className="text-[18px] md:text-[20px] font-bold text-[#222] tracking-tight">
{title}
</h2>
</div>
) : null}
<div
className={`grid grid-cols-1 sm:grid-cols-2 gap-4 ${
tiles.length >= 4 ? 'xl:grid-cols-4' : 'xl:grid-cols-3'
}`}
>
{tiles.map((item) => (
<div
key={item.id}
className="flex items-center gap-[18px] bg-[#F8F8F8] rounded-[8px] px-6 py-[22px] min-h-[100px]"
>
<div className="shrink-0 w-10 h-10 flex items-center justify-center text-primary">
<FeatureIcon type={item.icon} className="w-9 h-8 text-primary" />
</div>
<div className="text-left min-w-0 flex flex-col gap-0.5">
<h4 className="text-[15px] font-bold text-[#222] leading-[1.25]">
{item.title}
</h4>
<p className="text-[13px] font-normal text-[#777] leading-[1.35]">
{item.desc}
</p>
</div>
</div>
))}
</div>
</div>
</section>
);
};