From 0a2c88a4caa1f5a24ae4b0498d4ed6c36316e8d0 Mon Sep 17 00:00:00 2001 From: almorbah <149511814+almorbah@users.noreply.github.com> Date: Thu, 25 Jul 2024 11:14:37 -0500 Subject: [PATCH] Al/APPEALS-45335 (#22228) * added additional option to check box list * fixed some tests and code clean up * fixed more tests * fixed jest tests * changes per Pr feedback * added custom error display * fixed style for error message --------- Co-authored-by: Sean Craig --- client/app/nonComp/pages/ReportPage.jsx | 159 ++++++++++++++---- .../REPORT_PAGE_VALIDATION_ERRORS.json | 1 + client/constants/REPORT_TYPE_CONSTANTS.json | 128 +++++++++----- .../test/app/nonComp/pages/ReportPage.test.js | 21 ++- 4 files changed, 228 insertions(+), 81 deletions(-) diff --git a/client/app/nonComp/pages/ReportPage.jsx b/client/app/nonComp/pages/ReportPage.jsx index 3e3a7ba89a8..cedae7187b3 100644 --- a/client/app/nonComp/pages/ReportPage.jsx +++ b/client/app/nonComp/pages/ReportPage.jsx @@ -1,3 +1,4 @@ +/* eslint-disable max-lines */ import React, { useEffect } from 'react'; import { useController, useForm, FormProvider, useFormContext } from 'react-hook-form'; import { useDispatch, useSelector } from 'react-redux'; @@ -5,6 +6,7 @@ import { downloadReportCSV } from 'app/nonComp/actions/changeHistorySlice'; import { css } from 'glamor'; import PropTypes from 'prop-types'; +import Alert from 'app/components/Alert'; import Button from 'app/components/Button'; import NonCompLayout from '../components/NonCompLayout'; import { conditionsSchema, ReportPageConditions } from '../components/ReportPage/ReportPageConditions'; @@ -27,7 +29,7 @@ import { RADIO_STATUS_OPTIONS, RADIO_STATUS_REPORT_TYPE_OPTIONS, SPECIFIC_STATUS_OPTIONS, - SPECTIFIC_EVENT_OPTIONS + SPECIFIC_EVENT_OPTIONS } from 'constants/REPORT_TYPE_CONSTANTS'; import * as ERRORS from 'constants/REPORT_PAGE_VALIDATION_ERRORS'; @@ -42,6 +44,13 @@ const buttonOuterContainerStyling = css({ marginTop: '4rem', }); +const outerContainerStyling = css({ + display: 'flex', + justifyContent: 'space-between', + paddingLeft: '30px', + gap: '3em', +}); + const specificEventTypeSchema = yup.lazy((value) => { // eslint-disable-next-line no-undefined if (value === undefined) { @@ -52,13 +61,22 @@ const specificEventTypeSchema = yup.lazy((value) => { added_decision_date: yup.boolean(), added_issue: yup.boolean(), added_issue_no_decision_date: yup.boolean(), + removed_issue: yup.boolean(), + withdrew_issue: yup.boolean(), + completed_disposition: yup.boolean(), claim_created: yup.boolean(), claim_closed: yup.boolean(), claim_status_incomplete: yup.boolean(), + claim_status_pending: yup.boolean(), claim_status_inprogress: yup.boolean(), - completed_disposition: yup.boolean(), - removed_issue: yup.boolean(), - withdrew_issue: yup.boolean(), + requested_issue_modification: yup.boolean(), + requested_issue_addition: yup.boolean(), + requested_issue_removal: yup.boolean(), + requested_issue_withdrawal: yup.boolean(), + approval_of_request: yup.boolean(), + rejection_of_request: yup.boolean(), + cancellation_of_request: yup.boolean(), + edit_of_request: yup.boolean(), }).test('at-least-one-true', ERRORS.AT_LEAST_ONE_OPTION, (obj) => { return Object.values(obj).some((val) => val === true); }); @@ -130,28 +148,11 @@ const ReportPageButtons = ({ ); }; -const RHFCheckboxGroup = ({ options, name, control }) => { - const { field } = useController({ - control, - name - }); - - const { errors } = useFormContext(); - - const [value, setValue] = React.useState({}); - - let fieldClasses = 'checkbox'; - - const errorMessage = get(errors, name)?.message; - - if (errorMessage) { - fieldClasses += ' usa-input-error'; - fieldClasses += ' less-error-padding'; - } +const EventCheckboxGroup = ({ header, options, name, onChange }) => { return ( -
- {errorMessage ?
{ errorMessage }
: null} +
+ { header &&

{header}

} {options.map((option) => (
{ key={`${name}.${option.id}`} label={option.label} stronglabel - onChange={(val) => { - value[option.id] = val; - field.onChange(value); - setValue(value); - }} unpadded + onChange={(val) => onChange({ option, val })} />
))} -
+ + ); +}; + +const RHFCheckboxGroup = ({ options, name, control }) => { + const { errors } = useFormContext(); + + let fieldClasses = 'checkbox'; + const errorMessage = get(errors, name)?.message; + + const { field } = useController({ + control, + name + }); + + if (errorMessage) { + fieldClasses += ' usa-input-error'; + fieldClasses += ' less-error-padding'; + } + + const [value, setValue] = React.useState({}); + + const onCheckboxClick = ({ option, val }) => { + value[option.id] = val; + field.onChange(value); + setValue(value); + }; + + const messageStyling = css({ + fontSize: '17px !important', + paddingTop: '2px !important' + }); + + return ( +
+ {name === 'specificEventType' ? +
+ {errorMessage && + + } +
+ + + +
+
: +
+ {errorMessage ?
{ errorMessage }
: null} + +
+ } +
); }; @@ -210,20 +281,30 @@ const ReportPage = ({ history }) => { specificStatus: { incomplete: '', in_progress: '', + pending: '', completed: '', cancelled: '' }, specificEventType: { - added_decision_date: '', - added_issue: '', - added_issue_no_decision_date: '', claim_created: '', claim_closed: '', claim_status_incomplete: '', + claim_status_pending: '', claim_status_inprogress: '', - completed_disposition: '', + added_decision_date: '', + added_issue: '', + added_issue_no_decision_date: '', removed_issue: '', withdrew_issue: '', + completed_disposition: '', + requested_issue_modification: '', + requested_issue_addition: '', + requested_issue_removal: '', + requested_issue_withdrawal: '', + approval_of_request: '', + rejection_of_request: '', + cancellation_of_request: '', + edit_of_request: '', } }; @@ -374,7 +455,7 @@ const ReportPage = ({ history }) => { {watchReportType === 'event_type_action' && watchRadioEventAction === 'specific_events_action' ? ( @@ -411,6 +492,13 @@ RHFCheckboxGroup.propTypes = { errorMessage: PropTypes.string }; +EventCheckboxGroup.propTypes = { + options: PropTypes.array, + onChange: PropTypes.func, + header: PropTypes.string, + name: PropTypes.string +}; + RHFRadioButton.propTypes = { options: PropTypes.array, control: PropTypes.object, @@ -419,3 +507,4 @@ RHFRadioButton.propTypes = { }; export default ReportPage; +/* eslint-enable max-lines */ diff --git a/client/constants/REPORT_PAGE_VALIDATION_ERRORS.json b/client/constants/REPORT_PAGE_VALIDATION_ERRORS.json index 6757f9945d4..17ec7ce7621 100644 --- a/client/constants/REPORT_PAGE_VALIDATION_ERRORS.json +++ b/client/constants/REPORT_PAGE_VALIDATION_ERRORS.json @@ -8,5 +8,6 @@ "END_DATE_SMALL": "End date must be greater than the start date", "DATE_FUTURE": "Date cannot be in the future", "AT_LEAST_ONE_OPTION": "Please select at least one option", + "AT_LEAST_ONE_CHECKBOX_OPTION": "Please select at least one checkbox from one of the sections below.", "MISSING_PERSONNEL": "Please select at least one team member" } diff --git a/client/constants/REPORT_TYPE_CONSTANTS.json b/client/constants/REPORT_TYPE_CONSTANTS.json index f84e99bb1c2..739bf7caf22 100644 --- a/client/constants/REPORT_TYPE_CONSTANTS.json +++ b/client/constants/REPORT_TYPE_CONSTANTS.json @@ -46,6 +46,10 @@ "label": "Incomplete", "id": "incomplete" }, + { + "label": "Pending", + "id": "pending" + }, { "label": "In Progress", "id": "in_progress" @@ -59,46 +63,90 @@ "id": "cancelled" } ], - "SPECTIFIC_EVENT_OPTIONS": [ - { - "label": "Added decision date", - "id": "added_decision_date" - }, - { - "label": "Added issue", - "id": "added_issue" - }, - { - "label": "Added issue - No decision date", - "id":"added_issue_no_decision_date" - }, - { - "label": "Claim created", - "id":"claim_created" - }, - { - "label": "Claim closed", - "id":"claim_closed" - }, - { - "label": "Claim status - Incomplete", - "id":"claim_status_incomplete" - }, - { - "label": "Claim status - In progress", - "id":"claim_status_inprogress" - }, - { - "label": "Completed disposition", - "id":"completed_disposition" - }, - { - "label": "Removed issue", - "id":"removed_issue" - }, - { - "label": "Withdrew issue", - "id":"withdrew_issue" + "SPECIFIC_EVENT_OPTIONS": [ + { + "system": [ + { + "label": "Claim created", + "id":"claim_created" + }, + { + "label": "Claim closed", + "id":"claim_closed" + }, + { + "label": "Claim status - Incomplete", + "id":"claim_status_incomplete" + }, + { + "label": "Claim status - Pending", + "id":"claim_status_pending" + }, + { + "label": "Claim status - In progress", + "id":"claim_status_inprogress" + } + ], + "general": [ + { + "label": "Added decision date", + "id": "added_decision_date" + }, + { + "label": "Added issue", + "id": "added_issue" + }, + { + "label": "Added issue - No decision date", + "id":"added_issue_no_decision_date" + }, + { + "label": "Removed issue", + "id":"removed_issue" + }, + { + "label": "Withdrew issue", + "id":"withdrew_issue" + }, + { + "label": "Completed disposition", + "id":"completed_disposition" + } + ], + "requests": [ + { + "label": "Requested issue modification", + "id":"requested_issue_modification" + }, + { + "label": "Requested issue addition", + "id":"requested_issue_addition" + }, + { + "label": "Requested issue removal", + "id":"requested_issue_removal" + }, + { + "label": "Requested issue withdrawal", + "id":"requested_issue_withdrawal" + }, + { + "label": "Approval of request", + "id":"approval_of_request" + }, + { + "label": "Rejection of request", + "id":"rejection_of_request" + }, + { + "label": "Cancellation of request", + "id":"cancellation_of_request" + }, + { + "label": "Edit of request", + "id":"edit_of_request" + } + ] } ], "TIMING_SPECIFIC_OPTIONS": [ diff --git a/client/test/app/nonComp/pages/ReportPage.test.js b/client/test/app/nonComp/pages/ReportPage.test.js index 502d9832392..000efd127af 100644 --- a/client/test/app/nonComp/pages/ReportPage.test.js +++ b/client/test/app/nonComp/pages/ReportPage.test.js @@ -13,6 +13,7 @@ import { getVhaUsers } from 'test/helpers/reportPageHelper'; import CombinedNonCompReducer from 'app/nonComp/reducers'; import REPORT_TYPE_CONSTANTS from 'constants/REPORT_TYPE_CONSTANTS'; +import * as ERRORS from 'constants/REPORT_PAGE_VALIDATION_ERRORS'; describe('ReportPage', () => { const setup = (storeValues = {}) => { @@ -375,7 +376,7 @@ describe('ReportPage', () => { }); - it('should add 10 checkboxes when radio Specific Events/ Actions is clicked', async () => { + it('should add 19 checkboxes when radio Specific Events/ Actions is clicked', async () => { setup(); await selectEvent.select(screen.getByLabelText('Report Type'), ['Status', 'Event / Action']); @@ -386,9 +387,17 @@ describe('ReportPage', () => { expect(specificEvents.length).toBe(1); fireEvent.click(screen.getByLabelText('Specific Events / Actions')); - expect(screen.getAllByRole('checkbox').length).toBe(10); + expect(screen.getAllByRole('checkbox').length).toBe(19); - REPORT_TYPE_CONSTANTS.SPECTIFIC_EVENT_OPTIONS.forEach((option) => { + REPORT_TYPE_CONSTANTS.SPECIFIC_EVENT_OPTIONS[0].system.forEach((option) => { + expect(screen.getAllByText(option.label)).toBeTruthy(); + }); + + REPORT_TYPE_CONSTANTS.SPECIFIC_EVENT_OPTIONS[0].general.forEach((option) => { + expect(screen.getAllByText(option.label)).toBeTruthy(); + }); + + REPORT_TYPE_CONSTANTS.SPECIFIC_EVENT_OPTIONS[0].requests.forEach((option) => { expect(screen.getAllByText(option.label)).toBeTruthy(); }); }); @@ -407,14 +416,14 @@ describe('ReportPage', () => { fireEvent.click(screen.getByLabelText('Specific Events / Actions')); - expect(screen.getAllByRole('checkbox').length).toBe(10); + expect(screen.getAllByRole('checkbox').length).toBe(19); const generateTaskReport = screen.getByRole('button', { name: /Generate task report/i }); await userEvent.click(generateTaskReport); await waitFor(() => { - expect(screen.getAllByText('Please select at least one option').length).toBe(1); + expect(screen.getAllByText(ERRORS.AT_LEAST_ONE_CHECKBOX_OPTION).length).toBe(1); }); }); @@ -430,7 +439,7 @@ describe('ReportPage', () => { expect(specificEvents.length).toBe(1); fireEvent.click(screen.getByLabelText('Specific Status')); - expect(screen.getAllByRole('checkbox').length).toBe(4); + expect(screen.getAllByRole('checkbox').length).toBe(5); REPORT_TYPE_CONSTANTS.SPECIFIC_STATUS_OPTIONS.map((option) => expect(screen.getAllByText(option.label)).toBeTruthy()