feat: add date range filter with predefined options for apartment availability and creation dates
This commit is contained in:
84
src/App.jsx
84
src/App.jsx
@@ -21,6 +21,64 @@ const SORT_OPTIONS = [
|
|||||||
{ value: "recent", label: "Plus recent" },
|
{ value: "recent", label: "Plus recent" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const DATE_RANGE_OPTIONS = [
|
||||||
|
{ value: "", label: "Date: Toutes" },
|
||||||
|
{ value: "today", label: "Aujourd'hui" },
|
||||||
|
{ value: "yesterday", label: "Hier" },
|
||||||
|
{ value: "last7", label: "7 derniers jours" },
|
||||||
|
{ value: "last30", label: "30 derniers jours" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const parseDate = (value) => {
|
||||||
|
if (!value) return null;
|
||||||
|
const date = new Date(value);
|
||||||
|
return Number.isNaN(date.getTime()) ? null : date;
|
||||||
|
};
|
||||||
|
|
||||||
|
const matchesDateRange = (annonce, range) => {
|
||||||
|
if (!range) return true;
|
||||||
|
|
||||||
|
const today = new Date();
|
||||||
|
const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
||||||
|
const startOfTomorrow = new Date(startOfToday);
|
||||||
|
startOfTomorrow.setDate(startOfTomorrow.getDate() + 1);
|
||||||
|
|
||||||
|
let start = null;
|
||||||
|
let end = null;
|
||||||
|
|
||||||
|
switch (range) {
|
||||||
|
case "today":
|
||||||
|
start = startOfToday;
|
||||||
|
end = startOfTomorrow;
|
||||||
|
break;
|
||||||
|
case "yesterday": {
|
||||||
|
const startOfYesterday = new Date(startOfToday);
|
||||||
|
startOfYesterday.setDate(startOfYesterday.getDate() - 1);
|
||||||
|
start = startOfYesterday;
|
||||||
|
end = startOfToday;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "last7": {
|
||||||
|
start = new Date(startOfToday);
|
||||||
|
start.setDate(start.getDate() - 6);
|
||||||
|
end = startOfTomorrow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "last30": {
|
||||||
|
start = new Date(startOfToday);
|
||||||
|
start.setDate(start.getDate() - 29);
|
||||||
|
end = startOfTomorrow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dates = [parseDate(annonce.DATE_DISPO), parseDate(annonce.createdAt)].filter(Boolean);
|
||||||
|
if (!dates.length) return false;
|
||||||
|
return dates.some((date) => date >= start && date < end);
|
||||||
|
};
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [annonces, setAnnonces] = useState([]);
|
const [annonces, setAnnonces] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
@@ -33,6 +91,7 @@ function App() {
|
|||||||
balcon: null,
|
balcon: null,
|
||||||
maxPrix: "",
|
maxPrix: "",
|
||||||
minSurface: "",
|
minSurface: "",
|
||||||
|
dateRange: "",
|
||||||
});
|
});
|
||||||
const [showFilters, setShowFilters] = useState(false);
|
const [showFilters, setShowFilters] = useState(false);
|
||||||
|
|
||||||
@@ -94,6 +153,9 @@ function App() {
|
|||||||
if (filters.minSurface) {
|
if (filters.minSurface) {
|
||||||
list = list.filter((a) => a.SURFACE >= parseInt(filters.minSurface));
|
list = list.filter((a) => a.SURFACE >= parseInt(filters.minSurface));
|
||||||
}
|
}
|
||||||
|
if (filters.dateRange) {
|
||||||
|
list = list.filter((a) => matchesDateRange(a, filters.dateRange));
|
||||||
|
}
|
||||||
|
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case "prix_asc":
|
case "prix_asc":
|
||||||
@@ -127,6 +189,7 @@ function App() {
|
|||||||
filters.balcon !== null,
|
filters.balcon !== null,
|
||||||
!!filters.maxPrix,
|
!!filters.maxPrix,
|
||||||
!!filters.minSurface,
|
!!filters.minSurface,
|
||||||
|
!!filters.dateRange,
|
||||||
].filter(Boolean).length;
|
].filter(Boolean).length;
|
||||||
|
|
||||||
const stats = useMemo(() => {
|
const stats = useMemo(() => {
|
||||||
@@ -302,6 +365,26 @@ function App() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<span className="text-xs text-sand-600 font-medium">Date</span>
|
||||||
|
<select
|
||||||
|
value={filters.dateRange}
|
||||||
|
onChange={(e) =>
|
||||||
|
setFilters((f) => ({
|
||||||
|
...f,
|
||||||
|
dateRange: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className="px-2 py-1 text-xs border border-sand-200 rounded-lg bg-white text-sand-700 focus:outline-none focus:ring-1 focus:ring-warm-300"
|
||||||
|
>
|
||||||
|
{DATE_RANGE_OPTIONS.map((option) => (
|
||||||
|
<option key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
{activeFilterCount > 0 && (
|
{activeFilterCount > 0 && (
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -311,6 +394,7 @@ function App() {
|
|||||||
balcon: null,
|
balcon: null,
|
||||||
maxPrix: "",
|
maxPrix: "",
|
||||||
minSurface: "",
|
minSurface: "",
|
||||||
|
dateRange: "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className="text-xs text-warm-600 hover:text-warm-800 font-semibold"
|
className="text-xs text-warm-600 hover:text-warm-800 font-semibold"
|
||||||
|
|||||||
Reference in New Issue
Block a user