diff --git a/services/app-web/src/components/SubmissionSummarySection/ContractDetailsSummarySection/ContractDetailsSummarySection.test.tsx b/services/app-web/src/components/SubmissionSummarySection/ContractDetailsSummarySection/ContractDetailsSummarySection.test.tsx index 34899bc55f..7a7a67bbf3 100644 --- a/services/app-web/src/components/SubmissionSummarySection/ContractDetailsSummarySection/ContractDetailsSummarySection.test.tsx +++ b/services/app-web/src/components/SubmissionSummarySection/ContractDetailsSummarySection/ContractDetailsSummarySection.test.tsx @@ -31,6 +31,7 @@ describe('ContractDetailsSummarySection', () => { renderWithProviders( { it('can render state submission on summary page without errors (submission summary behavior)', () => { renderWithProviders( { it('can render all contract details fields', () => { renderWithProviders( { it('displays correct effective dates text for base contract', () => { renderWithProviders( @@ -137,6 +141,7 @@ describe('ContractDetailsSummarySection', () => { it('displays correct effective dates text for contract amendment', () => { renderWithProviders( @@ -179,6 +184,7 @@ describe('ContractDetailsSummarySection', () => { } renderWithProviders( @@ -220,6 +226,7 @@ describe('ContractDetailsSummarySection', () => { it('does not render supporting contract documents table when no documents exist', () => { renderWithProviders( @@ -235,6 +242,7 @@ describe('ContractDetailsSummarySection', () => { it('does not render download all button when on previous submission', () => { renderWithProviders( @@ -249,6 +257,7 @@ describe('ContractDetailsSummarySection', () => { it('renders federal authorities for a medicaid contract', async () => { renderWithProviders( { it('renders federal authorities for a CHIP contract as expected, removing invalid authorities', async () => { renderWithProviders( { it('renders provisions and MLR references for a medicaid amendment', () => { renderWithProviders( @@ -354,9 +367,7 @@ describe('ContractDetailsSummarySection', () => { ).toBeInTheDocument() expect( - within(modifiedProvisions).getByText( - /Risk-sharing strategy/ - ) + within(modifiedProvisions).getByText(/Risk-sharing strategy/) ).toBeInTheDocument() expect( within(modifiedProvisions).getByText( @@ -425,6 +436,9 @@ describe('ContractDetailsSummarySection', () => { it('renders provisions and MLR references for a medicaid base contract', () => { renderWithProviders( { ).toBeInTheDocument() expect( - within(modifiedProvisions).getByText( - /Risk-sharing strategy/ - ) + within(modifiedProvisions).getByText(/Risk-sharing strategy/) ).toBeInTheDocument() expect( within(modifiedProvisions).getByText( @@ -475,6 +487,9 @@ describe('ContractDetailsSummarySection', () => { it('renders provisions with correct MLR references for CHIP amendment', () => { renderWithProviders( { } renderWithProviders( { } renderWithProviders( { } renderWithProviders( , @@ -701,6 +725,9 @@ describe('ContractDetailsSummarySection', () => { } renderWithProviders( { } renderWithProviders( , diff --git a/services/app-web/src/components/SubmissionSummarySection/ContractDetailsSummarySection/ContractDetailsSummarySection.tsx b/services/app-web/src/components/SubmissionSummarySection/ContractDetailsSummarySection/ContractDetailsSummarySection.tsx index bc8670307e..519dd3fb6d 100644 --- a/services/app-web/src/components/SubmissionSummarySection/ContractDetailsSummarySection/ContractDetailsSummarySection.tsx +++ b/services/app-web/src/components/SubmissionSummarySection/ContractDetailsSummarySection/ContractDetailsSummarySection.tsx @@ -29,12 +29,12 @@ import { HealthPlanFormDataType, federalAuthorityKeysForCHIP, } from '../../../common-code/healthPlanFormDataType' -import { useOutletContext } from 'react-router-dom' -import { SideNavOutletContextType } from '../../../pages/SubmissionSideNav/SubmissionSideNav' +import { DocumentDateLookupTableType } from '../../../documentHelpers/makeDocumentDateLookupTable' export type ContractDetailsSummarySectionProps = { submission: HealthPlanFormDataType navigateTo?: string + documentDateLookupTable: DocumentDateLookupTableType isCMSUser?: boolean submissionName: string } @@ -42,6 +42,7 @@ export type ContractDetailsSummarySectionProps = { export const ContractDetailsSummarySection = ({ submission, navigateTo, // this is the edit link for the section. When this prop exists, summary section is loaded in edit mode + documentDateLookupTable, isCMSUser, submissionName, }: ContractDetailsSummarySectionProps): React.ReactElement => { @@ -62,8 +63,7 @@ export const ContractDetailsSummarySection = ({ const [modifiedProvisions, unmodifiedProvisions] = sortModifiedProvisions(submission) const provisionsAreInvalid = isMissingProvisions(submission) && isEditing - const { documentDates } = - useOutletContext() + useEffect(() => { // get all the keys for the documents we want to zip async function fetchZipUrl() { @@ -168,7 +168,11 @@ export const ContractDetailsSummarySection = ({ )} @@ -184,7 +188,11 @@ export const ContractDetailsSummarySection = ({ { it('can render draft submission without errors', () => { renderWithProviders( { it('can render state submission without errors', () => { renderWithProviders( { it('can render all rate details fields for amendment to prior rate certification submission', () => { renderWithProviders( { const statePrograms = mockMNState().programs renderWithProviders( { renderWithProviders( { 'MCR-MN-0005-SNBC-RATE-20221014-20221014-CERTIFICATION-20221014' renderWithProviders( { } renderWithProviders( { it('does not render supporting rate documents when they do not exist', () => { renderWithProviders( { it('does not render download all button when on previous submission', () => { renderWithProviders( { it('renders rate cell capitation type', () => { renderWithProviders( { draftSubmission.rateInfos[0].rateCapitationType = 'RATE_RANGE' renderWithProviders( { ] renderWithProviders( { ] renderWithProviders( { draftSubmission.rateInfos = mockRateInfos renderWithProviders( { renderWithProviders( { draftSubmission.rateInfos = mockRateInfos renderWithProviders( { draftSubmission.rateInfos = mockRateInfos renderWithProviders( { ] renderWithProviders( { ] renderWithProviders( { } renderWithProviders( { it('renders submitted package without errors', () => { renderWithProviders( () const [packageNamesLookup, setPackageNamesLookup] = React.useState(null) @@ -340,7 +339,7 @@ export const RateDetailsSummarySection = ({ rateInfo )} documentDateLookupTable={ - documentDates + documentDateLookupTable } isCMSUser={isCMSUser} caption="Rate certification" @@ -356,7 +355,7 @@ export const RateDetailsSummarySection = ({ rateInfo )} documentDateLookupTable={ - documentDates + documentDateLookupTable } isCMSUser={isCMSUser} caption="Rate supporting documents" @@ -378,7 +377,7 @@ export const RateDetailsSummarySection = ({ !supportingDocsByRate && ( { - const emptyDocumentsTable = () => {return {}} + const emptyDocumentsTable = () => { + return { previousSubmissionDate: '01/01/01' } + } it('renders documents without errors', async () => { const testDocuments = [ { @@ -61,7 +63,7 @@ describe('UploadedDocumentsTable', () => { renderWithProviders( { ) renderWithProviders( doc.documentCategories.includes('CONTRACT_RELATED') && @@ -68,15 +74,14 @@ export const UploadedDocumentsTable = ({ documentCategory, packagesWithSharedRateCerts, isSupportingDocuments = false, + documentDateLookupTable, isEditing = false, isCMSUser, }: UploadedDocumentsTableProps): React.ReactElement => { - const { documentDatesLookup } = - useOutletContext() const initialDocState = documents.map((doc) => ({ ...doc, url: null, - s3Key: null + s3Key: null, })) const { getDocumentsWithS3KeyAndUrl } = useDocument() const [refreshedDocs, setRefreshedDocs] = @@ -87,33 +92,27 @@ export const UploadedDocumentsTable = ({ ) // this is util needed to guard against passing in null or undefined to dayjs - we would get back today's date - const canDisplayDateAddedForDocument = (doc: DocumentWithS3Data) =>{ - console.log(doc, doc.s3Key, documentDatesLookup[ - doc.s3Key! - ]) - return doc.s3Key && documentDatesLookup[ - doc.s3Key - ] -} + const canDisplayDateAddedForDocument = (doc: DocumentWithS3Data) => { + const documentKey = getDocumentKey(doc) + return documentKey && documentDateLookupTable[documentKey] + } const shouldHaveNewTag = (doc: DocumentWithS3Data) => { if (!isCMSUser) { return false // design requirement, don't show new tag to state users on review submit } - if (!documentDatesLookup || !doc || !doc.s3Key) { + if (!documentDateLookupTable || !doc || !doc.s3Key) { return false // this is a document with bad s3 data } - const documentDate = documentDatesLookup?.[doc.s3Key] - const previousSubmissionDate = documentDatesLookup.previousSubmissionDate + const documentDate = documentDateLookupTable?.[doc.s3Key] + const previousSubmissionDate = + documentDateLookupTable.previousSubmissionDate if (!documentDate || !previousSubmissionDate) { return false // this document is on an initial submission or not submitted yet } - return ( - documentDate > - previousSubmissionDate - ) + return documentDate > previousSubmissionDate } const hasSharedRateCert = @@ -144,22 +143,19 @@ export const UploadedDocumentsTable = ({ ) useEffect(() => { - console.log(' in effect ') const refreshDocuments = async () => { - const newDocuments = await getDocumentsWithS3KeyAndUrl( + const newDocuments = (await getDocumentsWithS3KeyAndUrl( documents, 'HEALTH_PLAN_DOCS' - ) as DocumentWithS3Data[] - - console.log('new documents', newDocuments) + )) as DocumentWithS3Data[] if (newDocuments.length) { - console.log(newDocuments) setRefreshedDocs(newDocuments) } } void refreshDocuments() }, [documents, getDocumentsWithS3KeyAndUrl]) + // Empty State if (refreshedDocs.length === 0) { return ( @@ -213,7 +209,7 @@ export const UploadedDocumentsTable = ({ target="_blank" > {isSupportingDocuments && - isBothContractAndRateSupporting(doc) + isBothContractAndRateSupporting(doc) ? `*${doc.name}` : doc.name} @@ -227,27 +223,28 @@ export const UploadedDocumentsTable = ({ )} - {canDisplayDateAddedForDocument(doc) && !isEditing + {canDisplayDateAddedForDocument(doc) && + !isEditing ? dayjs( - documentDatesLookup[ - // can disable non-null here because we check in canDisplayDateAddedForDocument - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - doc.s3Key! - ] - ).format('M/D/YY') + documentDateLookupTable[ + // can disable non-null here because we check in canDisplayDateAddedForDocument + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + doc.s3Key! + ] + ).format('M/D/YY') : ''} {documentCategory && {documentCategory}} {showSharedInfo ? packagesWithSharedRateCerts && ( - - {linkedPackagesList({ - unlinkDrafts: Boolean(isCMSUser), - packages: - packagesWithSharedRateCerts, - })} - - ) + + {linkedPackagesList({ + unlinkDrafts: Boolean(isCMSUser), + packages: + packagesWithSharedRateCerts, + })} + + ) : null} ))} diff --git a/services/app-web/src/documentHelpers/makeDocumentDateLookupTable.test.ts b/services/app-web/src/documentHelpers/makeDocumentDateLookupTable.test.ts index 0c183925ed..396b30b040 100644 --- a/services/app-web/src/documentHelpers/makeDocumentDateLookupTable.test.ts +++ b/services/app-web/src/documentHelpers/makeDocumentDateLookupTable.test.ts @@ -52,7 +52,9 @@ describe('makeDocumentDateTable', () => { } const lookupTable = makeDocumentDateTable(revisionsLookup) - expect(lookupTable).toEqual({}) + expect(lookupTable).toEqual({ + previousSubmissionDate: null, + }) }) it('should use earliest document added date based that revisions submit date', () => { diff --git a/services/app-web/src/documentHelpers/makeDocumentDateLookupTable.ts b/services/app-web/src/documentHelpers/makeDocumentDateLookupTable.ts index 4ee5d3b953..a9673b959c 100644 --- a/services/app-web/src/documentHelpers/makeDocumentDateLookupTable.ts +++ b/services/app-web/src/documentHelpers/makeDocumentDateLookupTable.ts @@ -8,7 +8,7 @@ import { getDocumentKey } from './getDocumentKey' // DocumentDateLookupTableType - { document key string : date string for "date added" } // see logic in getDocumentKey for how document key string is calculated type DocumentDateLookupTableType = { - previousSubmissionDate: string | null, + previousSubmissionDate: string | null [key: string]: string | null } @@ -25,14 +25,17 @@ const getDateAdded = ( function makeDocumentDateTable( revisionsLookup: RevisionsLookupType ): DocumentDateLookupTableType { - const lookupTable: DocumentDateLookupTableType = { previousSubmissionDate: null} + const lookupTable: DocumentDateLookupTableType = { + previousSubmissionDate: null, + } Object.keys(revisionsLookup).forEach( (revisionId: string, index: number) => { const revision = revisionsLookup[revisionId] if (index === 1) { // second most recent revision const previousSubmission = getDateAdded(revision) // used in UploadedDocumentsTable to determine if we should show NEW tag - if (previousSubmission) lookupTable['previousSubmissionDate'] = previousSubmission + if (previousSubmission) + lookupTable['previousSubmissionDate'] = previousSubmission } const allDocuments = getAllDocuments(revision.formData) @@ -43,7 +46,6 @@ function makeDocumentDateTable( }) } ) - return lookupTable } diff --git a/services/app-web/src/gqlHelpers/fetchHealthPlanPackageWrapper.ts b/services/app-web/src/gqlHelpers/fetchHealthPlanPackageWrapper.ts index a17b490e2a..1c46cc14f1 100644 --- a/services/app-web/src/gqlHelpers/fetchHealthPlanPackageWrapper.ts +++ b/services/app-web/src/gqlHelpers/fetchHealthPlanPackageWrapper.ts @@ -15,6 +15,10 @@ import { } from './apolloQueryWrapper' import { QueryFunctionOptions } from '@apollo/client' import { recordJSException } from '../otelHelpers' +import { + DocumentDateLookupTableType, + makeDocumentDateTable, +} from '../documentHelpers/makeDocumentDateLookupTable' // ExpandedRevisionsType - HPP revision plus an additional formData field containing values of formDataProto decoded into typescript type ExpandedRevisionsType = HealthPlanRevision & { @@ -26,6 +30,7 @@ type RevisionsLookupType = { [revisionID: string]: ExpandedRevisionsType } // all of these fields will be added to the SUCCESS type type AdditionalParsedDataType = { revisionsLookup: RevisionsLookupType + documentDates: DocumentDateLookupTableType } type ParsedFetchResultType = ApolloResultType< @@ -79,6 +84,7 @@ function parseProtos( return { ...result, revisionsLookup: {}, + documentDates: { previousSubmissionDate: null }, } } @@ -92,6 +98,7 @@ function parseProtos( error: err, } } + const revisionsLookup = buildRevisionsLookup(pkg) if (revisionsLookup instanceof Error) { return { @@ -99,9 +106,12 @@ function parseProtos( error: revisionsLookup, } } else { + const documentDates = makeDocumentDateTable(revisionsLookup) + return { ...result, revisionsLookup, + documentDates, } } } diff --git a/services/app-web/src/pages/QuestionResponse/QATable/QATable.tsx b/services/app-web/src/pages/QuestionResponse/QATable/QATable.tsx index cdae871ad7..261b50ace4 100644 --- a/services/app-web/src/pages/QuestionResponse/QATable/QATable.tsx +++ b/services/app-web/src/pages/QuestionResponse/QATable/QATable.tsx @@ -45,7 +45,7 @@ export const QATable = ({ round: number user: User }) => { - const { getDocumentsUrl } = useDocument() + const { getDocumentsWithS3KeyAndUrl } = useDocument() const tableDocuments = [ ...question.documents.map((doc) => ({ ...doc, @@ -84,7 +84,7 @@ export const QATable = ({ useDeepCompareEffect(() => { const refreshDocuments = async () => { - const newDocuments = await getDocumentsUrl( + const newDocuments = await getDocumentsWithS3KeyAndUrl( tableDocuments, 'QUESTION_ANSWER_DOCS' ) @@ -94,7 +94,7 @@ export const QATable = ({ } void refreshDocuments() - }, [tableDocuments, getDocumentsUrl, setRefreshedDocs]) + }, [tableDocuments, getDocumentsWithS3KeyAndUrl, setRefreshedDocs]) return ( <> diff --git a/services/app-web/src/pages/StateSubmission/ReviewSubmit/ReviewSubmit.test.tsx b/services/app-web/src/pages/StateSubmission/ReviewSubmit/ReviewSubmit.test.tsx index 2bee86db31..10e1be427c 100644 --- a/services/app-web/src/pages/StateSubmission/ReviewSubmit/ReviewSubmit.test.tsx +++ b/services/app-web/src/pages/StateSubmission/ReviewSubmit/ReviewSubmit.test.tsx @@ -10,6 +10,7 @@ describe('ReviewSubmit', () => { it('renders without errors', async () => { renderWithProviders( { it('displays edit buttons for every section', async () => { renderWithProviders( { it('does not display zip download buttons', async () => { renderWithProviders( { it('renders info from a DraftSubmission', async () => { renderWithProviders( { it('displays back and save as draft buttons', async () => { renderWithProviders( { it('displays submit button', async () => { renderWithProviders( { @@ -52,6 +54,7 @@ export const ReviewSubmit = ({ submission={draftSubmission} navigateTo="../contract-details" submissionName={submissionName} + documentDateLookupTable={documentDateLookupTable} /> {isContractActionAndRateCertification && ( @@ -59,6 +62,7 @@ export const ReviewSubmit = ({ submission={draftSubmission} navigateTo="../rate-details" submissionName={submissionName} + documentDateLookupTable={documentDateLookupTable} statePrograms={statePrograms} /> )} diff --git a/services/app-web/src/pages/StateSubmission/StateSubmissionForm.tsx b/services/app-web/src/pages/StateSubmission/StateSubmissionForm.tsx index 6bcbb520c4..5eb8b859da 100644 --- a/services/app-web/src/pages/StateSubmission/StateSubmissionForm.tsx +++ b/services/app-web/src/pages/StateSubmission/StateSubmissionForm.tsx @@ -318,6 +318,7 @@ export const StateSubmissionForm = (): React.ReactElement => { element={ diff --git a/services/app-web/src/pages/SubmissionRevisionSummary/SubmissionRevisionSummary.tsx b/services/app-web/src/pages/SubmissionRevisionSummary/SubmissionRevisionSummary.tsx index fe157c211f..691e7a1645 100644 --- a/services/app-web/src/pages/SubmissionRevisionSummary/SubmissionRevisionSummary.tsx +++ b/services/app-web/src/pages/SubmissionRevisionSummary/SubmissionRevisionSummary.tsx @@ -20,7 +20,6 @@ import { recordJSException } from '../../otelHelpers/tracingHelper' import { useFetchHealthPlanPackageWrapper } from '../../gqlHelpers' import { ApolloError } from '@apollo/client' import { handleApolloError } from '../../gqlHelpers/apolloErrors' -import { makeDocumentDateTable } from '../../documentHelpers/makeDocumentDateLookupTable' export const SubmissionRevisionSummary = (): React.ReactElement => { // Page level state @@ -61,7 +60,7 @@ export const SubmissionRevisionSummary = (): React.ReactElement => { return // api failure or protobuf decode failure } - const { data, revisionsLookup } = fetchResult + const { data, revisionsLookup, documentDates } = fetchResult const pkg = data.fetchHealthPlanPackage.pkg // fetchHPP returns null if no package is found with the given ID @@ -79,7 +78,6 @@ export const SubmissionRevisionSummary = (): React.ReactElement => { return } const packageData = revisionsLookup[revision.id].formData - const documentDates = makeDocumentDateTable(revisionsLookup) const statePrograms = pkg.state.programs const name = packageName(packageData, statePrograms) @@ -121,13 +119,14 @@ export const SubmissionRevisionSummary = (): React.ReactElement => { {isContractActionAndRateCertification && ( diff --git a/services/app-web/src/pages/SubmissionSideNav/SubmissionSideNav.tsx b/services/app-web/src/pages/SubmissionSideNav/SubmissionSideNav.tsx index 95b0a6a220..cbcd0eae30 100644 --- a/services/app-web/src/pages/SubmissionSideNav/SubmissionSideNav.tsx +++ b/services/app-web/src/pages/SubmissionSideNav/SubmissionSideNav.tsx @@ -28,7 +28,10 @@ import { } from '../../common-code/healthPlanFormDataType' import { useLDClient } from 'launchdarkly-react-client-sdk' import { featureFlags } from '../../common-code/featureFlags' -import { DocumentDateLookupTableType, makeDocumentDateTable } from '../../documentHelpers/makeDocumentDateLookupTable' +import { + DocumentDateLookupTableType, + makeDocumentDateTable, +} from '../../documentHelpers/makeDocumentDateLookupTable' export type SideNavOutletContextType = { pkg: HealthPlanPackage diff --git a/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.tsx b/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.tsx index abf342031b..5069614102 100644 --- a/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.tsx +++ b/services/app-web/src/pages/SubmissionSummary/SubmissionSummary.tsx @@ -65,7 +65,7 @@ export const SubmissionSummary = (): React.ReactElement => { featureFlags.CMS_QUESTIONS.defaultValue ) - const { pkg, currentRevision, packageData, user} = + const { pkg, currentRevision, packageData, user, documentDates } = useOutletContext() const isCMSUser = user?.role === 'CMS_USER' @@ -160,6 +160,7 @@ export const SubmissionSummary = (): React.ReactElement => { initiallySubmittedAt={pkg.initiallySubmittedAt} /> { {isContractActionAndRateCertification && (