diff --git a/app/components/FilterMenu.tsx b/app/components/FilterMenu.tsx index 2425ed3..00a7cbd 100644 --- a/app/components/FilterMenu.tsx +++ b/app/components/FilterMenu.tsx @@ -5,7 +5,6 @@ import { AccordionIcon, AccordionItem, AccordionPanel, - Button, Box, } from "@nycplanning/streetscape"; @@ -37,9 +36,6 @@ export const FilterMenu = ({ children, defaultIndex }: FilterMenuProps) => ( {children} - diff --git a/app/components/GoToDistrictBtn/GoToCityCouncilDistrictBtn.test.tsx b/app/components/GoToDistrictBtn/GoToCityCouncilDistrictBtn.test.tsx new file mode 100644 index 0000000..6a1624f --- /dev/null +++ b/app/components/GoToDistrictBtn/GoToCityCouncilDistrictBtn.test.tsx @@ -0,0 +1,28 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { GoToCityCouncilDistrictBtn } from "./GoToCityCouncilDistrictBtn"; + +describe("GoToCommunityDistrictBtn", () => { + it("should call 'goToDistrict' when all ids are provided", () => { + const goToDistrict = vi.fn(); + render( + , + ); + fireEvent.click(screen.getByText(/Go to Selected District/)); + expect(goToDistrict).toHaveBeenCalled(); + }); + + it("should not call 'goToDistrict' when an id is null", () => { + const goToDistrict = vi.fn(); + render( + , + ); + fireEvent.click(screen.getByText(/Go to Selected District/)); + expect(goToDistrict).not.toHaveBeenCalled(); + }); +}); diff --git a/app/components/GoToDistrictBtn/GoToCityCouncilDistrictBtn.tsx b/app/components/GoToDistrictBtn/GoToCityCouncilDistrictBtn.tsx new file mode 100644 index 0000000..eca549b --- /dev/null +++ b/app/components/GoToDistrictBtn/GoToCityCouncilDistrictBtn.tsx @@ -0,0 +1,22 @@ +import { GoToDistrictBtn, GoToDistrictBtnProps } from "."; + +export interface GoToCityCouncilDistrictBtnProps + extends Pick { + districtId: string | null; +} + +export function GoToCityCouncilDistrictBtn({ + districtId, + ...props +}: GoToCityCouncilDistrictBtnProps) { + return ( + + ); +} diff --git a/app/components/GoToDistrictBtn/GoToCommunityDistrictBtn.test.tsx b/app/components/GoToDistrictBtn/GoToCommunityDistrictBtn.test.tsx new file mode 100644 index 0000000..d56f502 --- /dev/null +++ b/app/components/GoToDistrictBtn/GoToCommunityDistrictBtn.test.tsx @@ -0,0 +1,30 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { GoToCommunityDistrictBtn } from "./GoToCommunityDistrictBtn"; + +describe("GoToCommunityDistrictBtn", () => { + it("should call 'goToDistrict' when all ids are provided", () => { + const goToDistrict = vi.fn(); + render( + , + ); + fireEvent.click(screen.getByText(/Go to Selected District/)); + expect(goToDistrict).toHaveBeenCalled(); + }); + + it("should not call 'goToDistrict' when an id is null", () => { + const goToDistrict = vi.fn(); + render( + , + ); + fireEvent.click(screen.getByText(/Go to Selected District/)); + expect(goToDistrict).not.toHaveBeenCalled(); + }); +}); diff --git a/app/components/GoToDistrictBtn/GoToCommunityDistrictBtn.tsx b/app/components/GoToDistrictBtn/GoToCommunityDistrictBtn.tsx new file mode 100644 index 0000000..f4777ee --- /dev/null +++ b/app/components/GoToDistrictBtn/GoToCommunityDistrictBtn.tsx @@ -0,0 +1,24 @@ +import { GoToDistrictBtn, GoToDistrictBtnProps } from "."; + +export interface GoToCommunityDistrictBtnProps + extends Pick { + boroughId: string | null; + districtId: string | null; +} + +export function GoToCommunityDistrictBtn({ + boroughId, + districtId, + ...props +}: GoToCommunityDistrictBtnProps) { + return ( + + ); +} diff --git a/app/components/GoToDistrictBtn/index.test.tsx b/app/components/GoToDistrictBtn/index.test.tsx new file mode 100644 index 0000000..f40316d --- /dev/null +++ b/app/components/GoToDistrictBtn/index.test.tsx @@ -0,0 +1,24 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { GoToDistrictBtn } from "."; + +describe("GoToDistrictBtn", () => { + it("should render with 'Go To' text", () => { + const goToDistrict = vi.fn(); + render(); + expect(screen.getByText(/Go to Selected District/)).toBeVisible(); + }); + + it("should call 'goToDistrict' when path is a string", () => { + const goToDistrict = vi.fn(); + render(); + fireEvent.click(screen.getByText(/Go to Selected District/)); + expect(goToDistrict).toHaveBeenCalled(); + }); + + it("should not call 'goToDistrict' when path is null", () => { + const goToDistrict = vi.fn(); + render(); + fireEvent.click(screen.getByText(/Go to Selected District/)); + expect(goToDistrict).not.toHaveBeenCalled(); + }); +}); diff --git a/app/components/GoToDistrictBtn/index.tsx b/app/components/GoToDistrictBtn/index.tsx new file mode 100644 index 0000000..af49267 --- /dev/null +++ b/app/components/GoToDistrictBtn/index.tsx @@ -0,0 +1,20 @@ +import { Button } from "@nycplanning/streetscape"; + +export { GoToCityCouncilDistrictBtn } from "./GoToCityCouncilDistrictBtn"; + +export interface GoToDistrictBtnProps { + goToDistrict: (path: string) => void; + path: string | null; +} +export function GoToDistrictBtn({ goToDistrict, path }: GoToDistrictBtnProps) { + return ( + + ); +} diff --git a/app/root.tsx b/app/root.tsx index 2f9355b..a50597d 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -15,6 +15,8 @@ import { ScrollRestoration, isRouteErrorResponse, useLoaderData, + useLocation, + useNavigate, useRouteError, useSearchParams, } from "@remix-run/react"; @@ -38,6 +40,11 @@ import { CityCouncilDistrictDropdown, } from "./components/AdminDropdown"; import { URLSearchParamsInit } from "react-router-dom"; +import { + GoToCityCouncilDistrictBtn, + GoToDistrictBtn, +} from "./components/GoToDistrictBtn"; +import { GoToCommunityDistrictBtn } from "./components/GoToDistrictBtn/GoToCommunityDistrictBtn"; export type BoroughId = null | string; export type DistrictType = null | "cd" | "ccd"; @@ -126,6 +133,8 @@ function Document({ } export default function App() { + const navigate = useNavigate(); + const { pathname } = useLocation(); const [searchParams, setSearchParams] = useSearchParams(); const districtType = searchParams.get("districtType") as DistrictType; const boroughId = searchParams.get("boroughId") as BoroughId; @@ -146,33 +155,62 @@ export default function App() { | undefined, ) => setSearchParams(nextSearchParams, { replace: true }); - const AdminDropdowns = () => ( - - - - - {districtType !== "ccd" ? ( - (nextPath: string) => { + // Avoid adding the same path to the history stack multiple times + if (currentPath !== `/${nextPath}`) + navigate({ + pathname: nextPath, + search: `?${searchParams.toString()}`, + }); + }; + + const goToNextDistrict = goToDistrict(pathname); + + const FilterMenuContent = () => ( + <> + + - ) : ( - + + {districtType !== "ccd" ? ( + + ) : ( + + )} + + {districtType === null && ( + + )} + {districtType === "ccd" && ( + + )} + {districtType === "cd" && ( + )} - + ); return ( @@ -185,12 +223,12 @@ export default function App() { - + - +