Skip to content

Commit

Permalink
refactor: displays CAN obligate_by as MM/DD/YY (#2873)
Browse files Browse the repository at this point in the history
  • Loading branch information
fpigeonjr authored Oct 2, 2024
1 parent b2de276 commit e00aed2
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 125 deletions.
64 changes: 33 additions & 31 deletions backend/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -291,11 +291,11 @@ paths:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUpdateCANRequestSchema"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANRequestSchema"
schema:
$ref: "#/components/schemas/CreateUpdateCANRequestSchema"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANRequestSchema"
responses:
"200":
description: CAN Updated
Expand Down Expand Up @@ -329,11 +329,11 @@ paths:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUpdateCANRequestSchema"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANRequestSchema"
schema:
$ref: "#/components/schemas/CreateUpdateCANRequestSchema"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANRequestSchema"
responses:
"200":
description: CAN Updated
Expand Down Expand Up @@ -391,11 +391,11 @@ paths:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUpdateCANFundingBudgetRequest"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANFundingBudgetRequest"
schema:
$ref: "#/components/schemas/CreateUpdateCANFundingBudgetRequest"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANFundingBudgetRequest"
responses:
"201":
description: Created
Expand Down Expand Up @@ -457,11 +457,11 @@ paths:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUpdateCANFundingBudgetRequest"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANFundingBudgetRequest"
schema:
$ref: "#/components/schemas/CreateUpdateCANFundingBudgetRequest"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANFundingBudgetRequest"
responses:
"200":
description: CANFundingBudget Updated
Expand Down Expand Up @@ -495,11 +495,11 @@ paths:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUpdateCANFundingBudgetRequest"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANFundingBudgetRequest"
schema:
$ref: "#/components/schemas/CreateUpdateCANFundingBudgetRequest"
examples:
"0":
$ref: "#/components/examples/CreateUpdateCANFundingBudgetRequest"
responses:
"200":
description: CAN Updated
Expand Down Expand Up @@ -2355,6 +2355,8 @@ components:
type: array
items:
$ref: "#/components/schemas/BudgetLineItem"
description:
type: string
display_name:
type: string
funding_budgets:
Expand All @@ -2371,8 +2373,14 @@ components:
type: array
items:
$ref: "#/components/schemas/FundingReceived"
id:
type: integer
nick_name:
type: string
number:
type: string
obligate_by:
type: integer
portfolio:
type: integer
portfolio_id:
Expand All @@ -2381,12 +2389,6 @@ components:
type: array
items:
$ref: "#/components/schemas/Project"
nick_name:
type: string
description:
type: string
id:
type: integer
created_on:
$ref: "#/components/parameters/created_on"
updated_on:
Expand Down
27 changes: 27 additions & 0 deletions frontend/src/components/CANs/CANTable/CANTable.helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Gets the last day of the fiscal year for a given year.
* @param {number} fiscalYear - The fiscal year
* @returns {Date} The last day of the fiscal year
*/
const getLastDayOfFiscalYear = (fiscalYear) => {
// Fiscal year ends on September 30 of the previous calendar year
return new Date(fiscalYear - 1, 8, 30); // Month is 0-indexed, so 8 is September
};
/**
* Formats the obligate by date to the last day of the fiscal year.
* @param {number | undefined} obligateBy - The obligate by value
* @returns {string} Formatted date string or "TBD"
*/
export const formatObligateBy = (obligateBy) => {
if (!obligateBy) return "TBD"; // Default value
if (typeof obligateBy !== "number" || isNaN(obligateBy)) return "TBD"; // Default if parsing fails

const lastDay = getLastDayOfFiscalYear(obligateBy);

// Format as MM/DD/YY
return lastDay.toLocaleDateString("en-US", {
month: "2-digit",
day: "2-digit",
year: "2-digit"
});
};
24 changes: 24 additions & 0 deletions frontend/src/components/CANs/CANTable/CANTable.helpers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { formatObligateBy } from "./CANTable.helpers";

describe("formatObligateBy", () => {
test('returns "TBD" for undefined input', () => {
expect(formatObligateBy(undefined)).toBe("TBD");
});

test('returns "TBD" for non-numeric input', () => {
expect(formatObligateBy("not a number")).toBe("TBD");
});

test('returns "TBD" for NaN input', () => {
expect(formatObligateBy(NaN)).toBe("TBD");
});

test("formats valid fiscal year correctly", () => {
expect(formatObligateBy(2023)).toBe("09/30/22");
});

test("handles different fiscal years", () => {
expect(formatObligateBy(2024)).toBe("09/30/23");
expect(formatObligateBy(2025)).toBe("09/30/24");
});
});
78 changes: 9 additions & 69 deletions frontend/src/components/CANs/CANTable/CANTable.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import _ from "lodash";
import PropTypes from "prop-types";
import React from "react";
import PaginationNav from "../../UI/PaginationNav";
import Tooltip from "../../UI/USWDS/Tooltip";
import CANTableHead from "./CANTableHead";
import CANTableRow from "./CANTableRow";
import styles from "./style.module.css";
import { formatObligateBy } from "./CANTable.helpers";

/**
* CANTable component of CanList
* @component
Expand All @@ -16,7 +17,7 @@ import styles from "./style.module.css";
const CANTable = ({ cans }) => {
const CANS_PER_PAGE = 10;
const [currentPage, setCurrentPage] = React.useState(1);
let cansPerPage = _.cloneDeep(cans);
let cansPerPage = [...cans];
cansPerPage = cansPerPage.slice((currentPage - 1) * CANS_PER_PAGE, currentPage * CANS_PER_PAGE);

if (cans.length === 0) {
Expand All @@ -26,18 +27,18 @@ const CANTable = ({ cans }) => {
return (
<>
<table className={`usa-table usa-table--borderless width-full ${styles.tableHover}`}>
<TableHead />
<CANTableHead />
<tbody>
{cansPerPage.map((can) => (
<CANTableRow
key={can.id}
canId={can.id}
name={can.display_name}
nickname={can.nick_name}
name={can.display_name ?? ""}
nickname={can.nick_name ?? ""}
portfolio={can.portfolio.abbreviation}
fiscalYear={can.funding_budgets[0]?.fiscal_year ?? "TBD"}
activePeriod={can.active_period ?? "TBD"}
obligateBy={can.obligate_by ?? "09/30/25"}
activePeriod={can.active_period?.toString() ?? "TBD"}
obligateBy={formatObligateBy(can.obligate_by)}
transfer={can.funding_details.method_of_transfer ?? "TBD"}
fyBudget={can.funding_budgets[0]?.budget ?? 0}
/>
Expand All @@ -56,67 +57,6 @@ const CANTable = ({ cans }) => {
);
};

const TableHead = () => {
const availbleTooltip =
"$ Available is the remaining amount of the total budget that is available to plan from (Total FY Budget minus budget lines in Planned, Executing or Obligated Status)";
return (
<thead>
<tr>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
CAN
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
Portfolio
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
FY
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
Active Period
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
Obligate By
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
Transfer
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
FY Budget
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
<Tooltip label={availbleTooltip}>
<span>$ Available</span>
</Tooltip>
</th>
</tr>
</thead>
);
};

CANTable.propTypes = {
cans: PropTypes.array.isRequired
};
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/CANs/CANTable/CANTable.test.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { render, screen } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import CANTable from "./CANTable";
import { cans } from "../../../tests/data";
import { useGetCansQuery, useGetCanFundingSummaryQuery } from "../../../api/opsAPI";
import { MemoryRouter } from "react-router-dom";
import { describe, expect, it, vi } from "vitest";
import { useGetCanFundingSummaryQuery, useGetCansQuery } from "../../../api/opsAPI";
import { cans } from "../../../tests/data";
import CANTable from "./CANTable";

// Mock the PaginationNav component
vi.mock("../../UI/PaginationNav", () => ({
Expand Down
65 changes: 65 additions & 0 deletions frontend/src/components/CANs/CANTable/CANTableHead.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import Tooltip from "../../UI/USWDS/Tooltip";

const CANTableHead = () => {
const availbleTooltip =
"$ Available is the remaining amount of the total budget that is available to plan from (Total FY Budget minus budget lines in Planned, Executing or Obligated Status)";

return (
<thead>
<tr>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
CAN
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
Portfolio
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
FY
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
Active Period
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
Obligate By
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
Transfer
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
FY Budget
</th>
<th
scope="col"
style={{ whiteSpace: "nowrap" }}
>
<Tooltip label={availbleTooltip}>
<span>$ Available</span>
</Tooltip>
</th>
</tr>
</thead>
);
};

export default CANTableHead;
Loading

0 comments on commit e00aed2

Please sign in to comment.