146 lines
6.7 KiB
TypeScript
146 lines
6.7 KiB
TypeScript
/**
|
|
* @component HeroBanner
|
|
* @purpose Main Homepage Hero Banner slider fetching 100% dynamic CMS content from DB 2 via Storefront API.
|
|
* @dependencies storefrontService, lucide-react
|
|
*/
|
|
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import Image from 'next/image';
|
|
import Link from 'next/link';
|
|
import { ChevronLeft, ChevronRight, ShoppingCart } from 'lucide-react';
|
|
import { storefrontService, BannerItem } from '@/services/api/storefrontService';
|
|
|
|
export function HeroBanner() {
|
|
const [banners, setBanners] = useState<BannerItem[]>([]);
|
|
const [currentSlide, setCurrentSlide] = useState(0);
|
|
|
|
useEffect(() => {
|
|
// Fetch live layout content from backend
|
|
fetch('http://127.0.0.1:8000/api/v1/storefront/layout/home?region=hero')
|
|
.then((res) => (res.ok ? res.json() : []))
|
|
.then((data) => {
|
|
if (data && data.length > 0) {
|
|
const items: BannerItem[] = data.map((d: any) => ({
|
|
id: d.content_id,
|
|
title: d.title,
|
|
subtitle: d.subtitle || '',
|
|
discount_tag: d.metadata?.discount_tag || 'SPECIAL OFFER',
|
|
image_url: d.image_url || '',
|
|
cta_text: d.button_text || 'Shop Now',
|
|
cta_link: d.button_url || '/products',
|
|
}));
|
|
setBanners(items);
|
|
} else {
|
|
// Fallback to storefrontService
|
|
storefrontService.getBanners().then(setBanners);
|
|
}
|
|
})
|
|
.catch(() => {
|
|
storefrontService.getBanners().then(setBanners);
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (banners.length <= 1) return;
|
|
const timer = setInterval(() => {
|
|
setCurrentSlide((prev) => (prev + 1) % banners.length);
|
|
}, 6000);
|
|
return () => clearInterval(timer);
|
|
}, [banners.length]);
|
|
|
|
if (!banners || banners.length === 0) return null;
|
|
|
|
const current = banners[currentSlide] || banners[0];
|
|
|
|
return (
|
|
<div className="w-full max-w-7xl mx-auto px-4 mt-6">
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
{/* Main Hero Slider (Takes 2 Columns) */}
|
|
<div className="lg:col-span-2 relative h-[360px] md:h-[420px] rounded-2xl overflow-hidden shadow-sm group bg-[#111111] text-white">
|
|
<Image
|
|
src={current.image_url}
|
|
alt={current.title}
|
|
fill
|
|
priority
|
|
className="object-cover opacity-60 group-hover:scale-105 transition-transform duration-700"
|
|
/>
|
|
|
|
<div className="absolute inset-0 bg-gradient-to-r from-black/80 via-black/40 to-transparent p-8 md:p-12 flex flex-col justify-center max-w-xl">
|
|
<span className="text-[10px] md:text-xs font-black uppercase tracking-wider text-[#1877f2] bg-blue-500/20 px-3 py-1 rounded-full border border-blue-500/30 w-fit mb-3">
|
|
{current.discount_tag}
|
|
</span>
|
|
<h1 className="text-2xl md:text-4xl font-black text-white leading-tight mb-3">
|
|
{current.title}
|
|
</h1>
|
|
<p className="text-xs md:text-sm text-gray-300 font-medium mb-6 line-clamp-2">
|
|
{current.subtitle}
|
|
</p>
|
|
<Link
|
|
href={current.cta_link}
|
|
className="bg-[#1877f2] hover:bg-[#1565c0] text-white text-xs font-extrabold px-6 py-3 rounded-xl transition-colors shadow-lg flex items-center gap-2 w-fit cursor-pointer"
|
|
>
|
|
<span>{current.cta_text}</span>
|
|
<ChevronRight className="w-4 h-4" />
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Navigation Controls */}
|
|
{banners.length > 1 && (
|
|
<>
|
|
<button
|
|
onClick={() => setCurrentSlide((prev) => (prev - 1 + banners.length) % banners.length)}
|
|
className="absolute left-4 top-1/2 -translate-y-1/2 p-2 bg-black/40 hover:bg-black/70 text-white rounded-full transition-colors cursor-pointer"
|
|
>
|
|
<ChevronLeft className="w-5 h-5" />
|
|
</button>
|
|
<button
|
|
onClick={() => setCurrentSlide((prev) => (prev + 1) % banners.length)}
|
|
className="absolute right-4 top-1/2 -translate-y-1/2 p-2 bg-black/40 hover:bg-black/70 text-white rounded-full transition-colors cursor-pointer"
|
|
>
|
|
<ChevronRight className="w-5 h-5" />
|
|
</button>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* 2 Right Promo Cards (Takes 1 Column) */}
|
|
<div className="space-y-6 flex flex-col justify-between">
|
|
<div className="relative h-[170px] md:h-[198px] rounded-2xl overflow-hidden shadow-2xs group bg-gray-900 text-white">
|
|
<Image
|
|
src="https://images.unsplash.com/photo-1581092160607-ee22621dd758?w=500&auto=format&fit=crop&q=60"
|
|
alt="Certified Repair Booking"
|
|
fill
|
|
className="object-cover opacity-50 group-hover:scale-105 transition-transform duration-500"
|
|
/>
|
|
<div className="absolute inset-0 p-5 flex flex-col justify-center bg-gradient-to-r from-black/70 to-transparent">
|
|
<span className="text-[9px] font-bold text-amber-400 uppercase tracking-wider mb-1">iFixKart Repair Hub</span>
|
|
<h3 className="text-base font-black text-white leading-tight">Same-Day Screen & Battery Repair</h3>
|
|
<p className="text-[11px] text-gray-300 mt-1">Book certified technician pickup in 60s</p>
|
|
<Link href="/services" className="text-xs font-bold text-[#1877f2] hover:underline mt-2 inline-flex items-center gap-1">
|
|
Book Repair <ChevronRight className="w-3 h-3" />
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="relative h-[170px] md:h-[198px] rounded-2xl overflow-hidden shadow-2xs group bg-gray-900 text-white">
|
|
<Image
|
|
src="https://images.unsplash.com/photo-1597740985671-2a8a3b80502e?w=500&auto=format&fit=crop&q=60"
|
|
alt="OEM Spare Parts"
|
|
fill
|
|
className="object-cover opacity-50 group-hover:scale-105 transition-transform duration-500"
|
|
/>
|
|
<div className="absolute inset-0 p-5 flex flex-col justify-center bg-gradient-to-r from-black/70 to-transparent">
|
|
<span className="text-[9px] font-bold text-emerald-400 uppercase tracking-wider mb-1">100% Genuine Spare Parts</span>
|
|
<h3 className="text-base font-black text-white leading-tight">Original Display Assemblies & Batteries</h3>
|
|
<p className="text-[11px] text-gray-300 mt-1">12-Month replacement warranty</p>
|
|
<Link href="/products?category=smartphones" className="text-xs font-bold text-[#1877f2] hover:underline mt-2 inline-flex items-center gap-1">
|
|
Browse Parts <ChevronRight className="w-3 h-3" />
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|