diff --git a/services/app-web/src/pages/App/AppRoutes.tsx b/services/app-web/src/pages/App/AppRoutes.tsx index 299677ea3c..7fb031922b 100644 --- a/services/app-web/src/pages/App/AppRoutes.tsx +++ b/services/app-web/src/pages/App/AppRoutes.tsx @@ -185,10 +185,6 @@ const CMSUserRoutes = ({ /> )} - } - /> }> {showQuestionResponse && ( @@ -205,6 +201,10 @@ const CMSUserRoutes = ({ /> )} + } + /> } diff --git a/services/app-web/src/pages/MccrsId/MccrsId.test.tsx b/services/app-web/src/pages/MccrsId/MccrsId.test.tsx new file mode 100644 index 0000000000..a1379a688b --- /dev/null +++ b/services/app-web/src/pages/MccrsId/MccrsId.test.tsx @@ -0,0 +1,165 @@ +import { screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' + +import { + ldUseClientSpy, + renderWithProviders, +} from '../../testHelpers/jestHelpers' +import { MccrsId } from './MccrsId' + +describe('MCCRSID', () => { + beforeEach(() => { + ldUseClientSpy({ 'cms-questions': false }) + }) + afterEach(() => { + jest.resetAllMocks() + }) + + it('renders without errors', async () => { + renderWithProviders(, { + routerProvider: { + route: '/submissions/15/MCCRS-record-number', + }, + }) + + expect( + await screen.findByRole('heading', { name: 'MC-CRS record number' }) + ).toBeInTheDocument() + expect( + screen.getByRole('button', { name: 'Save MC-CRS number' }) + ).not.toHaveAttribute('aria-disabled') + }) + + it('displays the text field for mccrs id', async () => { + renderWithProviders(, { + routerProvider: { + route: '/submissions/15/MCCRS-record-number', + }, + }) + + expect(screen.getByTestId('textInput')).toBeInTheDocument() + }) + + it('cannot continue without providing a MCCRS ID', async () => { + renderWithProviders(, { + routerProvider: { + route: '/submissions/15/MCCRS-record-number', + }, + }) + const continueButton = screen.getByRole('button', { + name: 'Save MC-CRS number', + }) + continueButton.click() + await waitFor(() => { + expect( + screen.getAllByText( + 'You must enter a record number or delete this field.' + ) + ).toHaveLength(1) + expect(continueButton).toHaveAttribute('aria-disabled', 'true') + }) + }) + + it('cannot continue with MCCRS ID less than 4 digits', async () => { + renderWithProviders(, { + routerProvider: { + route: '/submissions/15/MCCRS-record-number', + }, + }) + + screen + .getByLabelText( + 'Enter the Managed Care Contract and Rate Review System (MC-CRS) record number.' + ) + .focus() + await userEvent.paste('123') + const continueButton = screen.getByRole('button', { + name: 'Save MC-CRS number', + }) + continueButton.click() + await waitFor(() => { + expect( + screen.getAllByText( + 'You must enter no more than [4] characters' + ) + ).toHaveLength(1) + expect(continueButton).toHaveAttribute('aria-disabled', 'true') + }) + }) + + it('cannot continue with MCCRS ID more than 4 digits', async () => { + renderWithProviders(, { + routerProvider: { + route: '/submissions/15/MCCRS-record-number', + }, + }) + + screen + .getByLabelText( + 'Enter the Managed Care Contract and Rate Review System (MC-CRS) record number.' + ) + .focus() + await userEvent.paste('12345') + const continueButton = screen.getByRole('button', { + name: 'Save MC-CRS number', + }) + continueButton.click() + await waitFor(() => { + expect( + screen.getAllByText( + 'You must enter no more than [4] characters' + ) + ).toHaveLength(1) + expect(continueButton).toHaveAttribute('aria-disabled', 'true') + }) + }) + + it('cannot continue with MCCRS ID with non number input', async () => { + renderWithProviders(, { + routerProvider: { + route: '/submissions/15/MCCRS-record-number', + }, + }) + + screen + .getByLabelText( + 'Enter the Managed Care Contract and Rate Review System (MC-CRS) record number.' + ) + .focus() + await userEvent.paste('123a') + const continueButton = screen.getByRole('button', { + name: 'Save MC-CRS number', + }) + continueButton.click() + await waitFor(() => { + expect(screen.getAllByText('You must enter a number')).toHaveLength( + 1 + ) + expect(continueButton).toHaveAttribute('aria-disabled', 'true') + }) + }) + + it('successfully adds the MCCRS ID', async () => { + renderWithProviders(, { + routerProvider: { + route: '/submissions/15/MCCRS-record-number', + }, + }) + + screen + .getByLabelText( + 'Enter the Managed Care Contract and Rate Review System (MC-CRS) record number.' + ) + .focus() + await userEvent.paste('1234') + const continueButton = screen.getByRole('button', { + name: 'Save MC-CRS number', + }) + continueButton.click() + await waitFor(() => { + expect( + screen.getByText('Add MC-CRS record number') + ).toBeInTheDocument() + }) + }) +}) diff --git a/services/app-web/src/pages/MccrsId/MccrsId.tsx b/services/app-web/src/pages/MccrsId/MccrsId.tsx index c529f8ff2d..ea78554ae9 100644 --- a/services/app-web/src/pages/MccrsId/MccrsId.tsx +++ b/services/app-web/src/pages/MccrsId/MccrsId.tsx @@ -1,18 +1,15 @@ import React, { useState } from 'react' -import { Form as UswdsForm, ButtonGroup, Button } from '@trussworks/react-uswds' -import { Formik, FormikErrors, FormikHelpers } from 'formik' +import { Form as UswdsForm, ButtonGroup } from '@trussworks/react-uswds' +import { Formik, FormikErrors } from 'formik' import { FieldTextInput } from '../../components/Form' -import { ActionButton } from '../../components/ActionButton' import { MccrsIdFormSchema } from './MccrsIdSchema' import { recordJSException } from '../../otelHelpers/tracingHelper' -import { useNavigate, useOutletContext, useParams } from 'react-router-dom' - +import { useNavigate, useParams } from 'react-router-dom' +import { GenericApiErrorBanner } from '../../components/Banner/GenericApiErrorBanner/GenericApiErrorBanner' +import { ActionButton } from '../../components/ActionButton' import { - User, HealthPlanPackage, - UpdateInformation, useUpdateContractMutation, - UpdateContractInput } from '../../gen/gqlClient' import styles from './MccrsId.module.scss' @@ -23,151 +20,145 @@ type FormError = FormikErrors[keyof FormikErrors] type RouteParams = { - submissionId: string + id: string } + export const MccrsId = ({ - mccrsId, showValidations = false, -}: {mccrsId: string, showValidations: boolean}): React.ReactElement => { +}: { + showValidations: boolean +}): React.ReactElement => { const [shouldValidate, setShouldValidate] = React.useState(showValidations) - const { submissionId } = useParams() + const { id } = useParams() + const navigate = useNavigate() const mccrsIDInitialValues: MccrsIdFormValues = { - mccrsId: Number(mccrsId), + mccrsId: undefined, } const showFieldErrors = (error?: FormError) => shouldValidate && Boolean(error) const [showPageErrorMessage, setShowPageErrorMessage] = useState< - boolean | string + boolean | string >(false) // string is a custom error message, defaults to generic of true const [updateFormData] = useUpdateContractMutation() - const handleFormSubmit = async (values: MccrsIdFormValues): Promise => { + const handleFormSubmit = async ( + values: MccrsIdFormValues + ): Promise => { setShowPageErrorMessage(false) try { const updateResult = await updateFormData({ variables: { input: { mccrsID: values?.mccrsId?.toString(), - // id: submissionId - id: '217f8e1e-1b09-4d4a-92b9-189d2dbb1c63' + id: id || '', }, }, }) + const updatedSubmission: HealthPlanPackage | undefined = updateResult?.data?.updateContract.pkg - console.log(updatedSubmission) + if (!updatedSubmission) { setShowPageErrorMessage(true) + console.info('Failed to update form data', updateResult) recordJSException( `MCCRSIDForm: Apollo error reported. Error message: Failed to update form data ${updateResult}` ) return new Error('Failed to update form data') + } else if (updatedSubmission) { + navigate(`/submissions/${updatedSubmission.id}`) + return updatedSubmission } - console.log(updatedSubmission) return updatedSubmission } catch (serverError) { setShowPageErrorMessage(true) recordJSException( `MCCRSIDForm: Apollo error reported. Error message: ${serverError.message}` ) - console.log(serverError) return new Error(serverError) } } - - return ( - { - return handleFormSubmit(values) - }} - validationSchema={() => MccrsIdFormSchema()} - > - {({ - values, - errors, - handleSubmit, - setSubmitting, - isSubmitting, - setFieldValue, - }) => ( - <> - { - setShouldValidate(true) - // setFocusErrorSummaryHeading(true) - handleSubmit(e) - }} - > -
-

MC-CRS record number

- - Add MC-CRS record number - - {/* {shouldValidate && ( - - )} */} - (i.e 4375))} - /> -
- - console.info('click')} - // onClick={actionInProgress ? undefined : backOnClick} - > - Delete Number - + return ( + <> + {showPageErrorMessage && } + { + return handleFormSubmit(values) + }} + validationSchema={() => MccrsIdFormSchema()} + > + {({ values, errors, handleSubmit, isSubmitting }) => ( + <> + { + setShouldValidate(true) + handleSubmit(e) + }} + > +
+

MC-CRS record number

+ + Add MC-CRS record number + + + (i.e 4375) + + } + /> +
+ + console.info('delete')} + > + Delete Number + - handleFormSubmit(values)} - // animationTimeout={1000} - // loading={actionInProgress && !disableContinue} - > - Save MC-CRS number - - -
- - )} -
+ handleFormSubmit(values)} + animationTimeout={1000} + loading={ + isSubmitting && + shouldValidate && + !errors.mccrsId + } + > + Save MC-CRS number + +
+
+ + )} +
+ ) } diff --git a/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.test.tsx b/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.test.tsx index 25d888500c..ffc0d84e57 100644 --- a/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.test.tsx +++ b/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.test.tsx @@ -22,7 +22,6 @@ import { } from '../../testHelpers/jestHelpers' import { SubmissionSummary } from './SubmissionSummary' import { SubmissionSideNav } from '../SubmissionSideNav' -import React from 'react' import { testS3Client } from '../../testHelpers/s3Helpers' describe('SubmissionSummary', () => { @@ -161,6 +160,78 @@ describe('SubmissionSummary', () => { }) }) + it('renders add mccrs-id link for CMS user', async () => { + const submissionsWithRevisions = mockUnlockedHealthPlanPackage() + renderWithProviders( + + }> + } + /> + + , + { + apolloProvider: { + mocks: [ + fetchCurrentUserMock({ + user: mockValidCMSUser(), + statusCode: 200, + }), + fetchStateHealthPlanPackageWithQuestionsMockSuccess({ + stateSubmission: submissionsWithRevisions, + id: '15', + }), + ], + }, + routerProvider: { + route: '/submissions/15', + }, + } + ) + await waitFor(() => { + expect( + screen.getByText('Add MC-CRS record number') + ).toBeInTheDocument() + }) + }) + + it('does not render an add mccrs-id link for state user', async () => { + const submissionsWithRevisions = mockUnlockedHealthPlanPackage() + renderWithProviders( + + }> + } + /> + + , + { + apolloProvider: { + mocks: [ + fetchCurrentUserMock({ + user: mockValidUser(), + statusCode: 200, + }), + fetchStateHealthPlanPackageWithQuestionsMockSuccess({ + stateSubmission: submissionsWithRevisions, + id: '15', + }), + ], + }, + routerProvider: { + route: '/submissions/15', + }, + } + ) + await waitFor(() => { + expect( + screen.queryByText('Add MC-CRS record number') + ).not.toBeInTheDocument() + }) + }) + it('renders submission unlocked banner for State user', async () => { const submissionsWithRevisions = mockUnlockedHealthPlanPackage() renderWithProviders( diff --git a/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.tsx b/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.tsx index 45f47f0262..7c8f1a3c2c 100644 --- a/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.tsx +++ b/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.tsx @@ -70,7 +70,6 @@ export const SubmissionSummary = (): React.ReactElement => { const { pkg, currentRevision, packageData, user, documentDates } = useOutletContext() - const isCMSUser = user?.role === 'CMS_USER' const submissionStatus = pkg.status const statePrograms = pkg.state.programs @@ -161,8 +160,12 @@ export const SubmissionSummary = (): React.ReactElement => { )}