Skip to content

Commit

Permalink
feat: api integration for summary cards (#3157)
Browse files Browse the repository at this point in the history
* feat: use api data for in-draft spending

* refactor: api integration

* refactor: adds procurement shop name

* chore: cleanup

* refactor: correct simple agreement required types

* test: fix tests

* test: fix test data

---------

Co-authored-by: Santi-3rd <[email protected]>
Co-authored-by: Frank Pigeon Jr. <[email protected]>
  • Loading branch information
3 people authored Dec 5, 2024
1 parent 0cdfd24 commit d025186
Show file tree
Hide file tree
Showing 16 changed files with 107 additions and 49 deletions.
3 changes: 3 additions & 0 deletions backend/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3564,6 +3564,9 @@ components:
awarding_entity_id:
type: integer
example: 3
required:
- agreement_type
- name
BudgetLineItemCAN:
type: object
properties:
Expand Down
4 changes: 2 additions & 2 deletions backend/ops_api/ops/schemas/budget_line_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,8 @@ class BudgetLineItemCANSchema(Schema):


class SimpleAgreementSchema(Schema):
agreement_type = fields.String(allow_none=True)
name = fields.String(allow_none=True)
agreement_type = fields.String(allow_none=False)
name = fields.String(allow_none=False)
awarding_entity_id = fields.Integer(allow_none=True)


Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Agreements/AgreementTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ type ProcurementShop = {

type SimpleAgreement = {
agreement_type: string;
awarding_entity_id?: number;
name: string;
awarding_entity_id?: number;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { SimpleAgreement } from "../Agreements/AgreementTypes";

export type BudgetLine = {
agreement_id: number;
agreement: SimpleAgreement[];
agreement: SimpleAgreement;
amount?: number;
can?: CAN;
can_id?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const CANBudgetLineTable = ({ budgetLines, totalFunding }) => {
key={budgetLine.id}
budgetLine={budgetLine}
blId={budgetLine.id}
agreementName="TBD"
agreementName={budgetLine.agreement.name ?? "TBD"}
obligateDate={formatDateNeeded(budgetLine.date_needed || "")}
fiscalYear={budgetLine.fiscal_year || "TBD"}
amount={budgetLine.amount ?? 0}
Expand All @@ -48,7 +48,7 @@ const CANBudgetLineTable = ({ budgetLines, totalFunding }) => {
inReview={budgetLine.in_review}
creatorId={budgetLine.created_by}
creationDate={budgetLine.created_on}
procShopCode="TBD"
procShopId={budgetLine.agreement.awarding_entity_id ?? -1}
procShopFeePercentage={budgetLine.proc_shop_fee_percentage}
notes={budgetLine.comments || "No Notes added"}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { useTableRow } from "../../UI/TableRowExpandable/TableRowExpandable.hooks";
import TableTag from "../../UI/TableTag";
import { useChangeRequestsForTooltip } from "../../../hooks/useChangeRequests.hooks";
import { useGetAbbreviationForProcurementShopId } from "../../../hooks/lookup.hooks";

/**
* @typedef {import("../../../components/BudgetLineItems/BudgetLineTypes").BudgetLine} BudgetLine
Expand All @@ -25,17 +26,17 @@ import { useChangeRequestsForTooltip } from "../../../hooks/useChangeRequests.ho
* @typedef {Object} CANBudgetLineTableRowProps
* @property {BudgetLine} budgetLine
* @property {number} blId
* @property {string} agreementName - TODO
* @property {string} agreementName
* @property {string} obligateDate
* @property {number | string } fiscalYear
* @property {number} amount
* @property {number} fee
* @property {number} percentOfCAN - TODO
* @property {number} percentOfCAN
* @property {string} status
* @property {boolean} inReview
* @property {number} creatorId
* @property {string} creationDate
* @property {string} procShopCode - TODO
* @property {number} procShopId
* @property {number} procShopFeePercentage
* @property {string} notes
*/
Expand All @@ -58,7 +59,7 @@ const CANBudgetLineTableRow = ({
inReview,
creatorId,
creationDate,
procShopCode,
procShopId,
procShopFeePercentage,
notes
}) => {
Expand All @@ -70,6 +71,7 @@ const CANBudgetLineTableRow = ({
const feeTotal = totalBudgetLineFeeAmount(amount, fee);
const budgetLineTotalPlusFees = totalBudgetLineAmountPlusFees(amount, feeTotal);
const displayCreatedDate = formatDateToMonthDayYear(creationDate);
const procShopName = useGetAbbreviationForProcurementShopId(procShopId);

const TableRowData = (
<>
Expand Down Expand Up @@ -175,7 +177,7 @@ const CANBudgetLineTableRow = ({
className="margin-0"
style={{ maxWidth: "25rem" }}
>
{`${procShopCode}-Fee Rate: ${procShopFeePercentage * 100}%`}
{`${procShopName}-Fee Rate: ${procShopFeePercentage * 100}%`}
</dd>
</dl>
<div className="font-12px display-flex margin-top-1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ const LegendItem = ({ activeId, id, label, value, color, percent, tagStyleActive
const isGraphActive = activeId === id;

return (
<div className="grid-row margin-top-2 font-12px">
<div className="grid-col-5">
<div className="display-flex flex-justify margin-top-2 font-12px">
<div>
<div className="display-flex flex-align-center">
<FontAwesomeIcon
icon={faCircle}
Expand All @@ -41,12 +41,13 @@ const LegendItem = ({ activeId, id, label, value, color, percent, tagStyleActive
</span>
</div>
</div>
<div className="grid-col-5">
<div >
<CurrencyFormat
value={value}
displayType={"text"}
thousandSeparator={true}
prefix={"$"}
decimalScale={2}
renderText={(value) => (
<span
className={isGraphActive ? "fake-bold" : ""}
Expand All @@ -55,16 +56,17 @@ const LegendItem = ({ activeId, id, label, value, color, percent, tagStyleActive
{value}
</span>
)}
fixedDecimalScale
/>
</div>
<div className="grid-col-2">
<Tag
className="margin-left-1"
tagStyle="darkTextWhiteBackground"
text={percent}
label={label}
active={isGraphActive}
tagStyleActive={tagStyleActive}
dataTestId="legend-tag"
isLegend={true}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe("LegendItem", () => {
render(<LegendItem {...defaultProps} />);

expect(screen.getByText("Test Label")).toBeInTheDocument();
expect(screen.getByText("$1,000")).toBeInTheDocument();
expect(screen.getByText("$1,000.00")).toBeInTheDocument();
expect(screen.getByText("10%")).toBeInTheDocument();
});

Expand Down Expand Up @@ -62,7 +62,7 @@ describe("LegendItem", () => {
/>
);

expect(screen.getByText("$1,234,567")).toBeInTheDocument();
expect(screen.getByText("$1,234,567.00")).toBeInTheDocument();
});

it("renders Tag component with correct props", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const ProjectAgreementBLICard = ({ fiscalYear, projects, agreements, budgetLines
className={`bg-brand-primary-light text-brand-primary-dark ${
index > 0 ? "margin-top-1" : ""
}`}
text={`${count} ${convertCodeForDisplay("agreementType", type)}`}
text={`${count} ${convertCodeForDisplay("agreement", type)}`}
/>
))}
</div>
Expand Down
45 changes: 28 additions & 17 deletions frontend/src/components/UI/Tag/Tag.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import PropTypes from "prop-types";

/**
* @typedef {Object} TagProps
* @property {string} [tagStyle] - The style of the tag.
Expand All @@ -9,6 +7,7 @@ import PropTypes from "prop-types";
* @property {string} [label] - The label of the tag.
* @property {string} [className] - Additional CSS classes.
* @property {number} [dataTestId] - The data test id.
* @property {boolean} [isLegend] - Used within a legend.
* @property {Object} [rest] - Additional props.
* @property {React.ReactNode} [children] - Child elements.
*/
Expand All @@ -18,7 +17,17 @@ import PropTypes from "prop-types";
* @param {TagProps} props - The props.
* @returns {JSX.Element} - The tag element.
*/
const Tag = ({ tagStyle, tagStyleActive, text, active = false, label, className, children, ...rest }) => {
const Tag = ({
tagStyle,
tagStyleActive,
text,
active = false,
label,
className,
children,
isLegend = false,
...rest
}) => {
let tagClasses = "font-12px height-205 radius-md",
activeClass = "";
// OVERRIDES FOR DEFAULT CLASSES
Expand Down Expand Up @@ -108,28 +117,30 @@ const Tag = ({ tagStyle, tagStyleActive, text, active = false, label, className,
}
}

/**
* @param {boolean} isLegend
* @returns {Object} - The styles for the tag.
*/
const handleLegendStyles = (isLegend) => {
if (isLegend) {
return { width: "40px", padding: ".25em .5em", display: "inline-block", textAlign: "center" };
} else {
return {
width: "fit-content", // Ensures the tag's width adapts to its content
padding: ".25em .5em" // Adds some space inside the tag for better readability}
};
}
};

return (
<span
className={`${tagClasses} ${activeClass} ${className}`}
style={{
width: "fit-content", // Ensures the tag's width adapts to its content
padding: ".25em .5em" // Adds some space inside the tag for better readability
}}
style={handleLegendStyles(isLegend)}
data-testid={rest.dataTestId}
>
{text ? text : children}
</span>
);
};

Tag.propTypes = {
tagStyle: PropTypes.string,
text: PropTypes.string,
active: PropTypes.bool,
label: PropTypes.string,
className: PropTypes.string,
children: PropTypes.node,
tagStyleActive: PropTypes.string
};

export default Tag;
7 changes: 7 additions & 0 deletions frontend/src/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@ export const codesToDisplayText = {
project: {
ADMINISTRATIVE_AND_SUPPORT: "Admin & Support",
RESEARCH: "Research"
},
agreement: {
"AgreementType.CONTRACT": "Contract",
"AgreementType.GRANT": "Grant",
"AgreementType.DIRECT_ALLOCATION": "Direct Allocation",
"AgreementType.IAA": "IAA",
"AgreementType.MISCELLANEOUS": "Misc"
}
};

Expand Down
20 changes: 20 additions & 0 deletions frontend/src/hooks/lookup.hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ export const useGetNameForProcurementShopId = (id) => {
return displayName;
};

/**
* This hook returns the abbreviation of a Procurement Shop given the id.
* @param {number} id - The id of the Procurement Shop.
* @returns {string} - The abbreviation of the Procurement Shop.
*/
export const useGetAbbreviationForProcurementShopId = (id) => {
const [displayName, setDisplayName] = React.useState("unknown");

const { data, isSuccess } = useGetProcurementShopsQuery();

React.useEffect(() => {
if (isSuccess) {
const item = data.find((element) => element.id === id);
if (item) setDisplayName(`${item.abbr}`);
}
}, [id, data, isSuccess]);

return displayName;
};

/**
* This hook returns the display name of a Research Project given the id.
* @param {number} id - The id of the Research Project.
Expand Down
21 changes: 13 additions & 8 deletions frontend/src/pages/cans/detail/Can.hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,17 @@ export default function useCan() {
[budgetLineItemsByFiscalYear]
);

const testAgreements = [
{ type: "CONTRACT", count: 8 },
{ type: "GRANT", count: 2 },
{ type: "DIRECT_ALLOCATION", count: 1 },
{ type: "IAA", count: 1 },
{ type: "MISCELLANEOUS", count: 1 }
];

const budgetLineAgreements = can?.budget_line_items?.map(
(item) => item.agreement
) ?? [];


const agreementTypesCount = React.useMemo(
() => getTypesCounts(budgetLineAgreements, "agreement_type"),
[fiscalYear, can]
);


return {
can: can ?? null,
Expand All @@ -71,11 +75,12 @@ export default function useCan() {
plannedFunding: CANFunding?.planned_funding,
obligatedFunding: CANFunding?.obligated_funding,
inExecutionFunding: CANFunding?.in_execution_funding,
inDraftFunding: CANFunding?.in_draft_funding,
expectedFunding: CANFunding?.expected_funding,
receivedFunding: CANFunding?.received_funding,
subTitle: can ? `${can.nick_name} - ${can.active_period} ${can.active_period > 1 ? "Years" : "Year"}` : "",
projectTypesCount,
budgetLineTypesCount,
testAgreements
agreementTypesCount
};
}
6 changes: 4 additions & 2 deletions frontend/src/pages/cans/detail/Can.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ const Can = () => {
plannedFunding,
obligatedFunding,
inExecutionFunding,
inDraftFunding,
subTitle,
projectTypesCount,
budgetLineTypesCount,
testAgreements,
agreementTypesCount,
receivedFunding
} = useCan();

Expand Down Expand Up @@ -85,8 +86,9 @@ const Can = () => {
fiscalYear={fiscalYear}
projectTypesCount={projectTypesCount}
budgetLineTypesCount={budgetLineTypesCount}
agreementTypesCount={testAgreements}
agreementTypesCount={agreementTypesCount}
inExecutionFunding={inExecutionFunding}
inDraftFunding={inDraftFunding}
obligatedFunding={obligatedFunding}
plannedFunding={plannedFunding}
totalFunding={totalFunding}
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/pages/cans/detail/CanSpending.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { calculatePercent } from "../../../helpers/utils";
* @property {ItemCount[]} [agreementTypesCount]
* @property {number} plannedFunding
* @property {number} inExecutionFunding
* @property {number} inDraftFunding
* @property {number} obligatedFunding
* @property {number} totalFunding
*/
Expand All @@ -41,19 +42,19 @@ const CanSpending = ({
agreementTypesCount,
plannedFunding,
inExecutionFunding,
inDraftFunding,
obligatedFunding,
totalFunding
}) => {
const totalSpending = Number(plannedFunding) + Number(obligatedFunding) + Number(inExecutionFunding);
const DRAFT_FUNDING = 1_000_000; // replace with actual data

const graphData = [
{
id: 1,
label: "Draft",
value: Math.round(DRAFT_FUNDING) || 0,
value: Math.round(inDraftFunding) || 0,
color: "var(--neutral-lighter)",
percent: `${calculatePercent(DRAFT_FUNDING, totalFunding)}%`
percent: `${calculatePercent(inDraftFunding, totalFunding)}%`
},
{
id: 2,
Expand Down
Loading

0 comments on commit d025186

Please sign in to comment.