diff --git a/bun.lock b/bun.lock index 2c0561c..b67e06e 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "dependencies": { "@tailwindcss/vite": "^4.1.3", "@tanstack/react-query": "^5.74.4", + "@tanstack/react-query-devtools": "^5.74.7", "@tweenjs/tween.js": "^25.0.0", "@uidotdev/usehooks": "^2.4.1", "clsx": "^2.1.1", @@ -218,8 +219,12 @@ "@tanstack/query-core": ["@tanstack/query-core@5.74.4", "", {}, "sha512-YuG0A0+3i9b2Gfo9fkmNnkUWh5+5cFhWBN0pJAHkHilTx6A0nv8kepkk4T4GRt4e5ahbtFj2eTtkiPcVU1xO4A=="], + "@tanstack/query-devtools": ["@tanstack/query-devtools@5.74.7", "", {}, "sha512-nSNlfuGdnHf4yB0S+BoNYOE1o3oAH093weAYZolIHfS2stulyA/gWfSk/9H4ZFk5mAAHb5vNqAeJOmbdcGPEQw=="], + "@tanstack/react-query": ["@tanstack/react-query@5.74.4", "", { "dependencies": { "@tanstack/query-core": "5.74.4" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-mAbxw60d4ffQ4qmRYfkO1xzRBPUEf/72Dgo3qqea0J66nIKuDTLEqQt0ku++SDFlMGMnB6uKDnEG1xD/TDse4Q=="], + "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.74.7", "", { "dependencies": { "@tanstack/query-devtools": "5.74.7" }, "peerDependencies": { "@tanstack/react-query": "^5.74.7", "react": "^18 || ^19" } }, "sha512-j60esTQF+ES0x52kQUYOX0Z8AJUcqCGANj6GaOf8J3YQz2bZPB1imLSw4SFeM3Ozv8uO/X/Dmh3IT1z+y57ZLQ=="], + "@tweenjs/tween.js": ["@tweenjs/tween.js@25.0.0", "", {}, "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A=="], "@types/bun": ["@types/bun@1.2.9", "", { "dependencies": { "bun-types": "1.2.9" } }, "sha512-epShhLGQYc4Bv/aceHbmBhOz1XgUnuTZgcxjxk+WXwNyDXavv5QHD1QEFV0FwbTSQtNq6g4ZcV6y0vZakTjswg=="], diff --git a/package.json b/package.json index 49a8c99..9b3aaa0 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "dependencies": { "@tailwindcss/vite": "^4.1.3", "@tanstack/react-query": "^5.74.4", + "@tanstack/react-query-devtools": "^5.74.7", "@tweenjs/tween.js": "^25.0.0", "@uidotdev/usehooks": "^2.4.1", "clsx": "^2.1.1", diff --git a/src/components/ProjectSelect.tsx b/src/components/ProjectSelect.tsx index ca5a684..7f79789 100644 --- a/src/components/ProjectSelect.tsx +++ b/src/components/ProjectSelect.tsx @@ -7,15 +7,15 @@ import Select from "./ui/Select"; function ProjectSelect({ projects, onSelect, + defaultProject, }: { projects: Project[]; onSelect: (project: Project) => void; + defaultProject: Project; }) { - const [selectedProject, setSelectedProject] = useState(projects[0]); + const [selectedProject, setSelectedProject] = useState(defaultProject); - useEffect(() => { - onSelect(selectedProject); - }, [selectedProject]); + useEffect(() => onSelect(selectedProject), [selectedProject]); return ( <> @@ -45,9 +45,11 @@ function ProjectSelect({ options={projects.map((project) => project.title)} onSelect={(option) => setSelectedProject( - projects.find((project) => project.title === option) || projects[0] + projects.find((project) => project.title === option) || + defaultProject ) } + defaultOption={defaultProject.title} className="md:hidden" /> diff --git a/src/components/SearchFilters.tsx b/src/components/SearchFilters.tsx index a80152a..0b557ea 100644 --- a/src/components/SearchFilters.tsx +++ b/src/components/SearchFilters.tsx @@ -24,12 +24,14 @@ export interface Filters { function SearchFilters({ inModal = false, + filters, ref, }: { inModal?: boolean; + filters?: Filters; ref?: RefObject; }) { - const [project, setProject] = useState(projects[0].title); + const [project, setProject] = useState(); const [unitTypes, setUnitTypes] = useState([]); const [view, setView] = useState("Any view"); @@ -37,19 +39,10 @@ function SearchFilters({ const navigate = useNavigate(); - const { data: filters } = useQuery({ - queryKey: ["filters", project], - queryFn: () => - api - .get(`units/filters?${project ? `project=${project}` : ""}`) - .json(), - }); - useEffect(() => { const projectValue = searchParams.get("project"); - // const unitTypesValue = searchParams.getAll("unitTypes"); if (projectValue) setProject(projectValue); - // if (unitTypesValue) setUnitTypes(unitTypesValue); + const viewValue = searchParams.get("view"); if (viewValue) setView(viewValue); }, [searchParams]); @@ -110,6 +103,7 @@ function SearchFilters({ debouncedMinFloor, debouncedMaxFloor, ], + enabled: !!project, queryFn: () => api .get( @@ -138,43 +132,6 @@ function SearchFilters({ .json(), }); - useEffect(() => { - if (debouncedMinCost && debouncedMaxCost) - setSearchParams((prev) => { - prev.set( - "cost", - `${Math.round(debouncedMinCost)},${Math.round(debouncedMaxCost)}` - ); - return prev; - }); - - if (debouncedMinArea && debouncedMaxArea) - setSearchParams((prev) => { - prev.set( - "area", - `${Math.round(debouncedMinArea)},${Math.round(debouncedMaxArea)}` - ); - return prev; - }); - - if (debouncedMinFloor && debouncedMaxFloor) - setSearchParams((prev) => { - prev.set( - "floor", - `${Math.round(debouncedMinFloor)},${Math.round(debouncedMaxFloor)}` - ); - return prev; - }); - }, [ - debouncedMinCost, - debouncedMaxCost, - debouncedMinArea, - debouncedMaxArea, - debouncedMinFloor, - debouncedMaxFloor, - setSearchParams, - ]); - function handleProjectSelect(project: Project) { setProject(project.title); setSearchParams((prev) => { @@ -208,7 +165,13 @@ function SearchFilters({

Search

- + {project && ( + title === project)!} + /> + )}
{filters && ( @@ -255,6 +218,7 @@ function SearchFilters({ label="View" options={["Any view", ...filters.views]} onSelect={handleViewSelect} + defaultOption={view} />
diff --git a/src/components/UnitTypesSelect.tsx b/src/components/UnitTypesSelect.tsx index 43c4a08..06a0d11 100644 --- a/src/components/UnitTypesSelect.tsx +++ b/src/components/UnitTypesSelect.tsx @@ -18,7 +18,6 @@ function UnitTypesSelect({ useEffect(() => { const unitTypesValue = searchParams.getAll("unitTypes"); - if (unitTypesValue) setSelectedUnitTypes(unitTypesValue); }, [searchParams]); diff --git a/src/components/ui/Select.tsx b/src/components/ui/Select.tsx index 3c402b9..75f7bba 100644 --- a/src/components/ui/Select.tsx +++ b/src/components/ui/Select.tsx @@ -6,24 +6,26 @@ import { useClickAway } from "@uidotdev/usehooks"; import clsx from "clsx"; import ChevronDownIcon from "../icons/ChevronDownIcon"; import CheckIcon from "../icons/CheckIcon"; + function Select({ options, onSelect, className = "", label = "", + defaultOption = "", }: { options: string[]; onSelect: (option: string) => void; + defaultOption: string; className?: string; label?: string; }) { const [isShow, setIsShow] = useState(false); - const [selectedOption, setSelectedOption] = useState(options[0]); + const [selectedOption, setSelectedOption] = useState(defaultOption); + const ref = useClickAway(() => setIsShow(false)); - useEffect(() => { - onSelect(selectedOption); - }, [selectedOption]); + useEffect(() => onSelect(selectedOption), [selectedOption]); return (
diff --git a/src/data/projects.ts b/src/data/projects.ts index fd19249..336e50c 100644 --- a/src/data/projects.ts +++ b/src/data/projects.ts @@ -1,4 +1,6 @@ -export const projects = [ +import Project from "../types/Project"; + +export const projects: Project[] = [ { title: "Rove Home Marasi Drive", img: "/images/search/rove_home_marasi_drive.png", diff --git a/src/main.tsx b/src/main.tsx index 71273d5..f6bf20e 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,4 +1,5 @@ import "./index.css"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { QueryClientProvider } from "@tanstack/react-query"; import { createRoot } from "react-dom/client"; import { createBrowserRouter, RouterProvider } from "react-router"; @@ -60,6 +61,7 @@ createRoot(document.getElementById("root")!).render( + ); diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx index 6f55970..b8b7a2e 100644 --- a/src/pages/SearchPage.tsx +++ b/src/pages/SearchPage.tsx @@ -1,9 +1,9 @@ -import { useInfiniteQuery } from "@tanstack/react-query"; +import { useInfiniteQuery, useQuery } from "@tanstack/react-query"; import { api } from "../api/ky"; import { IUnit } from "../types/IUnit"; import UnitCard from "../components/UnitCard"; import { useEffect, useRef, useState } from "react"; -import SearchFilters from "../components/SearchFilters"; +import SearchFilters, { Filters } from "../components/SearchFilters"; import { useNavigate, useSearchParams } from "react-router"; import Button from "../components/ui/Button"; import FiltersIcon from "../components/icons/FiltersIcon"; @@ -17,12 +17,37 @@ function SearchPage() { const [searchParams] = useSearchParams(); const navigate = useNavigate(); - const project = searchParams.get("project"); - const unitTypes = searchParams.getAll("unitTypes"); - const cost = searchParams.getAll("cost"); - const floor = searchParams.getAll("floor"); - const area = searchParams.getAll("area"); - const view = searchParams.get("view"); + // const project = searchParams.get("project"); + // const unitTypes = searchParams.getAll("unitTypes"); + // const cost = searchParams.getAll("cost"); + // const floor = searchParams.getAll("floor"); + // const area = searchParams.getAll("area"); + // const view = searchParams.get("view"); + + const [project, setProject] = useState(); + const [unitTypes, setUnitTypes] = useState([]); + const [cost, setCost] = useState([]); + const [floor, setFloor] = useState([]); + const [area, setArea] = useState([]); + const [view, setView] = useState(); + + const { data: filters } = useQuery({ + queryKey: ["filters", project], + enabled: !!project, + queryFn: () => + api + .get(`units/filters?${project ? `project=${project}` : ""}`) + .json(), + }); + + useEffect(() => { + setProject(searchParams.get("project")); + setUnitTypes(searchParams.getAll("unitTypes")); + setCost(searchParams.getAll("cost")); + setFloor(searchParams.getAll("floor")); + setArea(searchParams.getAll("area")); + setView(searchParams.get("view")); + }, [searchParams]); const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({ @@ -95,7 +120,11 @@ function SearchPage() { return (
- +
{project && unitTypes && cost && area && floor && (