From 1443faa65726a107018a1fea1e682fc56fad2c13 Mon Sep 17 00:00:00 2001 From: Nechama Krigsman Date: Tue, 26 Nov 2024 10:43:31 -0500 Subject: [PATCH 01/38] 10489: generate freeText for default docket entry descriptions; set eventCode to OJR when stricken from trial and jurisdiction is retained; --- .../fileCourtIssuedOrderInteractor.test.ts | 366 ++++++++++++++++-- .../fileCourtIssuedOrderInteractor.ts | 81 +++- 2 files changed, 407 insertions(+), 40 deletions(-) diff --git a/web-api/src/business/useCases/courtIssuedOrder/fileCourtIssuedOrderInteractor.test.ts b/web-api/src/business/useCases/courtIssuedOrder/fileCourtIssuedOrderInteractor.test.ts index c83d9a05950..0543eca983c 100644 --- a/web-api/src/business/useCases/courtIssuedOrder/fileCourtIssuedOrderInteractor.test.ts +++ b/web-api/src/business/useCases/courtIssuedOrder/fileCourtIssuedOrderInteractor.test.ts @@ -21,6 +21,7 @@ import { } from '@shared/test/mockAuthUsers'; import { updateMessage } from '@web-api/persistence/postgres/messages/updateMessage'; +/* eslint-disable max-lines */ describe('fileCourtIssuedOrderInteractor', () => { const mockUserId = applicationContext.getUniqueId(); const caseRecord = { @@ -146,41 +147,6 @@ describe('fileCourtIssuedOrderInteractor', () => { ).toEqual(4); }); - it('should add order document to case and set freeText and draftOrderState.freeText to the document title if it is a generic order (eventCode O)', async () => { - await fileCourtIssuedOrderInteractor( - applicationContext, - { - documentMetadata: { - docketNumber: caseRecord.docketNumber, - documentTitle: 'Order to do anything', - documentType: 'Order', - draftOrderState: {}, - eventCode: 'O', - signedAt: '2019-03-01T21:40:46.415Z', - signedByUserId: mockUserId, - signedJudgeName: 'Dredd', - }, - primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', - }, - mockDocketClerkUser, - ); - - expect( - applicationContext.getPersistenceGateway().getCaseByDocketNumber, - ).toHaveBeenCalled(); - expect( - applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] - .caseToUpdate.docketEntries.length, - ).toEqual(4); - expect( - applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] - .caseToUpdate.docketEntries[3], - ).toMatchObject({ - draftOrderState: { freeText: 'Order to do anything' }, - freeText: 'Order to do anything', - }); - }); - it('should delete draftOrderState properties if they exists on the documentMetadata, after saving the document', async () => { await fileCourtIssuedOrderInteractor( applicationContext, @@ -507,4 +473,334 @@ describe('fileCourtIssuedOrderInteractor', () => { identifiers: [`case|${caseRecord.docketNumber}`], }); }); + + describe('freeText', () => { + describe('eventCode "NOT"', () => { + it('should add order document to case and set freeText and draftOrderState.freeText to the document title if it eventCode NOT', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + docketNumber: caseRecord.docketNumber, + documentTitle: 'Order to do anything', + documentType: 'Order', + draftOrderState: {}, + eventCode: 'NOT', + signedAt: '2019-03-01T21:40:46.415Z', + signedByUserId: mockUserId, + signedJudgeName: 'Dredd', + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries.length, + ).toEqual(4); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { freeText: 'Order to do anything' }, + freeText: 'Order to do anything', + }); + }); + }); + + describe('eventCode "O"', () => { + it('should add order document to case and set freeText and draftOrderState.freeText correctly for orderType status report', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + draftOrderState: {}, + dueDate: '2024-11-05', + eventCode: 'O', + orderType: 'statusReport', + strickenFromTrialSessions: false, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: 'Order parties by 11/05/2024 shall file a status report.', + }, + freeText: 'Order parties by 11/05/2024 shall file a status report.', + }); + }); + + it('should add order document to case and set freeText and draftOrderState.freeText correctly for orderType status report and when case is stricken from current trial session', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + draftOrderState: {}, + dueDate: '2024-11-05', + eventCode: 'O', + orderType: 'statusReport', + strickenFromTrialSessions: true, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: + 'Order parties by 11/05/2024 shall file a status report. Case is stricken from the current trial session.', + }, + freeText: + 'Order parties by 11/05/2024 shall file a status report. Case is stricken from the current trial session.', + }); + }); + + it('should add order document to case and set freeText and draftOrderState.freeText correctly for orderType status report and when case is stricken from current trial session and jurisdiction is restored to general docket', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + draftOrderState: {}, + dueDate: '2024-11-05', + eventCode: 'O', + jurisdiction: 'restoredToGeneralDocket', + orderType: 'statusReport', + strickenFromTrialSessions: true, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: + 'Order parties by 11/05/2024 shall file a status report. Case is stricken from the current trial session. Case is no longer jurisdiction retained and is restored to the general docket.', + }, + freeText: + 'Order parties by 11/05/2024 shall file a status report. Case is stricken from the current trial session. Case is no longer jurisdiction retained and is restored to the general docket.', + }); + }); + + it('should add order document to case and set freeText and draftOrderState.freeText correctly for orderType status report stipulated decision', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + draftOrderState: {}, + dueDate: '2024-11-05', + eventCode: 'O', + orderType: 'statusReportStipulatedDecision', + strickenFromTrialSessions: false, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: + 'Order parties by 11/05/2024 shall file a status report or proposed stipulated decision.', + }, + freeText: + 'Order parties by 11/05/2024 shall file a status report or proposed stipulated decision.', + }); + }); + + it('should add order document to case and set freeText and draftOrderState.freeText correctly for orderType status report stipulated decision and when case is stricken from current trial session', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + draftOrderState: {}, + dueDate: '2024-11-05', + eventCode: 'O', + orderType: 'statusReportStipulatedDecision', + strickenFromTrialSessions: true, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: + 'Order parties by 11/05/2024 shall file a status report or proposed stipulated decision. Case is stricken from the current trial session.', + }, + freeText: + 'Order parties by 11/05/2024 shall file a status report or proposed stipulated decision. Case is stricken from the current trial session.', + }); + }); + + it('should add order document to case and set freeText and draftOrderState.freeText correctly for orderType status report stipulated decision and when case is stricken from current trial session and jurisdiction is restored to general docket', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + draftOrderState: {}, + dueDate: '2024-11-05', + eventCode: 'O', + jurisdiction: 'restoredToGeneralDocket', + orderType: 'statusReportStipulatedDecision', + strickenFromTrialSessions: true, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: + 'Order parties by 11/05/2024 shall file a status report or proposed stipulated decision. Case is stricken from the current trial session. Case is no longer jurisdiction retained and is restored to the general docket.', + }, + freeText: + 'Order parties by 11/05/2024 shall file a status report or proposed stipulated decision. Case is stricken from the current trial session. Case is no longer jurisdiction retained and is restored to the general docket.', + }); + }); + }); + + describe('eventcode "OJR"', () => { + it('should add order document to case and set freeText and draftOrderState.freeText correctly when order type is statusReport', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + docketNumber: caseRecord.docketNumber, + draftOrderState: {}, + dueDate: '2024-11-05', + eventCode: 'O', + jurisdiction: 'retained', + orderType: 'statusReport', + strickenFromTrialSessions: true, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: + '. Parties by 11/05/2024 shall file a status report. Case is stricken from the current trial session.', + }, + freeText: + '. Parties by 11/05/2024 shall file a status report. Case is stricken from the current trial session.', + }); + }); + + it('should add order document to case and set freeText and draftOrderState.freeText correctly when order type is statusReportStipulatedDecision and case is stricken from the current trial session', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + docketNumber: caseRecord.docketNumber, + draftOrderState: {}, + dueDate: '2024-11-05', + eventCode: 'O', + jurisdiction: 'retained', + orderType: 'statusReportStipulatedDecision', + strickenFromTrialSessions: true, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: + '. Parties by 11/05/2024 shall file a status report or proposed stipulated decision. Case is stricken from the current trial session.', + }, + freeText: + '. Parties by 11/05/2024 shall file a status report or proposed stipulated decision. Case is stricken from the current trial session.', + }); + }); + + it('should add order document to case and set freeText and draftOrderState.freeText correctly when case is stricken from the current trial session', async () => { + await fileCourtIssuedOrderInteractor( + applicationContext, + { + documentMetadata: { + docketNumber: caseRecord.docketNumber, + draftOrderState: {}, + eventCode: 'O', + jurisdiction: 'retained', + strickenFromTrialSessions: true, + }, + primaryDocumentFileId: 'c54ba5a9-b37b-479d-9201-067ec6e335bb', + }, + mockDocketClerkUser, + ); + expect( + applicationContext.getPersistenceGateway().getCaseByDocketNumber, + ).toHaveBeenCalled(); + expect( + applicationContext.getPersistenceGateway().updateCase.mock.calls[0][0] + .caseToUpdate.docketEntries[3], + ).toMatchObject({ + draftOrderState: { + freeText: '. Case is stricken from the current trial session.', + }, + freeText: '. Case is stricken from the current trial session.', + }); + }); + }); + }); }); diff --git a/web-api/src/business/useCases/courtIssuedOrder/fileCourtIssuedOrderInteractor.ts b/web-api/src/business/useCases/courtIssuedOrder/fileCourtIssuedOrderInteractor.ts index b7402b20a36..796a0381cb4 100644 --- a/web-api/src/business/useCases/courtIssuedOrder/fileCourtIssuedOrderInteractor.ts +++ b/web-api/src/business/useCases/courtIssuedOrder/fileCourtIssuedOrderInteractor.ts @@ -1,6 +1,13 @@ +import { + COURT_ISSUED_EVENT_CODES, + DOCUMENT_RELATIONSHIPS, +} from '../../../../../shared/src/business/entities/EntityConstants'; import { Case } from '../../../../../shared/src/business/entities/cases/Case'; -import { DOCUMENT_RELATIONSHIPS } from '../../../../../shared/src/business/entities/EntityConstants'; import { DocketEntry } from '../../../../../shared/src/business/entities/DocketEntry'; +import { + FORMATS, + formatDateString, +} from '@shared/business/utilities/DateHandler'; import { Message } from '../../../../../shared/src/business/entities/Message'; import { ROLE_PERMISSIONS, @@ -40,11 +47,22 @@ export const fileCourtIssuedOrder = async ( }); const caseEntity = new Case(caseToUpdate, { authorizedUser }); - if (['O', 'NOT'].includes(documentMetadata.eventCode)) { - documentMetadata.freeText = documentMetadata.documentTitle; + if ( + documentMetadata.strickenFromTrialSessions && + documentMetadata.jurisdiction === 'retained' + ) { + const ojrEventCode = COURT_ISSUED_EVENT_CODES.find( + e => e.eventCode === 'OJR', + ); + documentMetadata.documentType = ojrEventCode?.documentType; + documentMetadata.eventCode = 'OJR'; + } + + if (['O', 'NOT', 'OJR'].includes(documentMetadata.eventCode)) { + const freeText = generateFreeText(documentMetadata); + documentMetadata.freeText = freeText; if (documentMetadata.draftOrderState) { - documentMetadata.draftOrderState.freeText = - documentMetadata.documentTitle; + documentMetadata.draftOrderState.freeText = freeText; } } @@ -138,3 +156,56 @@ export const fileCourtIssuedOrderInteractor = withLocking( identifiers: [`case|${documentMetadata.docketNumber}`], }), ); + +function generateFreeText(documentMetadata: { + orderType: string; + documentTitle: string; + dueDate: string; + eventCode: string; + strickenFromTrialSessions: boolean; + jurisdiction: string; +}) { + const { + documentTitle, + dueDate, + eventCode, + jurisdiction, + orderType, + strickenFromTrialSessions, + } = documentMetadata; + + const formattedDueDate = formatDateString(dueDate, FORMATS.MMDDYYYY); + if (eventCode === 'OJR') { + return [ + orderType === 'statusReport' && + `. Parties by ${formattedDueDate} shall file a status report.`, + orderType === 'statusReportStipulatedDecision' && + `. Parties by ${formattedDueDate} shall file a status report or proposed stipulated decision.`, + orderType !== 'statusReportStipulatedDecision' && + orderType !== 'statusReport' && + strickenFromTrialSessions && + '.', + strickenFromTrialSessions && + 'Case is stricken from the current trial session.', + ] + .filter(Boolean) + .join(' '); + } + + if (eventCode === 'O' && (orderType || jurisdiction)) { + return [ + 'Order', + orderType === 'statusReport' && + `parties by ${formattedDueDate} shall file a status report.`, + orderType === 'statusReportStipulatedDecision' && + `parties by ${formattedDueDate} shall file a status report or proposed stipulated decision.`, + strickenFromTrialSessions && + 'Case is stricken from the current trial session.', + jurisdiction === 'restoredToGeneralDocket' && + 'Case is no longer jurisdiction retained and is restored to the general docket.', + ] + .filter(Boolean) + .join(' '); + } + return documentTitle; +} From 47ed28073816aaba200ee96e14f4746c789f07fa Mon Sep 17 00:00:00 2001 From: Nechama Krigsman Date: Tue, 26 Nov 2024 10:44:39 -0500 Subject: [PATCH 02/38] 10489: fix extra space showing before the period on docket entry description; --- shared/src/business/utilities/replaceBracketed.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/business/utilities/replaceBracketed.ts b/shared/src/business/utilities/replaceBracketed.ts index b7a3b0bfc9f..62d3899b3dc 100644 --- a/shared/src/business/utilities/replaceBracketed.ts +++ b/shared/src/business/utilities/replaceBracketed.ts @@ -6,6 +6,7 @@ export const replaceBracketed = ( while (bracketsMatcher.test(template)) { template = template.replace(bracketsMatcher, values.shift() || ''); } + template = template.replace(/\s+\./g, '.'); template = template.trim(); return template; }; From f766dcb23640220fa89f40cd18d3894292c5543d Mon Sep 17 00:00:00 2001 From: Nechama Krigsman Date: Tue, 26 Nov 2024 10:45:14 -0500 Subject: [PATCH 03/38] 10489: set default judge when eventCode is OJR; --- ...urtIssuedDocumentInitialDataAction.test.ts | 44 +++++++++++++++++++ ...setCourtIssuedDocumentInitialDataAction.ts | 11 +++++ 2 files changed, 55 insertions(+) diff --git a/web-client/src/presenter/actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction.test.ts b/web-client/src/presenter/actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction.test.ts index 6d89a183086..98398ba3e31 100644 --- a/web-client/src/presenter/actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction.test.ts +++ b/web-client/src/presenter/actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction.test.ts @@ -8,6 +8,7 @@ describe('setCourtIssuedDocumentInitialDataAction', () => { const docketEntryIds = [ 'ddfd978d-6be6-4877-b004-2b5735a41fee', '11597d22-0874-4c5e-ac98-a843d1472baf', + '22597d22-0874-4c5e-ac98-a843d1472baf', ]; beforeAll(() => { @@ -22,6 +23,11 @@ describe('setCourtIssuedDocumentInitialDataAction', () => { eventCode: 'O', freeText: 'something', }); + MOCK_CASE.docketEntries.push({ + docketEntryId: docketEntryIds[2], + eventCode: 'OJR', + signedByUserId: '4497d22-0874-4c5e-ac98-a843d1472baf', + }); }); it('should set correct values on state.form for the docketEntryId passed in via props', async () => { @@ -108,4 +114,42 @@ describe('setCourtIssuedDocumentInitialDataAction', () => { expect(result.state.form).toEqual({}); }); + + it('should set the judge name when eventcode is OJR and docketEntry was signed by the judge', async () => { + const result = await runAction(setCourtIssuedDocumentInitialDataAction, { + modules: { + presenter, + }, + props: { + docketEntryId: '22597d22-0874-4c5e-ac98-a843d1472baf', + }, + state: { + caseDetail: MOCK_CASE, + form: {}, + judges: [ + { name: 'Colvin', userId: '4497d22-0874-4c5e-ac98-a843d1472baf' }, + ], + }, + }); + expect(result.state.form.judge).toEqual('Colvin'); + }); + + it('should not set the judge name when eventcode is OJR and docketEntry was signed by a non judge user', async () => { + const result = await runAction(setCourtIssuedDocumentInitialDataAction, { + modules: { + presenter, + }, + props: { + docketEntryId: '22597d22-0874-4c5e-ac98-a843d1472baf', + }, + state: { + caseDetail: MOCK_CASE, + form: {}, + judges: [ + { name: 'Cohen', userId: '3297d22-0874-4c5e-ac98-a843d1472baf' }, + ], + }, + }); + expect(result.state.form.judge).toEqual(undefined); + }); }); diff --git a/web-client/src/presenter/actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction.ts b/web-client/src/presenter/actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction.ts index a99dd05072c..0fbd5c9596a 100644 --- a/web-client/src/presenter/actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction.ts +++ b/web-client/src/presenter/actions/CourtIssuedDocketEntry/setCourtIssuedDocumentInitialDataAction.ts @@ -18,6 +18,8 @@ export const setCourtIssuedDocumentInitialDataAction = ({ }: ActionProps) => { const { docketEntries } = get(state.caseDetail); + const judges = get(state.judges); + const docketEntry = docketEntries.find( item => item.docketEntryId === props.docketEntryId, ); @@ -34,6 +36,15 @@ export const setCourtIssuedDocumentInitialDataAction = ({ store.set(state.form.attachments, false); } + if (docketEntry.eventCode === 'OJR') { + const signingJudge = judges.find(judge => { + return judge.userId === docketEntry.signedByUserId; + }); + if (signingJudge) { + store.set(state.form.judge, signingJudge.name); + } + } + if (docketEntry.freeText) { store.set(state.form.freeText, docketEntry.freeText); } From 478463ae3a7c08616e8feb5ec183c929d81fb335 Mon Sep 17 00:00:00 2001 From: Nechama Krigsman Date: Tue, 26 Nov 2024 12:25:50 -0500 Subject: [PATCH 04/38] 10489: add cypress tests; --- ...atus-report-order-description-fields.cy.ts | 81 +++++++++++++++++++ .../CourtIssuedDocketEntry.tsx | 5 +- web-client/src/views/StatusReportOrder.tsx | 1 + 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 cypress/local-only/tests/integration/statusReportOrder/status-report-order-description-fields.cy.ts diff --git a/cypress/local-only/tests/integration/statusReportOrder/status-report-order-description-fields.cy.ts b/cypress/local-only/tests/integration/statusReportOrder/status-report-order-description-fields.cy.ts new file mode 100644 index 00000000000..8063b6b6c20 --- /dev/null +++ b/cypress/local-only/tests/integration/statusReportOrder/status-report-order-description-fields.cy.ts @@ -0,0 +1,81 @@ +import { + FORMATS, + formatNow, +} from '../../../../../shared/src/business/utilities/DateHandler'; +import { + docketNumber, + getLastDraftOrderElementFromDrafts, +} from '../../../support/statusReportOrder'; +import { + loginAsColvin, + loginAsDocketClerk, +} from '../../../../helpers/authentication/login-as-helpers'; +import { logout } from '../../../../helpers/authentication/logout'; + +describe('should default status report order descriptions', () => { + const today = formatNow(FORMATS.MMDDYYYY); + it('should display default description when document type is an Order', () => { + judgeCreatesAndSavesStatusReportOrder(today); + loginAsDocketClerk(); + cy.visit(`/case-detail/${docketNumber}`); + cy.get('#tab-drafts').click(); + getLastDraftOrderElementFromDrafts().click(); + cy.get('[data-testid="add-court-issued-docket-entry-button"]').click(); + cy.get('.select-react-element__control').should('have.text', 'Order'); + cy.get('[data-testid="document-description-input"]').should( + 'have.value', + `Order parties by ${today} shall file a status report.`, + ); + cy.get('[data-testid="docket-entry-preview-text"]').should( + 'have.text', + `Docket entry preview: Order parties by ${today} shall file a status report.`, + ); + }); + it('should set event code to OJR when case is stricken from trial session and jurisdiction is retained and display default description', () => { + judgeCreatesAndSavesStatusReportOrder(today, true); + loginAsDocketClerk(); + cy.visit(`/case-detail/${docketNumber}`); + cy.get('#tab-drafts').click(); + getLastDraftOrderElementFromDrafts().click(); + cy.get('[data-testid="add-court-issued-docket-entry-button"]').click(); + cy.get('.select-react-element__control').should( + 'have.text', + 'Order that jurisdiction is retained', + ); + cy.get('[data-testid="document-description-input"]').should( + 'have.value', + `. Parties by ${today} shall file a status report. Case is stricken from the current trial session.`, + ); + cy.get('#judge-label').click(); + cy.get('[data-testid="docket-entry-preview-text"]').should( + 'have.text', + `Docket entry preview: Order that jurisdiction is retained by Colvin. Parties by ${today} shall file a status report. Case is stricken from the current trial session.`, + ); + }); +}); + +function judgeCreatesAndSavesStatusReportOrder( + today: string, + jurisdictionRetain: boolean = false, +) { + loginAsColvin(); + cy.visit(`/case-detail/${docketNumber}`); + cy.get('#tab-document-view').click(); + cy.contains('Status Report').click(); + cy.get('[data-testid="status-report-order-button"]').click(); + cy.get('[data-testid="order-type-status-report"]').check({ force: true }); + cy.get('#status-report-due-date-picker').type(today); + + if (jurisdictionRetain) { + cy.get('#stricken-from-trial-sessions-label').click(); + + cy.get( + '#jurisdiction-form-group > :nth-child(2) > .usa-radio__label', + ).click(); + cy.get('#jurisdiction-retained').check(); + } + cy.get('[data-testid="save-draft-button"]').click(); + cy.get('[data-testid="sign-pdf-canvas"]').click(); + cy.get('[data-testid="save-signature-button"]').click(); + logout(); +} diff --git a/web-client/src/views/CourtIssuedDocketEntry/CourtIssuedDocketEntry.tsx b/web-client/src/views/CourtIssuedDocketEntry/CourtIssuedDocketEntry.tsx index a0130b97787..8a0bea98655 100644 --- a/web-client/src/views/CourtIssuedDocketEntry/CourtIssuedDocketEntry.tsx +++ b/web-client/src/views/CourtIssuedDocketEntry/CourtIssuedDocketEntry.tsx @@ -96,7 +96,10 @@ export const CourtIssuedDocketEntry = connect(
-
+
Docket entry preview: {addCourtIssuedDocketEntryHelper.formattedDocumentTitle}
diff --git a/web-client/src/views/StatusReportOrder.tsx b/web-client/src/views/StatusReportOrder.tsx index 09247c74aee..b1fc668d836 100644 --- a/web-client/src/views/StatusReportOrder.tsx +++ b/web-client/src/views/StatusReportOrder.tsx @@ -155,6 +155,7 @@ export const StatusReportOrder = connect( .statusReport } className="usa-radio__input" + data-testid="order-type-status-report" id="order-type-status-report" name="orderType" type="radio" From e1ee1f43289f455667b3d2a623c316fb4b7893d2 Mon Sep 17 00:00:00 2001 From: Nechama Krigsman Date: Tue, 26 Nov 2024 14:27:50 -0500 Subject: [PATCH 05/38] 10489: display judge name and title on docket description; --- .../status-report-order-description-fields.cy.ts | 9 ++++----- .../sequences/gotoAddCourtIssuedDocketEntrySequence.ts | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cypress/local-only/tests/integration/statusReportOrder/status-report-order-description-fields.cy.ts b/cypress/local-only/tests/integration/statusReportOrder/status-report-order-description-fields.cy.ts index 8063b6b6c20..d07e42b1d12 100644 --- a/cypress/local-only/tests/integration/statusReportOrder/status-report-order-description-fields.cy.ts +++ b/cypress/local-only/tests/integration/statusReportOrder/status-report-order-description-fields.cy.ts @@ -46,17 +46,17 @@ describe('should default status report order descriptions', () => { 'have.value', `. Parties by ${today} shall file a status report. Case is stricken from the current trial session.`, ); - cy.get('#judge-label').click(); + cy.get('[data-testid="judge-select"]').should('have.value', 'Colvin'); cy.get('[data-testid="docket-entry-preview-text"]').should( 'have.text', - `Docket entry preview: Order that jurisdiction is retained by Colvin. Parties by ${today} shall file a status report. Case is stricken from the current trial session.`, + `Docket entry preview: Order that jurisdiction is retained by Judge Colvin. Parties by ${today} shall file a status report. Case is stricken from the current trial session.`, ); }); }); function judgeCreatesAndSavesStatusReportOrder( today: string, - jurisdictionRetain: boolean = false, + jurisdictionRetained: boolean = false, ) { loginAsColvin(); cy.visit(`/case-detail/${docketNumber}`); @@ -66,9 +66,8 @@ function judgeCreatesAndSavesStatusReportOrder( cy.get('[data-testid="order-type-status-report"]').check({ force: true }); cy.get('#status-report-due-date-picker').type(today); - if (jurisdictionRetain) { + if (jurisdictionRetained) { cy.get('#stricken-from-trial-sessions-label').click(); - cy.get( '#jurisdiction-form-group > :nth-child(2) > .usa-radio__label', ).click(); diff --git a/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts b/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts index d115deb4354..20c959566fb 100644 --- a/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts +++ b/web-client/src/presenter/sequences/gotoAddCourtIssuedDocketEntrySequence.ts @@ -1,4 +1,5 @@ import { clearFormAction } from '../actions/clearFormAction'; +import { computeJudgeNameWithTitleAction } from '@web-client/presenter/actions/computeJudgeNameWithTitleAction'; import { generateCourtIssuedDocumentTitleAction } from '../actions/CourtIssuedDocketEntry/generateCourtIssuedDocumentTitleAction'; import { getCaseAction } from '../actions/getCaseAction'; import { getFilterCurrentJudgeUsersAction } from '../actions/getFilterCurrentJudgeUsersAction'; @@ -28,6 +29,7 @@ export const gotoAddCourtIssuedDocketEntrySequence = setDocketEntryIdAction, setCourtIssuedDocumentInitialDataAction, setDefaultServiceStampAction, + computeJudgeNameWithTitleAction, generateCourtIssuedDocumentTitleAction, setIsEditingDocketEntryAction(false), setupCurrentPageAction('CourtIssuedDocketEntry'), From 44a562548fc9982c2d06fba1c5ddb22ee53f48b9 Mon Sep 17 00:00:00 2001 From: Tejha Bollu Date: Mon, 2 Dec 2024 09:48:48 -0500 Subject: [PATCH 06/38] 10549- Fix long docket number cut off --- run-local.sh | 4 ++-- web-client/src/styles/typography.scss | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/run-local.sh b/run-local.sh index 718a35f514d..27279c6f2d4 100755 --- a/run-local.sh +++ b/run-local.sh @@ -6,10 +6,10 @@ if [[ -z "$CI" ]]; then echo "Stopping postgres in case it's already running" - docker compose -f web-api/src/persistence/postgres/docker-compose.yml down || true + docker-compose -f web-api/src/persistence/postgres/docker-compose.yml down || true echo "Starting postgres" - docker compose -f web-api/src/persistence/postgres/docker-compose.yml up -d || { echo "Failed to start Postgres containers"; exit 1; } + docker-compose -f web-api/src/persistence/postgres/docker-compose.yml up -d || { echo "Failed to start Postgres containers"; exit 1; } echo "Stopping dynamodb in case it's already running" pkill -f DynamoDBLocal diff --git a/web-client/src/styles/typography.scss b/web-client/src/styles/typography.scss index 13d2f016dee..88536d97a4f 100644 --- a/web-client/src/styles/typography.scss +++ b/web-client/src/styles/typography.scss @@ -207,3 +207,10 @@ a:hover { font-size: 17px; font-weight: bold; } + +h1, +.heading-2 { + @media only screen and (max-width: $medium-screen) { + font-size: 1.125em + } +} From 409ab9f305f6cb12534948f3cd3857f0d33b1cce Mon Sep 17 00:00:00 2001 From: Tejha Bollu <20894935+btejha@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:54:16 -0500 Subject: [PATCH 07/38] Reverted local changes --- run-local.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run-local.sh b/run-local.sh index 27279c6f2d4..718a35f514d 100755 --- a/run-local.sh +++ b/run-local.sh @@ -6,10 +6,10 @@ if [[ -z "$CI" ]]; then echo "Stopping postgres in case it's already running" - docker-compose -f web-api/src/persistence/postgres/docker-compose.yml down || true + docker compose -f web-api/src/persistence/postgres/docker-compose.yml down || true echo "Starting postgres" - docker-compose -f web-api/src/persistence/postgres/docker-compose.yml up -d || { echo "Failed to start Postgres containers"; exit 1; } + docker compose -f web-api/src/persistence/postgres/docker-compose.yml up -d || { echo "Failed to start Postgres containers"; exit 1; } echo "Stopping dynamodb in case it's already running" pkill -f DynamoDBLocal From 288d0707f9bb2a6aa3e830947fe401ee585b3205 Mon Sep 17 00:00:00 2001 From: Tejha Bollu Date: Mon, 2 Dec 2024 15:58:48 -0500 Subject: [PATCH 08/38] 10549:Reverted the font size to its original setting and wrapped the docket number. --- web-client/src/styles/typography.scss | 10 +++++----- web-client/src/views/CaseDetail/CaseDetailHeader.tsx | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/web-client/src/styles/typography.scss b/web-client/src/styles/typography.scss index 88536d97a4f..2cc8872ae65 100644 --- a/web-client/src/styles/typography.scss +++ b/web-client/src/styles/typography.scss @@ -208,9 +208,9 @@ a:hover { font-weight: bold; } -h1, -.heading-2 { - @media only screen and (max-width: $medium-screen) { - font-size: 1.125em +.no-wrap-text { + @media only screen and (max-width: $small-screen) { + white-space: normal; + word-wrap: break-word; } -} +} \ No newline at end of file diff --git a/web-client/src/views/CaseDetail/CaseDetailHeader.tsx b/web-client/src/views/CaseDetail/CaseDetailHeader.tsx index ebab31cd75b..a62f2c10c67 100644 --- a/web-client/src/views/CaseDetail/CaseDetailHeader.tsx +++ b/web-client/src/views/CaseDetail/CaseDetailHeader.tsx @@ -168,7 +168,10 @@ export const CaseDetailHeader = connect< size="1x" /> )} - + Docket Number:{' '} {formattedCaseDetail.docketNumberWithSuffix} From ce2f89d32e295edaa3a7aaf528775fa809413afb Mon Sep 17 00:00:00 2001 From: Tejha Bollu Date: Tue, 3 Dec 2024 09:45:05 -0500 Subject: [PATCH 09/38] 10549:Classname updated --- web-client/src/styles/typography.scss | 7 ------- web-client/src/views/CaseDetail/CaseDetailHeader.tsx | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/web-client/src/styles/typography.scss b/web-client/src/styles/typography.scss index 2cc8872ae65..e0bd253810e 100644 --- a/web-client/src/styles/typography.scss +++ b/web-client/src/styles/typography.scss @@ -206,11 +206,4 @@ a:hover { .petitioner-label { font-size: 17px; font-weight: bold; -} - -.no-wrap-text { - @media only screen and (max-width: $small-screen) { - white-space: normal; - word-wrap: break-word; - } } \ No newline at end of file diff --git a/web-client/src/views/CaseDetail/CaseDetailHeader.tsx b/web-client/src/views/CaseDetail/CaseDetailHeader.tsx index a62f2c10c67..e78ecbd184b 100644 --- a/web-client/src/views/CaseDetail/CaseDetailHeader.tsx +++ b/web-client/src/views/CaseDetail/CaseDetailHeader.tsx @@ -169,7 +169,7 @@ export const CaseDetailHeader = connect< /> )} Docket Number:{' '} From 865d602d12b9572fa9777b254ba3f108bdeda369 Mon Sep 17 00:00:00 2001 From: Javis Sullivan Date: Wed, 13 Nov 2024 23:57:00 -0500 Subject: [PATCH 10/38] 10472: PDF Preview in new Tab 10472: open pdf previews in new tab wip wip, working irspractioner when opening pdf to new tab wip, add functioning tab sequence rm log statement rm log statements more cleanup rm docstring add check for reader add test and some wip add test for loadPDFForTabAction add void return for promise, explicit readerResult check fix type errors rm globals ignore problematic type checks oops rm modal checks --- .../petitions-clerk-creates-paper-case.cy.ts | 11 +- .../PDFPreviewModal/loadPdfAction.test.ts | 34 +++-- .../actions/PDFPreviewModal/loadPdfAction.ts | 2 +- .../PDFPreviewTab/loadPdfForTabAction.test.ts | 122 ++++++++++++++++++ .../PDFPreviewTab/loadPdfForTabAction.ts | 44 +++++++ .../actions/getPDFForPreviewTabAction.test.ts | 50 +++++++ .../actions/getPDFForPreviewTabAction.ts | 21 +++ .../openCaseDocumentDownloadUrlAction.ts | 6 - .../presenter/computeds/fileDocumentHelper.ts | 1 + web-client/src/presenter/presenter.ts | 2 + .../PDFPreviewTab/loadPdfForTabSequence.ts | 9 ++ web-client/src/utilities/fileReader.ts | 0 .../DocketRecord/DocumentViewerDocument.tsx | 8 +- web-client/src/views/PDFPreviewButton.tsx | 8 +- 14 files changed, 284 insertions(+), 34 deletions(-) create mode 100644 web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.test.ts create mode 100644 web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts create mode 100644 web-client/src/presenter/actions/getPDFForPreviewTabAction.test.ts create mode 100644 web-client/src/presenter/actions/getPDFForPreviewTabAction.ts create mode 100644 web-client/src/presenter/sequences/PDFPreviewTab/loadPdfForTabSequence.ts create mode 100644 web-client/src/utilities/fileReader.ts diff --git a/cypress/local-only/tests/integration/fileAPetition/petitions-clerk-creates-paper-case.cy.ts b/cypress/local-only/tests/integration/fileAPetition/petitions-clerk-creates-paper-case.cy.ts index b06406e85cb..a96ccb6f43a 100644 --- a/cypress/local-only/tests/integration/fileAPetition/petitions-clerk-creates-paper-case.cy.ts +++ b/cypress/local-only/tests/integration/fileAPetition/petitions-clerk-creates-paper-case.cy.ts @@ -19,6 +19,11 @@ import { unchecksOrdersAndNoticesBoxesInCase } from '../../../support/pages/unch describe('Petition clerk creates a paper filing', function () { describe('Create and submit a paper petition', () => { + beforeEach(() => { + cy.window().then(win => { + cy.stub(win, 'open').as('windowOpen'); + }); + }); it('should create a paper petition', () => { navigateToDocumentQC('petitionsclerk'); @@ -43,8 +48,6 @@ describe('Petition clerk creates a paper filing', function () { it('should display attachment links in the attachment section', () => { cy.get('[data-testid="petitionFileButton"]').should('be.visible'); cy.get('[data-testid="petitionFileButton"]').click(); - cy.get('[data-testid="modal-dialog-header"]').should('be.visible'); - cy.get('[data-testid="close-modal-button"]').click(); cy.get('[data-testid="stinFileDisplay"]').should('be.visible'); cy.get('[data-testid="stinFileDisplay"]').should('not.be.enabled'); @@ -52,14 +55,10 @@ describe('Petition clerk creates a paper filing', function () { 'be.visible', ); cy.get('[data-testid="requestForPlaceOfTrialFileButton"]').click(); - cy.get('[data-testid="modal-dialog-header"]').should('be.visible'); - cy.get('[data-testid="close-modal-button"]').click(); cy.get('[data-testid="attachmentToPetitionFileButton"]').should( 'be.visible', ); cy.get('[data-testid="attachmentToPetitionFileButton"]').click(); - cy.get('[data-testid="modal-dialog-header"]').should('be.visible'); - cy.get('[data-testid="close-modal-button"]').click(); }); it('should display Orders/Notices Automatically Created notification', () => { diff --git a/web-client/src/presenter/actions/PDFPreviewModal/loadPdfAction.test.ts b/web-client/src/presenter/actions/PDFPreviewModal/loadPdfAction.test.ts index 61fd51c3bdf..f23482d392a 100644 --- a/web-client/src/presenter/actions/PDFPreviewModal/loadPdfAction.test.ts +++ b/web-client/src/presenter/actions/PDFPreviewModal/loadPdfAction.test.ts @@ -5,32 +5,35 @@ import { runAction } from '@web-client/presenter/test.cerebral'; import { testPdfDoc } from '../../../../../shared/src/business/test/getFakeFile'; describe('loadPdfAction', () => { - global.Blob = function () {}; - const fakeFile = testPdfDoc; const b64File = `data:application/pdf;base64,${Buffer.from( - String.fromCharCode.apply(null, fakeFile), + String.fromCharCode(...fakeFile), ).toString('base64')}`; const mocks = { - readAsArrayBufferMock: jest.fn().mockImplementation(async function () { + readAsArrayBufferMock: jest.fn().mockImplementation(async function (this: { + result: any; + onload: any; + }) { this.result = fakeFile; await this.onload(); }), - readAsDataURLMock: jest.fn().mockImplementation(async function () { + readAsDataURLMock: jest.fn().mockImplementation(async function (this: { + result: any; + onload: any; + }) { this.result = b64File; await this.onload(); }), }; - /** - * Mock FileReader Implementation - */ - function MockFileReader() { - this.onload = null; - this.onerror = null; - this.readAsDataURL = mocks.readAsDataURLMock; - this.readAsArrayBuffer = mocks.readAsArrayBufferMock; + class MockFileReader { + public result: unknown = null; + public onload: any; + public onerror: any; + + readAsDataURL = mocks.readAsDataURLMock; + readAsArrayBuffer = mocks.readAsArrayBufferMock; } beforeAll(() => { @@ -100,7 +103,10 @@ describe('loadPdfAction', () => { }); it('should error out when the FileReader fails', async () => { - mocks.readAsArrayBufferMock.mockImplementationOnce(function () { + mocks.readAsArrayBufferMock.mockImplementationOnce(function (this: { + result: any; + onerror: any; + }) { this.result = 'abc'; this.onerror(new Error('An error called via reader.onerror.')); }); diff --git a/web-client/src/presenter/actions/PDFPreviewModal/loadPdfAction.ts b/web-client/src/presenter/actions/PDFPreviewModal/loadPdfAction.ts index 629d3ac3e5b..dcfa993d2b6 100644 --- a/web-client/src/presenter/actions/PDFPreviewModal/loadPdfAction.ts +++ b/web-client/src/presenter/actions/PDFPreviewModal/loadPdfAction.ts @@ -19,7 +19,7 @@ export const loadPdfAction = ({ store.set(state.modal.pdfPreviewModal, {}); - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const reader = applicationContext.getFileReaderInstance(); reader.onload = () => { diff --git a/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.test.ts b/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.test.ts new file mode 100644 index 00000000000..9eaca35b931 --- /dev/null +++ b/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.test.ts @@ -0,0 +1,122 @@ +import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; +import { loadPdfForTabAction } from '../PDFPreviewTab/loadPdfForTabAction'; +import { presenter } from '../../presenter-mock'; +import { runAction } from '@web-client/presenter/test.cerebral'; +import { testPdfDoc } from '../../../../../shared/src/business/test/getFakeFile'; + +describe('loadPdfForTabAction', () => { + let originalWindowOpen; + + const fakeFile = testPdfDoc; + const b64File = `data:application/pdf;base64,${Buffer.from( + String.fromCharCode(...fakeFile), + ).toString('base64')}`; + + const mocks = { + readAsArrayBufferMock: jest.fn().mockImplementation(async function (this: { + result: any; + onload: any; + }) { + this.result = fakeFile; + await this.onload(); + }), + readAsDataURLMock: jest.fn().mockImplementation(async function (this: { + result: any; + onload: any; + }) { + this.result = b64File; + await this.onload(); + }), + }; + + class MockFileReader { + public result: unknown = null; + public onload: any; + public onerror: any; + + readAsDataURL = mocks.readAsDataURLMock; + readAsArrayBuffer = mocks.readAsArrayBufferMock; + } + + beforeAll(() => { + global.atob = x => x; + presenter.providers.path = { + error: jest.fn(), + success: jest.fn(), + }; + applicationContext.getFileReaderInstance.mockReturnValue( + new MockFileReader(), + ); + presenter.providers.applicationContext = applicationContext; + presenter.providers.router = { + createObjectURL: jest.fn().mockReturnValue('some url'), + }; + originalWindowOpen = window.open; + window.open = jest.fn(); + }); + + afterAll(() => { + window.open = originalWindowOpen; + }); + + it('should call window.open with correcturl for pdf file', async () => { + await runAction(loadPdfForTabAction, { + modules: { + presenter, + }, + props: { file: fakeFile }, + }); + + expect(window.open).toHaveBeenCalledWith('some url', '_blank'); + }); + + it('should detect binary (not base64-encoded) pdf data and read it successfully', async () => { + await runAction(loadPdfForTabAction, { + modules: { + presenter, + }, + props: { + file: fakeFile, + }, + }); + + expect(mocks.readAsArrayBufferMock).toHaveBeenCalled(); + }); + + it('should return an error when given an invalid pdf', async () => { + presenter.providers.router.createObjectURL.mockImplementationOnce(() => { + throw new Error('bad pdf data'); + }); + await expect( + runAction(loadPdfForTabAction, { + modules: { + presenter, + }, + props: { + file: 'data:binary/pdf,INVALID-BYTES', + }, + }), + ).rejects.toThrow('bad pdf data'); + }); + + it('should error out when the FileReader fails', async () => { + mocks.readAsArrayBufferMock.mockImplementationOnce(function (this: { + result: any; + onerror: any; + }) { + this.result = 'abc'; + this.onerror(new Error('An error called via reader.onerror.')); + }); + + await expect( + runAction(loadPdfForTabAction, { + modules: { + presenter, + }, + props: { + file: 'this my file', + }, + }), + ).rejects.toThrow('An error called via reader.onerror.'); + }); +}); diff --git a/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts b/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts new file mode 100644 index 00000000000..232b6246ffc --- /dev/null +++ b/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts @@ -0,0 +1,44 @@ +export const loadPdfForTabAction = ({ + applicationContext, + props, + router, +}: ActionProps) => { + const { file } = props; + const isBase64Encoded = typeof file === 'string' && file.startsWith('data'); + + return new Promise((resolve, reject) => { + const reader = applicationContext.getFileReaderInstance(); + + reader.onload = () => { + let binaryFile: string | ArrayBuffer | null; + if (isBase64Encoded && reader.result === 'string') { + const base64File = reader.result.replace(/[^,]+,/, ''); + binaryFile = atob(base64File); + } else { + binaryFile = reader.result; + } + + try { + const pdfDataUri = router.createObjectURL( + // @ts-ignore + new Blob([binaryFile], { type: 'application/pdf' }), + ); + window.open(pdfDataUri, '_blank'); + resolve(); + } catch (err) { + reject(err); + } + }; + + reader.onerror = function (err) { + reject(err); + }; + + if (isBase64Encoded) { + // @ts-ignore + reader.readAsDataURL(file); + } else { + reader.readAsArrayBuffer(file); + } + }); +}; diff --git a/web-client/src/presenter/actions/getPDFForPreviewTabAction.test.ts b/web-client/src/presenter/actions/getPDFForPreviewTabAction.test.ts new file mode 100644 index 00000000000..4ec450b8b97 --- /dev/null +++ b/web-client/src/presenter/actions/getPDFForPreviewTabAction.test.ts @@ -0,0 +1,50 @@ +import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; +import { getPDFForPreviewTabAction } from './getPDFForPreviewTabAction'; +import { presenter } from '../presenter-mock'; +import { runAction } from '@web-client/presenter/test.cerebral'; + +describe('getPDFForPreviewTabAction', () => { + beforeAll(() => { + presenter.providers.applicationContext = applicationContext; + applicationContext + .getUseCases() + .loadPDFForPreviewInteractor.mockResolvedValue('fake file data'); + }); + + it('returns original props if we already have what appears to be an actual file', async () => { + const props = { file: { name: 'name of a file on a real file object' } }; + const result = await runAction(getPDFForPreviewTabAction, { + modules: { + presenter, + }, + props, + state: {}, + }); + expect(result.props).toEqual(props); + expect( + applicationContext.getUseCases().loadPDFForPreviewInteractor, + ).not.toHaveBeenCalled(); + }); + + it('returns results from loadPDFForPreviewInteractor if provided a docketNumber and docketEntryId', async () => { + const props = { file: { docketEntryId: '456' } }; + await runAction(getPDFForPreviewTabAction, { + modules: { + presenter, + }, + props, + state: { + caseDetail: { + docketNumber: '123-20', + }, + }, + }); + expect( + applicationContext.getUseCases().loadPDFForPreviewInteractor.mock + .calls[0][1], + ).toMatchObject({ + docketEntryId: '456', + docketNumber: '123-20', + }); + }); +}); diff --git a/web-client/src/presenter/actions/getPDFForPreviewTabAction.ts b/web-client/src/presenter/actions/getPDFForPreviewTabAction.ts new file mode 100644 index 00000000000..cdce9fbd7f0 --- /dev/null +++ b/web-client/src/presenter/actions/getPDFForPreviewTabAction.ts @@ -0,0 +1,21 @@ +import { state } from '@web-client/presenter/app.cerebral'; + +export const getPDFForPreviewTabAction = async ({ + applicationContext, + get, + props, +}: ActionProps) => { + if (props.file.name) { + return props; + } + const { docketEntryId } = props.file; + const docketNumber = get(state.caseDetail.docketNumber); + + const pdfObj = await applicationContext + .getUseCases() + .loadPDFForPreviewInteractor(applicationContext, { + docketEntryId, + docketNumber, + }); + return { file: pdfObj }; +}; diff --git a/web-client/src/presenter/actions/openCaseDocumentDownloadUrlAction.ts b/web-client/src/presenter/actions/openCaseDocumentDownloadUrlAction.ts index 85c2756b40b..82fbea29075 100644 --- a/web-client/src/presenter/actions/openCaseDocumentDownloadUrlAction.ts +++ b/web-client/src/presenter/actions/openCaseDocumentDownloadUrlAction.ts @@ -1,11 +1,5 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * opens the document in a new tab - * @param {object} providers the providers object - * @param {object} providers.props the cerebral props object - * @param {object} providers.store the cerebral store object used for clearing alertError, alertSuccess - */ export const openCaseDocumentDownloadUrlAction = async ({ applicationContext, props, diff --git a/web-client/src/presenter/computeds/fileDocumentHelper.ts b/web-client/src/presenter/computeds/fileDocumentHelper.ts index 14978154883..28cac600bbd 100644 --- a/web-client/src/presenter/computeds/fileDocumentHelper.ts +++ b/web-client/src/presenter/computeds/fileDocumentHelper.ts @@ -119,6 +119,7 @@ export const fileDocumentHelper = ( supportingDocumentTypeList, ...showSecondaryProperties, ...supportingDocumentFlags, + docketNumber: caseDetail.docketNumber, }; if (form.hasSupportingDocuments) { diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 57c2751f0d1..a931dad7115 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -234,6 +234,7 @@ import { loadDefaultDraftViewerDocumentToDisplaySequence } from './sequences/Doc import { loadDefaultViewerCorrespondenceSequence } from './sequences/loadDefaultViewerCorrespondenceSequence'; import { loadMoreCaseDeadlinesSequence } from './sequences/loadMoreCaseDeadlinesSequence'; import { loadMorePendingItemsSequence } from './sequences/loadMorePendingItemsSequence'; +import { loadPdfForTabSequence } from './sequences/PDFPreviewTab/loadPdfForTabSequence'; import { loadPdfSequence } from './sequences/PDFPreviewModal/loadPdfSequence'; import { navigateBackSequence } from './sequences/navigateBackSequence'; import { navigateToCaseDetailFromPaperServiceSequence } from './sequences/navigateToCaseDetailFromPaperServiceSequence'; @@ -976,6 +977,7 @@ export const presenterSequences = { loadMoreCaseDeadlinesSequence as unknown as Function, loadMorePendingItemsSequence: loadMorePendingItemsSequence as unknown as Function, + loadPdfForTabSequence: loadPdfForTabSequence as unknown as Function, loadPdfSequence: loadPdfSequence as unknown as Function, navigateBackSequence: navigateBackSequence as unknown as Function, navigateToCaseDetailFromPaperServiceSequence: diff --git a/web-client/src/presenter/sequences/PDFPreviewTab/loadPdfForTabSequence.ts b/web-client/src/presenter/sequences/PDFPreviewTab/loadPdfForTabSequence.ts new file mode 100644 index 00000000000..cd4f245ca7a --- /dev/null +++ b/web-client/src/presenter/sequences/PDFPreviewTab/loadPdfForTabSequence.ts @@ -0,0 +1,9 @@ +import { getPDFForPreviewTabAction } from '../../actions/getPDFForPreviewTabAction'; +import { loadPdfForTabAction } from '../../actions/PDFPreviewTab/loadPdfForTabAction'; + +import { showProgressSequenceDecorator } from '../../utilities/showProgressSequenceDecorator'; + +export const loadPdfForTabSequence = showProgressSequenceDecorator([ + getPDFForPreviewTabAction, + loadPdfForTabAction, +]); diff --git a/web-client/src/utilities/fileReader.ts b/web-client/src/utilities/fileReader.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/web-client/src/views/DocketRecord/DocumentViewerDocument.tsx b/web-client/src/views/DocketRecord/DocumentViewerDocument.tsx index 3c8a79705a8..fa7b4f0eb2e 100644 --- a/web-client/src/views/DocketRecord/DocumentViewerDocument.tsx +++ b/web-client/src/views/DocketRecord/DocumentViewerDocument.tsx @@ -207,12 +207,12 @@ export const DocumentViewerDocument = connect( link icon="file-pdf" iconColor="white" - onClick={() => - openCaseDocumentDownloadUrlSequence({ + onClick={() => { + return openCaseDocumentDownloadUrlSequence({ docketEntryId: viewerDocumentToDisplay.docketEntryId, docketNumber: caseDetail.docketNumber, - }) - } + }); + }} > View Full PDF diff --git a/web-client/src/views/PDFPreviewButton.tsx b/web-client/src/views/PDFPreviewButton.tsx index 1bf1f948a47..9132d046a41 100644 --- a/web-client/src/views/PDFPreviewButton.tsx +++ b/web-client/src/views/PDFPreviewButton.tsx @@ -9,7 +9,9 @@ import { state } from '@web-client/presenter/app.cerebral'; import React from 'react'; const pdfPreviewButtonDeps = { - openPdfPreviewModalSequence: sequences.openPdfPreviewModalSequence, + loadPdfForTabSequence: sequences.loadPdfForTabSequence, + openCaseDocumentDownloadUrlSequence: + sequences.openCaseDocumentDownloadUrlSequence, pdfPreviewModalHelper: state.pdfPreviewModalHelper, showModal: state.modal.showModal, }; @@ -30,7 +32,7 @@ export const PDFPreviewButton = connect< function PDFPreviewButton({ file, id, - openPdfPreviewModalSequence, + loadPdfForTabSequence, pdfPreviewModalHelper, shouldAbbreviateTitle = false, shouldWrapText = true, @@ -72,7 +74,7 @@ export const PDFPreviewButton = connect< - {showModal == modalId && - (pdfPreviewModalHelper.displayErrorText ? ( - - ) : ( - - ))} ); }, diff --git a/web-client/src/views/PDFPreviewErrorModal.tsx b/web-client/src/views/PDFPreviewErrorModal.tsx deleted file mode 100644 index 9928a0cf5b4..00000000000 --- a/web-client/src/views/PDFPreviewErrorModal.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { ModalDialog } from './ModalDialog'; -import { connect } from '@web-client/presenter/shared.cerebral'; -import { sequences } from '@web-client/presenter/app.cerebral'; -import React from 'react'; - -export const PDFPreviewErrorModal = connect( - { - cancelSequence: sequences.dismissModalSequence, - confirmSequence: sequences.dismissModalSequence, - }, - function PDFPreviewErrorModal({ cancelSequence, confirmSequence, title }) { - return ( - - - There was an error loading the document preview. Please try again. - - - ); - }, -); - -PDFPreviewErrorModal.displayName = 'PDFPreviewErrorModal'; diff --git a/web-client/src/views/PDFPreviewModal.tsx b/web-client/src/views/PDFPreviewModal.tsx deleted file mode 100644 index 6b863e38217..00000000000 --- a/web-client/src/views/PDFPreviewModal.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { Button } from '../ustc-ui/Button/Button'; -import { Mobile } from '../ustc-ui/Responsive/Responsive'; -import { ModalDialog } from './ModalDialog'; -import { connect } from '@web-client/presenter/shared.cerebral'; -import { sequences } from '@web-client/presenter/app.cerebral'; -import { state } from '@web-client/presenter/app.cerebral'; -import React, { useEffect } from 'react'; - -import { PdfPreview } from '../ustc-ui/PdfPreview/PdfPreview'; - -export const PDFPreviewModal = connect( - { - cancelSequence: sequences.dismissModalSequence, - confirmSequence: sequences.dismissModalSequence, - currentPage: state.modal.pdfPreviewModal.currentPage, - loadPdfSequence: sequences.loadPdfSequence, - pdfPreviewModal: state.modal.pdfPreviewModal, - pdfPreviewModalHelper: state.pdfPreviewModalHelper, - previewPdfFile: state.previewPdfFile, - totalPages: state.modal.pdfPreviewModal.totalPages, - }, - function PDFPreviewModal({ - cancelSequence, - confirmSequence, - loadPdfSequence, - preventScrolling, - previewPdfFile, - title, - }) { - useEffect(() => { - loadPdfSequence({ - file: previewPdfFile, - }); - }, []); - - return ( - - -
- -
- -
-
-
- -
-
-
- ); - }, -); - -PDFPreviewModal.displayName = 'PDFPreviewModal'; From 8e4bd1d11bb7985c6a06f2dc25f628ea8e9cbf73 Mon Sep 17 00:00:00 2001 From: Javis Sullivan Date: Thu, 19 Dec 2024 15:18:20 -0500 Subject: [PATCH 30/38] 10472-story: add back mistakenly deleted sequence --- web-client/src/presenter/presenter.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 02583c8a430..66e47997728 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -232,6 +232,8 @@ import { leaveCaseForLaterServiceSequence } from './sequences/leaveCaseForLaterS import { loadDefaultDocketViewerDocumentToDisplaySequence } from './sequences/DocketEntry/loadDefaultDocketViewerDocumentToDisplaySequence'; import { loadDefaultDraftViewerDocumentToDisplaySequence } from './sequences/DocketEntry/loadDefaultDraftViewerDocumentToDisplaySequence'; import { loadDefaultViewerCorrespondenceSequence } from './sequences/loadDefaultViewerCorrespondenceSequence'; +import { loadMoreCaseDeadlinesSequence } from './sequences/loadMoreCaseDeadlinesSequence'; +import { loadMorePendingItemsSequence } from './sequences/loadMorePendingItemsSequence'; import { loadPdfForTabSequence } from './sequences/PDFPreviewTab/loadPdfForTabSequence'; import { navigateBackSequence } from './sequences/navigateBackSequence'; import { navigateToCaseDetailFromPaperServiceSequence } from './sequences/navigateToCaseDetailFromPaperServiceSequence'; @@ -971,6 +973,10 @@ export const presenterSequences = { loadDefaultDraftViewerDocumentToDisplaySequence as unknown as Function, loadDefaultViewerCorrespondenceSequence: loadDefaultViewerCorrespondenceSequence as unknown as Function, + loadMoreCaseDeadlinesSequence: + loadMoreCaseDeadlinesSequence as unknown as Function, + loadMorePendingItemsSequence: + loadMorePendingItemsSequence as unknown as Function, loadPdfForTabSequence: loadPdfForTabSequence as unknown as Function, navigateBackSequence: navigateBackSequence as unknown as Function, navigateToCaseDetailFromPaperServiceSequence: From d91a4438faa5efb04f47ba44c821f4a47918e536 Mon Sep 17 00:00:00 2001 From: Andy Kuny Date: Thu, 19 Dec 2024 15:44:32 -0500 Subject: [PATCH 31/38] dep-updates-2024-12-20: bump ecr image version --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b6337939578..c4021d6910d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2.1 orbs: git-shallow-clone: guitarrapc/git-shallow-clone@2.8.0 -efcms-docker-image: &efcms-docker-image $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/ef-cms-us-east-1:4.3.21.1 +efcms-docker-image: &efcms-docker-image $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/ef-cms-us-east-1:4.3.24 parameters: run_build_and_deploy: From 8a53504c82f447fec2a27b581191a7eeb509d63c Mon Sep 17 00:00:00 2001 From: Andy Kuny Date: Fri, 20 Dec 2024 09:38:19 -0500 Subject: [PATCH 32/38] dep-updates-2024-12-20: fix type errors introduced by updating react types dep --- .../presenter/utilities/focusPaginatorTop.ts | 4 ++- .../DateInput/DateRangePickerComponent.tsx | 7 ++-- .../src/ustc-ui/FormGroup/FormGroup.tsx | 2 +- web-client/src/ustc-ui/Table/TableFilters.tsx | 4 +-- web-client/src/ustc-ui/Tabs/Tabs.tsx | 34 ++++++++----------- .../PractitionerSearchResults.tsx | 4 +-- .../SearchDateRangePickerComponent.tsx | 10 +++--- .../FileDocument/StateDrivenFileInput.tsx | 4 ++- web-client/src/views/InfoNotification.tsx | 1 + .../views/JudgeActivityReport/Statistics.tsx | 6 ++-- web-client/src/views/StepIndicator.tsx | 10 ++++-- web-client/src/views/SuccessNotification.tsx | 4 +-- web-client/src/views/WarningNotification.tsx | 2 +- 13 files changed, 49 insertions(+), 43 deletions(-) diff --git a/web-client/src/presenter/utilities/focusPaginatorTop.ts b/web-client/src/presenter/utilities/focusPaginatorTop.ts index 22e450618a7..e532e8399f6 100644 --- a/web-client/src/presenter/utilities/focusPaginatorTop.ts +++ b/web-client/src/presenter/utilities/focusPaginatorTop.ts @@ -1,4 +1,6 @@ -export const focusPaginatorTop = (ref: React.RefObject) => { +export const focusPaginatorTop = ( + ref: React.RefObject, +) => { if (!ref.current) { return; } diff --git a/web-client/src/ustc-ui/DateInput/DateRangePickerComponent.tsx b/web-client/src/ustc-ui/DateInput/DateRangePickerComponent.tsx index 5a554654fff..275f056c27a 100644 --- a/web-client/src/ustc-ui/DateInput/DateRangePickerComponent.tsx +++ b/web-client/src/ustc-ui/DateInput/DateRangePickerComponent.tsx @@ -49,10 +49,9 @@ export const DateRangePickerComponent = ({ maxDate?: string; // Must be in YYYY-MM-DD format minDate?: string; // Must be in YYYY-MM-DD format }) => { - const dateRangePickerRef = useRef(); - const startDatePickerRef = useRef(); - const endDatePickerRef = useRef(); - + const dateRangePickerRef = useRef(null); + const startDatePickerRef = useRef(null); + const endDatePickerRef = useRef(null); const startDateInputRef = useRef(null); const endDateInputRef = useRef(null); diff --git a/web-client/src/ustc-ui/FormGroup/FormGroup.tsx b/web-client/src/ustc-ui/FormGroup/FormGroup.tsx index 2981c07dd29..a37d91d7048 100644 --- a/web-client/src/ustc-ui/FormGroup/FormGroup.tsx +++ b/web-client/src/ustc-ui/FormGroup/FormGroup.tsx @@ -17,7 +17,7 @@ export const FormGroup = ({ confirmationText?: string; errorText?: string | string[]; errorMessageId?: string; - formGroupRef?: React.RefObject; + formGroupRef?: React.RefObject; id?: string; grow?: boolean; omitFormGroupClass?: boolean; diff --git a/web-client/src/ustc-ui/Table/TableFilters.tsx b/web-client/src/ustc-ui/Table/TableFilters.tsx index 7af63d1a050..1f95d87a3d4 100644 --- a/web-client/src/ustc-ui/Table/TableFilters.tsx +++ b/web-client/src/ustc-ui/Table/TableFilters.tsx @@ -20,7 +20,7 @@ export const TableFilters = ({ filters, onSelect }) => { {filters.map( ({ isSelected, key, label, options, useInlineSelect = true }) => { // track the input element so we can manually reset the value - const ref = useRef(); + const ref = useRef(null); const clearSelect = e => { e.preventDefault(); @@ -30,7 +30,7 @@ export const TableFilters = ({ filters, onSelect }) => { }); // the select input is not resetting back (due to cerebral js state or react) not // correctly updating the dom, so we need to reset it manually - ref.current.value = ''; + if (ref.current) ref.current.value = ''; }; return ( diff --git a/web-client/src/ustc-ui/Tabs/Tabs.tsx b/web-client/src/ustc-ui/Tabs/Tabs.tsx index 52c2726101d..66680e5b594 100644 --- a/web-client/src/ustc-ui/Tabs/Tabs.tsx +++ b/web-client/src/ustc-ui/Tabs/Tabs.tsx @@ -42,7 +42,7 @@ const renderTabFactory = ({ activeKey, asSwitch, boxed, setTab }) => role: 'presentation', }; - const buttonProps = { + const buttonProps: React.ButtonHTMLAttributes = { 'aria-controls': tabContentId, 'aria-selected': isActiveTab, className: childClassName, @@ -70,7 +70,7 @@ export function Tab(properties: { children?: React.ReactNode; className?: string; disabled?: boolean; - icon?: JSX.Element; + icon?: React.JSX.Element; id?: string; tabName?: string; title?: string; @@ -147,15 +147,13 @@ export function TabsComponent({ const isActiveTab = tabName === activeKey; const tabContentId = `tabContent-${camelCase(tabName)}`; - let contentProps = { - className: 'tab-content', - id: tabContentId, - role: 'tabpanel', - }; - - if (asSwitch) { - contentProps = {}; - } + const contentProps = asSwitch + ? {} + : { + className: 'tab-content', + id: tabContentId, + role: 'tabpanel', + }; if (tabName && isActiveTab && tabChildren) { return ( @@ -192,14 +190,12 @@ export function TabsComponent({ hasNav && `ustc-num-tabs-${navItems.length}`, ); - let baseProps = { - className: tabsClass, - id, - }; - - if (asSwitch) { - baseProps = {}; - } + const baseProps = asSwitch + ? {} + : { + className: tabsClass, + id, + }; const TabComponent = renderTabFactory({ activeKey, diff --git a/web-client/src/views/AdvancedSearch/PractitionerSearchResults.tsx b/web-client/src/views/AdvancedSearch/PractitionerSearchResults.tsx index 9ea2a9e83bc..d798b55522e 100644 --- a/web-client/src/views/AdvancedSearch/PractitionerSearchResults.tsx +++ b/web-client/src/views/AdvancedSearch/PractitionerSearchResults.tsx @@ -17,8 +17,8 @@ export const PractitionerSearchResults = connect( practitionerSearchHelper, submitPractitionerNameSearchSequence, }) { - const paginatorTop = useRef(null); - const paginatorBottom = useRef(null); + const paginatorTop = useRef(null); + const paginatorBottom = useRef(null); return ( <> {practitionerSearchHelper.showSearchResults && ( diff --git a/web-client/src/views/AdvancedSearch/SearchDateRangePickerComponent.tsx b/web-client/src/views/AdvancedSearch/SearchDateRangePickerComponent.tsx index b7aea41abe6..7092f01c1b2 100644 --- a/web-client/src/views/AdvancedSearch/SearchDateRangePickerComponent.tsx +++ b/web-client/src/views/AdvancedSearch/SearchDateRangePickerComponent.tsx @@ -17,12 +17,12 @@ export const SearchDateRangePickerComponent = connect( validateSequence, validationErrors, }) { - const dateRangePickerRef = useRef(); - const startDatePickerRef = useRef(); - const endDatePickerRef = useRef(); + const dateRangePickerRef = useRef(null); + const startDatePickerRef = useRef(null); + const endDatePickerRef = useRef(null); - const startDateInputRef = useRef(); - const endDateInputRef = useRef(); + const startDateInputRef = useRef(null); + const endDateInputRef = useRef(null); useEffect(() => { if (startDatePickerRef.current && endDatePickerRef.current) { diff --git a/web-client/src/views/FileDocument/StateDrivenFileInput.tsx b/web-client/src/views/FileDocument/StateDrivenFileInput.tsx index beb8f96fa10..7005ed3b8c4 100644 --- a/web-client/src/views/FileDocument/StateDrivenFileInput.tsx +++ b/web-client/src/views/FileDocument/StateDrivenFileInput.tsx @@ -117,7 +117,9 @@ export const StateDrivenFileInput = connect< data-testid={id} id={id} name={fileInputName} - ref={ref => (inputRef = ref)} + ref={ref => { + inputRef = ref; + }} style={{ display: fileOnForm || selectedFilename ? 'none' : 'block', }} diff --git a/web-client/src/views/InfoNotification.tsx b/web-client/src/views/InfoNotification.tsx index 80905163e63..529849ecc80 100644 --- a/web-client/src/views/InfoNotification.tsx +++ b/web-client/src/views/InfoNotification.tsx @@ -15,6 +15,7 @@ export const InfoNotificationComponent = function InfoNotificationComponent({ }: { alertInfo: { title?: string; + linkText?: string; linkUrl?: string; inlineLinkUrl?: string; inlineLinkText?: string; diff --git a/web-client/src/views/JudgeActivityReport/Statistics.tsx b/web-client/src/views/JudgeActivityReport/Statistics.tsx index b04f3ff391c..2686aaeb653 100644 --- a/web-client/src/views/JudgeActivityReport/Statistics.tsx +++ b/web-client/src/views/JudgeActivityReport/Statistics.tsx @@ -27,7 +27,7 @@ export const Statistics = connect( submitJudgeActivityStatisticsReportSequence, validationErrors, }) { - const closedCases: () => JSX.Element = () => ( + const closedCases: () => React.JSX.Element = () => ( <> ); - const trialSessionsHeld: () => JSX.Element = () => ( + const trialSessionsHeld: () => React.JSX.Element = () => ( <>
); - const ordersIssued: () => JSX.Element = () => ( + const ordersIssued: () => React.JSX.Element = () => ( <>
{completed ? 'completed' : 'not completed'} diff --git a/web-client/src/views/SuccessNotification.tsx b/web-client/src/views/SuccessNotification.tsx index 5fc20a8211c..0840c3b471f 100644 --- a/web-client/src/views/SuccessNotification.tsx +++ b/web-client/src/views/SuccessNotification.tsx @@ -59,8 +59,8 @@ export const SuccessNotification = connect< className={classNames( 'usa-alert', 'usa-alert--success', - `${className}`, - isMessageOnly && 'usa-alert-success-message-only', + className, + isMessageOnly ? 'usa-alert-success-message-only' : null, )} data-metadata={`${alertSuccess.metaData}`} data-testid="success-alert" diff --git a/web-client/src/views/WarningNotification.tsx b/web-client/src/views/WarningNotification.tsx index 9faa31a25ec..54eb6713db0 100644 --- a/web-client/src/views/WarningNotification.tsx +++ b/web-client/src/views/WarningNotification.tsx @@ -47,7 +47,7 @@ export const WarningNotificationComponent = className={classNames( 'usa-alert', 'usa-alert--warning', - isMessageOnly && 'usa-alert-warning-message-only', + isMessageOnly ? 'usa-alert-warning-message-only' : null, )} data-testid="warning-alert" ref={notificationRef} From a765c92e667baffbc9aaab0cdd3b13ae192c7a12 Mon Sep 17 00:00:00 2001 From: Javis Sullivan Date: Fri, 20 Dec 2024 09:57:33 -0500 Subject: [PATCH 33/38] 10472: rm empty file --- web-client/src/utilities/fileReader.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 web-client/src/utilities/fileReader.ts diff --git a/web-client/src/utilities/fileReader.ts b/web-client/src/utilities/fileReader.ts deleted file mode 100644 index e69de29bb2d..00000000000 From 2eaa79bcd73e329ccec9f172f07c31c23073cadd Mon Sep 17 00:00:00 2001 From: Andy Kuny Date: Fri, 20 Dec 2024 10:38:41 -0500 Subject: [PATCH 34/38] dep-updates-2024-12-20: fix ref handling in SearchDateRangePicker component --- .../SearchDateRangePickerComponent.tsx | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/web-client/src/views/AdvancedSearch/SearchDateRangePickerComponent.tsx b/web-client/src/views/AdvancedSearch/SearchDateRangePickerComponent.tsx index 7092f01c1b2..95131d495ad 100644 --- a/web-client/src/views/AdvancedSearch/SearchDateRangePickerComponent.tsx +++ b/web-client/src/views/AdvancedSearch/SearchDateRangePickerComponent.tsx @@ -17,20 +17,28 @@ export const SearchDateRangePickerComponent = connect( validateSequence, validationErrors, }) { - const dateRangePickerRef = useRef(null); - const startDatePickerRef = useRef(null); - const endDatePickerRef = useRef(null); + const dateRangePickerRef = useRef(null); + const startDatePickerRef = useRef(null); + const endDatePickerRef = useRef(null); - const startDateInputRef = useRef(null); - const endDateInputRef = useRef(null); + const startDateInputRef = useRef(null); + const endDateInputRef = useRef(null); useEffect(() => { - if (startDatePickerRef.current && endDatePickerRef.current) { + if ( + startDatePickerRef.current && + endDatePickerRef.current && + dateRangePickerRef.current + ) { datePicker.on(startDatePickerRef.current); datePicker.on(endDatePickerRef.current); dateRangePicker.on(dateRangePickerRef.current); } - }, [dateRangePickerRef]); + }, [ + startDatePickerRef.current, + endDatePickerRef.current, + dateRangePickerRef.current, + ]); useEffect(() => { const startInput = window.document.getElementById('startDate-date-start'); From 935bf704d1a61be1a966611f3fbcf68521c46313 Mon Sep 17 00:00:00 2001 From: Javis Sullivan Date: Fri, 20 Dec 2024 12:23:41 -0500 Subject: [PATCH 35/38] 10472: correct return type of loadPDFForPreviewInteractor --- shared/src/business/useCases/loadPDFForPreviewInteractor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/business/useCases/loadPDFForPreviewInteractor.ts b/shared/src/business/useCases/loadPDFForPreviewInteractor.ts index 3ea2ba77967..6fef5517ea5 100644 --- a/shared/src/business/useCases/loadPDFForPreviewInteractor.ts +++ b/shared/src/business/useCases/loadPDFForPreviewInteractor.ts @@ -13,7 +13,7 @@ export const loadPDFForPreviewInteractor = async ( docketEntryId, docketNumber, }: { docketEntryId?: string; docketNumber?: string }, -): Promise => { +): Promise => { try { return await applicationContext.getPersistenceGateway().getDocument({ applicationContext, From c21a605fbfd39560fe9a86059482f81d3dec49a8 Mon Sep 17 00:00:00 2001 From: Javis Sullivan Date: Fri, 20 Dec 2024 12:53:42 -0500 Subject: [PATCH 36/38] 10472: address final feedback --- .../actions/PDFPreviewTab/loadPdfForTabAction.test.ts | 7 ++++++- .../presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.test.ts b/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.test.ts index 9eaca35b931..9fb60f4d6c6 100644 --- a/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.test.ts +++ b/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.test.ts @@ -1,9 +1,12 @@ import { applicationContextForClient as applicationContext } from '@web-client/test/createClientTestApplicationContext'; import { loadPdfForTabAction } from '../PDFPreviewTab/loadPdfForTabAction'; +import { openUrlInNewTab } from '@web-client/presenter/utilities/openUrlInNewTab'; import { presenter } from '../../presenter-mock'; import { runAction } from '@web-client/presenter/test.cerebral'; import { testPdfDoc } from '../../../../../shared/src/business/test/getFakeFile'; +jest.mock('@web-client/presenter/utilities/openUrlInNewTab'); + describe('loadPdfForTabAction', () => { let originalWindowOpen; @@ -52,11 +55,13 @@ describe('loadPdfForTabAction', () => { createObjectURL: jest.fn().mockReturnValue('some url'), }; originalWindowOpen = window.open; + (openUrlInNewTab as jest.Mock).mockImplementation(jest.fn()); window.open = jest.fn(); }); afterAll(() => { window.open = originalWindowOpen; + jest.restoreAllMocks(); }); it('should call window.open with correcturl for pdf file', async () => { @@ -67,7 +72,7 @@ describe('loadPdfForTabAction', () => { props: { file: fakeFile }, }); - expect(window.open).toHaveBeenCalledWith('some url', '_blank'); + expect(openUrlInNewTab).toHaveBeenCalledWith({ url: 'some url' }); }); it('should detect binary (not base64-encoded) pdf data and read it successfully', async () => { diff --git a/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts b/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts index 232b6246ffc..aac2bd84b38 100644 --- a/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts +++ b/web-client/src/presenter/actions/PDFPreviewTab/loadPdfForTabAction.ts @@ -1,3 +1,4 @@ +import { openUrlInNewTab } from '../../utilities/openUrlInNewTab'; export const loadPdfForTabAction = ({ applicationContext, props, @@ -23,7 +24,7 @@ export const loadPdfForTabAction = ({ // @ts-ignore new Blob([binaryFile], { type: 'application/pdf' }), ); - window.open(pdfDataUri, '_blank'); + openUrlInNewTab({ url: pdfDataUri }); resolve(); } catch (err) { reject(err); From 8baeafaed33cd9c45405692b28a36d6c7e591bb8 Mon Sep 17 00:00:00 2001 From: Andy Kuny Date: Fri, 20 Dec 2024 16:19:43 -0500 Subject: [PATCH 37/38] dep-updates-2024-12-20: add warning about react 18 -> 19 to dependency-updates.md --- docs/dependency-updates.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/dependency-updates.md b/docs/dependency-updates.md index b1a429b58f2..2f066d9c276 100644 --- a/docs/dependency-updates.md +++ b/docs/dependency-updates.md @@ -69,6 +69,10 @@ regex search the entire project for `aws = "\d+.\d+.\d+"` and make sure it's to ## Do Not Upgrade +### React and ReactDOM + +- cerebral version 5.2.1 and @cerebral/react version 4.2.1 are not compatible with React and ReactDOM version 19. Keep these pinned at version 18 for the time being. See https://github.com/cerebral/cerebral/pull/1441. + ### @fortawesome - fortawesome packages are locked down to pre-6.x.x to maintain consistency of icon styling until there is usability feedback and research that determines we should change them. This includes `@fortawesome/free-solid-svg-icons`, `@fortawesome/free-regular-svg-icons`, and `@fortawesome/fontawesome-svg-core`. From 66e33a6924a1b634cab45dbf8e8cdf57bc73a1ab Mon Sep 17 00:00:00 2001 From: Andy Kuny Date: Mon, 23 Dec 2024 11:34:50 -0500 Subject: [PATCH 38/38] dep-updates-2024-12-20: trigger CI