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

Main -> Val #139764

Merged
merged 6 commits into from
Sep 17, 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
16 changes: 15 additions & 1 deletion .github/workflows/destroy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,18 @@ jobs:
inputs: '{ "topics": "mgmt.connect.cms-carts-seds.carts-bigmac-streams-${{env.BRANCH_NAME}}.config,mgmt.connect.cms-carts-seds.carts-bigmac-streams-${{env.BRANCH_NAME}}.offsets,mgmt.connect.cms-carts-seds.carts-bigmac-streams-${{env.BRANCH_NAME}}.status"}'
ref: refs/heads/master # Otherwise workflow-dispatch tries to operate off of our default name
- name: Destroy
run: ./run destroy --stage $STAGE_PREFIX$branch_name --verify false
run: ./run destroy --stage $STAGE_PREFIX$branch_name --verify false

# Notify the integrations channel when a destroy action fails
notify_on_destroy_failure:
runs-on: ubuntu-latest
needs:
- destroy
if: ${{ failure() }}
steps:
- name: Slack Notification
uses: rtCamp/action-slack-notify@v2
env:
SLACK_TITLE: ":boom: A destroy action has failed on ${{ github.repository }}."
MSG_MINIMAL: true
SLACK_WEBHOOK: ${{ secrets.INTEGRATIONS_SLACK_WEBHOOK }}
2 changes: 1 addition & 1 deletion .images/architecture.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions services/app-api/libs/validation/backend-section.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ export const sectionSchema = {
hint: {
type: "string",
},
mask: {
type: "string",
},
questions: {
type: "array",
items: {
Expand Down
14,633 changes: 3,693 additions & 10,940 deletions services/database/data/seed-local/seed-section.json

Large diffs are not rendered by default.

19 changes: 6 additions & 13 deletions services/ui-src/src/components/fields/DataGrid.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import PropTypes from "prop-types";
import Question from "./Question";
import { connect, useDispatch } from "react-redux";
import { ADD_TO_TOTAL, FINISH_CALCULATION } from "../../store/lastYearTotals";

const DataGrid = ({ question, lastYearFormData }) => {
const DataGrid = ({ question, printView }) => {
const [renderQuestions, setRenderQuestions] = useState([]);
const [questionsToSet, setQuestionsToSet] = useState([]);
const lastYearFormData = useSelector((state) => state.lastYearFormData);
const dispatch = useDispatch();

const rowStyle =
Expand Down Expand Up @@ -138,6 +139,7 @@ const DataGrid = ({ question, lastYearFormData }) => {
hideNumber={question.type !== "fieldset"}
question={question.question}
prevYear={question.prevYear}
printView={printView}
/>
</div>
);
Expand All @@ -148,16 +150,7 @@ const DataGrid = ({ question, lastYearFormData }) => {

DataGrid.propTypes = {
question: PropTypes.object.isRequired,
year: PropTypes.number.isRequired,
state: PropTypes.string.isRequired,
lastYearFormData: PropTypes.object.isRequired,
printView: PropTypes.bool,
};

const mapStateToProps = (state) => ({
year: state.formData[0].contents.section.year,
state: state.formData[0].contents.section.state,
lastYearFormData: state.lastYearFormData,
lastYearTotals: state.lastYearTotals,
});

export default connect(mapStateToProps)(DataGrid);
export default DataGrid;
86 changes: 66 additions & 20 deletions services/ui-src/src/components/fields/Integer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,54 @@ import { TextField } from "@cmsgov/design-system";
import { useSelector } from "react-redux";
import { generateQuestionNumber } from "../utils/helperFunctions";

const Integer = ({ onChange, question, prevYear, ...props }) => {
const getPrevYearValue = (question, lastYearFormData) => {
let prevYearValue;

// Split and create array from id
const splitID = question.id.split("-");

// the subquestion id (a, b, c, etc)
const questionId = splitID[5];

// Custom handling for -03-c-05 and -03-c-06
if (
splitID[1] === "03" &&
splitID[2] === "c" &&
(splitID[3] === "05" || splitID[3] === "06") &&
questionId === "a" &&
parseInt(splitID[4]) > 2 &&
parseInt(splitID[4]) < 10
) {
// Set year to last year
splitID[0] = parseInt(splitID[0]) - 1;
splitID.pop();

const fieldsetId = splitID.join("-");
const partIndex = parseInt(splitID[3]) - 1;

// Get questions from last years JSON
const questions =
lastYearFormData[3].contents.section.subsections[2].parts[partIndex]
.questions;

// Filter down to this question
const matchingQuestion = questions.filter(
(question) => fieldsetId === question?.fieldset_info?.id
);

// The first will always be correct
if (matchingQuestion[0]) {
prevYearValue = parseInt(matchingQuestion[0].questions[0].answer?.entry);
}
}
return prevYearValue;
};

const Integer = ({ onChange, question, prevYear, printView, ...props }) => {
const [error, setError] = useState(false);
const [answer, setAnswer] = useState(question.answer.entry);
const lastYearTotals = useSelector((state) => state.lastYearTotals);
const prevYearNumber =
lastYearTotals[question.id.substring(0, question.id.length - 2)];
const lastYearFormData = useSelector((state) => state.lastYearFormData);

const change = ({ target: { name, value } }) => {
const stripped = value.replace(/[^0-9]+/g, "");
const parsed = parseFloat(stripped);
Expand All @@ -25,22 +67,26 @@ const Integer = ({ onChange, question, prevYear, ...props }) => {
}
};

if (prevYearNumber && question.id.indexOf("-a") > -1) {
const isLessThanElevenMask = (value) => {
return (
<TextField
className="ds-c-input"
errorMessage={error}
label={`${generateQuestionNumber(question.id)} ${question.label}`}
hint={question.hint}
name={question.id}
numeric
onChange={change}
value={prevYearNumber}
{...props}
/>
printView &&
question.mask === "lessThanEleven" &&
value <= 10 &&
value > 0
);
}
const renderAnswer = (val) => (val || Number.isInteger(val) ? val : ""); // may attempt to rerender string on page load, so both val || isInteger
};

const renderAnswer = () => {
if (answer === null) {
const value =
getPrevYearValue(question, lastYearFormData) ?? prevYear?.value;
if (isLessThanElevenMask(value)) return "<11";
return value;
} else {
if (isLessThanElevenMask(answer)) return "<11";
return answer || Number.isInteger(answer) ? answer : "";
}
};
return (
<TextField
className="ds-c-input"
Expand All @@ -50,7 +96,7 @@ const Integer = ({ onChange, question, prevYear, ...props }) => {
name={question.id}
numeric
onChange={change}
value={answer != null ? renderAnswer(answer) : prevYear && prevYear.value}
value={renderAnswer()}
{...props}
/>
);
Expand All @@ -59,7 +105,7 @@ Integer.propTypes = {
onChange: PropTypes.func.isRequired,
question: PropTypes.object.isRequired,
prevYear: PropTypes.object,
printView: PropTypes.bool,
};

export { Integer };
export default Integer;
105 changes: 101 additions & 4 deletions services/ui-src/src/components/fields/Integer.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,48 @@ import Integer from "./Integer";
import { screen, render, fireEvent } from "@testing-library/react";

const mockStore = configureMockStore();
const store = mockStore({ lastYearTotals: { 2022: [] } });
const lastYearFormData = [
{},
{},
{},
{
contents: {
section: {
subsections: [
{},
{},
{
parts: [
{},
{},
{},
{},
{
questions: [
{
fieldset_info: {
id: "2022-03-c-05-03",
},
questions: [{ answer: { entry: 3000 } }],
},
],
},
],
},
],
},
},
},
];
const store = mockStore({ lastYearTotals: { 2022: [] }, lastYearFormData });
const buildInteger = (intProps) => {
return (
<Provider store={store}>
<Integer onChange={() => {}} {...intProps} />
</Provider>
);
};

describe("<Integer />", () => {
it("should render correctly", () => {
const props = { question: { id: "2023-00-a-01-01", answer: 1 } };
Expand All @@ -29,7 +63,7 @@ describe("<Integer />", () => {
const props = {
question: {
id: "2023-00-a-01-01",
label: "How many lightbulbs does it take to change a man?",
label: "Example Question",
answer: { entry: 123 },
},
};
Expand All @@ -45,7 +79,7 @@ describe("<Integer />", () => {
const props = {
question: {
id: "2023-00-a-01-01",
label: "How many lightbulbs does it take to change a man?",
label: "Example Question",
answer: { entry: 123 },
},
};
Expand All @@ -61,7 +95,7 @@ describe("<Integer />", () => {
const props = {
question: {
id: "2023-00-a-01-01",
label: "How many lightbulbs does it take to change a man?",
label: "Example Question",
answer: { entry: "hope" },
},
};
Expand All @@ -73,4 +107,67 @@ describe("<Integer />", () => {
expect(screen.queryByDisplayValue("raw text")).not.toBeInTheDocument();
expect(screen.getByRole("alert")).toBeInTheDocument();
});

it("should show <11 if passed >0 and <=10 with printView and lessThanEleven", () => {
const props = {
question: {
id: "2023-00-a-01-01",
label: "Example Question",
answer: { entry: "5" },
mask: "lessThanEleven",
},
printView: true,
};

render(buildInteger(props));
expect(screen.getByDisplayValue("<11")).toBeInTheDocument();
expect(screen.queryByDisplayValue("5")).not.toBeInTheDocument();
});

it("should show original answer if passed >=11 with printView and lessThanEleven mask", () => {
const props = {
question: {
id: "2023-00-a-01-01",
label: "Example Question",
answer: { entry: "12" },
mask: "lessThanEleven",
},
printView: true,
};

render(buildInteger(props));
expect(screen.getByDisplayValue("12")).toBeInTheDocument();
});

it("should show original answer if passed 0 with printView and lessThanEleven mask", () => {
const props = {
question: {
id: "2023-00-a-01-01",
label: "Example Question",
answer: { entry: "0" },
mask: "lessThanEleven",
},
printView: true,
};

render(buildInteger(props));
expect(screen.getByDisplayValue("0")).toBeInTheDocument();
});

it("should render previous year value for appropriate 3c part 5 or 6 questions", () => {
const props = {
question: {
id: "2023-03-c-05-03-a",
label: "How much?",
answer: { entry: null },
},
};

render(buildInteger(props));

expect(screen.getByDisplayValue("3000")).toBeInTheDocument();
const input = screen.getByRole("textbox");
fireEvent.change(input, { target: { value: 234 } });
expect(screen.getByDisplayValue("234")).toBeInTheDocument();
});
});
2 changes: 1 addition & 1 deletion services/ui-src/src/components/fields/Money.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import PropTypes from "prop-types";
import { Integer } from "./Integer";
import Integer from "./Integer";

const Money = ({ ...props }) => {
return <Integer {...props} inputMode="currency" mask="currency" />;
Expand Down
6 changes: 3 additions & 3 deletions services/ui-src/src/components/fields/Objective.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import { AccordionButton, AccordionPanel } from "@reach/accordion";

import Question from "./Question";

const Objective = ({ headerRef, objective, objectiveNumber }) => {
const Objective = ({ headerRef, objective, objectiveNumber, printView }) => {
const first = objective.questions[0].answer.readonly === true;
const name = first
? objective.questions[0].answer.default_entry
: objective.questions[0].answer.entry;

const children = first ? objective.questions.slice(1) : objective.questions;

return (
<>
<div className="accordion-header" ref={headerRef}>
Expand All @@ -27,7 +26,7 @@ const Objective = ({ headerRef, objective, objectiveNumber }) => {
<AccordionPanel>
{children.map((q) => (
<div className="ds-c-choice__checkedChild">
<Question key={q.id} question={q} />
<Question key={q.id} question={q} printView={printView} />
</div>
))}
</AccordionPanel>
Expand All @@ -38,6 +37,7 @@ Objective.propTypes = {
headerRef: PropTypes.func.isRequired,
objective: PropTypes.object.isRequired,
objectiveNumber: PropTypes.number.isRequired,
printView: PropTypes.bool,
};

export { Objective };
Expand Down
Loading
Loading