96 lines
3.9 KiB
JavaScript
96 lines
3.9 KiB
JavaScript
"use client";
|
|
import React, { useEffect, useState } from "react";
|
|
import Image from "next/image";
|
|
import axios from "axios";
|
|
|
|
export default function Gallery({ componentName = "Gallery", className = "" }) {
|
|
const [data, setData] = useState(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState(null);
|
|
|
|
useEffect(() => {
|
|
async function fetchData() {
|
|
try {
|
|
setLoading(true);
|
|
const res = await axios.get("/api/get-component-data", {
|
|
params: { component_name: componentName },
|
|
});
|
|
setData(res.data.data);
|
|
} catch (err) {
|
|
setError(`Failed to fetch ${componentName} data`);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
fetchData();
|
|
}, [componentName]);
|
|
|
|
if (loading) return null;
|
|
if (error) return null;
|
|
if (!data) return null;
|
|
|
|
const title = data.title || "";
|
|
const subtitle = data.subtitle || "";
|
|
const buttonText = data.button_text || "MORE";
|
|
const buttonLink = data.button_link || "#";
|
|
|
|
const items = Array.isArray(data.items) ? data.items : [];
|
|
|
|
return (
|
|
<section className={`wrapper bg-[#f6f6f7] py-12 ${className}`}>
|
|
<div className="container mx-auto px-4">
|
|
<div className="flex items-center justify-between mb-8">
|
|
<div>
|
|
<h2 className="text-3xl md:text-4xl font-extrabold text-[#222] tracking-tight">{title}</h2>
|
|
{subtitle && <div className="text-base text-gray-500 mt-1">{subtitle}</div>}
|
|
</div>
|
|
<a
|
|
href={buttonLink}
|
|
className="inline-flex items-center px-5 py-2 bg-[#22b573] rounded shadow hover:bg-[#1e9e4a] transition-colors duration-200 text-base font-semibold"
|
|
style={{ color: "#f8fafc" }}
|
|
>
|
|
{buttonText}
|
|
<span className="ml-2">
|
|
<svg width="18" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 13l5-4-5-4" stroke="#f8fafc" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
|
|
</span>
|
|
</a>
|
|
</div>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-5">
|
|
{items.map((item, idx) => {
|
|
const link = item.item_link || "#";
|
|
return (
|
|
<a
|
|
key={item.no || idx}
|
|
href={link}
|
|
className="relative group rounded-lg overflow-hidden shadow-md bg-white/60 hover:shadow-xl transition-all duration-300 cursor-pointer block"
|
|
style={{ minHeight: 240 }}
|
|
target={link.startsWith('http') ? '_blank' : undefined}
|
|
rel={link.startsWith('http') ? 'noopener noreferrer' : undefined}
|
|
>
|
|
<Image
|
|
src={item.item_image || ""}
|
|
alt={item.item_title || ""}
|
|
width={400}
|
|
height={240}
|
|
className="object-cover w-full h-56 group-hover:scale-105 transition-transform duration-300"
|
|
/>
|
|
<div className="absolute inset-0 flex flex-col items-center justify-center bg-black/10">
|
|
<div className="mb-2 flex items-center justify-center">
|
|
{item.item_icon && (
|
|
<span className="bg-white/80 group-hover:bg-white/95 transition-colors duration-200 rounded-full p-3 shadow-lg flex items-center justify-center">
|
|
<img src={item.item_icon} alt="icon" className="w-9 h-9" />
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="text-white font-extrabold text-lg md:text-xl drop-shadow-lg group-hover:text-[#fff] group-hover:scale-105 transition-all duration-200 text-center">
|
|
{item.item_title || ""}
|
|
</div>
|
|
</div>
|
|
</a>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|