187 lines
9.7 KiB
TypeScript
187 lines
9.7 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
|
|
interface PropertyFiltersProps {
|
|
onFilterChange: (filters: FilterState) => void;
|
|
}
|
|
|
|
export interface FilterState {
|
|
search: string;
|
|
type: string;
|
|
budgetMin: string;
|
|
budgetMax: string;
|
|
bhk: string;
|
|
sortBy: string;
|
|
}
|
|
|
|
export default function PropertyFilters({ onFilterChange }: PropertyFiltersProps) {
|
|
const [filters, setFilters] = useState<FilterState>({
|
|
search: "",
|
|
type: "all",
|
|
budgetMin: "",
|
|
budgetMax: "",
|
|
bhk: "all",
|
|
sortBy: "popularity"
|
|
});
|
|
|
|
const [showFilters, setShowFilters] = useState(false);
|
|
|
|
const handleFilterUpdate = (key: keyof FilterState, value: string) => {
|
|
const newFilters = { ...filters, [key]: value };
|
|
setFilters(newFilters);
|
|
onFilterChange(newFilters);
|
|
};
|
|
|
|
const clearFilters = () => {
|
|
const defaultFilters: FilterState = {
|
|
search: "",
|
|
type: "all",
|
|
budgetMin: "",
|
|
budgetMax: "",
|
|
bhk: "all",
|
|
sortBy: "popularity"
|
|
};
|
|
setFilters(defaultFilters);
|
|
onFilterChange(defaultFilters);
|
|
};
|
|
|
|
const hasActiveFilters = filters.search || filters.type !== "all" || filters.budgetMin || filters.budgetMax || filters.bhk !== "all" || filters.sortBy !== "popularity";
|
|
|
|
return (
|
|
<div className="bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 sticky top-0 z-40">
|
|
<div className="max-w-7xl mx-auto px-6 py-4">
|
|
{/* Main Filter Bar */}
|
|
<div className="flex flex-col md:flex-row gap-4 items-center">
|
|
{/* Search */}
|
|
<div className="flex-1 w-full">
|
|
<div className="relative">
|
|
<svg className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
</svg>
|
|
<input
|
|
type="text"
|
|
placeholder="Try Godrej or Whitefield"
|
|
value={filters.search}
|
|
onChange={(e) => handleFilterUpdate("search", e.target.value)}
|
|
className="w-full pl-10 pr-4 py-3 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent bg-white dark:bg-gray-800 text-foreground"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Type Dropdown */}
|
|
<select
|
|
value={filters.type}
|
|
onChange={(e) => handleFilterUpdate("type", e.target.value)}
|
|
className="px-4 py-3 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-primary bg-white dark:bg-gray-800 text-foreground cursor-pointer"
|
|
>
|
|
<option value="all">All Types</option>
|
|
<option value="Apartments">Apartments</option>
|
|
<option value="Premium Homes">Premium Homes</option>
|
|
<option value="Luxury">Luxury</option>
|
|
<option value="Villas">Villas</option>
|
|
<option value="Plots">Plots</option>
|
|
</select>
|
|
|
|
{/* Budget Dropdown */}
|
|
<button
|
|
onClick={() => setShowFilters(!showFilters)}
|
|
className="px-4 py-3 border border-gray-300 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 flex items-center gap-2 bg-white dark:bg-gray-900 text-foreground"
|
|
>
|
|
<span>Budget</span>
|
|
{filters.budgetMin || filters.budgetMax ? (
|
|
<span className="bg-primary text-white text-xs px-2 py-0.5 rounded-full">1</span>
|
|
) : null}
|
|
</button>
|
|
|
|
{/* More Filters */}
|
|
<button
|
|
onClick={() => setShowFilters(!showFilters)}
|
|
className="px-4 py-3 border border-gray-300 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 flex items-center gap-2 bg-white dark:bg-gray-900 text-foreground"
|
|
>
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
|
|
</svg>
|
|
<span>Filters</span>
|
|
</button>
|
|
|
|
{/* Sort By */}
|
|
<select
|
|
value={filters.sortBy}
|
|
onChange={(e) => handleFilterUpdate("sortBy", e.target.value)}
|
|
className="px-4 py-3 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-primary bg-white dark:bg-gray-800 text-foreground cursor-pointer"
|
|
>
|
|
<option value="popularity">Sort By: Popularity</option>
|
|
<option value="price-low">Price: Low to High</option>
|
|
<option value="price-high">Price: High to Low</option>
|
|
<option value="newest">Newest First</option>
|
|
</select>
|
|
|
|
{/* Clear Filters Button */}
|
|
{hasActiveFilters && (
|
|
<button
|
|
onClick={clearFilters}
|
|
className="px-4 py-3 border border-red-300 dark:border-red-700 text-red-600 dark:text-red-400 rounded-lg hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors whitespace-nowrap font-medium flex items-center gap-2"
|
|
>
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
Clear
|
|
</button>
|
|
)}
|
|
|
|
{/* Help Me Decide CTA */}
|
|
<button className="px-6 py-3 bg-primary text-white rounded-lg hover:bg-blue-700 transition-colors whitespace-nowrap font-medium">
|
|
Help Me Decide
|
|
</button>
|
|
</div>
|
|
|
|
{/* Expanded Filters */}
|
|
{showFilters && (
|
|
<div className="mt-4 p-4 border border-gray-200 dark:border-gray-800 rounded-lg bg-gray-50 dark:bg-gray-800">
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Min Budget (Cr)</label>
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
placeholder="1.0"
|
|
value={filters.budgetMin}
|
|
onChange={(e) => handleFilterUpdate("budgetMin", e.target.value)}
|
|
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-900 text-foreground"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Max Budget (Cr)</label>
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
placeholder="5.0"
|
|
value={filters.budgetMax}
|
|
onChange={(e) => handleFilterUpdate("budgetMax", e.target.value)}
|
|
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-900 text-foreground"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">BHK</label>
|
|
<select
|
|
value={filters.bhk}
|
|
onChange={(e) => handleFilterUpdate("bhk", e.target.value)}
|
|
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-900 text-foreground"
|
|
>
|
|
<option value="all">All BHK</option>
|
|
<option value="1">1 BHK</option>
|
|
<option value="2">2 BHK</option>
|
|
<option value="3">3 BHK</option>
|
|
<option value="4">4 BHK</option>
|
|
<option value="4+">4+ BHK</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|