Skip to content

Commit

Permalink
Add capital commitments
Browse files Browse the repository at this point in the history
- Add capital commitments to capital project panel
- Add capital commitments timeline to capital project

closes #17
  • Loading branch information
TangoYankee committed Aug 21, 2024
1 parent 7ade2c2 commit 9049b5a
Show file tree
Hide file tree
Showing 22 changed files with 2,513 additions and 1,234 deletions.
50 changes: 0 additions & 50 deletions app/components/CapitalProjectDetailPanel/index.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
CapitalCommitment,
CapitalCommitmentType,
createCapitalCommitment,
createCapitalCommitmentType,
} from "~/gen";
import { CapitalCommitmentsTable } from "./CapitalCommitmentsTable";
import { render, screen } from "@testing-library/react";

describe("CapitalCommitmentsTable", () => {
let capitalCommitments: Array<CapitalCommitment> = [];
let capitalCommitmentTypes: Array<CapitalCommitmentType> = [];
beforeAll(() => {
capitalCommitments = Array.from(Array(1), () =>
createCapitalCommitment({
type: "CONS",
plannedDate: `${new Date("April 2024")}`,
totalValue: 1e6,
}),
);
capitalCommitmentTypes = Array.from(Array(1), () =>
createCapitalCommitmentType({
code: "CONS",
description: "CONSTRUCTION",
}),
);
});

it("should render the table header", () => {
render(
<CapitalCommitmentsTable
capitalCommitments={capitalCommitments}
capitalCommitmentTypes={capitalCommitmentTypes}
/>,
);

expect(screen.getByText(/Date/)).toBeVisible();
expect(screen.getByText(/Description/)).toBeVisible();
expect(screen.getByText(/Commitment/)).toBeVisible();
});

it("should render the month and year of the commitment", () => {
render(
<CapitalCommitmentsTable
capitalCommitments={capitalCommitments}
capitalCommitmentTypes={capitalCommitmentTypes}
/>,
);
expect(screen.getByText(/Apr 2024/)).toBeVisible();
});

it("should render the description of the commitment type", () => {
render(
<CapitalCommitmentsTable
capitalCommitments={capitalCommitments}
capitalCommitmentTypes={capitalCommitmentTypes}
/>,
);
expect(screen.getByText(/CONSTRUCTION/)).toBeVisible();
});

it("should render the value of the commitment", () => {
render(
<CapitalCommitmentsTable
capitalCommitments={capitalCommitments}
capitalCommitmentTypes={capitalCommitmentTypes}
/>,
);

expect(screen.getByText(/\$1.00M/)).toBeVisible();
});
});
75 changes: 75 additions & 0 deletions app/components/CapitalProjectPanel/CapitalCommitmentsTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import numbro from "numbro";
import { format } from "date-fns";
import {
TableContainer,
Table,
Thead,
Tr,
Th,
Tbody,
Td,
} from "@nycplanning/streetscape";
import { CapitalCommitment, CapitalCommitmentType } from "~/gen";

export interface CapitalCommitmentsTableProps {
capitalCommitments: Array<CapitalCommitment>;
capitalCommitmentTypes: Array<CapitalCommitmentType>;
}
export function CapitalCommitmentsTable({
capitalCommitments,
capitalCommitmentTypes,
}: CapitalCommitmentsTableProps) {
return (
<TableContainer
backgroundColor={"gray.50"}
overflowY={"auto"}
padding={{ base: 3, lg: "unset" }}
>
<Table
backgroundColor={"white"}
textAlign="left"
fontSize="xs"
width={"100%"}
sx={{ borderCollapse: "separate" }}
borderRadius={10}
>
<Thead>
<Tr textTransform={"uppercase"}>
<Th padding={1} lineHeight={1.5}>
Date
</Th>
<Th padding={1} lineHeight={1.5}>
Description
</Th>
<Th padding={1} lineHeight={1.5}>
Commitment
</Th>
</Tr>
</Thead>
<Tbody>
{capitalCommitments.map((commitment) => (
<Tr key={commitment.id} verticalAlign={"text-top"}>
<Td padding={1} lineHeight={1.5}>
{format(commitment.plannedDate, "MMM yyyy")}
</Td>
<Td padding={1} lineHeight={1.5} sx={{ textWrap: "wrap" }}>
{capitalCommitmentTypes.find(
(type) => type.code === commitment.type,
)?.description ?? commitment.type}
</Td>
<Td padding={1} lineHeight={1.5}>
{numbro(commitment.totalValue)
.format({
average: true,
output: "currency",
mantissa: 2,
})
.toUpperCase()}
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
);
}
121 changes: 121 additions & 0 deletions app/components/CapitalProjectPanel/CapitalCommitmentsTimeline.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { render, screen } from "@testing-library/react";
import { CapitalCommitmentsTimeline } from "./CapitalCommitmentsTimeline";
import { createCapitalCommitment } from "~/gen";

describe("CapitalCommitmentsTimeline", () => {
const currentYear = new Date().getFullYear();

it("should label past, current, and future commitments", () => {
const capitalCommitments = Array.from(Array(1), () =>
createCapitalCommitment(),
);
render(
<CapitalCommitmentsTimeline capitalCommitments={capitalCommitments} />,
);

expect(screen.getByText(/Past/)).toBeVisible();
expect(screen.getByText(/Current/)).toBeVisible();
expect(screen.getByText(/Future/)).toBeVisible();
});

it("should sum commitments two in the past, one current, and none in the future", () => {
const capitalCommitments = Array.from(Array(3), (_, i) =>
createCapitalCommitment({
plannedDate: new Date(`Jan ${currentYear - i}`).toString(),
totalValue: 1e6,
}),
);
render(
<CapitalCommitmentsTimeline capitalCommitments={capitalCommitments} />,
);

expect(screen.getByText(/\$2.00M/)).toBeVisible();
expect(screen.getByText(/\$1.00M/)).toBeVisible();
expect(screen.getByText(/\$0.00/)).toBeVisible();
});

it("should sum commitments none in the past, one current, and three in the future", () => {
const capitalCommitments = Array.from(Array(4), (_, i) =>
createCapitalCommitment({
plannedDate: new Date(`Jan ${currentYear + i}`).toString(),
totalValue: 1e6,
}),
);
render(
<CapitalCommitmentsTimeline capitalCommitments={capitalCommitments} />,
);

expect(screen.getByText(/\$0.00/)).toBeVisible();
expect(screen.getByText(/\$1.00M/)).toBeVisible();
expect(screen.getByText(/\$3.00M/)).toBeVisible();
});

it("should show a range of past years", () => {
const capitalCommitments = Array.from(Array(4), (_, i) =>
createCapitalCommitment({
plannedDate: new Date(`Jan ${currentYear - i}`).toString(),
}),
);
render(
<CapitalCommitmentsTimeline capitalCommitments={capitalCommitments} />,
);

expect(
screen.getByText(`${currentYear - 3} - ${currentYear - 1}`),
).toBeVisible();
});

it("should show a single past year", () => {
const capitalCommitments = Array.from(Array(2), (_, i) =>
createCapitalCommitment({
plannedDate: new Date(`Jan ${currentYear - i}`).toString(),
}),
);
render(
<CapitalCommitmentsTimeline capitalCommitments={capitalCommitments} />,
);

expect(screen.getByText(`${currentYear - 1}`)).toBeVisible();
});

it("should show the current year", () => {
const capitalCommitments = Array.from(Array(1), () =>
createCapitalCommitment({
plannedDate: new Date(`Jan ${currentYear}`).toString(),
}),
);
render(
<CapitalCommitmentsTimeline capitalCommitments={capitalCommitments} />,
);

expect(screen.getByText(currentYear)).toBeVisible();
});

it("should show a range of future years", () => {
const capitalCommitments = Array.from(Array(4), (_, i) =>
createCapitalCommitment({
plannedDate: new Date(`Jan ${currentYear + i}`).toString(),
}),
);
render(
<CapitalCommitmentsTimeline capitalCommitments={capitalCommitments} />,
);

expect(
screen.getByText(`${currentYear + 1} - ${currentYear + 3}`),
).toBeVisible();
});

it("should show a single future year", () => {
const capitalCommitments = Array.from(Array(2), (_, i) =>
createCapitalCommitment({
plannedDate: new Date(`Jan ${currentYear + i}`).toString(),
}),
);
render(
<CapitalCommitmentsTimeline capitalCommitments={capitalCommitments} />,
);

expect(screen.getByText(`${currentYear + 1}`)).toBeVisible();
});
});
Loading

0 comments on commit 9049b5a

Please sign in to comment.