Skip to content

Commit

Permalink
Capital Projects in Community District
Browse files Browse the repository at this point in the history
Implement the panel to show capital projects in a community district

closes #15
  • Loading branch information
TangoYankee committed Aug 21, 2024
1 parent a1e78cf commit 6d2e6ab
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 48 deletions.
17 changes: 17 additions & 0 deletions app/components/CapitalProjectsList/CapitalProjectsPanel.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { render, screen } from "@testing-library/react";
import { CapitalProjectsPanel } from "./CapitalProjectsPanel";

describe("CapitalProjectsPanel", () => {
it("should contain a project list", () => {
render(
<CapitalProjectsPanel
capitalProjects={[]}
agencies={[]}
district="Community District"
>
<></>
</CapitalProjectsPanel>,
);
expect(screen.getByText(/Mapped Capital Projects/)).toBeVisible();
});
});
38 changes: 38 additions & 0 deletions app/components/CapitalProjectsList/CapitalProjectsPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Hide, Show } from "@nycplanning/streetscape";
import {
CapitalProjectsAccordionPanel,
CapitalProjectsAccordionPanelProps,
} from "./CapitalProjectsAccordionPanel";
import {
CapitalProjectsDrawer,
CapitalProjectsDrawerProps,
} from "./CapitalProjectsDrawer";

export interface CapitalProjectsPanelProps
extends CapitalProjectsAccordionPanelProps,
CapitalProjectsDrawerProps {}

export function CapitalProjectsPanel(props: CapitalProjectsPanelProps) {
return (
<>
<Show above="sm">
<CapitalProjectsAccordionPanel
capitalProjects={props.capitalProjects}
agencies={props.agencies}
district={props.district}
>
{props.children}
</CapitalProjectsAccordionPanel>
</Show>
<Hide above="sm">
<CapitalProjectsDrawer
capitalProjects={props.capitalProjects}
agencies={props.agencies}
district={props.district}
>
{props.children}
</CapitalProjectsDrawer>
</Hide>
</>
);
}
1 change: 1 addition & 0 deletions app/components/CapitalProjectsList/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { CapitalProjectsAccordionPanel } from "./CapitalProjectsAccordionPanel";
export { CapitalProjectsList } from "./CapitalProjectsList";
export { CapitalProjectsListItem } from "./CapitalProjectsListItem";
export { CapitalProjectsPanel } from "./CapitalProjectsPanel";
Original file line number Diff line number Diff line change
@@ -1,3 +1,88 @@
import { Flex } from "@nycplanning/streetscape";
import { json, LoaderFunctionArgs } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { CapitalProjectsPanel } from "~/components/CapitalProjectsList";
import { Pagination } from "~/components/Pagination";
import {
findAgencies,
findBoroughs,
findCapitalProjectsByBoroughIdCommunityDistrictId,
} from "~/gen";

export async function loader({ request, params }: LoaderFunctionArgs) {
const url = new URL(request.url);
const itemsPerPage = 7;
const pageParam = url.searchParams.get("page");
const page = pageParam === null ? 1 : parseInt(pageParam);

const { boroughId, communityDistrictId } = params;
if (
boroughId === undefined ||
communityDistrictId === undefined ||
isNaN(page)
) {
throw json("Bad request", { status: 400 });
}

const offset = (page - 1) * itemsPerPage;
const projectsByCommunityDistrictPromise =
findCapitalProjectsByBoroughIdCommunityDistrictId(
boroughId,
communityDistrictId,
{
limit: itemsPerPage,
offset: offset,
},
{
baseURL: `${import.meta.env.VITE_ZONING_API_URL}/api`,
},
);

const agenciesPromise = findAgencies({
baseURL: `${import.meta.env.VITE_ZONING_API_URL}/api`,
});
const boroughsPromise = findBoroughs({
baseURL: `${import.meta.env.VITE_ZONING_API_URL}/api`,
});
const [agenciesResponse, boroughsResponse, capitalProjectsResponse] =
await Promise.all([
agenciesPromise,
boroughsPromise,
projectsByCommunityDistrictPromise,
]);
const boroughAbbr = boroughsResponse.boroughs.find(
(borough) => borough.id === boroughId,
)?.abbr;
return {
capitalProjectsResponse,
agencies: agenciesResponse.agencies,
boroughAbbr,
communityDistrictId,
};
}

export default function CapitalProjectsByBoroughIdCommunityDistrictId() {
return <></>;
const {
capitalProjectsResponse: { total: capitalProjectsTotal, capitalProjects },
agencies,
boroughAbbr,
communityDistrictId,
} = useLoaderData<typeof loader>();

return (
<CapitalProjectsPanel
capitalProjects={capitalProjects}
agencies={agencies}
district={`Community District ${boroughAbbr}${communityDistrictId}`}
>
<Flex
paddingTop={4}
alignItems="center"
justifyContent={"space-between"}
marginTop={"auto"}
>
<Pagination total={capitalProjectsTotal} />
</Flex>
</CapitalProjectsPanel>
);
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
import { LoaderFunctionArgs, json } from "@remix-run/node";
import { findCapitalProjectsByCityCouncilId, findAgencies } from "../gen";
import { useLoaderData } from "@remix-run/react";
import { CapitalProjectsAccordionPanel } from "../components/CapitalProjectsList";
import { Flex, Hide, Show } from "@nycplanning/streetscape";
import { CapitalProjectsDrawer } from "~/components/CapitalProjectsList/CapitalProjectsDrawer";
import { CapitalProjectsPanel } from "../components/CapitalProjectsList";
import { Flex } from "@nycplanning/streetscape";
import { Pagination } from "~/components/Pagination";

export async function loader({ request, params }: LoaderFunctionArgs) {
const url = new URL(request.url);
const agenciesResponse = await findAgencies({
baseURL: `${import.meta.env.VITE_ZONING_API_URL}/api`,
});

const itemsPerPage = 7;
const pageParam = url.searchParams.get("page");
const page = pageParam === null ? 1 : parseInt(pageParam);
const offset = (page - 1) * itemsPerPage;

const { cityCouncilDistrictId } = params;
if (cityCouncilDistrictId === undefined) {
if (cityCouncilDistrictId === undefined || isNaN(page)) {
throw json("Bad Request", { status: 400 });
}
const offset = (page - 1) * itemsPerPage;

const projectsByCityCouncilDistrictResponse =
await findCapitalProjectsByCityCouncilId(
const projectsByCityCouncilDistrictPromise =
findCapitalProjectsByCityCouncilId(
cityCouncilDistrictId,
{
limit: itemsPerPage,
Expand All @@ -34,48 +28,41 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
},
);

const agenciesPromise = findAgencies({
baseURL: `${import.meta.env.VITE_ZONING_API_URL}/api`,
});

const [agenciesResponse, projectsByCityCouncilDistrictResponse] =
await Promise.all([agenciesPromise, projectsByCityCouncilDistrictPromise]);

return {
projects: projectsByCityCouncilDistrictResponse,
capitalProjectsResponse: projectsByCityCouncilDistrictResponse,
agencies: agenciesResponse.agencies,
cityCouncilDistrictId: cityCouncilDistrictId,
cityCouncilDistrictId,
};
}

export default function CapitalProjectsByCityCouncilDistrict() {
const { projects, agencies, cityCouncilDistrictId } =
useLoaderData<typeof loader>();

const pagination = (
<Flex
paddingTop={4}
alignItems="center"
justifyContent={"space-between"}
marginTop={"auto"}
>
<Pagination total={projects.total} />
</Flex>
);
const {
capitalProjectsResponse: { total: capitalProjectsTotal, capitalProjects },
agencies,
cityCouncilDistrictId,
} = useLoaderData<typeof loader>();

return (
<>
<Show above="sm">
<CapitalProjectsAccordionPanel
capitalProjects={projects.capitalProjects}
agencies={agencies}
district={"City Council District " + cityCouncilDistrictId}
>
{pagination}
</CapitalProjectsAccordionPanel>
</Show>
<Hide above="sm">
<CapitalProjectsDrawer
capitalProjects={projects.capitalProjects}
agencies={agencies}
district={"City Council District " + cityCouncilDistrictId}
>
{pagination}
</CapitalProjectsDrawer>
</Hide>
</>
<CapitalProjectsPanel
capitalProjects={capitalProjects}
agencies={agencies}
district={`City Council District ${cityCouncilDistrictId}`}
>
<Flex
paddingTop={4}
alignItems="center"
justifyContent={"space-between"}
marginTop={"auto"}
>
<Pagination total={capitalProjectsTotal} />
</Flex>
</CapitalProjectsPanel>
);
}

0 comments on commit 6d2e6ab

Please sign in to comment.