118 lines
5.1 KiB
TypeScript
118 lines
5.1 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
import Link from 'next/link';
|
|
import { Layers } from 'lucide-react';
|
|
import { motion } from 'framer-motion';
|
|
import { AnnouncementBar } from '@/layout/AnnouncementBar';
|
|
import { Header } from '@/layout/Header';
|
|
import { Navbar } from '@/layout/Navbar';
|
|
import { Footer } from '@/layout/Footer';
|
|
import { StickyHeaderSpacer } from '@/components/StickyHeaderSpacer';
|
|
import { catalogService, CategoryResponse } from '@/services/api/catalogService';
|
|
import { getImageUrl } from '@/lib/utils';
|
|
|
|
export default function AllCategoriesPage() {
|
|
const [categories, setCategories] = useState<CategoryResponse[]>([]);
|
|
const [loading, setLoading] = useState<boolean>(true);
|
|
const [error, setError] = useState<boolean>(false);
|
|
|
|
useEffect(() => {
|
|
setLoading(true);
|
|
catalogService.getCategories()
|
|
.then((res) => {
|
|
setLoading(false);
|
|
if (res && res.length > 0) {
|
|
const sorted = [...res].sort((a, b) => {
|
|
const orderA = parseInt(a.sort_order || '0', 10);
|
|
const orderB = parseInt(b.sort_order || '0', 10);
|
|
return orderA - orderB;
|
|
});
|
|
setCategories(sorted);
|
|
} else {
|
|
setCategories([]);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.error("Failed to load categories:", err);
|
|
setLoading(false);
|
|
setError(true);
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#F8F9FB] text-[#1E293B] flex flex-col font-sans">
|
|
<AnnouncementBar />
|
|
<Header />
|
|
<StickyHeaderSpacer />
|
|
<Navbar />
|
|
|
|
<main className="flex-grow py-8 pb-24 text-gray-800 antialiased">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
{loading ? (
|
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-6">
|
|
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
|
|
<div key={i} className="flex flex-col items-center animate-pulse">
|
|
<div className="w-full aspect-square bg-gray-200 rounded-theme mb-3" />
|
|
<div className="h-4 bg-gray-200 rounded w-2/3 mb-1" />
|
|
<div className="h-3 bg-gray-200 rounded w-1/3" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
) : error || categories.length === 0 ? (
|
|
<div className="bg-white border border-gray-250 rounded-2xl p-12 text-center max-w-lg mx-auto shadow-xs">
|
|
<Layers className="w-16 h-16 text-gray-300 mx-auto mb-4 stroke-1" />
|
|
<h2 className="text-lg font-bold text-gray-800">No Categories Available</h2>
|
|
<p className="text-xs text-gray-400 mt-1 mb-6">We could not retrieve catalog categories at this moment.</p>
|
|
<Link href="/" className="bg-[#1877f2] text-white text-xs font-bold px-6 py-3 rounded-lg hover:bg-[#1565c0] transition-colors inline-block">
|
|
Go to Homepage
|
|
</Link>
|
|
</div>
|
|
) : (
|
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-6">
|
|
{categories.map((cat: any) => {
|
|
const catImage = getImageUrl(cat.image_url || cat.image || cat.icon_url);
|
|
return (
|
|
<motion.div
|
|
key={cat.category_id || cat.slug}
|
|
whileHover={{ y: -6 }}
|
|
transition={{ type: 'spring', stiffness: 300, damping: 25 }}
|
|
>
|
|
<Link
|
|
href={`/products?category=${cat.slug}`}
|
|
className="flex flex-col items-center group text-center"
|
|
>
|
|
{/* Image Box */}
|
|
<div className="w-full aspect-square bg-white rounded-theme flex items-center justify-center p-6 border border-gray-200 group-hover:border-blue-200 group-hover:bg-blue-50/10 transition-all duration-300 relative overflow-hidden shadow-xs">
|
|
{catImage ? (
|
|
<motion.img
|
|
whileHover={{ scale: 1.06 }}
|
|
src={catImage}
|
|
alt={cat.name}
|
|
className="max-h-full max-w-full object-contain rounded-lg drop-shadow-md"
|
|
/>
|
|
) : (
|
|
<Layers className="w-12 h-12 text-gray-400 group-hover:text-primary transition-colors stroke-[1.5]" />
|
|
)}
|
|
</div>
|
|
|
|
{/* Title & Count */}
|
|
<h3 className="text-[13px] font-bold text-gray-800 mt-3.5 group-hover:text-primary transition-colors line-clamp-1">
|
|
{cat.name}
|
|
</h3>
|
|
<span className="text-[10px] font-bold text-gray-400 mt-0.5 tracking-wide">
|
|
{cat.product_count !== undefined ? `${cat.product_count} Products` : 'Catalog Item'}
|
|
</span>
|
|
</Link>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</main>
|
|
|
|
<Footer />
|
|
</div>
|
|
);
|
|
}
|