Skip to content

Commit

Permalink
Implement go to selected geo button
Browse files Browse the repository at this point in the history
Implement a go to selected geo button
Navigate to capital projects of city council or community district

closes #67
  • Loading branch information
TangoYankee committed Aug 14, 2024
1 parent 5923db5 commit e877149
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 28 deletions.
4 changes: 0 additions & 4 deletions app/components/FilterMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
AccordionIcon,
AccordionItem,
AccordionPanel,
Button,
Box,
} from "@nycplanning/streetscape";

Expand Down Expand Up @@ -37,9 +36,6 @@ export const FilterMenu = ({ children, defaultIndex }: FilterMenuProps) => (
</AccordionButton>
<AccordionPanel pb={0} borderTopWidth="1px" borderColor="gray.200" px={0}>
{children}
<Button width="full" isDisabled={true} mt={4}>
Go to Selected District
</Button>
</AccordionPanel>
</AccordionItem>
</Accordion>
Expand Down
28 changes: 28 additions & 0 deletions app/components/GoToDistrictBtn/GoToCityCouncilDistrictBtn.test.tsx
Original file line number Diff line number Diff line change
@@ -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(
<GoToCityCouncilDistrictBtn
goToDistrict={goToDistrict}
districtId={"10"}
/>,
);
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(
<GoToCityCouncilDistrictBtn
goToDistrict={goToDistrict}
districtId={null}
/>,
);
fireEvent.click(screen.getByText(/Go to Selected District/));
expect(goToDistrict).not.toHaveBeenCalled();
});
});
22 changes: 22 additions & 0 deletions app/components/GoToDistrictBtn/GoToCityCouncilDistrictBtn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { GoToDistrictBtn, GoToDistrictBtnProps } from ".";

export interface GoToCityCouncilDistrictBtnProps
extends Pick<GoToDistrictBtnProps, "goToDistrict"> {
districtId: string | null;
}

export function GoToCityCouncilDistrictBtn({
districtId,
...props
}: GoToCityCouncilDistrictBtnProps) {
return (
<GoToDistrictBtn
path={
districtId === null
? null
: `city-council-districts/${districtId}/capital-projects`
}
{...props}
/>
);
}
30 changes: 30 additions & 0 deletions app/components/GoToDistrictBtn/GoToCommunityDistrictBtn.test.tsx
Original file line number Diff line number Diff line change
@@ -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(
<GoToCommunityDistrictBtn
goToDistrict={goToDistrict}
boroughId={"1"}
districtId={"01"}
/>,
);
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(
<GoToCommunityDistrictBtn
goToDistrict={goToDistrict}
boroughId={"1"}
districtId={null}
/>,
);
fireEvent.click(screen.getByText(/Go to Selected District/));
expect(goToDistrict).not.toHaveBeenCalled();
});
});
24 changes: 24 additions & 0 deletions app/components/GoToDistrictBtn/GoToCommunityDistrictBtn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { GoToDistrictBtn, GoToDistrictBtnProps } from ".";

export interface GoToCommunityDistrictBtnProps
extends Pick<GoToDistrictBtnProps, "goToDistrict"> {
boroughId: string | null;
districtId: string | null;
}

export function GoToCommunityDistrictBtn({
boroughId,
districtId,
...props
}: GoToCommunityDistrictBtnProps) {
return (
<GoToDistrictBtn
path={
boroughId === null || districtId === null
? null
: `boroughs/${boroughId}/community-districts/${districtId}/capital-projects`
}
{...props}
/>
);
}
24 changes: 24 additions & 0 deletions app/components/GoToDistrictBtn/index.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<GoToDistrictBtn goToDistrict={goToDistrict} path={null} />);
expect(screen.getByText(/Go to Selected District/)).toBeVisible();
});

it("should call 'goToDistrict' when path is a string", () => {
const goToDistrict = vi.fn();
render(<GoToDistrictBtn goToDistrict={goToDistrict} path={"/"} />);
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(<GoToDistrictBtn goToDistrict={goToDistrict} path={null} />);
fireEvent.click(screen.getByText(/Go to Selected District/));
expect(goToDistrict).not.toHaveBeenCalled();
});
});
20 changes: 20 additions & 0 deletions app/components/GoToDistrictBtn/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Button
width="full"
onClick={path !== null ? () => goToDistrict(path) : () => undefined}
isDisabled={path === null}
mt={4}
>
Go to Selected District
</Button>
);
}
86 changes: 62 additions & 24 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
ScrollRestoration,
isRouteErrorResponse,
useLoaderData,
useLocation,
useNavigate,
useRouteError,
useSearchParams,
} from "@remix-run/react";
Expand All @@ -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";
Expand Down Expand Up @@ -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;
Expand All @@ -146,33 +155,62 @@ export default function App() {
| undefined,
) => setSearchParams(nextSearchParams, { replace: true });

const AdminDropdowns = () => (
<VStack>
<DistrictTypeDropdown
selectValue={districtType}
updateSearchParams={updateSearchParams}
/>
<BoroughDropdown
selectValue={boroughId}
updateSearchParams={updateSearchParams}
boroughs={loaderData.boroughs}
/>

{districtType !== "ccd" ? (
<CommunityDistrictDropdown
boroughId={boroughId}
selectValue={districtId}
communityDistricts={loaderData.communityDistricts}
const goToDistrict = (currentPath: string) => (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 = () => (
<>
<VStack>
<DistrictTypeDropdown
selectValue={districtType}
updateSearchParams={updateSearchParams}
/>
) : (
<CityCouncilDistrictDropdown
selectValue={districtId}
cityCouncilDistricts={loaderData.cityCouncilDistricts}
<BoroughDropdown
selectValue={boroughId}
updateSearchParams={updateSearchParams}
boroughs={loaderData.boroughs}
/>

{districtType !== "ccd" ? (
<CommunityDistrictDropdown
boroughId={boroughId}
selectValue={districtId}
communityDistricts={loaderData.communityDistricts}
updateSearchParams={updateSearchParams}
/>
) : (
<CityCouncilDistrictDropdown
selectValue={districtId}
cityCouncilDistricts={loaderData.cityCouncilDistricts}
updateSearchParams={updateSearchParams}
/>
)}
</VStack>
{districtType === null && (
<GoToDistrictBtn goToDistrict={goToNextDistrict} path={null} />
)}
{districtType === "ccd" && (
<GoToCityCouncilDistrictBtn
goToDistrict={goToNextDistrict}
districtId={districtId}
/>
)}
{districtType === "cd" && (
<GoToCommunityDistrictBtn
goToDistrict={goToNextDistrict}
boroughId={boroughId}
districtId={districtId}
/>
)}
</VStack>
</>
);

return (
Expand All @@ -185,12 +223,12 @@ export default function App() {
<Overlay>
<Show above="lg">
<FilterMenu defaultIndex={0}>
<AdminDropdowns />
<FilterMenuContent />
</FilterMenu>
</Show>
<Hide above="lg">
<FilterMenu>
<AdminDropdowns />
<FilterMenuContent />
</FilterMenu>
</Hide>
<Flex
Expand Down

0 comments on commit e877149

Please sign in to comment.