second shop concept
This commit is contained in:
parent
6aec40b660
commit
bc89babc13
@ -1,320 +1,714 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { StarIcon } from '@heroicons/react/20/solid'
|
||||
import { HeartIcon, ShoppingCartIcon } from '@heroicons/react/24/outline'
|
||||
import { HeartIcon as HeartIconSolid } from '@heroicons/react/24/solid'
|
||||
import { useState } from 'react'
|
||||
import { MagnifyingGlassIcon, FunnelIcon, Squares2X2Icon, ListBulletIcon, HeartIcon, StarIcon, ShoppingCartIcon } from '@heroicons/react/20/solid'
|
||||
import { HeartIcon as HeartOutlineIcon } from '@heroicons/react/24/outline'
|
||||
import { ChevronDownIcon } from '@heroicons/react/24/outline'
|
||||
import PageLayout from '../../components/PageLayout'
|
||||
|
||||
// Mock-Produktdaten im Tailwind UI Plus Format
|
||||
const products = [
|
||||
const categories = [
|
||||
'Alle Kategorien',
|
||||
'Technik',
|
||||
'Beauty',
|
||||
'Kleidung',
|
||||
'Getränke',
|
||||
'Lifestyle',
|
||||
'Büro'
|
||||
]
|
||||
|
||||
const sortOptions = [
|
||||
{ name: 'Beliebteste', href: '#', current: true },
|
||||
{ name: 'Neueste', href: '#', current: false },
|
||||
{ name: 'Preis: Niedrig zu Hoch', href: '#', current: false },
|
||||
{ name: 'Preis: Hoch zu Niedrig', href: '#', current: false },
|
||||
]
|
||||
|
||||
// Sample Products Data - Profit Planet Theme
|
||||
const sampleProducts = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Premium Bio-Kaffee Starter Set',
|
||||
price: '€24.99',
|
||||
rating: 5,
|
||||
reviewCount: 142,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1559056199-641a0ac8b55e?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Premium Bio-Kaffee Set mit Bohnen und Filter',
|
||||
href: '#',
|
||||
category: 'Getränke',
|
||||
name: 'EcoDesk Pro',
|
||||
category: 'Büro',
|
||||
price: 299.99,
|
||||
originalPrice: 399.99,
|
||||
rating: 4.8,
|
||||
reviews: 124,
|
||||
image: 'https://images.unsplash.com/photo-1586953208448-b95a79798f07?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80',
|
||||
badge: 'Bestseller',
|
||||
inStock: true,
|
||||
brand: 'EcoTech',
|
||||
description: 'Nachhaltiger Steh-Sitz-Schreibtisch aus recyceltem Bambus'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Nachhaltiger Laptop-Ständer',
|
||||
price: '€89.99',
|
||||
rating: 5,
|
||||
reviewCount: 87,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1527864550417-7fd91fc51a46?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Ergonomischer Laptop-Ständer aus Bambus',
|
||||
href: '#',
|
||||
category: 'Technik',
|
||||
name: 'Smart Success Journal',
|
||||
category: 'Lifestyle',
|
||||
price: 49.99,
|
||||
rating: 3,
|
||||
reviews: 89,
|
||||
image: 'https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80',
|
||||
badge: 'Neu',
|
||||
inStock: true,
|
||||
brand: 'GreenLife',
|
||||
description: 'Digital verknüpftes Erfolgs-Tagebuch mit App-Integration'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Öko-Sportbekleidung Set',
|
||||
price: '€149.99',
|
||||
rating: 5,
|
||||
reviewCount: 203,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1506629905607-b5f9a71351e8?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Nachhaltige Sportkleidung aus recycelten Materialien',
|
||||
href: '#',
|
||||
category: 'Kleidung',
|
||||
inStock: false,
|
||||
name: 'Wireless Charging Pad Pro',
|
||||
category: 'Technik',
|
||||
price: 79.99,
|
||||
originalPrice: 99.99,
|
||||
rating: 4.6,
|
||||
reviews: 203,
|
||||
image: 'https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80',
|
||||
badge: 'Sale',
|
||||
inStock: true,
|
||||
brand: 'EcoTech',
|
||||
description: 'Schnelles kabelloses Laden mit Solarenergie-Option'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Smart Home Energie-Monitor',
|
||||
price: '€199.99',
|
||||
rating: 4,
|
||||
reviewCount: 156,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Smart Home Gerät zur Energieüberwachung',
|
||||
href: '#',
|
||||
category: 'Technik',
|
||||
name: 'Organic Green Tea Set',
|
||||
category: 'Getränke',
|
||||
price: 34.99,
|
||||
rating: 3.1,
|
||||
reviews: 67,
|
||||
image: 'https://images.unsplash.com/photo-1556679343-c7306c1976bc?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80',
|
||||
inStock: true,
|
||||
brand: 'GreenLife',
|
||||
description: 'Premium Bio-Tee-Sammlung für mehr Fokus und Energie'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Bio-Hautpflege Starter-Set',
|
||||
price: '€79.99',
|
||||
rating: 4,
|
||||
reviewCount: 92,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1556228578-8c89e6adf883?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Natürliche Hautpflege Produkte ohne Chemikalien',
|
||||
href: '#',
|
||||
category: 'Beauty',
|
||||
inStock: true,
|
||||
name: 'Sustainable Business Shirt',
|
||||
category: 'Kleidung',
|
||||
price: 89.99,
|
||||
rating: 4.5,
|
||||
reviews: 156,
|
||||
image: 'https://images.unsplash.com/photo-1596755094514-f87e34085b2c?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80',
|
||||
inStock: false,
|
||||
brand: 'SustainableStyle',
|
||||
description: 'Elegantes Businesshemd aus nachhaltiger Bio-Baumwolle'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Solarbetriebene Powerbank',
|
||||
price: '€129.99',
|
||||
rating: 5,
|
||||
reviewCount: 78,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1609091839311-d5365f9ff1c5?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Portable Solarenergie Powerbank',
|
||||
href: '#',
|
||||
category: 'Technik',
|
||||
name: 'Anti-Blue Light Glasses',
|
||||
category: 'Lifestyle',
|
||||
price: 59.99,
|
||||
rating: 4.4,
|
||||
reviews: 91,
|
||||
image: 'https://images.unsplash.com/photo-1574258495973-f010dfbb5371?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80',
|
||||
inStock: true,
|
||||
brand: 'EcoTech',
|
||||
description: 'Stilvolle Blaulichtfilter-Brille für digitale Professionals'
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Nachhaltige Trinkflasche',
|
||||
price: '€25.99',
|
||||
rating: 4,
|
||||
reviewCount: 64,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1523362628745-0c100150b504?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Wiederverwendbare Edelstahl Trinkflasche',
|
||||
href: '#',
|
||||
category: 'Lifestyle',
|
||||
name: 'Glow Serum Vitamin C',
|
||||
category: 'Beauty',
|
||||
price: 24.99,
|
||||
rating: 2.8,
|
||||
reviews: 234,
|
||||
image: 'https://images.unsplash.com/photo-1620916566398-39f1143ab7be?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80',
|
||||
badge: 'Bestseller',
|
||||
inStock: true,
|
||||
brand: 'GreenLife',
|
||||
description: 'Natürliches Vitamin C Serum für strahlende Haut'
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Öko-Notizbuch Set',
|
||||
price: '€19.99',
|
||||
rating: 5,
|
||||
reviewCount: 41,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Recyceltes Papier Notizbuch Set',
|
||||
href: '#',
|
||||
name: 'Productivity Planner 2025',
|
||||
category: 'Büro',
|
||||
price: 39.99,
|
||||
rating: 4.3,
|
||||
reviews: 445,
|
||||
image: 'https://images.unsplash.com/photo-1517842645767-c639042777db?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80',
|
||||
badge: 'Bestseller',
|
||||
inStock: true,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: 'Bambus Handy-Halterung',
|
||||
price: '€32.99',
|
||||
rating: 4,
|
||||
reviewCount: 24,
|
||||
imageSrc: 'https://images.unsplash.com/photo-1572635196237-14b3f281503f?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
imageAlt: 'Nachhaltige Bambus Handy-Halterung',
|
||||
href: '#',
|
||||
category: 'Technik',
|
||||
inStock: true,
|
||||
},
|
||||
brand: 'SustainableStyle',
|
||||
description: 'Der ultimative Planer für maximale Produktivität'
|
||||
}
|
||||
]
|
||||
|
||||
function classNames(...classes: (string | undefined | null | boolean)[]): string {
|
||||
return classes.filter(Boolean).join(' ')
|
||||
}
|
||||
|
||||
export default function ShopPage() {
|
||||
export default function StorePage() {
|
||||
const [selectedCategory, setSelectedCategory] = useState('Alle Kategorien')
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid')
|
||||
const [showFilters, setShowFilters] = useState(false)
|
||||
const [favorites, setFavorites] = useState<number[]>([])
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
// Load favorites from localStorage on component mount
|
||||
useEffect(() => {
|
||||
const savedFavorites = localStorage.getItem('shop-favorites')
|
||||
if (savedFavorites) {
|
||||
try {
|
||||
setFavorites(JSON.parse(savedFavorites))
|
||||
} catch (error) {
|
||||
console.error('Error parsing favorites from localStorage:', error)
|
||||
}
|
||||
}
|
||||
setIsLoading(false)
|
||||
}, [])
|
||||
// Filter states
|
||||
const [priceRange, setPriceRange] = useState({ min: '', max: '' })
|
||||
const [selectedRatings, setSelectedRatings] = useState<number[]>([])
|
||||
const [selectedAvailability, setSelectedAvailability] = useState<string[]>([])
|
||||
const [selectedBrand, setSelectedBrand] = useState('Alle Marken')
|
||||
const [sortBy, setSortBy] = useState('Beliebteste')
|
||||
|
||||
// Save favorites to localStorage whenever favorites change
|
||||
useEffect(() => {
|
||||
if (!isLoading) {
|
||||
localStorage.setItem('shop-favorites', JSON.stringify(favorites))
|
||||
}
|
||||
}, [favorites, isLoading])
|
||||
// Filter products based on all criteria
|
||||
const filteredProducts = sampleProducts.filter(product => {
|
||||
// Search filter
|
||||
const matchesSearch = product.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
product.description.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
|
||||
// Category filter
|
||||
const matchesCategory = selectedCategory === 'Alle Kategorien' || product.category === selectedCategory
|
||||
|
||||
// Price filter
|
||||
const minPrice = priceRange.min ? parseFloat(priceRange.min) : 0
|
||||
const maxPrice = priceRange.max ? parseFloat(priceRange.max) : Infinity
|
||||
const matchesPrice = product.price >= minPrice && product.price <= maxPrice
|
||||
|
||||
// Rating filter
|
||||
const matchesRating = selectedRatings.length === 0 || selectedRatings.some(rating => {
|
||||
if (rating === 5) return product.rating >= 4.8
|
||||
if (rating === 4) return product.rating >= 4.0
|
||||
if (rating === 3) return product.rating >= 3.0
|
||||
return false
|
||||
})
|
||||
|
||||
// Availability filter
|
||||
const matchesAvailability = selectedAvailability.length === 0 || selectedAvailability.some(availability => {
|
||||
if (availability === 'inStock') return product.inStock
|
||||
if (availability === 'preOrder') return !product.inStock
|
||||
return false
|
||||
})
|
||||
|
||||
// Brand filter
|
||||
const matchesBrand = selectedBrand === 'Alle Marken' || product.brand === selectedBrand
|
||||
|
||||
return matchesSearch && matchesCategory && matchesPrice && matchesRating && matchesAvailability && matchesBrand
|
||||
})
|
||||
|
||||
// Sort products
|
||||
const sortedProducts = [...filteredProducts].sort((a, b) => {
|
||||
switch (sortBy) {
|
||||
case 'Neueste':
|
||||
return b.id - a.id // Assuming higher ID means newer
|
||||
case 'Preis: Niedrig zu Hoch':
|
||||
return a.price - b.price
|
||||
case 'Preis: Hoch zu Niedrig':
|
||||
return b.price - a.price
|
||||
case 'Beliebteste':
|
||||
default:
|
||||
return b.rating - a.rating // Higher rating first
|
||||
}
|
||||
})
|
||||
|
||||
// Reset all filters
|
||||
const resetFilters = () => {
|
||||
setSelectedCategory('Alle Kategorien')
|
||||
setSearchQuery('')
|
||||
setPriceRange({ min: '', max: '' })
|
||||
setSelectedRatings([])
|
||||
setSelectedAvailability([])
|
||||
setSelectedBrand('Alle Marken')
|
||||
setSortBy('Beliebteste')
|
||||
}
|
||||
|
||||
// Toggle favorite status
|
||||
const toggleFavorite = (productId: number) => {
|
||||
setFavorites(prev => {
|
||||
const newFavorites = prev.includes(productId)
|
||||
setFavorites(prev =>
|
||||
prev.includes(productId)
|
||||
? prev.filter(id => id !== productId)
|
||||
: [...prev, productId]
|
||||
|
||||
// Show feedback to user
|
||||
const product = products.find(p => p.id === productId)
|
||||
if (product) {
|
||||
if (newFavorites.includes(productId)) {
|
||||
console.log(`❤️ ${product.name} zu Favoriten hinzugefügt`)
|
||||
} else {
|
||||
console.log(`💔 ${product.name} aus Favoriten entfernt`)
|
||||
}
|
||||
}
|
||||
|
||||
return newFavorites
|
||||
})
|
||||
}
|
||||
|
||||
const addToCart = (productId: number) => {
|
||||
const product = products.find(p => p.id === productId)
|
||||
if (product) {
|
||||
console.log(`🛒 ${product.name} zum Warenkorb hinzugefügt`)
|
||||
// Hier würde die echte Add-to-Cart Logik implementiert werden
|
||||
// z.B. API-Call oder Zustand-Update
|
||||
}
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<PageLayout>
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#8D6B1D] mx-auto mb-4"></div>
|
||||
<p className="text-[#4A4A4A]">Shop wird geladen...</p>
|
||||
</div>
|
||||
</div>
|
||||
</PageLayout>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<PageLayout>
|
||||
<div className="bg-white">
|
||||
{/* Header Section */}
|
||||
{/* Modern Compact Header with Background Image */}
|
||||
<div className="relative bg-gray-900">
|
||||
{/* Background Image with Overlay */}
|
||||
<div
|
||||
className="text-white py-16 relative"
|
||||
className="absolute inset-0 bg-cover bg-center bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: 'url(/images/misc/grey_BG.jpg)',
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat'
|
||||
backgroundImage: 'url(https://images.unsplash.com/photo-1441986300917-64674bd600d8?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80)',
|
||||
}}
|
||||
>
|
||||
<div className="absolute inset-0 bg-black/40"></div>
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
|
||||
<div className="text-center">
|
||||
<h1 className="text-4xl font-bold mb-4">Profit Planet Shop</h1>
|
||||
<p className="text-xl text-gray-300 max-w-2xl mx-auto">
|
||||
Entdecke nachhaltige und innovative Produkte, die sowohl deinem Geldbeutel als auch dem Planeten helfen
|
||||
<div className="absolute inset-0 bg-gray-900/70 backdrop-blur-sm" />
|
||||
</div>
|
||||
|
||||
{/* Header Content */}
|
||||
<div className="relative z-10 px-4 py-12 sm:px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
{/* Store Title */}
|
||||
<div className="text-center mb-8">
|
||||
<h1 className="text-3xl font-bold tracking-tight text-white sm:text-4xl">
|
||||
Profit Planet Store
|
||||
</h1>
|
||||
<p className="mt-2 text-lg text-gray-300">
|
||||
Nachhaltige Produkte für deinen Erfolg
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Products Section - Tailwind UI Plus "Product Grid" */}
|
||||
<div className="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:max-w-7xl lg:px-8">
|
||||
<h2 className="sr-only">Products</h2>
|
||||
|
||||
<div className="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
|
||||
{products.map((product) => (
|
||||
<a key={product.id} href={product.href} className="group">
|
||||
{/* Search & Navigation Section */}
|
||||
<div className="space-y-6">
|
||||
{/* Search Bar - Tailwind UI Plus Style */}
|
||||
<div className="mx-auto max-w-2xl">
|
||||
<div className="relative">
|
||||
{/* Product Image */}
|
||||
<div className="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg bg-gray-200 xl:aspect-h-8 xl:aspect-w-7">
|
||||
<img
|
||||
alt={product.imageAlt}
|
||||
src={product.imageSrc}
|
||||
className="h-full w-full object-cover object-center group-hover:opacity-75"
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
||||
<MagnifyingGlassIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
<input
|
||||
type="search"
|
||||
name="search"
|
||||
id="search"
|
||||
className="block w-full rounded-lg border-0 bg-white/90 backdrop-blur-sm py-3 pl-10 pr-3 text-gray-900 placeholder-gray-500 shadow-lg ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-[#8D6B1D] sm:text-sm sm:leading-6"
|
||||
placeholder="Produkte durchsuchen..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Favorite Button - Now with better positioning */}
|
||||
{/* Category Navigation - Horizontal Tabs Style */}
|
||||
<div className="flex justify-center">
|
||||
<div className="inline-flex rounded-lg bg-white/10 backdrop-blur-sm p-1">
|
||||
<nav className="flex space-x-1" aria-label="Kategorien">
|
||||
{categories.map((category) => (
|
||||
<button
|
||||
key={category}
|
||||
onClick={() => setSelectedCategory(category)}
|
||||
className={`
|
||||
${selectedCategory === category
|
||||
? 'bg-white text-gray-900 shadow-sm'
|
||||
: 'text-white hover:bg-white/20'
|
||||
}
|
||||
rounded-md px-3 py-2 text-sm font-medium transition-all duration-200
|
||||
`}
|
||||
>
|
||||
{category}
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Filters & View Options Bar */}
|
||||
<div className="border-b border-gray-200 bg-white">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex h-16 items-center justify-between">
|
||||
{/* Left: Results Count & Filters */}
|
||||
<div className="flex items-center space-x-4">
|
||||
<p className="text-sm text-gray-700">
|
||||
<span className="font-medium">{sortedProducts.length}</span> Produkte gefunden
|
||||
</p>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
className="inline-flex items-center gap-x-1.5 rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
|
||||
>
|
||||
<FunnelIcon className="-ml-0.5 h-4 w-4" />
|
||||
Filter
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Right: Sort & View Options */}
|
||||
<div className="flex items-center space-x-4">
|
||||
{/* Sort Dropdown */}
|
||||
<div className="relative">
|
||||
<select
|
||||
value={sortBy}
|
||||
onChange={(e) => setSortBy(e.target.value)}
|
||||
className="rounded-md border-0 bg-white py-1.5 pl-3 pr-8 text-sm text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-[#8D6B1D]"
|
||||
>
|
||||
{sortOptions.map((option) => (
|
||||
<option key={option.name} value={option.name}>
|
||||
{option.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* View Mode Toggle */}
|
||||
<div className="flex rounded-md shadow-sm">
|
||||
<button
|
||||
onClick={() => setViewMode('grid')}
|
||||
className={`
|
||||
${viewMode === 'grid'
|
||||
? 'bg-[#8D6B1D] text-white'
|
||||
: 'bg-white text-gray-400 hover:text-gray-500'
|
||||
}
|
||||
relative inline-flex items-center rounded-l-md px-3 py-2 text-sm font-medium ring-1 ring-inset ring-gray-300 focus:z-10 focus:ring-2 focus:ring-[#8D6B1D]
|
||||
`}
|
||||
>
|
||||
<Squares2X2Icon className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setViewMode('list')}
|
||||
className={`
|
||||
${viewMode === 'list'
|
||||
? 'bg-[#8D6B1D] text-white'
|
||||
: 'bg-white text-gray-400 hover:text-gray-500'
|
||||
}
|
||||
relative -ml-px inline-flex items-center rounded-r-md px-3 py-2 text-sm font-medium ring-1 ring-inset ring-gray-300 focus:z-10 focus:ring-2 focus:ring-[#8D6B1D]
|
||||
`}
|
||||
>
|
||||
<ListBulletIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expandable Filters Section */}
|
||||
{showFilters && (
|
||||
<div className="border-b border-gray-200 bg-gray-50">
|
||||
<div className="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8">
|
||||
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
|
||||
{/* Price Range */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-900">Preis</h3>
|
||||
<div className="mt-2 space-y-3">
|
||||
<div className="flex space-x-3">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="Min €"
|
||||
value={priceRange.min}
|
||||
onChange={(e) => setPriceRange({...priceRange, min: e.target.value})}
|
||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-[#8D6B1D] sm:text-sm sm:leading-6"
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="Max €"
|
||||
value={priceRange.max}
|
||||
onChange={(e) => setPriceRange({...priceRange, max: e.target.value})}
|
||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-[#8D6B1D] sm:text-sm sm:leading-6"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Rating Filter */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-900">Bewertung</h3>
|
||||
<div className="mt-2 space-y-2">
|
||||
{[
|
||||
{ label: '5 Sterne', value: 5 },
|
||||
{ label: '4+ Sterne', value: 4 },
|
||||
{ label: '3+ Sterne', value: 3 }
|
||||
].map((rating) => (
|
||||
<label key={rating.value} className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedRatings.includes(rating.value)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setSelectedRatings([...selectedRatings, rating.value])
|
||||
} else {
|
||||
setSelectedRatings(selectedRatings.filter(r => r !== rating.value))
|
||||
}
|
||||
}}
|
||||
className="h-4 w-4 rounded border-gray-300 text-[#8D6B1D] focus:ring-[#8D6B1D]"
|
||||
/>
|
||||
<span className="ml-2 text-sm text-gray-600">{rating.label}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Availability */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-900">Verfügbarkeit</h3>
|
||||
<div className="mt-2 space-y-2">
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedAvailability.includes('inStock')}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setSelectedAvailability([...selectedAvailability, 'inStock'])
|
||||
} else {
|
||||
setSelectedAvailability(selectedAvailability.filter(a => a !== 'inStock'))
|
||||
}
|
||||
}}
|
||||
className="h-4 w-4 rounded border-gray-300 text-[#8D6B1D] focus:ring-[#8D6B1D]"
|
||||
/>
|
||||
<span className="ml-2 text-sm text-gray-600">Auf Lager</span>
|
||||
</label>
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedAvailability.includes('preOrder')}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setSelectedAvailability([...selectedAvailability, 'preOrder'])
|
||||
} else {
|
||||
setSelectedAvailability(selectedAvailability.filter(a => a !== 'preOrder'))
|
||||
}
|
||||
}}
|
||||
className="h-4 w-4 rounded border-gray-300 text-[#8D6B1D] focus:ring-[#8D6B1D]"
|
||||
/>
|
||||
<span className="ml-2 text-sm text-gray-600">Vorbestellung</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Brand Filter */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-900">Marke</h3>
|
||||
<div className="mt-2">
|
||||
<select
|
||||
value={selectedBrand}
|
||||
onChange={(e) => setSelectedBrand(e.target.value)}
|
||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-[#8D6B1D] sm:text-sm sm:leading-6"
|
||||
>
|
||||
<option>Alle Marken</option>
|
||||
<option>EcoTech</option>
|
||||
<option>GreenLife</option>
|
||||
<option>SustainableStyle</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Filter Actions */}
|
||||
<div className="mt-6 flex justify-start">
|
||||
<button
|
||||
type="button"
|
||||
onClick={resetFilters}
|
||||
className="rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 transition-colors duration-200"
|
||||
>
|
||||
Filter zurücksetzen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Products Grid/List */}
|
||||
<div className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
|
||||
{sortedProducts.length === 0 ? (
|
||||
<div className="text-center py-16">
|
||||
<p className="text-lg text-gray-500">Keine Produkte gefunden</p>
|
||||
<p className="mt-2 text-sm text-gray-400">
|
||||
Versuche andere Suchbegriffe oder Filter
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* Grid View */}
|
||||
{viewMode === 'grid' && (
|
||||
<div className="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
|
||||
{sortedProducts.map((product) => (
|
||||
<div key={product.id} className="group relative flex flex-col h-full bg-white border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow duration-200">
|
||||
{/* Product Image - Clickable area for product page */}
|
||||
<div className="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-md bg-gray-200 xl:aspect-h-8 xl:aspect-w-7 relative">
|
||||
<a href="#" className="block h-full w-full">
|
||||
<img
|
||||
src={product.image}
|
||||
alt={product.name}
|
||||
className="h-full w-full object-cover object-center group-hover:opacity-75 transition-opacity duration-200"
|
||||
/>
|
||||
</a>
|
||||
|
||||
{/* Badge */}
|
||||
{product.badge && (
|
||||
<div className="absolute top-2 left-2 z-10">
|
||||
<span className={`
|
||||
inline-flex items-center rounded-full px-2 py-1 text-xs font-medium
|
||||
${product.badge === 'Bestseller' ? 'bg-yellow-100 text-yellow-800' : ''}
|
||||
${product.badge === 'Neu' ? 'bg-green-100 text-green-800' : ''}
|
||||
${product.badge === 'Sale' ? 'bg-red-100 text-red-800' : ''}
|
||||
`}>
|
||||
{product.badge}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Favorite Button */}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
toggleFavorite(product.id)
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
toggleFavorite(product.id);
|
||||
}}
|
||||
className={classNames(
|
||||
'absolute top-3 right-3 rounded-full bg-white p-2 text-gray-400 shadow-sm hover:bg-gray-50 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-[#8D6B1D]',
|
||||
'opacity-0 transition-opacity group-hover:opacity-100',
|
||||
favorites.includes(product.id) ? 'opacity-100 text-red-500 hover:text-red-600' : ''
|
||||
)}
|
||||
title={favorites.includes(product.id) ? 'Aus Favoriten entfernen' : 'Zu Favoriten hinzufügen'}
|
||||
className="absolute top-2 right-2 z-10 rounded-full bg-white/90 p-2 text-gray-400 hover:text-red-500 focus:outline-none focus:ring-2 focus:ring-[#8D6B1D] focus:ring-offset-2 transition-colors duration-200"
|
||||
>
|
||||
{favorites.includes(product.id) ? (
|
||||
<HeartIconSolid className="h-5 w-5" />
|
||||
<HeartIcon className="h-5 w-5 text-red-500" />
|
||||
) : (
|
||||
<HeartIcon className="h-5 w-5" />
|
||||
<HeartOutlineIcon className="h-5 w-5" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Category Badge */}
|
||||
<div className="absolute top-3 left-3">
|
||||
<span className="inline-flex items-center rounded-full bg-[#8D6B1D] px-2 py-1 text-xs font-medium text-white">
|
||||
{product.category}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Out of Stock Overlay */}
|
||||
{/* Stock Status */}
|
||||
{!product.inStock && (
|
||||
<div className="absolute inset-0 flex items-center justify-center rounded-lg bg-black bg-opacity-50">
|
||||
<span className="rounded-md bg-white px-3 py-1 text-sm font-semibold text-gray-900">
|
||||
<div className="absolute inset-0 z-5 flex items-center justify-center bg-gray-900/50">
|
||||
<span className="rounded-md bg-white px-3 py-1 text-sm font-medium text-gray-900">
|
||||
Ausverkauft
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Product Info */}
|
||||
<div className="mt-4 flex justify-between">
|
||||
<div>
|
||||
{/* Product Info - Non-clickable */}
|
||||
<div className="mt-3 flex-1 flex flex-col justify-between">
|
||||
<div className="flex-1">
|
||||
<h3 className="text-sm text-gray-700">
|
||||
<a href="#" className="hover:text-gray-900 transition-colors duration-200">
|
||||
{product.name}
|
||||
</a>
|
||||
</h3>
|
||||
<p className="mt-1 text-xs text-gray-500">{product.brand}</p>
|
||||
|
||||
{/* Rating */}
|
||||
<div className="mt-1 flex items-center">
|
||||
<div className="mt-2 flex items-center">
|
||||
<div className="flex items-center">
|
||||
{[0, 1, 2, 3, 4].map((rating) => (
|
||||
<StarIcon
|
||||
key={rating}
|
||||
aria-hidden="true"
|
||||
className={classNames(
|
||||
product.rating > rating ? 'text-yellow-400' : 'text-gray-300',
|
||||
'h-4 w-4 flex-shrink-0'
|
||||
)}
|
||||
className={`
|
||||
${product.rating > rating ? 'text-yellow-400' : 'text-gray-300'}
|
||||
h-3 w-3 flex-shrink-0
|
||||
`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<p className="ml-1 text-sm text-gray-500">({product.reviewCount})</p>
|
||||
<p className="ml-1 text-xs text-gray-600">({product.reviews})</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-lg font-medium text-gray-900">{product.price}</p>
|
||||
</div>
|
||||
|
||||
{/* Add to Cart Button */}
|
||||
{/* Price and Cart Button - Non-clickable for product page */}
|
||||
<div className="mt-4 flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className="text-lg font-medium text-gray-900">€{product.price}</p>
|
||||
{product.originalPrice && (
|
||||
<p className="text-sm text-gray-500 line-through">€{product.originalPrice}</p>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
addToCart(product.id)
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// Add to cart logic here
|
||||
console.log('Added to cart:', product.name);
|
||||
}}
|
||||
disabled={!product.inStock}
|
||||
className={classNames(
|
||||
'mt-4 flex w-full items-center justify-center rounded-md border border-transparent px-8 py-2 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-[#8D6B1D] focus:ring-offset-2',
|
||||
product.inStock
|
||||
? 'bg-[#8D6B1D] text-white hover:bg-[#7A5E1A]'
|
||||
className={`
|
||||
inline-flex items-center rounded-md px-3 py-2 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 transition-colors duration-200
|
||||
${product.inStock
|
||||
? 'bg-[#8D6B1D] text-white hover:bg-[#7A5E1A] focus-visible:outline-[#8D6B1D]'
|
||||
: 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
)}
|
||||
}
|
||||
`}
|
||||
>
|
||||
<ShoppingCartIcon className="mr-2 h-4 w-4" />
|
||||
{product.inStock ? 'In den Warenkorb' : 'Ausverkauft'}
|
||||
<ShoppingCartIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* List View */}
|
||||
{viewMode === 'list' && (
|
||||
<div className="space-y-4">
|
||||
{sortedProducts.map((product) => (
|
||||
<div key={product.id} className="flex items-center space-x-4 rounded-lg border border-gray-200 bg-white p-4 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
{/* Product Image */}
|
||||
<div className="relative h-24 w-24 flex-shrink-0 overflow-hidden rounded-md bg-gray-200">
|
||||
<img
|
||||
src={product.image}
|
||||
alt={product.name}
|
||||
className="h-full w-full object-cover object-center"
|
||||
/>
|
||||
{product.badge && (
|
||||
<div className="absolute -top-1 -left-1">
|
||||
<span className={`
|
||||
inline-flex items-center rounded-full px-2 py-1 text-xs font-medium
|
||||
${product.badge === 'Bestseller' ? 'bg-yellow-100 text-yellow-800' : ''}
|
||||
${product.badge === 'Neu' ? 'bg-green-100 text-green-800' : ''}
|
||||
${product.badge === 'Sale' ? 'bg-red-100 text-red-800' : ''}
|
||||
`}>
|
||||
{product.badge}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Product Details */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">{product.name}</h3>
|
||||
<p className="text-sm text-gray-500">{product.brand}</p>
|
||||
<p className="mt-1 text-sm text-gray-600">{product.description}</p>
|
||||
|
||||
{/* Rating */}
|
||||
<div className="mt-2 flex items-center">
|
||||
<div className="flex items-center">
|
||||
{[0, 1, 2, 3, 4].map((rating) => (
|
||||
<StarIcon
|
||||
key={rating}
|
||||
className={`
|
||||
${product.rating > rating ? 'text-yellow-400' : 'text-gray-300'}
|
||||
h-4 w-4 flex-shrink-0
|
||||
`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<p className="ml-2 text-sm text-gray-600">({product.reviews} Bewertungen)</p>
|
||||
{!product.inStock && (
|
||||
<span className="ml-4 inline-flex items-center rounded-full bg-red-100 px-2 py-1 text-xs font-medium text-red-800">
|
||||
Ausverkauft
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Price and Actions */}
|
||||
<div className="ml-6 flex flex-col items-end space-y-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className="text-xl font-medium text-gray-900">€{product.price}</p>
|
||||
{product.originalPrice && (
|
||||
<p className="text-sm text-gray-500 line-through">€{product.originalPrice}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<button
|
||||
onClick={() => toggleFavorite(product.id)}
|
||||
className="rounded-full bg-gray-50 p-2 text-gray-400 hover:text-red-500 focus:outline-none focus:ring-2 focus:ring-[#8D6B1D] focus:ring-offset-2"
|
||||
>
|
||||
{favorites.includes(product.id) ? (
|
||||
<HeartIcon className="h-5 w-5 text-red-500" />
|
||||
) : (
|
||||
<HeartOutlineIcon className="h-5 w-5" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
<button
|
||||
disabled={!product.inStock}
|
||||
className={`
|
||||
inline-flex items-center rounded-md px-4 py-2 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
|
||||
${product.inStock
|
||||
? 'bg-[#8D6B1D] text-white hover:bg-[#7A5E1A] focus-visible:outline-[#8D6B1D]'
|
||||
: 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
}
|
||||
`}
|
||||
>
|
||||
<ShoppingCartIcon className="mr-2 h-4 w-4" />
|
||||
{product.inStock ? 'In Warenkorb' : 'Ausverkauft'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</PageLayout>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user