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

MCR-4052 Re-implement unlock submission #2376

Merged
merged 9 commits into from
Apr 24, 2024
84 changes: 71 additions & 13 deletions services/app-web/src/components/Modal/V2/UnlockSubmitModalV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
Rate,
Contract,
useSubmitContractMutation,
useUnlockHealthPlanPackageMutation,
FetchHealthPlanPackageWithQuestionsDocument,
FetchContractDocument,
} from '../../../gen/gqlClient'
import { useFormik } from 'formik'
import { usePrevious } from '../../../hooks/usePrevious'
Expand All @@ -14,7 +17,10 @@ import * as Yup from 'yup'
import styles from '../UnlockSubmitModal.module.scss'
import { GenericApiErrorProps } from '../../Banner/GenericApiErrorBanner/GenericApiErrorBanner'
import { ERROR_MESSAGES } from '../../../constants/errors'
import { submitMutationWrapperV2 } from '../../../gqlHelpers/mutationWrappersForUserFriendlyErrors'
import {
submitMutationWrapperV2,
unlockMutationWrapper,
} from '../../../gqlHelpers/mutationWrappersForUserFriendlyErrors'

const RATE_UNLOCK_SUBMIT_TYPES = [
'SUBMIT_RATE',
Expand All @@ -38,12 +44,12 @@ type SharedAdditionalProps = {

type RateModalProps = {
submissionData: Rate
modalType: RateModalType[number]
modalType: RateModalType
} & SharedAdditionalProps

type ContractModalProps = {
submissionData: Contract
modalType: ContractModalType[number]
modalType: ContractModalType
} & SharedAdditionalProps

type UnlockSubmitModalProps = RateModalProps | ContractModalProps
Expand Down Expand Up @@ -89,11 +95,11 @@ const modalValueDictionary: { [Property in SharedModalType]: ModalValueType } =
errorHeading: ERROR_MESSAGES.unlock_error_heading,
},
UNLOCK_CONTRACT: {
modalHeading: 'Reason for unlocking rate',
modalHeading: 'Reason for unlocking submission',
onSubmitText: 'Unlock',
inputHint: 'Provide reason for unlocking',
unlockSubmitModalInputValidation:
'You must provide a reason for unlocking this contract',
'You must provide a reason for unlocking this submission',
errorHeading: ERROR_MESSAGES.unlock_error_heading,
},
SUBMIT_RATE: {
Expand Down Expand Up @@ -135,10 +141,14 @@ export const UnlockSubmitModalV2 = ({
}

const [submitContract, { loading: submitContractLoading }] =
useSubmitContractMutation() // TODO this should be unlockContract - linked rates epic
useSubmitContractMutation()

// TODO submitRate and unlockRate should also be set up here - nunlock and edit rate epic
// TODO unlockContract should also be set up here - nunlock and edit rate epic
const [
unlockHealthPlanPackage,
{ loading: unlockContractLoading, client },
] = useUnlockHealthPlanPackageMutation()

// TODO submitRate and unlockRate should also be set up here - unlock and edit rate epic
const formik = useFormik({
initialValues: modalFormInitialValues,
validationSchema: Yup.object().shape({
Expand All @@ -150,7 +160,10 @@ export const UnlockSubmitModalV2 = ({
})

const mutationLoading =
modalType === 'SUBMIT_CONTRACT' && submitContractLoading
modalType === 'UNLOCK_CONTRACT'
? unlockContractLoading
: submitContractLoading

const isSubmitting = mutationLoading || formik.isSubmitting
const includesFormInput =
modalType === 'UNLOCK_CONTRACT' ||
Expand All @@ -177,26 +190,61 @@ export const UnlockSubmitModalV2 = ({
console.info('unlock rate not implemented yet')
break

case 'SUBMIT_RATE' || 'RESUBMIT_RATE':
console.info('submit/resubmit rate not implemented yet')
case 'SUBMIT_RATE' :
console.info('submit rate not implemented yet')
break
case 'RESUBMIT_RATE' :
console.info('submit rate not implemented yet')
break
case 'SUBMIT_CONTRACT':
result = await submitMutationWrapperV2(
submitContract,
submissionData.id,
unlockSubmitModalInput
)
break
break;
case 'RESUBMIT_CONTRACT':
result = await submitMutationWrapperV2(
submitContract,
submissionData.id,
unlockSubmitModalInput
)
break
case 'UNLOCK_CONTRACT':
if (unlockSubmitModalInput) {
// TODO: Remove HPP code fully from here, this is a hack to get through linked rates since we have no viable unlockContract
result = await unlockMutationWrapper(
unlockHealthPlanPackage,
submissionData.id,
unlockSubmitModalInput
)
} else {
console.info('error has occured with unlocking contract')
}

break
}

if (result instanceof Error) {
//Allow submitting/unlocking to continue on EMAIL_ERROR.
if (result instanceof Error && result.cause === 'EMAIL_ERROR') {
modalRef.current?.toggleModal(undefined, false)

if (modalType !== 'UNLOCK_CONTRACT' && submissionName) {
navigate(
`/dashboard/submissions?justSubmitted=${submissionName}`
)
} else {
await client.refetchQueries({
include: [FetchContractDocument],
})
// TODO: Remove HPP code fully from here, this is a hack to get through linked rates
// neded because sidebar UI that also displays questions that assumes latest data fetched on this page
// and we haven't had to migrate that yet to contract and ratesyet
await client.refetchQueries({
include: [FetchHealthPlanPackageWithQuestionsDocument],
})
}
} else if (result instanceof Error) {
setModalAlert({
heading: modalValues.errorHeading,
message: result.message,
Expand All @@ -217,6 +265,16 @@ export const UnlockSubmitModalV2 = ({
navigate(
`/dashboard/submissions?justSubmitted=${submissionName}`
)
} else {
await client.refetchQueries({
include: [FetchContractDocument],
})
// TODO: Remove HPP code fully from here, this is a hack to get through linked rates
// neded because sidebar UI that also displays questions that assumes latest data fetched on this page
// and we haven't had to migrate that yet to contract and ratesyet
await client.refetchQueries({
include: [FetchHealthPlanPackageWithQuestionsDocument],
})
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ describe('SingleRateSummarySection', () => {
}),
],
},
featureFlags: { 'rate-edit-unlock': true },
featureFlags: {
'rate-edit-unlock': true,
'link-rates': false,
},
}
)
})
Expand Down Expand Up @@ -96,7 +99,8 @@ describe('SingleRateSummarySection', () => {
screen.getByRole('heading', { name: 'Rate documents' })
).toBeInTheDocument()
})
it('renders documents with linked submissions correctly', async () => {
// can delete the next test when linked rates flag is permanently on
it('renders documents with linked submissions correctly (legacy feature)', async () => {
const rateData = rateDataMock()
const parentContractRev = rateData.revisions[0].contractRevisions[0]
const rateDoc = rateData.revisions[0].formData.rateDocuments[0]
Expand Down Expand Up @@ -210,6 +214,65 @@ describe('SingleRateSummarySection', () => {
)
).toBeInTheDocument()
})
it('renders rates linked to other contract actions correctly', async () => {
const rateData = rateDataMock()
const parentContractRev = rateData.revisions[0].contractRevisions[0]

const contractPackageName = packageName(
parentContractRev.contract.stateCode,
parentContractRev.contract.stateNumber,
parentContractRev.formData.programIDs,
rateData.state.programs
)

await waitFor(() => {
renderWithProviders(
<SingleRateSummarySection
rate={rateData}
isSubmitted={true}
statePrograms={rateData.state.programs}
/>,
{
apolloProvider: {
mocks: [
fetchCurrentUserMock({
statusCode: 200,
user: mockValidCMSUser(),
}),
],
},
featureFlags: {
'rate-edit-unlock': true,
'link-rates': true,
},
}
)
})

expect(
screen.getByRole('heading', { name: 'Rate documents' })
).toBeInTheDocument()

const relatedContractActions = screen.getByRole('definition', {
name: 'Contract actions',
})

// Expect submissions this rate was submitted with link to exists
expect(relatedContractActions).toBeInTheDocument()
expect(
within(relatedContractActions).getByRole('link', {
name: contractPackageName,
})
).toBeInTheDocument()
expect(
within(relatedContractActions).getByRole('link', {
name: contractPackageName,
})
).toHaveAttribute(
'href',
`/submissions/${parentContractRev.contract.id}`
)
})

it('should not display missing field text to CMS users', async () => {
const rateData = rateDataMock({
Expand Down Expand Up @@ -370,10 +433,7 @@ describe('SingleRateSummarySection', () => {
name: 'Unlock rate',
})
await waitFor(() => {
const parentContractSubmissionID =
rateData.revisions[0].contractRevisions[
rateData.revisions[0].contractRevisions.length - 1
].contract.id
const parentContractSubmissionID = rateData.parentContractID
expect(testLocation.pathname).toBe(
`/submissions/${parentContractSubmissionID}`
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,7 @@ export const SingleRateSummarySection = ({
)
}
}
const parentContractSubmissionID =
rate.revisions[0].contractRevisions[
rate.revisions[0].contractRevisions.length - 1
].contract.id
const parentContractSubmissionID = rate.parentContractID
return (
<React.Fragment key={rate.id}>
<SectionCard
Expand Down Expand Up @@ -327,8 +324,11 @@ export const SingleRateSummarySection = ({
/>
<DataDetail
id="submittedWithContract"
label="Submission this rate was submitted with"
explainMissingData={explainMissingData}
label={
showLinkedRates
? 'Contract actions'
: 'Submission this rate was submitted with'
}
children={relatedSubmissions(
rateRevision?.contractRevisions,
statePrograms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ const Contacts = ({
showPageErrorMessage={showPageErrorMessage ?? false}
/>
</div>
<FormContainer id="state-submission-form-page">
<FormContainer id="Contacts">
<Formik
initialValues={contactsInitialValues}
onSubmit={handleFormSubmit}
Expand Down Expand Up @@ -448,6 +448,7 @@ const Contacts = ({
0 && (
<Button
type="button"

unstyled
className={
styles.removeContactBtn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ export const ContractDetails = ({
showPageErrorMessage={showPageErrorMessage ?? false}
/>
</div>
<FormContainer id="state-submission-form-page">
<FormContainer id="ContactDetails">
<Formik
initialValues={contractDetailsInitialValues}
onSubmit={(values, { setSubmitting }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export const Documents = (): React.ReactElement => {
showPageErrorMessage={showPageErrorMessage ?? false}
/>
</div>
<FormContainer id="state-submission-form-page">
<FormContainer id="Documents">
<UswdsForm
className={classNames(
styles.tableContainer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ export const RateDetails = ({
showPageErrorMessage={showPageErrorMessage ?? false}
/>
</div>
<FormContainer id="state-submission-form-page">
<FormContainer id="RateDetails">
<Formik
initialValues={rateInfosInitialValues}
onSubmit={({ rateInfos }, { setSubmitting }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const ReviewSubmit = (): React.ReactElement => {
/>
</div>

<FormContainer id="state-submission-form-page">
<FormContainer id="ReviewSubmit">
<GridContainer className={styles.reviewSectionWrapper}>
<SubmissionTypeSummarySection
submission={draftSubmission}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const StateSubmissionForm = (): React.ReactElement => {
featureFlags.LINK_RATES.defaultValue
)
return (
<div className={styles.formPage}>
<div data-testid='state-submission-form-page' className={styles.formPage}>
<Routes>
<Route
path={getRelativePathFromNestedRoute('SUBMISSIONS_TYPE')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ export const SubmissionType = ({
showPageErrorMessage={showPageErrorMessage ?? false}
/>
</div>
<FormContainer id="state-submission-form-page">
<FormContainer id="SubmissionType">
<Formik
initialValues={submissionTypeInitialValues}
onSubmit={handleFormSubmit}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export const SubmissionSummaryV2 = (): React.ReactElement => {
contractID: id ?? 'unknown-contract',
},
},
fetchPolicy: 'network-only'
})
const contract = fetchContractData?.fetchContract.contract
if (fetchContractLoading) {
Expand Down
Loading
Loading