diff --git a/bun.lock b/bun.lock
index b67e06e..a99a667 100644
--- a/bun.lock
+++ b/bun.lock
@@ -17,6 +17,7 @@
"react": "^19.0.0",
"react-device-detect": "^2.2.3",
"react-dom": "^19.0.0",
+ "react-loading-skeleton": "^3.5.0",
"react-router": "^7.5.0",
"react-swipeable": "^7.0.2",
"tailwindcss": "^4.1.3",
@@ -475,6 +476,8 @@
"react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
+ "react-loading-skeleton": ["react-loading-skeleton@3.5.0", "", { "peerDependencies": { "react": ">=16.8.0" } }, "sha512-gxxSyLbrEAdXTKgfbpBEFZCO/P153DnqSCQau2+o6lNy1jgMRr2MmRmOzMmyrwSaSYLRB8g7b0waYPmUjz7IhQ=="],
+
"react-router": ["react-router@7.5.0", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0", "turbo-stream": "2.4.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-estOHrRlDMKdlQa6Mj32gIks4J+AxNsYoE0DbTTxiMy2mPzZuWSDU+N85/r1IlNR7kGfznF3VCUlvc5IUO+B9g=="],
"react-swipeable": ["react-swipeable@7.0.2", "", { "peerDependencies": { "react": "^16.8.3 || ^17 || ^18 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-v1Qx1l+aC2fdxKa9aKJiaU/ZxmJ5o98RMoFwUqAAzVWUcxgfHFXDDruCKXhw6zIYXm6V64JiHgP9f6mlME5l8w=="],
diff --git a/package.json b/package.json
index 9b3aaa0..8ebff35 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"react": "^19.0.0",
"react-device-detect": "^2.2.3",
"react-dom": "^19.0.0",
+ "react-loading-skeleton": "^3.5.0",
"react-router": "^7.5.0",
"react-swipeable": "^7.0.2",
"tailwindcss": "^4.1.3",
diff --git a/src/components/Map.tsx b/src/components/Map.tsx
index f05e8ff..a16a19d 100644
--- a/src/components/Map.tsx
+++ b/src/components/Map.tsx
@@ -687,11 +687,13 @@ function Map({ maxZoom = 1 }: MapProps) {
))}
-
+
+
+
diff --git a/src/components/SearchFilters.tsx b/src/components/SearchFilters.tsx
index 185bdac..bf8e279 100644
--- a/src/components/SearchFilters.tsx
+++ b/src/components/SearchFilters.tsx
@@ -50,13 +50,13 @@ function SearchFilters({
const debouncedArea = useDebounce(inModal ? areaInModal : area, 1000);
const debouncedFloor = useDebounce(inModal ? floorInModal : floor, 1000);
- const [costChanged, setCostChanged] = useState(true);
- const [areaChanged, setAreaChanged] = useState(true);
- const [floorChanged, setFloorChanged] = useState(true);
+ const [costTouched, setCostTouched] = useState(false);
+ const [areaTouched, setAreaTouched] = useState(false);
+ const [floorTouched, setFloorTouched] = useState(false);
- const debouncedCostChanged = useDebounce(costChanged, 1000);
- const debouncedAreaChanged = useDebounce(areaChanged, 1000);
- const debouncedFloorChanged = useDebounce(floorChanged, 1000);
+ const debouncedCostChanged = useDebounce(costTouched, 1000);
+ const debouncedAreaChanged = useDebounce(areaTouched, 1000);
+ const debouncedFloorChanged = useDebounce(floorTouched, 1000);
const [searchParams, setSearchParams] = useSearchParams();
@@ -65,62 +65,28 @@ function SearchFilters({
"filters",
"unitTypes",
project,
- debouncedCostChanged ? debouncedCost : undefined,
- debouncedAreaChanged ? debouncedArea : undefined,
- debouncedFloorChanged ? debouncedFloor : undefined,
+ searchParams.get("cost"),
+ searchParams.get("floor"),
+ searchParams.get("area"),
view,
],
- enabled: !!project,
+ enabled: !!project && !searchParams.has("unitTypes"),
+ initialData: searchParams.has("unitTypes")
+ ? searchParams.getAll("unitTypes")
+ : undefined,
queryFn: () =>
api
.get(
`units/filters/unitTypes?${project ? `project=${project}` : ""}${
view !== "Any view" ? `&view=${view}` : ""
}${
- debouncedCost[0] >= 0 && debouncedCost[1] >= 0
- ? `&cost=${debouncedCost.map(Math.round).join()}`
+ searchParams.has("cost") ? `&cost=${searchParams.get("cost")}` : ""
+ }${
+ searchParams.has("floor")
+ ? `&floor=${searchParams.get("floor")}`
: ""
}${
- debouncedFloor[0] >= 0 && debouncedFloor[1] >= 0
- ? `&floor=${debouncedFloor.map(Math.round).join()}`
- : ""
- }${
- debouncedArea[0] >= 0 && debouncedArea[1] >= 0
- ? `&area=${debouncedArea.map(Math.round).join()}`
- : ""
- }`
- )
- .json
(),
- });
-
- const { data: viewsInFilters } = useQuery({
- queryKey: [
- "filters",
- "views",
- project,
- debouncedCostChanged ? debouncedCost : undefined,
- debouncedAreaChanged ? debouncedArea : undefined,
- debouncedFloorChanged ? debouncedFloor : undefined,
- unitTypes,
- ],
- enabled: !!project,
- queryFn: () =>
- api
- .get(
- `units/filters/views?${project ? `project=${project}` : ""}${unitTypes
- .map((unitType) => `&unitTypes=${unitType}`)
- .join("")}${
- debouncedCost[0] >= 0 && debouncedCost[1] >= 0
- ? `&cost=${debouncedCost.map(Math.round).join()}`
- : ""
- }${
- debouncedFloor[0] >= 0 && debouncedFloor[1] >= 0
- ? `&floor=${debouncedFloor.map(Math.round).join()}`
- : ""
- }${
- debouncedArea[0] >= 0 && debouncedArea[1] >= 0
- ? `&area=${debouncedArea.map(Math.round).join()}`
- : ""
+ searchParams.has("area") ? `&area=${searchParams.get("area")}` : ""
}`
)
.json(),
@@ -131,25 +97,29 @@ function SearchFilters({
"filters",
"cost",
project,
- debouncedAreaChanged ? debouncedArea : undefined,
- debouncedFloorChanged ? debouncedFloor : undefined,
unitTypes,
+ searchParams.get("floor"),
+ searchParams.get("area"),
view,
],
- enabled: !!project,
+ enabled: !!project && !searchParams.has("cost") && !debouncedCostChanged,
+ initialData: searchParams.has("cost")
+ ? {
+ min: searchParams.get("cost")!.split(",").map(Number)[0],
+ max: searchParams.get("cost")!.split(",").map(Number)[1],
+ }
+ : undefined,
queryFn: () =>
api
.get(
`units/filters/cost?${project ? `project=${project}` : ""}${unitTypes
.map((unitType) => `&unitTypes=${unitType}`)
.join("")}${view !== "Any view" ? `&view=${view}` : ""}${
- debouncedFloor[0] >= 0 && debouncedFloor[1] >= 0
- ? `&floor=${debouncedFloor.map(Math.round).join()}`
+ searchParams.has("floor")
+ ? `&floor=${searchParams.get("floor")}`
: ""
}${
- debouncedArea[0] >= 0 && debouncedArea[1] >= 0
- ? `&area=${debouncedArea.map(Math.round).join()}`
- : ""
+ searchParams.has("area") ? `&area=${searchParams.get("area")}` : ""
}`
)
.json<{ min: number; max: number }>(),
@@ -160,25 +130,32 @@ function SearchFilters({
"filters",
"floor",
project,
- debouncedCostChanged ? debouncedCost : undefined,
- debouncedAreaChanged ? debouncedArea : undefined,
unitTypes,
+ searchParams.get("cost"),
+ searchParams.get("area"),
view,
],
- enabled: !!project,
+ enabled: !!project && !searchParams.has("floor") && !debouncedFloorChanged,
+ initialData: searchParams.has("floor")
+ ? {
+ min: searchParams.get("floor")!.split(",").map(Number)[0],
+ max: searchParams.get("floor")!.split(",").map(Number)[1],
+ }
+ : floorInModal.every((bound) => bound >= 0)
+ ? {
+ min: floorInModal[0],
+ max: floorInModal[1],
+ }
+ : undefined,
queryFn: () =>
api
.get(
`units/filters/floor?${project ? `project=${project}` : ""}${unitTypes
.map((unitType) => `&unitTypes=${unitType}`)
.join("")}${view !== "Any view" ? `&view=${view}` : ""}${
- debouncedCost[0] >= 0 && debouncedCost[1] >= 0
- ? `&cost=${debouncedCost.map(Math.round).join()}`
- : ""
+ searchParams.has("cost") ? `&cost=${searchParams.get("cost")}` : ""
}${
- debouncedArea[0] >= 0 && debouncedArea[1] >= 0
- ? `&area=${debouncedArea.map(Math.round).join()}`
- : ""
+ searchParams.has("area") ? `&area=${searchParams.get("area")}` : ""
}`
)
.json<{ min: number; max: number }>(),
@@ -189,95 +166,67 @@ function SearchFilters({
"filters",
"area",
project,
- debouncedCostChanged ? debouncedCost : undefined,
- debouncedFloorChanged ? debouncedFloor : undefined,
unitTypes,
+ searchParams.get("cost"),
+ searchParams.get("floor"),
view,
],
- enabled: !!project,
+ enabled: !!project && !searchParams.has("area") && !debouncedAreaChanged,
+ initialData: searchParams.has("area")
+ ? {
+ min: searchParams.get("area")!.split(",").map(Number)[0],
+ max: searchParams.get("area")!.split(",").map(Number)[1],
+ }
+ : areaInModal.every((bound) => bound >= 0)
+ ? {
+ min: areaInModal[0],
+ max: areaInModal[1],
+ }
+ : undefined,
queryFn: () =>
api
.get(
`units/filters/area?${project ? `project=${project}` : ""}${unitTypes
.map((unitType) => `&unitTypes=${unitType}`)
.join("")}${view !== "Any view" ? `&view=${view}` : ""}${
- debouncedCost[0] >= 0 && debouncedCost[1] >= 0
- ? `&cost=${debouncedCost.map(Math.round).join()}`
- : ""
+ searchParams.has("cost") ? `&cost=${searchParams.get("cost")}` : ""
}${
- debouncedFloor[0] >= 0 && debouncedFloor[1] >= 0
- ? `&floor=${debouncedFloor.map(Math.round).join()}`
+ searchParams.has("floor")
+ ? `&floor=${searchParams.get("floor")}`
: ""
}`
)
.json<{ min: number; max: number }>(),
});
- useEffect(() => {
- const projectValue = searchParams.get("project") || projects[0].title;
- if (projectValue) setProject(projectValue);
-
- const viewValue = searchParams.get("view");
- if (viewValue) setView(viewValue);
-
- const unitTypesValue = searchParams.getAll("unitTypes");
- if (unitTypesValue) setUnitTypes(unitTypesValue);
- }, [searchParams]);
-
- function resetFilters() {
- window.location.href = "/search";
- }
-
- useEffect(() => {
- if (areaInFilters) {
- setAreaInModal([areaInFilters.min, areaInFilters.max]);
- setAreaChanged(false);
- }
- }, [areaInFilters]);
-
- useEffect(() => {
- if (costInFilters) {
- setCostInModal([costInFilters.min, costInFilters.max]);
- return () => setCostChanged(false);
- }
- }, [costInFilters]);
-
- useEffect(() => {
- if (floorInFilters) {
- setFloorInModal([floorInFilters.min, floorInFilters.max]);
- setFloorChanged(false);
- }
- }, [floorInFilters]);
-
- useEffect(() => {
- if (inModal) return;
- setCost(costInModal);
- }, [costInModal, inModal]);
-
- useEffect(() => {
- if (inModal) return;
- setArea(areaInModal);
- }, [areaInModal, inModal]);
-
- useEffect(() => {
- if (inModal) return;
- setFloor(floorInModal);
- }, [floorInModal, inModal]);
-
- function handleCostChange([min, max]: [number, number]) {
- setCostInModal([min, max]);
- setCostChanged(true);
- }
-
- function handleFloorChange([min, max]: [number, number]) {
- setFloorInModal([min, max]);
- setFloorChanged(true);
- }
-
- function handleAreaChange([min, max]: [number, number]) {
- setAreaInModal([min, max]);
- setAreaChanged(true);
- }
+ const { data: viewsInFilters } = useQuery({
+ queryKey: [
+ "filters",
+ "views",
+ project,
+ searchParams.get("cost"),
+ searchParams.get("floor"),
+ searchParams.get("area"),
+ unitTypes,
+ ],
+ enabled: !!project,
+ queryFn: () =>
+ api
+ .get(
+ `units/filters/views?${project ? `project=${project}` : ""}${unitTypes
+ .map((unitType) => `&unitTypes=${unitType}`)
+ .join("")}${
+ searchParams.has("cost") ? `&cost=${searchParams.get("cost")}` : ""
+ }${
+ searchParams.has("floor")
+ ? `&floor=${searchParams.get("floor")}`
+ : ""
+ }${
+ searchParams.has("area") ? `&area=${searchParams.get("area")}` : ""
+ }`
+ )
+ .json(),
+ });
const { data: count } = useQuery({
queryKey: [
@@ -285,10 +234,10 @@ function SearchFilters({
"count",
project,
unitTypes,
+ searchParams.get("cost"),
+ searchParams.get("area"),
+ searchParams.get("floor"),
view,
- debouncedCost,
- debouncedArea,
- debouncedFloor,
],
enabled:
!!project &&
@@ -304,57 +253,137 @@ function SearchFilters({
`units/count?${project ? `project=${project}` : ""}${unitTypes
.map((unitType) => `&unitTypes=${unitType}`)
.join("")}${view !== "Any view" ? `&view=${view}` : ""}${
- debouncedCost ? `&cost=${debouncedCost.map(Math.round).join()}` : ""
+ searchParams.has("cost") ? `&cost=${searchParams.get("cost")}` : ""
}${
- debouncedArea ? `&area=${debouncedArea.map(Math.round).join()}` : ""
+ searchParams.has("area") ? `&area=${searchParams.get("area")}` : ""
}${
- debouncedFloor
- ? `&floor=${debouncedFloor.map(Math.round).join()}`
+ searchParams.has("floor")
+ ? `&floor=${searchParams.get("floor")}`
: ""
}`
)
.json(),
});
- function handleClose() {
+ useEffect(() => {
const projectValue = searchParams.get("project") || projects[0].title;
if (projectValue) setProject(projectValue);
- const viewValue = searchParams.get("view");
- setView(viewValue || "Any view");
-
const unitTypesValue = searchParams.getAll("unitTypes");
if (unitTypesValue) setUnitTypes(unitTypesValue);
- setInModal(false);
- }
+
+ const costValue = searchParams.get("cost");
+ if (costValue)
+ setCostInModal(costValue.split(",").map(Number) as [number, number]);
+
+ const floorValue = searchParams.get("floor");
+ if (floorValue)
+ setFloorInModal(floorValue.split(",").map(Number) as [number, number]);
+
+ const areaValue = searchParams.get("area");
+ if (areaValue)
+ setAreaInModal(areaValue.split(",").map(Number) as [number, number]);
+
+ const viewValue = searchParams.get("view");
+ if (viewValue) setView(viewValue);
+ }, [searchParams]);
+
+ useEffect(() => {
+ if (costInFilters) setCostInModal([costInFilters.min, costInFilters.max]);
+ }, [costInFilters]);
+
+ useEffect(() => {
+ if (floorInFilters)
+ setFloorInModal([floorInFilters.min, floorInFilters.max]);
+ }, [floorInFilters]);
+
+ useEffect(() => {
+ if (areaInFilters) setAreaInModal([areaInFilters.min, areaInFilters.max]);
+ }, [areaInFilters]);
+
+ useEffect(() => {
+ if (inModal) return;
+ setCost(costInModal);
+ }, [costInModal, inModal]);
+
+ useEffect(() => {
+ if (inModal) return;
+ setFloor(floorInModal);
+ }, [floorInModal, inModal]);
+
+ useEffect(() => {
+ if (inModal) return;
+ setArea(areaInModal);
+ }, [areaInModal, inModal]);
+
+ useEffect(() => {
+ if (debouncedCostChanged)
+ setSearchParams((prev) => {
+ prev.set("cost", `${debouncedCost[0]},${debouncedCost[1]}`);
+ return prev;
+ });
+ }, [debouncedCost, debouncedCostChanged]);
+
+ useEffect(() => {
+ if (debouncedAreaChanged)
+ setSearchParams((prev) => {
+ prev.set("area", `${debouncedArea[0]},${debouncedArea[1]}`);
+ return prev;
+ });
+ }, [debouncedArea, debouncedAreaChanged]);
+
+ useEffect(() => {
+ if (debouncedFloorChanged)
+ setSearchParams((prev) => {
+ prev.set("floor", `${debouncedFloor[0]},${debouncedFloor[1]}`);
+ return prev;
+ });
+ }, [debouncedFloor, debouncedFloorChanged]);
function handleSelectProject(project: Project) {
setProject(project.title);
- if (!inModal)
- setSearchParams((prev) => {
- prev.set("project", project.title);
- return prev;
- });
+ setSearchParams((prev) => {
+ prev.set("project", project.title);
+ return prev;
+ });
}
function handleSelectUnitTypes(unitTypes: string[]) {
setUnitTypes(unitTypes);
- if (!inModal)
- setSearchParams((prev) => {
- prev.delete("unitTypes");
- unitTypes.forEach((unitType) => prev.append("unitTypes", unitType));
- return prev;
- });
+ setSearchParams((prev) => {
+ prev.delete("unitTypes");
+ unitTypes.forEach((unitType) => prev.append("unitTypes", unitType));
+ return prev;
+ });
}
function handleSelectView(view: string) {
setView(view);
- if (!inModal)
- setSearchParams((prev) => {
- if (view !== "Any view") prev.set("view", view);
- else prev.delete("view");
- return prev;
- });
+ setSearchParams((prev) => {
+ if (view !== "Any view") prev.set("view", view);
+ else prev.delete("view");
+ return prev;
+ });
+ }
+
+ function resetFilters() {
+ setCostTouched(false);
+ setFloorTouched(false);
+ setAreaTouched(false);
+ if (costInFilters) setCostInModal([costInFilters.min, costInFilters.max]);
+ if (floorInFilters)
+ setFloorInModal([floorInFilters.min, floorInFilters.max]);
+ if (areaInFilters) setAreaInModal([areaInFilters.min, areaInFilters.max]);
+ setView("Any view");
+ setUnitTypes([]);
+ setSearchParams((prev) => {
+ prev.delete("cost");
+ prev.delete("floor");
+ prev.delete("area");
+ prev.delete("view");
+ prev.delete("unitTypes");
+ return prev;
+ });
}
function applyFilters() {
@@ -378,7 +407,7 @@ function SearchFilters({
{inModal && (
setInModal(false)}
/>
)}
setInModal(false)}
>
)}
- {costInFilters &&
- areaInFilters &&
- floorInFilters &&
- viewsInFilters &&
- unitTypesInFilters && (
- <>
-
-
-
- {inModal ? "Filters" : "Search"}
-
-
- {project && (
-
title === project)!
- }
- />
- )}
-
-
-
-
- <>
-
-
-
-
-
-
-
-
- {inModal ? (
-
- ) : (
-
- {count && (
-
- {count} Apartments found
-
- )}
-
- )}
-
+
+ {unitTypesInFilters && (
+
+ Apartment type
+
+
)}
+
+
+
+ {costInFilters && (
+
+
+
+ )}
+
+
+ {floorInFilters && (
+
+
+
+ )}
+
+
+ {areaInFilters && (
+
+
+
+ )}
+
+
+ {viewsInFilters && (
+
+
+
+ )}
+
+
+
+ {inModal ? (
+
+ Show{" "}
+
+ {count !== undefined && (
+
+ {count}
+
+ )}
+ {" "}
+ apartments
+
+ ) : (
+
+
+ {count ? (
+
+ {count}
+
+ ) : (
+
+ ...
+
+ )}
+
+ Apartments found
+
+ )}
+
setInModal(true)}
+ >
+
+
+
+ Filters
+
+
+
+
+
+
+ Reset filters
+
+
+
>
);
diff --git a/src/components/UnitCard.tsx b/src/components/UnitCard.tsx
index e137007..0acc14a 100644
--- a/src/components/UnitCard.tsx
+++ b/src/components/UnitCard.tsx
@@ -1,8 +1,10 @@
-import { useFavoritesUnitsStore } from '../stores/useFavoritesUnitsStore';
-import { IUnit } from '../types/IUnit';
-import FilledHeartIcon from './icons/FilledHeartIcon';
-import HeartIcon from './icons/HeartIcon';
-import Button from './ui/Button';
+import { useFavoritesUnitsStore } from "../stores/useFavoritesUnitsStore";
+import { IUnit } from "../types/IUnit";
+import FilledHeartIcon from "./icons/FilledHeartIcon";
+import HeartIcon from "./icons/HeartIcon";
+import Button from "./ui/Button";
+import "react-loading-skeleton/dist/skeleton.css";
+import Skeleton from "react-loading-skeleton";
function UnitCard({ unit }: { unit: IUnit }) {
const { favoriteUnits, setFavoriteUnits } = useFavoritesUnitsStore();
@@ -18,22 +20,26 @@ function UnitCard({ unit }: { unit: IUnit }) {
}
return (
-
-
-
-
{unit.project}
-
-
- {(unit.unitNo.split('-')[0] === 'W' ? 'West' : 'East') + ' Wing'}
+
+
+
+
+ {unit.project || }
+
+
+
+
+ {`${unit.unitNo.split("-")[0] === "W" ? "West" : "East"} Wing`}
+
-
-
Floor {unit.floor}
-
-
{unit.unitNo}
+
+
Floor {unit.floor}
+
+
{unit.unitNo}
-
-
+
+
{favoriteUnits.some(
(favoriteUnit) => favoriteUnit.id === unit.id
) ? (
@@ -44,15 +50,15 @@ function UnitCard({ unit }: { unit: IUnit }) {
-
-
+
+
{`${unit.unitType}, ${unit.squareFt.toLocaleString(undefined, {
maximumFractionDigits: 2,
})} Sqft`}
-
- {`AED ${Intl.NumberFormat('ar-AE', {
- currency: 'AED',
+
+ {`AED ${Intl.NumberFormat("ar-AE", {
+ currency: "AED",
minimumFractionDigits: 0,
}).format(unit.salesPrice)}`}
diff --git a/src/components/ui/MultiRangeSlider.tsx b/src/components/ui/MultiRangeSlider.tsx
index 53f33b3..54958f8 100644
--- a/src/components/ui/MultiRangeSlider.tsx
+++ b/src/components/ui/MultiRangeSlider.tsx
@@ -17,6 +17,7 @@ interface IMultiRangeSlider {
disabled?: boolean;
label: string;
onChange: (value: [number, number]) => void;
+ setTouched?: (value: boolean) => void;
}
function MultiRangeSlider({
@@ -27,6 +28,7 @@ function MultiRangeSlider({
onChange,
offset,
label,
+ setTouched,
disabled = false,
}: IMultiRangeSlider) {
const [current, setCurrent] = useState<"min" | "max" | null>(null);
@@ -59,19 +61,26 @@ function MultiRangeSlider({
}
function handleMouseUp() {
- setCurrent(null);
+ if (current) {
+ setCurrent(null);
+ setTouched?.(true);
+ }
}
useEffect(() => {
- if (current) {
- document.addEventListener("mousemove", handleChange as EventListener);
- document.addEventListener("mouseup", handleMouseUp);
- document.addEventListener("mouseleave", handleMouseUp);
- }
+ document.addEventListener("mousemove", handleChange as EventListener);
+ document.addEventListener("mouseup", handleMouseUp);
+ document.addEventListener("mouseleave", handleMouseUp);
+ document.addEventListener("touchmove", handleChange as EventListener);
+ document.addEventListener("touchend", handleMouseUp);
+ document.addEventListener("touchcancel", handleMouseUp);
return () => {
document.removeEventListener("mousemove", handleChange as EventListener);
document.removeEventListener("mouseup", handleMouseUp);
document.removeEventListener("mouseleave", handleMouseUp);
+ document.removeEventListener("touchmove", handleChange as EventListener);
+ document.removeEventListener("touchend", handleMouseUp);
+ document.removeEventListener("touchcancel", handleMouseUp);
};
}, [current]);
@@ -84,10 +93,10 @@ function MultiRangeSlider({
{label}
- {Intl.NumberFormat("en").format(Math.round(currentMin))}
+ {Intl.NumberFormat("en").format(Math.ceil(currentMin))}
- {Intl.NumberFormat("en").format(Math.round(currentMax))}
+ {Intl.NumberFormat("en").format(Math.ceil(currentMax))}
{
+ if (el)
+ el.style.maxHeight = `calc(100vh - ${
+ el?.getBoundingClientRect().y
+ }px - 0.278vw)`;
+ }}
+ className="absolute 2xl:mt-[0.278vw] 2xl:pt-[0.278vw] mt-1 p-1 2xl:space-y-[0.139vw] space-y-0.5 shadow-[0px_2px_8px_rgba(0,0,0,0.15)] overflow-auto rounded-xl bg-white w-full z-10"
>
{options.map((option, index) => (
{
- // const filters = queryClient.getQueryData(["filters", project]);
- // if (filters) {
- // setActiveFiltersCount(
- // +!!view +
- // +!!unitTypes.length +
- // +(debouncedCost[0] !== filters.minCost) +
- // +(debouncedCost[1] !== filters.maxCost) +
- // +(debouncedArea[0] !== filters.minArea) +
- // +(debouncedArea[1] !== filters.maxArea) +
- // +(debouncedFloor[0] !== filters.minFloor) +
- // +(debouncedFloor[1] !== filters.maxFloor)
- // );
- // }
- // }, [
- // queryClient,
- // unitTypes,
- // view,
- // project,
- // debouncedCost,
- // cost,
- // debouncedArea,
- // area,
- // debouncedFloor,
- // floor,
- // ]);
+ useEffect(
+ () =>
+ setActiveFiltersCount(
+ +searchParams.has("view") +
+ +searchParams.has("unitTypes") +
+ +searchParams.has("cost") +
+ +searchParams.has("floor") +
+ +searchParams.has("area")
+ ),
+ [searchParams]
+ );
return (
<>
@@ -187,7 +171,18 @@ function SearchPage() {
/>
- {project &&
+ {isLoading ? (
+
+ {Array.from({ length: STEP }).map((_, i) => (
+
+ ))}
+
+ ) : (
+ project &&
unitTypes &&
debouncedCost &&
debouncedArea &&
@@ -211,8 +206,17 @@ function SearchPage() {
{data?.pages.map((page) =>
page.map((unit) => )
)}
+ {isFetchingNextPage &&
+ Array.from({ length: STEP }).map((_, i) => (
+
+ ))}
- )}
+ )
+ )}
{showButtons && (
@@ -229,11 +233,11 @@ function SearchPage() {
Filters
- {/* {!!activeFiltersCount && (
+ {!!activeFiltersCount && (
{activeFiltersCount}
- )} */}
+ )}