Update src/app/collections/[category]/page.tsx
This commit is contained in:
@@ -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 { usePathname } from 'next/navigation';
|
||||||
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';
|
|
||||||
|
|
||||||
// Dummy data for books
|
export default function CollectionPage() {
|
||||||
const allBooks = [
|
const pathname = usePathname();
|
||||||
{ id: '1', name: 'The Art of Programming', price: '$29.99', imageSrc: '/book-programming.jpg', imageAlt: 'Book cover for The Art of Programming', category: 'technology' },
|
const category = pathname.split('/').pop()?.replace(/-/g, ' ') || 'All Products';
|
||||||
{ 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);
|
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ name: "Home", id: "/" },
|
{ name: "Home", id: "/" },
|
||||||
{ name: "About", id: "#about" },
|
{ name: "Cart", id: "/cart" },
|
||||||
{ name: "Features", id: "#features" },
|
{ name: "Checkout", id: "/checkout" },
|
||||||
{ name: "Pricing", id: "#pricing" },
|
{ name: "Order Conf", id: "/order-confirmation" },
|
||||||
{ name: "Books", id: "/collections/all" }
|
{ name: "Products", id: "/products/1" },
|
||||||
|
{ name: "Collections", id: "/collections/all" }
|
||||||
];
|
];
|
||||||
|
|
||||||
const filteredAndSortedBooks = useMemo(() => {
|
// Dummy product data for the collection page
|
||||||
let books = allBooks;
|
const products = [
|
||||||
|
{
|
||||||
// Category filtering
|
id: "prod1", brand: "BrandA", name: "Stylish Shirt", price: "$29.99", rating: 4.5,
|
||||||
if (category !== 'all') {
|
reviewCount: "120", imageSrc: "https://via.placeholder.com/300x400?text=Product+1", imageAlt: "Stylish Shirt"
|
||||||
books = books.filter(book => book.category === category);
|
},
|
||||||
|
{
|
||||||
|
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 (
|
return (
|
||||||
<main className="min-h-screen bg-background text-foreground">
|
<ThemeProvider
|
||||||
<NavbarStyleFullscreen
|
defaultButtonVariant="hover-magnetic"
|
||||||
navItems={navItems}
|
defaultTextAnimation="entrance-slide"
|
||||||
brandName="BookShelf"
|
borderRadius="rounded"
|
||||||
logoSrc="/placeholder-logo.svg"
|
contentWidth="medium"
|
||||||
logoAlt="BookShelf Logo"
|
sizing="medium"
|
||||||
button={{ text: "Sign Up", href: "#" }}
|
background="none"
|
||||||
/>
|
cardStyle="solid"
|
||||||
|
primaryButtonStyle="gradient"
|
||||||
<div className="container mx-auto p-8">
|
secondaryButtonStyle="glass"
|
||||||
<h1 className="text-4xl font-bold text-center mb-8 capitalize">
|
headingFontWeight="bold"
|
||||||
{category === 'all' ? 'All Books' : `${category} Books`}
|
>
|
||||||
</h1>
|
<div id="nav" data-section="nav">
|
||||||
|
<NavbarStyleCentered navItems={navItems} brandName="Webild" logoSrc="https://via.placeholder.com/40" />
|
||||||
<div className="flex flex-wrap items-center justify-between gap-4 mb-8">
|
</div>
|
||||||
{/* Category Filter */}
|
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||||
<div className="flex items-center gap-2">
|
<div id="product-collection" data-section="product-collection">
|
||||||
<Filter className="w-5 h-5" />
|
<ProductCardTwo
|
||||||
<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"
|
|
||||||
>
|
|
||||||
{uniqueCategories.map(cat => (
|
|
||||||
<option key={cat} value={cat} className="capitalize">
|
|
||||||
{cat === 'all' ? 'All Categories' : cat}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</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
|
|
||||||
animationType="slide-up"
|
animationType="slide-up"
|
||||||
gridVariant="three-columns-all-equal-width"
|
gridVariant="three-columns-all-equal-width"
|
||||||
title="" // No title for the section itself, as the page title handles it
|
title={`Collection: ${category}`}
|
||||||
description=""
|
description="Explore our curated selection of products."
|
||||||
products={paginatedBooks.map(book => ({
|
products={products}
|
||||||
id: book.id,
|
className="my-10"
|
||||||
name: book.name,
|
textboxLayout="default"
|
||||||
price: book.price,
|
useInvertedBackground={false}
|
||||||
imageSrc: book.imageSrc,
|
|
||||||
imageAlt: book.imageAlt
|
|
||||||
// Add other necessary product props, e.g., onFavorite, onProductClick
|
|
||||||
}))}
|
|
||||||
className="mb-8"
|
|
||||||
/>
|
/>
|
||||||
) : (
|
<div className="flex justify-center mt-8 space-x-4">
|
||||||
<div className="text-center text-foreground/80 text-xl py-16">
|
<ButtonTextShift
|
||||||
No books found for this category or search term.
|
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>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
</main>
|
||||||
{/* Pagination */}
|
<FooterBaseReveal
|
||||||
{totalPages > 1 && (
|
logoText="Webild"
|
||||||
<div className="flex justify-center items-center gap-4 mt-8">
|
columns={[
|
||||||
<ButtonExpandHover
|
{
|
||||||
text=""
|
title: "Company", items: [
|
||||||
onClick={() => handlePageChange(currentPage - 1)}
|
{ label: "About Us", href: "/" },
|
||||||
disabled={currentPage === 1}
|
{ label: "Contact", href: "/" }
|
||||||
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"
|
{
|
||||||
>
|
title: "Legal", items: [
|
||||||
<ChevronLeft className="w-5 h-5" />
|
{ label: "Privacy Policy", href: "/" },
|
||||||
</ButtonExpandHover>
|
{ label: "Terms of Service", href: "/" }
|
||||||
{Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (
|
]
|
||||||
<button
|
}
|
||||||
key={page}
|
]}
|
||||||
onClick={() => handlePageChange(page)}
|
copyrightText="© 2023 Webild. All rights reserved."
|
||||||
className={`w-10 h-10 rounded-lg flex items-center justify-center text-lg font-medium
|
/>
|
||||||
${currentPage === page
|
</ThemeProvider>
|
||||||
? '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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user