Deploy
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
'use client'
|
||||
import { X } from 'lucide-react'
|
||||
|
||||
export interface FilterState {
|
||||
category: string
|
||||
maxPrice: number
|
||||
inStockOnly: boolean
|
||||
}
|
||||
|
||||
interface Category { id: string; title: string }
|
||||
|
||||
interface ProductFiltersProps {
|
||||
categories: Category[]
|
||||
filters: FilterState
|
||||
onChange: (f: FilterState) => void
|
||||
onReset: () => void
|
||||
isMobile?: boolean
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
export default function ProductFilters({ categories, filters, onChange, onReset, isMobile, onClose }: ProductFiltersProps) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{isMobile && (
|
||||
<div className="flex items-center justify-between pb-4 border-b border-border">
|
||||
<h2 className="font-semibold text-foreground">Filters</h2>
|
||||
<button onClick={onClose} className="p-1 hover:bg-muted rounded transition-colors">
|
||||
<X className="h-5 w-5 text-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Category */}
|
||||
{categories.length > 0 && (
|
||||
<div>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground mb-3 uppercase tracking-wider">Category</h3>
|
||||
<div className="space-y-1">
|
||||
<button
|
||||
onClick={() => onChange({ ...filters, category: '' })}
|
||||
className={`w-full text-left px-3 py-2 rounded-lg text-sm transition-colors ${filters.category === '' ? 'bg-primary text-primary-foreground font-medium' : 'hover:bg-muted text-muted-foreground hover:text-foreground'}`}
|
||||
>
|
||||
All Products
|
||||
</button>
|
||||
{categories.map(cat => (
|
||||
<button
|
||||
key={cat.id}
|
||||
onClick={() => onChange({ ...filters, category: cat.id })}
|
||||
className={`w-full text-left px-3 py-2 rounded-lg text-sm transition-colors ${filters.category === cat.id ? 'bg-primary text-primary-foreground font-medium' : 'hover:bg-muted text-muted-foreground hover:text-foreground'}`}
|
||||
>
|
||||
{cat.title}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Price */}
|
||||
<div>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground mb-3 uppercase tracking-wider">Max Price</h3>
|
||||
<div className="space-y-1">
|
||||
{[0, 250, 500, 1000, 2500].map(price => (
|
||||
<button
|
||||
key={price}
|
||||
onClick={() => onChange({ ...filters, maxPrice: price })}
|
||||
className={`w-full text-left px-3 py-2 rounded-lg text-sm transition-colors ${filters.maxPrice === price ? 'bg-primary text-primary-foreground font-medium' : 'hover:bg-muted text-muted-foreground hover:text-foreground'}`}
|
||||
>
|
||||
{price === 0 ? 'Any price' : `Under R${price.toLocaleString()}`}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* In Stock */}
|
||||
<div>
|
||||
<button
|
||||
onClick={() => onChange({ ...filters, inStockOnly: !filters.inStockOnly })}
|
||||
className="flex items-center gap-3 w-full"
|
||||
>
|
||||
<div className={`w-10 h-6 rounded-full transition-colors relative flex-shrink-0 ${filters.inStockOnly ? 'bg-primary' : 'bg-muted-foreground/30'}`}>
|
||||
<div className={`absolute top-1 w-4 h-4 rounded-full bg-white shadow transition-all ${filters.inStockOnly ? 'left-5' : 'left-1'}`} />
|
||||
</div>
|
||||
<span className="text-sm text-foreground">In stock only</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={onReset}
|
||||
className="w-full text-xs text-muted-foreground hover:text-foreground transition-colors underline text-left"
|
||||
>
|
||||
Reset all filters
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user