← back to Wine Finder Next
components/CategoryDropdowns.tsx
249 lines
'use client'
import { useState, useEffect } from 'react'
export interface FilterOptions {
wineTypes: string[]
regions: string[]
grapes: string[]
priceRanges: { label: string; min: number; max: number }[]
vintages: number[]
}
interface CategoryDropdownsProps {
onFilterChange: (filters: {
wineType?: string
region?: string
grape?: string
priceRange?: { min: number; max: number }
vintage?: number
}) => void
}
// Real wine categories from database
const WINE_TYPES = [
'All Types',
'Red Wine',
'White Wine',
'Rosé',
'Sparkling',
'Dessert Wine',
'Fortified Wine'
]
const POPULAR_REGIONS = [
'All Regions',
'Napa Valley, California',
'Sonoma, California',
'Paso Robles, California',
'Bordeaux, France',
'Burgundy, France',
'Champagne, France',
'Tuscany, Italy',
'Piedmont, Italy',
'Rioja, Spain',
'Ribera del Duero, Spain',
'Barossa Valley, Australia',
'Marlborough, New Zealand',
'Mendoza, Argentina',
'Willamette Valley, Oregon',
'Columbia Valley, Washington'
]
const POPULAR_GRAPES = [
'All Grapes',
'Cabernet Sauvignon',
'Pinot Noir',
'Merlot',
'Syrah / Shiraz',
'Zinfandel',
'Malbec',
'Chardonnay',
'Sauvignon Blanc',
'Pinot Grigio / Pinot Gris',
'Riesling',
'Moscato'
]
const PRICE_RANGES = [
{ label: 'All Prices', min: 0, max: 100000 },
{ label: 'Under $15', min: 0, max: 15 },
{ label: '$15 - $25', min: 15, max: 25 },
{ label: '$25 - $50', min: 25, max: 50 },
{ label: '$50 - $100', min: 50, max: 100 },
{ label: '$100 - $250', min: 100, max: 250 },
{ label: 'Over $250', min: 250, max: 100000 }
]
// Generate vintage years (current year back to 1990)
const currentYear = new Date().getFullYear()
const VINTAGES = [
'All Vintages',
...Array.from({ length: currentYear - 1989 }, (_, i) => currentYear - i)
]
export default function CategoryDropdowns({ onFilterChange }: CategoryDropdownsProps) {
const [selectedType, setSelectedType] = useState('All Types')
const [selectedRegion, setSelectedRegion] = useState('All Regions')
const [selectedGrape, setSelectedGrape] = useState('All Grapes')
const [selectedPriceRange, setSelectedPriceRange] = useState(PRICE_RANGES[0])
const [selectedVintage, setSelectedVintage] = useState<string>('All Vintages')
// Update filters when selections change
useEffect(() => {
const filters: any = {}
if (selectedType !== 'All Types') filters.wineType = selectedType
if (selectedRegion !== 'All Regions') filters.region = selectedRegion
if (selectedGrape !== 'All Grapes') filters.grape = selectedGrape
if (selectedPriceRange.label !== 'All Prices') {
filters.priceRange = { min: selectedPriceRange.min, max: selectedPriceRange.max }
}
if (selectedVintage !== 'All Vintages') filters.vintage = parseInt(selectedVintage)
onFilterChange(filters)
}, [selectedType, selectedRegion, selectedGrape, selectedPriceRange, selectedVintage, onFilterChange])
const selectClass = "w-full px-4 py-2.5 bg-white border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-wine-500 focus:border-transparent hover:border-wine-300 transition-all cursor-pointer appearance-none bg-no-repeat bg-right"
const selectStyle = {
backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`,
backgroundPosition: 'right 0.5rem center',
backgroundSize: '1.5em 1.5em',
paddingRight: '2.5rem'
}
return (
<div className="bg-gradient-to-br from-purple-50 to-pink-50 rounded-xl p-6 shadow-sm border border-purple-100 mb-6">
<h3 className="text-lg font-bold text-gray-800 mb-4 flex items-center gap-2">
<span className="text-2xl">🔍</span>
Filter Wines
</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4">
{/* Wine Type */}
<div>
<label className="block text-xs font-semibold text-gray-700 mb-1.5">
Wine Type
</label>
<select
value={selectedType}
onChange={(e) => setSelectedType(e.target.value)}
className={selectClass}
style={selectStyle}
>
{WINE_TYPES.map(type => (
<option key={type} value={type}>{type}</option>
))}
</select>
</div>
{/* Region */}
<div>
<label className="block text-xs font-semibold text-gray-700 mb-1.5">
Region
</label>
<select
value={selectedRegion}
onChange={(e) => setSelectedRegion(e.target.value)}
className={selectClass}
style={selectStyle}
>
{POPULAR_REGIONS.map(region => (
<option key={region} value={region}>{region}</option>
))}
</select>
</div>
{/* Grape Varietal */}
<div>
<label className="block text-xs font-semibold text-gray-700 mb-1.5">
Grape Varietal
</label>
<select
value={selectedGrape}
onChange={(e) => setSelectedGrape(e.target.value)}
className={selectClass}
style={selectStyle}
>
{POPULAR_GRAPES.map(grape => (
<option key={grape} value={grape}>{grape}</option>
))}
</select>
</div>
{/* Price Range */}
<div>
<label className="block text-xs font-semibold text-gray-700 mb-1.5">
Price Range
</label>
<select
value={selectedPriceRange.label}
onChange={(e) => {
const range = PRICE_RANGES.find(r => r.label === e.target.value)
if (range) setSelectedPriceRange(range)
}}
className={selectClass}
style={selectStyle}
>
{PRICE_RANGES.map(range => (
<option key={range.label} value={range.label}>{range.label}</option>
))}
</select>
</div>
{/* Vintage Year */}
<div>
<label className="block text-xs font-semibold text-gray-700 mb-1.5">
Vintage
</label>
<select
value={selectedVintage}
onChange={(e) => setSelectedVintage(e.target.value)}
className={selectClass}
style={selectStyle}
>
{VINTAGES.map(vintage => (
<option key={vintage} value={vintage}>{vintage}</option>
))}
</select>
</div>
</div>
{/* Active Filters Display */}
<div className="mt-4 flex flex-wrap gap-2">
{selectedType !== 'All Types' && (
<span className="inline-flex items-center gap-1 px-3 py-1 bg-wine-100 text-wine-800 rounded-full text-xs font-medium">
{selectedType}
<button onClick={() => setSelectedType('All Types')} className="hover:text-wine-900">×</button>
</span>
)}
{selectedRegion !== 'All Regions' && (
<span className="inline-flex items-center gap-1 px-3 py-1 bg-purple-100 text-purple-800 rounded-full text-xs font-medium">
{selectedRegion}
<button onClick={() => setSelectedRegion('All Regions')} className="hover:text-purple-900">×</button>
</span>
)}
{selectedGrape !== 'All Grapes' && (
<span className="inline-flex items-center gap-1 px-3 py-1 bg-pink-100 text-pink-800 rounded-full text-xs font-medium">
{selectedGrape}
<button onClick={() => setSelectedGrape('All Grapes')} className="hover:text-pink-900">×</button>
</span>
)}
{selectedPriceRange.label !== 'All Prices' && (
<span className="inline-flex items-center gap-1 px-3 py-1 bg-gold-100 text-gold-800 rounded-full text-xs font-medium">
{selectedPriceRange.label}
<button onClick={() => setSelectedPriceRange(PRICE_RANGES[0])} className="hover:text-gold-900">×</button>
</span>
)}
{selectedVintage !== 'All Vintages' && (
<span className="inline-flex items-center gap-1 px-3 py-1 bg-burgundy-100 text-burgundy-800 rounded-full text-xs font-medium">
{selectedVintage}
<button onClick={() => setSelectedVintage('All Vintages')} className="hover:text-burgundy-900">×</button>
</span>
)}
</div>
</div>
)
}