SFS/components/hero-section.tsx
2025-12-16 10:03:26 +05:30

145 lines
5.3 KiB
TypeScript

"use client"
import { useState, useEffect } from "react"
import { Lightbulb, BookOpen, Bot, Users, TrendingUp } from "lucide-react"
import heroFallback from "./hero-fallback.json"
// JSON file is empty by default, so assert the expected shape to avoid `never`
const fallbackData: ApiCard[] = heroFallback as ApiCard[]
// Icons mapping to match the order of API response
const ICONS = [Lightbulb, BookOpen, Bot, Users, TrendingUp]
type ApiCard = {
cardtitle?: string
carddescription?: string
svg_icon?: string | null
}
type ApiResponse = {
heading?: string
description?: string
cards?: ApiCard[]
}
export default function HeroSection() {
const [features, setFeatures] = useState<{ icon?: any; svg?: string; title: string; description: string }[]>([])
const [heading, setHeading] = useState("Why SFS")
const [description, setDescription] = useState("We combine expertise in education with cutting-edge technology to deliver solutions that truly make a difference.")
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("/api/whysfs")
if (!response.ok) throw new Error("API failed")
const json: ApiResponse = await response.json()
if (json.heading) setHeading(json.heading)
if (json.description) setDescription(json.description)
const mappedFeatures = (json.cards ?? []).map((item: ApiCard, index: number) => ({
svg: item.svg_icon || undefined,
icon: ICONS[index % ICONS.length], // fallback icon if svg missing
title: item.cardtitle || "Feature",
description: item.carddescription || "",
}))
// Swap positions: move 5th to 2nd and 2nd to 5th when available
if (mappedFeatures.length >= 5) {
const temp = mappedFeatures[1]
mappedFeatures[1] = mappedFeatures[4]
mappedFeatures[4] = temp
}
if (mappedFeatures.length === 0) {
throw new Error("No data found")
}
setFeatures(mappedFeatures)
} catch (error) {
console.warn("Failed to fetch Why SFS content, using fallback:", error)
// Use Fallback
const mappedFeatures = fallbackData.map((item, index) => ({
icon: ICONS[index % ICONS.length],
title: item.cardtitle || "Feature",
description: item.carddescription || "",
}))
if (mappedFeatures.length >= 5) {
const temp = mappedFeatures[1]
mappedFeatures[1] = mappedFeatures[4]
mappedFeatures[4] = temp
}
setFeatures(mappedFeatures)
}
}
fetchData()
}, [])
if (features.length === 0) {
return (
<section className="w-full bg-white py-12 md:py-20 lg:py-24">
<div className="max-w-[1400px] mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12 md:mb-16 lg:mb-20">
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold text-[#353535] mb-6 leading-tight">{heading}</h1>
{/* Loading state placeholder */}
</div>
</div>
</section>
)
}
return (
<section className="w-full bg-white py-12 md:py-20 lg:py-24">
<div className="max-w-[1400px] mx-auto px-4 sm:px-6 lg:px-8">
{/* Hero Content */}
<div className="text-center mb-12 md:mb-16 lg:mb-20">
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold text-[#353535] mb-6 leading-tight">{heading}</h1>
<p className="text-base md:text-lg text-[#353535] max-w-2xl mx-auto leading-relaxed">
{description}
</p>
</div>
{/* Features Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4 bg-white">
{features.map((feature, index) => {
return (
<div
key={index}
className="group bg-[#E8E8E8] hover:bg-[#F48120] p-6 flex flex-col justify-start transition-colors duration-300 min-h-[220px]"
>
<div className="mb-6">
<div className="w-16 h-16 flex items-center justify-start">
{feature.svg ? (
<span
aria-hidden
dangerouslySetInnerHTML={{ __html: feature.svg }}
className="block w-14 h-14 text-[#353535] group-hover:text-white transition-colors duration-300 [&>svg]:w-full [&>svg]:h-full [&>svg]:fill-none [&>svg]:stroke-current [&>svg]:shrink-0 [&>svg]:[stroke-width:1]"
/>
) : (
feature.icon && (
<feature.icon
strokeWidth={1}
className="w-14 h-14 text-[#353535] group-hover:text-white transition-colors duration-300 shrink-0"
/>
)
)}
</div>
</div>
<h3 className="text-lg font-bold mb-4 leading-tight text-[#353535] group-hover:text-white transition-colors duration-300">
{feature.title}
</h3>
<p className="text-sm leading-relaxed text-[#353535]/80 group-hover:text-white/90 transition-colors duration-300">
{feature.description}
</p>
</div>
)
})}
</div>
</div>
</section>
)
}