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

wip: adds CAN Funding Received form #3246

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
11 changes: 0 additions & 11 deletions frontend/src/components/CANs/CANBudgetForm/suite.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import CurrencyInput from "../../UI/Form/CurrencyInput";
import TextArea from "../../UI/Form/TextArea";
import icons from "../../../uswds/img/sprite.svg";

/**
* @typedef {Object} CANFundingReceivedFormProps
* @property {(arg: string) => string} cn
* @property {Object} res
* @property {Object} suite
* @property {string} receivedFundingAmount
* @property {(e: React.FormEvent<HTMLFormElement>) => void} handleSubmit
* @property {(name: string, value: string) => void} runValidate
* @property { React.Dispatch<React.SetStateAction<string>>} setReceivedFundingAmount
* @property {string} notes
* @property { React.Dispatch<React.SetStateAction<string>>} setNotes
*/

/**
* @component - The CAN Funding Received Form component.
* @param {CANFundingReceivedFormProps} props
* @returns {JSX.Element} - The component JSX.
*/

const CANFundingReceivedForm = ({
cn,
res,
runValidate,
handleSubmit,
receivedFundingAmount,
setReceivedFundingAmount,
notes,
setNotes
}) => {
return (
<form
onSubmit={(e) => {
handleSubmit(e);
}}
>
<CurrencyInput
name="funding-received-amount"
label="Funding Received"
onChange={(name, value) => {
runValidate("funding-received-amount", value);
}}
setEnteredAmount={setReceivedFundingAmount}
value={receivedFundingAmount || ""}
messages={res.getErrors("funding-received-amount")}
className={cn("funding-received-amount")}
/>
<TextArea
maxLength={75}
name="Notes"
label="Notes (optional)"
value={notes}
onChange={(name, value) => setNotes(value)}
/>
<button className="usa-button usa-button--outline margin-top-4">
<svg
className="height-2 width-2 margin-right-05 cursor-pointer"
style={{ fill: "#005ea2" }}
>
<use xlinkHref={`${icons}#add`}></use>
</svg>
Add Funding Received
</button>
</form>
);
};

export default CANFundingReceivedForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./CanFundingReceivedForm";
35 changes: 25 additions & 10 deletions frontend/src/pages/cans/detail/CanFunding.hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import { useAddCanFundingBudgetsMutation, useUpdateCanFundingBudgetMutation } from "../../../api/opsAPI.js";
import { getCurrentFiscalYear } from "../../../helpers/utils.js";
import useAlert from "../../../hooks/use-alert.hooks";
import suite from "../../../components/CANs/CANBudgetForm/suite.js";
import suite from "./CanFundingSuite.js";
import classnames from "vest/classnames";

/**
Expand All @@ -28,8 +28,12 @@ export default function useCanFunding(
) {
const currentFiscalYear = getCurrentFiscalYear();
const showButton = isBudgetTeamMember && fiscalYear === Number(currentFiscalYear) && !isEditMode;
const [budgetAmount, setBudgetAmount] = React.useState("");
const [submittedAmount, setSubmittedAmount] = React.useState("");
const [budgetAmount, setBudgetAmount] = React.useState(""); // user input
const [submittedAmount, setSubmittedAmount] = React.useState(""); // submitted from add FY budget
const [receivedFundingAmount, setReceivedFundingAmount] = React.useState(""); // user input
const [submittedReceivedFundingAmount, setSubmittedReceivedFundingAmount] = React.useState(""); // submitted from add funding received
const [notes, setNotes] = React.useState("");
const [submittedNotes, setSubmittedNotes] = React.useState("");
const [isBudgetFormSubmitted, setIsBudgetFormSubmitted] = React.useState(false);
const [showModal, setShowModal] = React.useState(false);
const [modalProps, setModalProps] = React.useState({
Expand Down Expand Up @@ -87,6 +91,14 @@ export default function useCanFunding(
setIsBudgetFormSubmitted(true);
};

const handleAddFundingReceived = (e) => {
e.preventDefault();
setSubmittedReceivedFundingAmount(receivedFundingAmount);
setReceivedFundingAmount("");
setSubmittedNotes(notes);
setNotes("");
};

const handleCancel = () => {
setShowModal(true);
setModalProps({
Expand All @@ -102,6 +114,8 @@ export default function useCanFunding(
setSubmittedAmount(totalFunding);
setIsBudgetFormSubmitted(false);
setShowModal(false);
setReceivedFundingAmount("");
setNotes("");
toggleEditMode();
setModalProps({
heading: "",
Expand All @@ -113,28 +127,29 @@ export default function useCanFunding(
};

const runValidate = (name, value) => {
suite(
{
...{ [name]: value }
},
name
);
suite({ submittedAmount, ...{ [name]: value } }, name);
};

return {
budgetAmount,
handleAddBudget,
handleAddFundingReceived,
handleCancel,
handleSubmit,
modalProps,
receivedFundingAmount,
runValidate,
res,
cn,
setBudgetAmount,
setReceivedFundingAmount,
setShowModal,
submittedReceivedFundingAmount,
showButton,
showModal,
submittedAmount,
isBudgetFormSubmitted
isBudgetFormSubmitted,
notes,
setNotes
};
}
115 changes: 76 additions & 39 deletions frontend/src/pages/cans/detail/CanFunding.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import CurrencyCard from "../../../components/UI/Cards/CurrencyCard";
import ConfirmationModal from "../../../components/UI/Modals/index.js";
import RoundedBox from "../../../components/UI/RoundedBox";
import useCanFunding from "./CanFunding.hooks.js";
import CANFundingReceivedForm from "../../../components/CANs/CANFundingReceivedForm";
import DebugCode from "../../../components/DebugCode";

/**
* @typedef {import("../../../components/CANs/CANTypes").FundingDetails} FundingDetails
Expand Down Expand Up @@ -58,16 +60,22 @@ const CanFunding = ({
const {
budgetAmount,
handleAddBudget,
handleAddFundingReceived,
handleCancel,
handleSubmit,
modalProps,
runValidate,
receivedFundingAmount,
cn,
notes,
res,
setBudgetAmount,
setNotes,
setReceivedFundingAmount,
setShowModal,
showButton,
showModal,
submittedReceivedFundingAmount,
submittedAmount,
isBudgetFormSubmitted
} = useCanFunding(
Expand Down Expand Up @@ -148,49 +156,78 @@ const CanFunding = ({
</div>
</section>
) : (
<section
id="can-budget-form-section"
className="margin-bottom-8"
>
<h2>{`Add FY ${fiscalYear} CAN Budget`}</h2>
<p>{`Enter the FY ${fiscalYear} CAN Budget that teams will utilize for planning. For Multi-Year CANs, the Previous FYs Carry-Forward will display for you to review and enter as-is or edit, if needed.`}</p>
<div className="display-flex flex-justify margin-top-4">
<div
className="border-right-1px border-base-light"
style={{ minWidth: "46%" }}
>
<RoundedBox
className="font-12px"
style={{ minHeight: "69px", width: "313px", padding: "17px 0 0 13px" }}
id="carry-forward-card"
<div>
<section
id="can-budget-form-section"
className="margin-bottom-8"
>
<h2>{`Add FY ${fiscalYear} CAN Budget`}</h2>
<p>{`Enter the FY ${fiscalYear} CAN Budget that teams will utilize for planning. For Multi-Year CANs, the Previous FYs Carry-Forward will display for you to review and enter as-is or edit, if needed.`}</p>
<div className="display-flex flex-justify margin-top-4">
<div
className="border-right-1px border-base-light"
style={{ minWidth: "46%" }}
>
<p className="margin-0 text-base-dark">Previous FYs Carry Forward</p>
<CurrencyFormat
value={carryForwardFunding}
displayType="text"
thousandSeparator={true}
decimalScale={2}
fixedDecimalScale={true}
prefix="$ "
<RoundedBox
className="font-12px"
style={{ minHeight: "69px", width: "313px", padding: "17px 0 0 13px" }}
id="carry-forward-card"
>
<p className="margin-0 text-base-dark">Previous FYs Carry Forward</p>
<CurrencyFormat
value={carryForwardFunding}
displayType="text"
thousandSeparator={true}
decimalScale={2}
fixedDecimalScale={true}
prefix="$ "
/>
</RoundedBox>
<CANBudgetForm
budgetAmount={budgetAmount}
cn={cn}
res={res}
fiscalYear={fiscalYear}
handleAddBudget={handleAddBudget}
runValidate={runValidate}
setBudgetAmount={setBudgetAmount}
/>
</RoundedBox>
<CANBudgetForm
budgetAmount={budgetAmount}
cn={cn}
res={res}
fiscalYear={fiscalYear}
handleAddBudget={handleAddBudget}
runValidate={runValidate}
setBudgetAmount={setBudgetAmount}
</div>
<CurrencyCard
amount={submittedAmount}
dataCy="can-budget-fy-card"
headerText={`FY ${fiscalYear} CAN Budget`}
/>
</div>
<CurrencyCard
amount={submittedAmount}
dataCy="can-budget-fy-card"
headerText={`FY ${fiscalYear} CAN Budget`}
/>
</div>
</section>
</section>
<section id="can-funding-received-form-section">
<h2>{`Add FY ${fiscalYear} Funding Received YTD`}</h2>
<p>{`Add funding received towards the Total FY ${fiscalYear} Budget or come back to add funding later. Funding Received means the money is in OPRE’s hands and ready to spend against.`}</p>
<div className="display-flex flex-justify margin-top-4">
<div
className="border-right-1px border-base-light"
style={{ minWidth: "46%" }}
>
<CANFundingReceivedForm
receivedFundingAmount={receivedFundingAmount}
setReceivedFundingAmount={setReceivedFundingAmount}
handleSubmit={handleAddFundingReceived}
setNotes={setNotes}
notes={notes}
cn={cn}
res={res}
runValidate={runValidate}
/>
</div>
<ReceivedFundingCard
title={`FY ${fiscalYear} Funding Received YTD`}
totalReceived={submittedReceivedFundingAmount || 0}
totalFunding={submittedAmount}
/>
</div>
<DebugCode data={{ receivedFundingAmount, submittedReceivedFundingAmount, notes }} />
</section>
</div>
)}
<Accordion
heading="Funding Received YTD"
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/pages/cans/detail/CanFundingSuite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { create, test, enforce, only } from "vest";

const suite = create((data = {}, fieldName) => {
only(fieldName);

test("budget-amount", "This is required information", () => {
enforce(data["budget-amount"]).isNotBlank();
});

test("funding-received-amount", "This is required information", () => {
enforce(data["funding-received-amount"]).isNotBlank();
});

test("funding-received-amount", "Amount cannot exceed FY Budget", () => {
enforce(data["funding-received-amount"]).lessThanOrEquals(data.submittedAmount);
});
});

export default suite;
Loading