Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨adds pagination to Can Budget Lines #3078

Merged
merged 6 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions frontend/cypress/e2e/canDetail.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,34 @@ describe("CAN detail page", () => {
cy.get("tbody").should("not.exist");
cy.get("p").should("contain", "No budget lines have been added to this CAN.");
});
it("pagination on the bli table works as expected", () => {
cy.visit("/cans/504/spending");
cy.get("#fiscal-year-select").select("2043");
cy.wait(1000);
cy.get("ul").should("have.class", "usa-pagination__list");
cy.get("li").should("have.class", "usa-pagination__item").contains("1");
cy.get("button").should("have.class", "usa-current").contains("1");
cy.get("li").should("have.class", "usa-pagination__item").contains("2");
cy.get("li").should("have.class", "usa-pagination__item").contains("Next");
cy.get("tbody").find("tr").should("have.length", 3);
cy.get("li")
.should("have.class", "usa-pagination__item")
.contains("Previous")
.find("svg")
.should("have.attr", "aria-hidden", "true");

// go to the second page
cy.get("li").should("have.class", "usa-pagination__item").contains("2").click();
cy.get("button").should("have.class", "usa-current").contains("2");
cy.get("li").should("have.class", "usa-pagination__item").contains("Previous");
cy.get("li")
.should("have.class", "usa-pagination__item")
.contains("Next")
.find("svg")
.should("have.attr", "aria-hidden", "true");

// go back to the first page
cy.get("li").should("have.class", "usa-pagination__item").contains("1").click();
cy.get("button").should("have.class", "usa-current").contains("1");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,7 @@ const BLIStatusSummaryCard = ({ budgetLines }) => {
};

return (
<RoundedBox
className="display-inline-block"
dataCy="bli-status-summary-card"
>
<RoundedBox dataCy="bli-status-summary-card">
<h3 className="margin-0 margin-bottom-3 font-12px text-base-dark text-normal">Budget Lines By Status</h3>

<div className="display-flex flex-justify">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { formatDateNeeded } from "../../../helpers/utils";
import React from "react";
import { calculatePercent, formatDateNeeded } from "../../../helpers/utils";
import Table from "../../UI/Table";
import { TABLE_HEADERS } from "./CABBudgetLineTable.constants";
import CANBudgetLineTableRow from "./CANBudgetLineTableRow";
import { calculatePercent } from "../../../helpers/utils";
import PaginationNav from "../../UI/PaginationNav";
/**
* @typedef {import("../../../components/BudgetLineItems/BudgetLineTypes").BudgetLine} BudgetLine
*/
Expand All @@ -19,33 +20,49 @@ import { calculatePercent } from "../../../helpers/utils";
* @returns {JSX.Element} - The component JSX.
*/
const CANBudgetLineTable = ({ budgetLines, totalFunding }) => {
// TODO: once in prod, change this to 25
const ITEMS_PER_PAGE = 3;
const [currentPage, setCurrentPage] = React.useState(1);
let visibleBudgetLines = [...budgetLines];
visibleBudgetLines = visibleBudgetLines.slice((currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE);

if (budgetLines.length === 0) {
return <p className="text-center">No budget lines have been added to this CAN.</p>;
}

return (
<Table tableHeadings={TABLE_HEADERS}>
{budgetLines.map((budgetLine) => (
<CANBudgetLineTableRow
key={budgetLine.id}
budgetLine={budgetLine}
blId={budgetLine.id}
agreementName="TBD"
obligateDate={formatDateNeeded(budgetLine.date_needed || "")}
fiscalYear={budgetLine.fiscal_year || "TBD"}
amount={budgetLine.amount ?? 0}
fee={budgetLine.proc_shop_fee_percentage}
percentOfCAN={calculatePercent(budgetLine.amount ?? 0, totalFunding)}
status={budgetLine.status}
inReview={budgetLine.in_review}
creatorId={budgetLine.created_by}
creationDate={budgetLine.created_on}
procShopCode="TBD"
procShopFeePercentage={budgetLine.proc_shop_fee_percentage}
notes={budgetLine.comments || "No Notes added"}
<>
<Table tableHeadings={TABLE_HEADERS}>
{visibleBudgetLines.map((budgetLine) => (
<CANBudgetLineTableRow
key={budgetLine.id}
budgetLine={budgetLine}
blId={budgetLine.id}
agreementName="TBD"
obligateDate={formatDateNeeded(budgetLine.date_needed || "")}
fiscalYear={budgetLine.fiscal_year || "TBD"}
amount={budgetLine.amount ?? 0}
fee={budgetLine.proc_shop_fee_percentage}
percentOfCAN={calculatePercent(budgetLine.amount ?? 0, totalFunding)}
status={budgetLine.status}
inReview={budgetLine.in_review}
creatorId={budgetLine.created_by}
creationDate={budgetLine.created_on}
procShopCode="TBD"
procShopFeePercentage={budgetLine.proc_shop_fee_percentage}
notes={budgetLine.comments || "No Notes added"}
/>
))}
</Table>
{budgetLines.length > ITEMS_PER_PAGE && (
<PaginationNav
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⭐ crux of the PR

currentPage={currentPage}
setCurrentPage={setCurrentPage}
items={budgetLines}
itemsPerPage={ITEMS_PER_PAGE}
/>
))}
</Table>
)}
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ const CANFundingCard = ({ can, pendingAmount, afterApproval }) => {

return (
<RoundedBox
className={"display-inline-block"}
dataCy={`can-funding-summary-card-${canId}`}
style={{ height: "14.5rem" }}
>
Expand Down
118 changes: 118 additions & 0 deletions frontend/src/components/CANs/CANFundingInfoCard/CANFundingInfoCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { NO_DATA } from "../../../constants";
import Card from "../../UI/Cards/Card";
import TermTag from "../../UI/Term/TermTag";
/**
* @typedef {import("../../../components/CANs/CANTypes").FundingDetails} FundingDetails
*/

/**
* @typedef {Object} CANFundingInfoCard
* @property {FundingDetails} [funding]
* @property {number} fiscalYear
*/

/**
* @component - The CAN Funding component.
* @param {CANFundingInfoCard} props
* @returns {JSX.Element} - The component JSX.
*/
const CANFundingInfoCard = ({ funding, fiscalYear }) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't mean to include this but here we are

if (!funding) {
return <div>No funding information available for this CAN.</div>;
}

return (
<Card className="width-full">
<h3
className="margin-0 margin-bottom-2 font-12px text-base-dark text-normal"
style={{ whiteSpace: "pre-line", lineHeight: "20px" }}
>
{`FY ${fiscalYear} CAN Funding Information`}
</h3>
<div className="grid-row grid-gap">
<div className="grid-col">
<dl>
<TermTag
term="FY"
description={funding.fiscal_year.toString()}
/>
<TermTag
term="Fund Code"
description={funding.fund_code}
/>
</dl>
</div>
<div className="grid-col">
<dl>
{funding.active_period && (
<TermTag
term="Active Period"
description={
funding.active_period > 1
? `${funding.active_period} Years`
: `${funding.active_period} Year`
}
/>
)}
<TermTag
term="Allowance"
description={funding.allowance ?? NO_DATA}
/>
</dl>
</div>
<div className="grid-col">
<dl>
<TermTag
term="Obligate By"
description={funding.obligate_by?.toString() ?? NO_DATA}
/>
<TermTag
term="Allotment"
description={funding.allotment ?? NO_DATA}
/>
</dl>
</div>
<div className="grid-col">
<dl>
{/* TODO: ask where this comes from */}
<TermTag
term="Funding Received*"
description={NO_DATA}
/>
<TermTag
term="Funding Source"
description={funding.funding_source ?? NO_DATA}
/>
</dl>
</div>
<div className="grid-col">
<dl>
<TermTag
term="Funding Method"
description={funding.method_of_transfer}
/>
<TermTag
term="Partner"
description={funding.funding_partner ?? NO_DATA}
/>
</dl>
</div>
<div className="grid-col">
<dl>
{/* TODO: ask where this comes from */}
<TermTag
term="Funding Type*"
description={NO_DATA}
/>
<TermTag
term="Method of Transfer"
description={funding.method_of_transfer ?? NO_DATA}
/>
</dl>
</div>
</div>
</Card>
);
};

export default CANFundingInfoCard;
1 change: 1 addition & 0 deletions frontend/src/components/CANs/CANFundingInfoCard/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./CANFundingInfoCard";
4 changes: 3 additions & 1 deletion frontend/src/components/CANs/CANTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,18 @@ export type FundingBudget = {
};

export type FundingDetails = {
active_period?: number;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rajohnson90 you may want to check the schema since I don't see these additions in the OpenAPI spec

allotment?: string;
allowance?: string;
appropriation?: string;
display_name?: string;
fiscal_year: number;
fund_code: string;
funding_partner?: string;
funding_source?: string;
funding_source?: "OPRE" | "ACF" | "HHS";
id: number;
method_of_transfer?: keyof typeof CAN_TRANSFER;
obligate_by?: number;
sub_allowance?: string;
created_by?: any;
created_by_user?: any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const PortfolioFundingByBudgetStatus = () => {
};

return (
<RoundedBox className="display-inline-block">
<RoundedBox>
<h3 className="margin-0 margin-bottom-3 font-12px text-base-dark text-normal">
FY {fiscalYear.value} Budget Status
</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const BigBudgetCard = ({ title, totalSpending, totalFunding }) => {
return (
<>
<RoundedBox
className="display-inline-block width-full"
className="width-full"
id="big-budget-summary-card"
dataCy={`big-budget-summary-card`}
style={{ minHeight: "10.125rem" }}
Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/UI/Cards/BudgetCard/BudgetCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ const BudgetCard = ({ title, totalSpending, totalFunding }) => {

return (
<RoundedBox
className="display-inline-block"
dataCy={`budget-summary-card`}
style={{ height: "14.5rem" }}
>
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/components/UI/Cards/Card/Card.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import RoundedBox from "../../RoundedBox";

/**
* @typedef {Object} CardProps
* @typedef {Object & React.HTMLAttributes<HTMLDivElement>} CardProps
* @property {string} [title] - The title of the card.
* @property {string} [dataCy] - The data-cy attribute to add to the card.
* @property {Object} [style] - The style object to apply to the card.
* @property {Object} [rest] - Additional props to be passed to the card.
* @property {React.ReactNode} children - The children to render.
*/

Expand All @@ -17,7 +16,6 @@ import RoundedBox from "../../RoundedBox";
const Card = ({ title, children, dataCy = "", ...rest }) => {
return (
<RoundedBox
className="display-inline-block"
dataCy={dataCy}
data-testid={dataCy}
{...rest} // this is real trust 🧡
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ const DonutGraphWithLegendCard = ({ data, title, totalFunding }) => {
const id = crypto.randomUUID();

return (
<RoundedBox
className="display-inline-block"
id="donut-graph-with-legend-card"
>
<RoundedBox id="donut-graph-with-legend-card">
<h3 className="margin-0 margin-bottom-3 font-12px text-base-dark text-normal">{title}</h3>
<div className="display-flex flex-justify">
<div className={totalFunding > 0 ? `${styles.widthLegend} font-12px` : "width-card-lg font-12px"}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,7 @@ const ProjectAgreementBLICard = ({ fiscalYear, projects, agreements, budgetLines
};

return (
<RoundedBox
className="display-inline-block"
id="project-agreement-bli-card"
>
<RoundedBox id="project-agreement-bli-card">
<div className="display-flex flex-justify">
<article>
<h3 className="margin-0 margin-bottom-3 font-12px text-base-dark text-normal">{projectHeading}</h3>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/UI/RoundedBox/RoundedBox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import cssClasses from "./styles.module.css";
* @param {string} [props.id] - Element ID.
* @param {string} [props.dataCy] - Data attribute for Cypress tests.
* @param {Object} [props.style] - Inline styles.
* @param {Object} [props.rest] - Additional props to be passed
* @property {React.HTMLAttributes<HTMLDivElement>} [rest] - Additional props to be spread onto
* @returns {JSX.Element} Rendered component.
*/
const RoundedBox = ({ children, className, dataCy, ...rest }) => {
const cardContainer = `bg-brand-base-light-variant border-base-light font-family-sans display-flex ${cssClasses.container} ${className ? className : ""}`;
const cardContainer = `bg-brand-base-light-variant border-base-light font-family-sans ${cssClasses.container} ${className ? className : ""}`;

return (
<div
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/UI/RoundedBox/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
border-style: solid;
}

.cardBody {
/* .cardBody {
flex: 3;
}
} */
2 changes: 1 addition & 1 deletion frontend/src/pages/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const Home = () => {
return (
<App>
<div className="display-flex flex-justify-center">
<RoundedBox className="margin-top-4 display-inline-block text-center">
<RoundedBox className="margin-top-4 text-center">
<h1>This is the OPRE OPS system prototype</h1>
<p>⚠️Tread with caution</p>
</RoundedBox>
Expand Down
Loading