Update src/app/collections/[category]/page.tsx

This commit is contained in:
2026-06-10 19:56:37 +00:00
parent e2c09ea896
commit 9f9d28b37a

View File

@@ -1,216 +1,115 @@
"use client";
'use client';
import { ThemeProvider } from '@/providers/themeProvider/ThemeProvider';
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
import ProductCardTwo from '@/components/sections/product/ProductCardTwo';
import ButtonTextShift from '@/components/button/ButtonTextShift/ButtonTextShift';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import { useState, useMemo } from 'react';
import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen';
import ProductCardThree from '@/components/sections/product/ProductCardThree';
import Input from '@/components/form/Input';
import ButtonExpandHover from '@/components/button/ButtonExpandHover';
import { useRouter } from 'next/navigation';
import { ChevronLeft, ChevronRight, Filter, Search, SlidersHorizontal } from 'lucide-react';
import { usePathname } from 'next/navigation';
// Dummy data for books
const allBooks = [
{ id: '1', name: 'The Art of Programming', price: '$29.99', imageSrc: '/book-programming.jpg', imageAlt: 'Book cover for The Art of Programming', category: 'technology' },
{ id: '2', name: 'Science Fiction Masterpiece', price: '$19.99', imageSrc: '/book-scifi.jpg', imageAlt: 'Book cover for Science Fiction Masterpiece', category: 'fiction' },
{ id: '3', name: 'A Culinary Journey', price: '$24.99', imageSrc: '/book-cooking.jpg', imageAlt: 'Book cover for A Culinary Journey', category: 'cooking' },
{ id: '4', name: 'History of the World', price: '$35.00', imageSrc: '/book-history.jpg', imageAlt: 'Book cover for History of the World', category: 'history' },
{ id: '5', name: 'Developing Modern Web Apps', price: '$39.99', imageSrc: '/book-webdev.jpg', imageAlt: 'Book cover for Developing Modern Web Apps', category: 'technology' },
{ id: '6', name: 'Fantasy Realms Saga', price: '$22.50', imageSrc: '/book-fantasy.jpg', imageAlt: 'Book cover for Fantasy Realms Saga', category: 'fiction' },
{ id: '7', name: 'Gourmet Baking Guide', price: '$28.00', imageSrc: '/book-baking.jpg', imageAlt: 'Book cover for Gourmet Baking Guide', category: 'cooking' },
{ id: '8', name: 'Ancient Civilizations', price: '$32.00', imageSrc: '/book-ancient.jpg', imageAlt: 'Book cover for Ancient Civilizations', category: 'history' },
{ id: '9', name: 'The Digital Frontier', price: '$31.99', imageSrc: '/book-digital.jpg', imageAlt: 'Book cover for The Digital Frontier', category: 'technology' },
{ id: '10', name: 'Mythical Beasts', price: '$18.75', imageSrc: '/book-myth.jpg', imageAlt: 'Book cover for Mythical Beasts', category: 'fiction' }
];
const ITEMS_PER_PAGE = 6;
export default function BookCollectionPage({ params }: { params: { category: string } }) {
const router = useRouter();
const { category } = params;
const [searchTerm, setSearchTerm] = useState('');
const [sortOrder, setSortOrder] = useState<'asc' | 'desc' | 'none'>('none');
const [currentPage, setCurrentPage] = useState(1);
export default function CollectionPage() {
const pathname = usePathname();
const category = pathname.split('/').pop()?.replace(/-/g, ' ') || 'All Products';
const navItems = [
{ name: "Home", id: "/" },
{ name: "About", id: "#about" },
{ name: "Features", id: "#features" },
{ name: "Pricing", id: "#pricing" },
{ name: "Books", id: "/collections/all" }
{ name: "Cart", id: "/cart" },
{ name: "Checkout", id: "/checkout" },
{ name: "Order Conf", id: "/order-confirmation" },
{ name: "Products", id: "/products/1" },
{ name: "Collections", id: "/collections/all" }
];
const filteredAndSortedBooks = useMemo(() => {
let books = allBooks;
// Category filtering
if (category !== 'all') {
books = books.filter(book => book.category === category);
// Dummy product data for the collection page
const products = [
{
id: "prod1", brand: "BrandA", name: "Stylish Shirt", price: "$29.99", rating: 4.5,
reviewCount: "120", imageSrc: "https://via.placeholder.com/300x400?text=Product+1", imageAlt: "Stylish Shirt"
},
{
id: "prod2", brand: "BrandB", name: "Comfy Jeans", price: "$49.99", rating: 4.2,
reviewCount: "85", imageSrc: "https://via.placeholder.com/300x400?text=Product+2", imageAlt: "Comfy Jeans"
},
{
id: "prod3", brand: "BrandC", name: "Running Shoes", price: "$79.99", rating: 4.8,
reviewCount: "200", imageSrc: "https://via.placeholder.com/300x400?text=Product+3", imageAlt: "Running Shoes"
},
{
id: "prod4", brand: "BrandD", name: "Elegant Dress", price: "$89.99", rating: 4.7,
reviewCount: "150", imageSrc: "https://via.placeholder.com/300x400?text=Product+4", imageAlt: "Elegant Dress"
},
{
id: "prod5", brand: "BrandE", name: "Smart Watch", price: "$199.99", rating: 4.6,
reviewCount: "230", imageSrc: "https://via.placeholder.com/300x400?text=Product+5", imageAlt: "Smart Watch"
}
// Search term filtering
if (searchTerm) {
books = books.filter(book =>
book.name.toLowerCase().includes(searchTerm.toLowerCase())
);
}
// Sorting
if (sortOrder === 'asc') {
books = [...books].sort((a, b) => a.name.localeCompare(b.name));
} else if (sortOrder === 'desc') {
books = [...books].sort((a, b) => b.name.localeCompare(a.name));
}
return books;
}, [category, searchTerm, sortOrder]);
const totalPages = Math.ceil(filteredAndSortedBooks.length / ITEMS_PER_PAGE);
const paginatedBooks = useMemo(() => {
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
const endIndex = startIndex + ITEMS_PER_PAGE;
return filteredAndSortedBooks.slice(startIndex, endIndex);
}, [filteredAndSortedBooks, currentPage]);
const handleCategoryChange = (newCategory: string) => {
router.push(`/collections/${newCategory}`);
setCurrentPage(1); // Reset page on category change
};
const handlePageChange = (page: number) => {
if (page >= 1 && page <= totalPages) {
setCurrentPage(page);
}
};
const uniqueCategories = useMemo(() => {
const categories = new Set(allBooks.map(book => book.category));
return ['all', ...Array.from(categories)];
}, []);
];
return (
<main className="min-h-screen bg-background text-foreground">
<NavbarStyleFullscreen
navItems={navItems}
brandName="BookShelf"
logoSrc="/placeholder-logo.svg"
logoAlt="BookShelf Logo"
button={{ text: "Sign Up", href: "#" }}
/>
<div className="container mx-auto p-8">
<h1 className="text-4xl font-bold text-center mb-8 capitalize">
{category === 'all' ? 'All Books' : `${category} Books`}
</h1>
<div className="flex flex-wrap items-center justify-between gap-4 mb-8">
{/* Category Filter */}
<div className="flex items-center gap-2">
<Filter className="w-5 h-5" />
<label htmlFor="category-filter" className="sr-only">Filter by Category</label>
<select
id="category-filter"
value={category}
onChange={(e) => handleCategoryChange(e.target.value)}
className="px-4 py-2 rounded-lg border border-border bg-card text-foreground focus:ring-2 focus:ring-primary-cta focus:outline-none"
<ThemeProvider
defaultButtonVariant="hover-magnetic"
defaultTextAnimation="entrance-slide"
borderRadius="rounded"
contentWidth="medium"
sizing="medium"
background="none"
cardStyle="solid"
primaryButtonStyle="gradient"
secondaryButtonStyle="glass"
headingFontWeight="bold"
>
{uniqueCategories.map(cat => (
<option key={cat} value={cat} className="capitalize">
{cat === 'all' ? 'All Categories' : cat}
</option>
))}
</select>
<div id="nav" data-section="nav">
<NavbarStyleCentered navItems={navItems} brandName="Webild" logoSrc="https://via.placeholder.com/40" />
</div>
{/* Search Input */}
<div className="relative flex-grow max-w-sm">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-foreground/60" />
<Input
value={searchTerm}
onChange={setSearchTerm}
placeholder="Search books..."
className="w-full pl-10 pr-4 py-2 rounded-lg border border-border bg-card text-foreground focus:ring-2 focus:ring-primary-cta focus:outline-none"
ariaLabel="Search books"
/>
</div>
{/* Sort Order */}
<div className="flex items-center gap-2">
<SlidersHorizontal className="w-5 h-5" />
<label htmlFor="sort-order" className="sr-only">Sort Order</label>
<select
id="sort-order"
value={sortOrder}
onChange={(e) => setSortOrder(e.target.value as 'asc' | 'desc' | 'none')}
className="px-4 py-2 rounded-lg border border-border bg-card text-foreground focus:ring-2 focus:ring-primary-cta focus:outline-none"
>
<option value="none">Sort By</option>
<option value="asc">Name (A-Z)</option>
<option value="desc">Name (Z-A)</option>
</select>
</div>
</div>
{paginatedBooks.length > 0 ? (
<ProductCardThree
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div id="product-collection" data-section="product-collection">
<ProductCardTwo
animationType="slide-up"
gridVariant="three-columns-all-equal-width"
title="" // No title for the section itself, as the page title handles it
description=""
products={paginatedBooks.map(book => ({
id: book.id,
name: book.name,
price: book.price,
imageSrc: book.imageSrc,
imageAlt: book.imageAlt
// Add other necessary product props, e.g., onFavorite, onProductClick
}))}
className="mb-8"
title={`Collection: ${category}`}
description="Explore our curated selection of products."
products={products}
className="my-10"
textboxLayout="default"
useInvertedBackground={false}
/>
<div className="flex justify-center mt-8 space-x-4">
<ButtonTextShift
text="View More"
onClick={() => alert("Loading more products...")}
disabled={false}
ariaLabel="View more products"
className="px-6 py-3"
textClassName="font-semibold"
/>
<ButtonTextShift
text="Filter"
onClick={() => alert("Opening filter options...")}
disabled={false}
ariaLabel="Filter products"
className="px-6 py-3"
textClassName="font-semibold"
/>
) : (
<div className="text-center text-foreground/80 text-xl py-16">
No books found for this category or search term.
</div>
)}
{/* Pagination */}
{totalPages > 1 && (
<div className="flex justify-center items-center gap-4 mt-8">
<ButtonExpandHover
text=""
onClick={() => handlePageChange(currentPage - 1)}
disabled={currentPage === 1}
ariaLabel="Previous page"
className="w-10 h-10 p-0 flex items-center justify-center bg-secondary-cta hover:bg-secondary-cta/80 disabled:opacity-50 disabled:cursor-not-allowed"
textClassName="sr-only"
>
<ChevronLeft className="w-5 h-5" />
</ButtonExpandHover>
{Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (
<button
key={page}
onClick={() => handlePageChange(page)}
className={`w-10 h-10 rounded-lg flex items-center justify-center text-lg font-medium
${currentPage === page
? 'bg-primary-cta text-primary-cta-foreground'
: 'bg-card text-foreground hover:bg-card/80'
}`}
>
{page}
</button>
))}
<ButtonExpandHover
text=""
onClick={() => handlePageChange(currentPage + 1)}
disabled={currentPage === totalPages}
ariaLabel="Next page"
className="w-10 h-10 p-0 flex items-center justify-center bg-secondary-cta hover:bg-secondary-cta/80 disabled:opacity-50 disabled:cursor-not-allowed"
textClassName="sr-only"
>
<ChevronRight className="w-5 h-5" />
</ButtonExpandHover>
</div>
)}
</div>
</main>
<FooterBaseReveal
logoText="Webild"
columns={[
{
title: "Company", items: [
{ label: "About Us", href: "/" },
{ label: "Contact", href: "/" }
]
},
{
title: "Legal", items: [
{ label: "Privacy Policy", href: "/" },
{ label: "Terms of Service", href: "/" }
]
}
]}
copyrightText="© 2023 Webild. All rights reserved."
/>
</ThemeProvider>
);
}