281 lines
8.8 KiB
TypeScript
281 lines
8.8 KiB
TypeScript
"use client";
|
||
|
||
import Image from "next/image";
|
||
import { motion } from "framer-motion";
|
||
import { useEffect, useState } from "react";
|
||
import { useTranslations } from "next-intl";
|
||
import {
|
||
getOperationalSystems,
|
||
SystemFeature,
|
||
} from "@/lib/api/demoapi/operationalSystems";
|
||
import { Breadcrumb } from "@/components/breadCrumb";
|
||
|
||
export default function OperationalSystemsPage() {
|
||
const t = useTranslations("operationalSystems");
|
||
const [data, setData] = useState<SystemFeature[] | null>(null);
|
||
const [loading, setLoading] = useState(true);
|
||
const [error, setError] = useState(false);
|
||
|
||
// Demo data - fallback ma'lumotlar
|
||
const demoData: SystemFeature[] = [
|
||
{
|
||
id: "1",
|
||
title: t("systems.sprinkler.title"),
|
||
shortDesc:t("systems.sprinkler.short-desc"),
|
||
description: t("systems.sprinkler.description"),
|
||
features: [
|
||
t("systems.sprinkler.features.0"),
|
||
t("systems.sprinkler.features.1"),
|
||
t("systems.sprinkler.features.2"),
|
||
t("systems.sprinkler.features.3"),
|
||
],
|
||
image: "/images/services/sprinkler.jpg",
|
||
},
|
||
];
|
||
|
||
const fetchData = async () => {
|
||
try {
|
||
setLoading(true);
|
||
setError(false);
|
||
|
||
const result = await getOperationalSystems();
|
||
|
||
// Agar backend ma'lumot qaytarsa
|
||
if (result && result.length > 0) {
|
||
setData(result);
|
||
} else {
|
||
// Backend bo'sh ma'lumot qaytarsa, demo ma'lumotlarni ishlatamiz
|
||
setData(demoData);
|
||
}
|
||
} catch (err) {
|
||
setError(true);
|
||
// Xatolik bo'lsa, demo ma'lumotlarni ishlatamiz
|
||
setData(demoData);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
fetchData();
|
||
}, []);
|
||
|
||
// Animation variants
|
||
const containerVariants = {
|
||
hidden: { opacity: 0 },
|
||
visible: {
|
||
opacity: 1,
|
||
transition: {
|
||
staggerChildren: 0.15,
|
||
},
|
||
},
|
||
};
|
||
|
||
const itemVariants = {
|
||
hidden: { opacity: 0, y: 30 },
|
||
visible: {
|
||
opacity: 1,
|
||
y: 0,
|
||
transition: {
|
||
duration: 0.6,
|
||
ease: [0.22, 1, 0.36, 1] as const,
|
||
},
|
||
},
|
||
};
|
||
|
||
const cardVariants = {
|
||
hidden: { opacity: 0, scale: 0.95 },
|
||
visible: {
|
||
opacity: 1,
|
||
scale: 1,
|
||
transition: {
|
||
duration: 0.5,
|
||
ease: [0.22, 1, 0.36, 1] as const,
|
||
},
|
||
},
|
||
};
|
||
|
||
// Loading state
|
||
if (loading) {
|
||
return (
|
||
<div className="min-h-screen flex items-center justify-center bg-black">
|
||
<motion.div
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
className="text-center space-y-6"
|
||
>
|
||
<motion.div
|
||
animate={{ rotate: 360 }}
|
||
transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
|
||
className="w-16 h-16 border-4 border-red-500 border-t-transparent rounded-full mx-auto"
|
||
/>
|
||
<p className="text-white text-xl font-medium font-unbounded">
|
||
{t("loading")}
|
||
</p>
|
||
</motion.div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// Error state with retry
|
||
if (error && !data) {
|
||
return (
|
||
<div className="min-h-screen flex items-center justify-center bg-black px-4">
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
className="text-center space-y-6 max-w-md"
|
||
>
|
||
<div className="text-7xl">⚠️</div>
|
||
<p className="text-white text-xl font-medium">{t("error")}</p>
|
||
<motion.button
|
||
whileHover={{ scale: 1.05 }}
|
||
whileTap={{ scale: 0.95 }}
|
||
onClick={fetchData}
|
||
className="px-6 py-3 bg-red-500 text-white rounded-lg font-medium hover:bg-red-600 transition-colors"
|
||
>
|
||
{t("retry")}
|
||
</motion.button>
|
||
</motion.div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="pt-20 md:pt-30 pb-35 max-w-6xl mx-auto w-full px-4">
|
||
{/* Header */}
|
||
{/* <motion.div
|
||
variants={containerVariants}
|
||
initial="hidden"
|
||
animate="visible"
|
||
className="flex md:flex-row flex-col items-start justify-between gap-6 md:gap-8 w-full mb-16 md:mb-24"
|
||
>
|
||
<motion.div variants={itemVariants} className="space-y-4 md:space-y-8 flex-1">
|
||
<h1 className="bg-linear-to-br from-white via-white to-gray-400 text-transparent bg-clip-text text-3xl md:text-4xl lg:text-5xl font-semibold font-almarai">
|
||
{t('title')}
|
||
</h1>
|
||
<p className="text-white font-medium font-unbounded text-base sm:text-lg md:text-xl max-w-2xl leading-relaxed">
|
||
{t('subtitle')}
|
||
</p>
|
||
</motion.div>
|
||
|
||
<motion.div
|
||
variants={itemVariants}
|
||
whileHover={{ scale: 1.05, rotate: 3 }}
|
||
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
||
className="shrink-0 relative"
|
||
>
|
||
<Image
|
||
src="/images/home/redShlang.png"
|
||
alt="Fire hose"
|
||
fill
|
||
priority
|
||
className="w-32 h-32 sm:w-40 sm:h-40 md:w-48 md:h-48 lg:w-52 lg:h-52 object-contain"
|
||
/>
|
||
</motion.div>
|
||
</motion.div> */}
|
||
<div className="mb-5">
|
||
<Breadcrumb />
|
||
</div>
|
||
|
||
{/* Main Content */}
|
||
{!data || data.length === 0 ? (
|
||
<motion.div
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
className="text-center py-20"
|
||
>
|
||
<p className="text-gray-400 text-xl font-unbounded">{t("noData")}</p>
|
||
</motion.div>
|
||
) : (
|
||
<motion.div
|
||
variants={containerVariants}
|
||
initial="hidden"
|
||
animate="visible"
|
||
className="space-y-12 md:space-y-20"
|
||
>
|
||
{data.map((system, index) => (
|
||
<motion.div
|
||
key={system.id}
|
||
variants={cardVariants}
|
||
whileHover={{ y: -8 }}
|
||
className={`flex flex-col gap-8 md:gap-12 items-center`}
|
||
>
|
||
{/* Image Section */}
|
||
<motion.div
|
||
whileHover={{ scale: 1.03 }}
|
||
transition={{ duration: 0.3 }}
|
||
className="w-full relative h-64 md:h-80 lg:h-96 rounded-xl overflow-hidden"
|
||
>
|
||
<Image
|
||
src={system.image}
|
||
alt={system.title}
|
||
fill
|
||
className="object-cover w-full h-auto"
|
||
/>
|
||
<div className="absolute inset-0 bg-linear-to-t from-black/10 to-transparent" />
|
||
</motion.div>
|
||
|
||
{/* Content Section */}
|
||
<div className="w-full space-y-6">
|
||
<motion.h2
|
||
initial={{ opacity: 0, x: index % 2 === 0 ? -20 : 20 }}
|
||
whileInView={{ opacity: 1, x: 0 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 0.6 }}
|
||
className="text-2xl md:text-3xl lg:text-4xl font-bold text-white font-almarai"
|
||
>
|
||
{system.title}
|
||
</motion.h2>
|
||
|
||
<motion.p
|
||
initial={{ opacity: 0, x: index % 2 === 0 ? -20 : 20 }}
|
||
whileInView={{ opacity: 1, x: 0 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 0.6, delay: 0.1 }}
|
||
className="text-gray-300 text-sm md:text-base leading-relaxed font-unbounded"
|
||
>
|
||
{system.shortDesc}
|
||
</motion.p>
|
||
|
||
<motion.p
|
||
initial={{ opacity: 0, x: index % 2 === 0 ? -20 : 20 }}
|
||
whileInView={{ opacity: 1, x: 0 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 0.6, delay: 0.1 }}
|
||
className="text-gray-300 text-sm md:text-base leading-relaxed font-unbounded"
|
||
>
|
||
{system.description}
|
||
</motion.p>
|
||
|
||
<div className="space-y-4">
|
||
|
||
<ul className="space-y-3">
|
||
{system.features.map((feature, featureIndex) => (
|
||
<motion.li
|
||
key={featureIndex}
|
||
initial={{ opacity: 0, x: index % 2 === 0 ? -20 : 20 }}
|
||
whileInView={{ opacity: 1, x: 0 }}
|
||
viewport={{ once: true }}
|
||
transition={{
|
||
duration: 0.5,
|
||
delay: 0.3 + featureIndex * 0.1,
|
||
}}
|
||
className="flex items-start gap-3 text-gray-300"
|
||
>
|
||
<span className="text-sm md:text-base font-unbounded">
|
||
{feature}
|
||
</span>
|
||
</motion.li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
))}
|
||
</motion.div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|