From f4c58b0b65f9372bb43f0f3bdfbd347e6bc19fad Mon Sep 17 00:00:00 2001 From: Jason Lin Date: Fri, 10 Jan 2025 18:08:02 -0500 Subject: [PATCH 1/3] Update mock --- .../src/apollo/contractPackageDataMock.ts | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/mocks/src/apollo/contractPackageDataMock.ts b/packages/mocks/src/apollo/contractPackageDataMock.ts index 08da819027..cd265d1e78 100644 --- a/packages/mocks/src/apollo/contractPackageDataMock.ts +++ b/packages/mocks/src/apollo/contractPackageDataMock.ts @@ -1686,6 +1686,7 @@ function mockContractPackageApprovedWithQuestions( function mockContractPackageSubmittedWithRevisions( partial?: Partial ): Contract { + const contractID = partial?.id || 'test-abc-123' return { __typename: 'Contract', status: 'SUBMITTED', @@ -1696,7 +1697,7 @@ function mockContractPackageSubmittedWithRevisions( lastUpdatedForDisplay: new Date(), initiallySubmittedAt: new Date('2024-01-01'), mccrsID: null, - id: 'test-abc-123', + id: contractID, webURL: 'https://testmcreview.example/submissions/test-abc-123', stateCode: 'MN', state: mockMNState(), @@ -1719,8 +1720,9 @@ function mockContractPackageSubmittedWithRevisions( }, updatedReason: 'submit 3', }, - submittedRevisions: [mockContractRevision('3')], + submittedRevisions: [mockContractRevision('3', { contractID })], contractRevision: mockContractRevision('3', { + contractID, unlockInfo: { __typename: 'UpdateInformation', updatedAt: '2024-03-01T17:54:39.173Z', @@ -1749,8 +1751,9 @@ function mockContractPackageSubmittedWithRevisions( }, updatedReason: 'submit 2', }, - submittedRevisions: [mockContractRevision('2')], + submittedRevisions: [mockContractRevision('2', { contractID })], contractRevision: mockContractRevision('2', { + contractID, unlockInfo: { __typename: 'UpdateInformation', updatedAt: '2024-01-25T21:13:56.174Z', @@ -1779,8 +1782,8 @@ function mockContractPackageSubmittedWithRevisions( }, updatedReason: 'submit 1', }, - submittedRevisions: [mockContractRevision('1')], - contractRevision: mockContractRevision('1'), + submittedRevisions: [mockContractRevision('1', { contractID })], + contractRevision: mockContractRevision('1', { contractID }), rateRevisions: [mockRateRevision('1')], }, ], @@ -2211,6 +2214,7 @@ function mockContractPackageWithDifferentProgramsInRevisions(): Contract { function mockContractPackageUnlockedWithUnlockedType( partial?: Partial ): UnlockedContract { + const contractID = partial?.id ?? 'test-abc-123' return { status: 'UNLOCKED', reviewStatus: 'UNDER_REVIEW', @@ -2220,7 +2224,7 @@ function mockContractPackageUnlockedWithUnlockedType( updatedAt: '2024-12-01T16:54:39.173Z', lastUpdatedForDisplay: '2024-12-01T16:54:39.173Z', initiallySubmittedAt: new Date('2023-01-01'), - id: 'test-abc-123', + id: contractID, webURL: 'https://testmcreview.example/submissions/test-abc-123', stateCode: 'MN', state: mockMNState(), @@ -2228,7 +2232,7 @@ function mockContractPackageUnlockedWithUnlockedType( mccrsID: '1234', draftRevision: { __typename: 'ContractRevision', - contractID: 'test-abc-123', + contractID, submitInfo: null, unlockInfo: { __typename: 'UpdateInformation', @@ -2312,7 +2316,7 @@ function mockContractPackageUnlockedWithUnlockedType( revisions: [], state: mockMNState(), stateNumber: 5, - parentContractID: 'test-abc-123', + parentContractID: contractID, draftRevision: { __typename: 'RateRevision', id: 'unlocked-rr-123', @@ -2401,7 +2405,7 @@ function mockContractPackageUnlockedWithUnlockedType( contractName: 'MCR-MN-0005-SNBC', createdAt: new Date('01/01/2024'), updatedAt: '2023-01-01T16:54:39.173Z', - contractID: 'test-abc-123', + contractID, submitInfo: { __typename: 'UpdateInformation', updatedAt: '2023-01-01T16:54:39.173Z', @@ -2465,7 +2469,7 @@ function mockContractPackageUnlockedWithUnlockedType( ], contractRevision: { __typename: 'ContractRevision', - contractID: 'test-abc-123', + contractID, contractName: 'MCR-MN-0005-SNBC', createdAt: new Date('01/01/2024'), updatedAt: '2024-01-01T18:54:39.173Z', From d76fa186c48bd14003ac0dc817fba7a7022dd9a0 Mon Sep 17 00:00:00 2001 From: Jason Lin Date: Fri, 10 Jan 2025 18:08:28 -0500 Subject: [PATCH 2/3] Fix UnlockedContract initiallySubmittedAt type --- services/app-graphql/src/schema.graphql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/app-graphql/src/schema.graphql b/services/app-graphql/src/schema.graphql index 44c060e0b3..62964efb1d 100644 --- a/services/app-graphql/src/schema.graphql +++ b/services/app-graphql/src/schema.graphql @@ -1976,7 +1976,7 @@ type UnlockedContract { """ consolidatedStatus: ConsolidatedContractStatus! "initiallySubmittedAt is the initial date this contract was submitted at. Is not changed by unlock or resubmission." - initiallySubmittedAt: Date + initiallySubmittedAt: DateTime "lastUpdatedForDisplay is the last time this contract was officially updated. When it's a draft it will be the last updatedAt date. Afterwards it will be the most recent submit or unlock or review action date." lastUpdatedForDisplay: DateTime! "stateCode is the state code (e.g. CA or TN) for the submitting state" From 64f89c2eb42797e78eb7e115b14308b3783c0377 Mon Sep 17 00:00:00 2001 From: Jason Lin Date: Fri, 10 Jan 2025 18:11:18 -0500 Subject: [PATCH 3/3] Use contracts from withdrawnFromContracts for contract actions --- .../SingleRateSummarySection.test.tsx | 79 +++++++++++++++++++ .../SingleRateSummarySection.tsx | 17 +++- .../RateDetails/rateDetailsHelpers.ts | 1 - 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.test.tsx b/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.test.tsx index 6b1640d5b0..29afab6f7d 100644 --- a/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.test.tsx +++ b/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.test.tsx @@ -2,6 +2,8 @@ import { renderWithProviders } from '../../../testHelpers' import { SingleRateSummarySection } from './SingleRateSummarySection' import { fetchCurrentUserMock, + mockContractPackageSubmittedWithRevisions, + mockContractPackageUnlockedWithUnlockedType, mockEmptyDraftContractAndRate, mockValidCMSUser, mockValidHelpDeskUser, @@ -9,6 +11,7 @@ import { } from '@mc-review/mocks' import { screen, within } from '@testing-library/react' import { rateWithHistoryMock } from '@mc-review/mocks' +import type { Contract } from '../../../gen/gqlClient' describe('SingleRateSummarySection', () => { it('can render rate details without errors', async () => { @@ -260,6 +263,82 @@ describe('SingleRateSummarySection', () => { ) }) + it('renders contract actions correctly after rate withdraw', async () => { + const rateData = rateWithHistoryMock() + const parentContractRev = + rateData.packageSubmissions?.[2].contractRevisions[0] + if (!parentContractRev) { + throw new Error('no parent') + } + + const withdrawnContractOne = mockContractPackageSubmittedWithRevisions({ + id: 'c-01', + }) + + const withdrawnContractOnePkgName = + withdrawnContractOne.packageSubmissions[0].contractRevision + .contractName + + const withdrawnContractTwo = + mockContractPackageUnlockedWithUnlockedType({ + id: 'c-02', + }) + + const withdrawnContractTwoPkgName = + withdrawnContractTwo.packageSubmissions[0].contractRevision + .contractName + + const withdrawnFromContracts = [ + withdrawnContractOne, + withdrawnContractTwo as Contract, + ] + + // add in contracts this rate was withdrawn from + rateData.withdrawnFromContracts = withdrawnFromContracts + + renderWithProviders( + , + { + apolloProvider: { + mocks: [ + fetchCurrentUserMock({ + statusCode: 200, + user: mockValidCMSUser(), + }), + ], + }, + } + ) + + 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: withdrawnContractOnePkgName, + }) + ).toBeInTheDocument() + expect( + within(relatedContractActions).getByRole('link', { + name: withdrawnContractTwoPkgName, + }) + ).toHaveAttribute( + 'href', + `/submissions/${parentContractRev.contractID}` + ) + }) + describe('Missing data error notifications', () => { const mockEmptyRateData = () => { const emptyDraftRates = mockEmptyDraftContractAndRate().draftRates diff --git a/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.tsx b/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.tsx index 9b5b72ad02..d238faf491 100644 --- a/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.tsx +++ b/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.tsx @@ -117,8 +117,21 @@ export const SingleRateSummarySection = ({ rate.status === 'SUBMITTED' || rate.status === 'RESUBMITTED' || isCMSUser + const isWithdrawn = rate.consolidatedStatus === 'WITHDRAWN' - const linkedContracts = latestSubmission.contractRevisions + const withdrawnFromContractRevs = + rate.withdrawnFromContracts?.reduce((acc, contract) => { + const latestRevision = + contract.packageSubmissions?.[0].contractRevision + if (latestRevision) { + acc.push(latestRevision) + } + return acc + }, [] as ContractRevision[]) ?? [] + + const contractActions = isWithdrawn + ? withdrawnFromContractRevs + : latestSubmission.contractRevisions // TODO BULK DOWNLOAD // needs to be wrap in a standalone hook @@ -338,7 +351,7 @@ export const SingleRateSummarySection = ({ diff --git a/services/app-web/src/pages/StateSubmission/RateDetails/rateDetailsHelpers.ts b/services/app-web/src/pages/StateSubmission/RateDetails/rateDetailsHelpers.ts index 962c204761..4c2fd862cc 100644 --- a/services/app-web/src/pages/StateSubmission/RateDetails/rateDetailsHelpers.ts +++ b/services/app-web/src/pages/StateSubmission/RateDetails/rateDetailsHelpers.ts @@ -144,7 +144,6 @@ const convertIndexRatesGQLRateToRateForm = (getKey: S3ClientT['getKey'], rate?: } } - // Convert from GQL Rate to FormikRateForm object used in the form // if rate is not passed in, return an empty RateForm // we need to pass in the s3 handler because 3 urls generated client-side // useLatestSubmission means to pull the latest submitted info rather than the draft info