This commit is contained in:
Vula Builder
2026-06-23 08:38:41 +00:00
parent f97af17105
commit fd9ef3f59d
+94
View File
@@ -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>
)
}