diff --git a/scripts/data-import/judge/judge_users.csv b/scripts/data-import/judge/judge_users.csv index 75087278c22..e60e655b01b 100644 --- a/scripts/data-import/judge/judge_users.csv +++ b/scripts/data-import/judge/judge_users.csv @@ -9,6 +9,7 @@ Cantrel,Judge,Cantrel,legacy.judge.cantrel@example.com,legacyJudge,legacyJudgesC Carluzzo,Chief Special Trial Judge,Lewis R. Carluzzo,stjudge.carluzzo@example.com,judge,carluzzosChambers Chabot,Judge,Chabot,legacy.judge.chabot@example.com,legacyJudge,legacyJudgesChambers Chiechi,Judge,Chiechi,legacy.judge.chiechi@example.com,legacyJudge,legacyJudgesChambers +Choi,Special Trial Judge,Eunkyong Choi,legacy.stjudge.choi@example.com,legacyJudge,legacyJudgesChambers Clapp,Judge,Clapp,legacy.judge.clapp@example.com,legacyJudge,legacyJudgesChambers Cohen,Judge,Mary Ann Cohen,judge.cohen@example.com,judge,cohensChambers Colvin,Judge,John O. Colvin,judge.colvin@example.com,judge,colvinsChambers @@ -20,6 +21,7 @@ Dinan,Special Trial Judge,Dinan,legacy.judge.dinan@example.com,legacyJudge,legac Drennen,Judge,Drennen,legacy.judge.drennen@example.com,legacyJudge,legacyJudgesChambers Fay,Judge,Fay,legacy.judge.fay@example.com,legacyJudge,legacyJudgesChambers Featherston,Judge,Featherston,legacy.judge.featherston@example.com,legacyJudge,legacyJudgesChambers +Fried,Special Trial Judge,Zachary S. Fried,stjudge.fried@example.com,judge,friedsChambers Foley,Chief Judge,Maurice B. Foley,judge.foley@example.com,judge,foleysChambers Gale,Judge,Joseph H. Gale,judge.gale@example.com,judge,galesChambers Galloway,Special Trial Judge,Galloway,legacy.judge.galloway@example.com,legacyJudge,legacyJudgesChambers @@ -40,6 +42,7 @@ Jones,Judge,Courtney D. Jones,judge.jones@example.com,judge,jonesChambers Kerrigan,Judge,Kathleen Kerrigan,judge.kerrigan@example.com,judge,kerrigansChambers Korner,Judge,Korner,legacy.judge.korner@example.com,legacyJudge,legacyJudgesChambers Kroupa,Judge,Kroupa,legacy.judge.kroupa@example.com,legacyJudge,legacyJudgesChambers +Landy,Special Trial Judge,Adam B. Landy,stjudge.landy@example.com,judge,landysChambers Laro,Judge,Laro,legacy.judge.laro@example.com,legacyJudge,legacyJudgesChambers Lauber,Judge,Albert G. Lauber,judge.lauber@example.com,judge,laubersChambers Leyden,Special Trial Judge,Diana L. Leyden,stjudge.leyden@example.com,judge,leydensChambers @@ -62,6 +65,7 @@ Raum,Judge,Raum,legacy.judge.raum@example.com,legacyJudge,legacyJudgesChambers Ruwe,Judge,Robert P. Ruwe,judge.ruwe@example.com,judge,ruwesChambers Scott,Judge,Scott,legacy.judge.scott@example.com,legacyJudge,legacyJudgesChambers Shields,Judge,Shields,legacy.judge.shields@example.com,legacyJudge,legacyJudgesChambers +Siegel,Special Trial Judge,Jennifer E. Siegel,stjudge.siegel@example.com,judge,siegelsChambers Simpson,Judge,Simpson,legacy.judge.simpson@example.com,legacyJudge,legacyJudgesChambers Sterrett,Judge,Sterrett,legacy.judge.sterrett@example.com,legacyJudge,legacyJudgesChambers Swift,Judge,Swift,legacy.judge.swift@example.com,legacyJudge,legacyJudgesChambers @@ -81,5 +85,3 @@ Wiles,Judge,Wiles,legacy.judge.wiles@example.com,legacyJudge,legacyJudgesChamber Williams,Judge,Williams,legacy.judge.williams@example.com,legacyJudge,legacyJudgesChambers Wolfe,Special Trial Judge,Wolfe,legacy.judge.wolfe@example.com,legacyJudge,legacyJudgesChambers Wright,Judge,Wright,legacy.judge.wright@example.com,legacyJudge,legacyJudgesChambers -Choi,Special Trial Judge,Eunkyong Choi,stjudge.choi@dawson.ustaxcourt.gov,judge,choisChambers -Landy,Special Trial Judge,Adam B. Landy,stjudge.landy@dawson.ustaxcourt.gov,judge,landysChambers diff --git a/shared/admin-tools/user/add-user.ts b/shared/admin-tools/user/add-user.ts index 785ced3a5d9..c4a79537b53 100644 --- a/shared/admin-tools/user/add-user.ts +++ b/shared/admin-tools/user/add-user.ts @@ -82,11 +82,11 @@ const checkParams = params => { 'reportersOffice', 'ashfordsChambers', 'buchsChambers', - 'choisChambers', 'cohensChambers', 'colvinsChambers', 'copelandsChambers', 'foleysChambers', + 'friedsChambers', 'galesChambers', 'goekesChambers', 'greavesChambers', @@ -103,6 +103,7 @@ const checkParams = params => { 'negasChambers', 'parisChambers', 'pughsChambers', + 'siegelsChambers', 'thorntonsChambers', 'torosChambers', 'urdasChambers', diff --git a/shared/src/business/useCases/messages/createMessageInteractor.test.ts b/shared/src/business/useCases/messages/createMessageInteractor.test.ts index fd481ed16a6..72c161f4d72 100644 --- a/shared/src/business/useCases/messages/createMessageInteractor.test.ts +++ b/shared/src/business/useCases/messages/createMessageInteractor.test.ts @@ -28,12 +28,16 @@ describe('createMessageInteractor', () => { }); it('creates the message', async () => { + const mockAttachments = [ + { + documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + }, + { + documentId: 'b1130321-0a69-43bc-b3eb-64a18f079873', + }, + ]; + const messageData = { - attachments: [ - { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', - }, - ], docketNumber: '101-20', isRepliedTo: false, message: "How's it going?", @@ -70,6 +74,7 @@ describe('createMessageInteractor', () => { await createMessageInteractor(applicationContext, { ...messageData, + attachments: mockAttachments, }); expect( @@ -80,6 +85,7 @@ describe('createMessageInteractor', () => { .message, ).toMatchObject({ ...messageData, + attachments: mockAttachments, caseStatus: CASE_STATUS_TYPES.generalDocket, caseTitle: 'Guy Fieri', docketNumber: '101-20', diff --git a/shared/src/business/useCases/messages/createMessageInteractor.ts b/shared/src/business/useCases/messages/createMessageInteractor.ts index ce47efcbe23..99d96f6e541 100644 --- a/shared/src/business/useCases/messages/createMessageInteractor.ts +++ b/shared/src/business/useCases/messages/createMessageInteractor.ts @@ -6,19 +6,25 @@ import { } from '../../../authorization/authorizationClientService'; import { UnauthorizedError } from '../../../../../web-api/src/errors/errors'; -/** - * creates a message on a case - * - * @param {object} applicationContext the application context - * @param {object} providers the providers object - * @param {array} providers.attachments array of objects containing documentId and documentTitle - * @param {string} providers.docketNumber the docket number of the case - * @param {string} providers.message the message text - * @param {string} providers.subject the message subject - * @param {string} providers.toSection the section of the user receiving the message - * @param {string} providers.toUserId the user id of the user receiving the message - * @returns {object} the created message - */ +export type MessageType = { + attachments: { + documentId: string; + }[]; + message: string; + subject: string; + toSection: string; + toUserId: string; +}; + +export type MessageWithMetaData = MessageType & { + docketNumber: string; +}; + +export type ReplyMessageType = MessageType & { + parentMessageId: string; + docketNumber: string; +}; + export const createMessageInteractor = async ( applicationContext: IApplicationContext, { @@ -28,15 +34,8 @@ export const createMessageInteractor = async ( subject, toSection, toUserId, - }: { - attachments: any; - docketNumber: string; - message: string; - subject: string; - toSection: string; - toUserId: string; - }, -) => { + }: MessageWithMetaData, +): Promise => { const authorizedUser = applicationContext.getCurrentUser(); if (!isAuthorized(authorizedUser, ROLE_PERMISSIONS.SEND_RECEIVE_MESSAGES)) { diff --git a/shared/src/business/useCases/messages/forwardMessageInteractor.ts b/shared/src/business/useCases/messages/forwardMessageInteractor.ts index 81fe268afff..4d1056d734b 100644 --- a/shared/src/business/useCases/messages/forwardMessageInteractor.ts +++ b/shared/src/business/useCases/messages/forwardMessageInteractor.ts @@ -1,21 +1,8 @@ +import { ReplyMessageType } from '@shared/business/useCases/messages/createMessageInteractor'; import { replyToMessage } from './replyToMessageInteractor'; -/** - * forwards a message - * - * @param {object} applicationContext the application context - * @param {object} providers the providers object - * @param {array} providers.attachments array of objects containing documentId and documentTitle - * @param {string} providers.docketNumber the docket number of the case - * @param {string} providers.message the message text - * @param {string} providers.parentMessageId the id of the parent message for the thread - * @param {string} providers.subject the message subject - * @param {string} providers.toSection the section of the user receiving the message - * @param {string} providers.toUserId the user id of the user receiving the message - * @returns {object} the message - */ export const forwardMessageInteractor = async ( - applicationContext, + applicationContext: IApplicationContext, { attachments, docketNumber, @@ -24,16 +11,8 @@ export const forwardMessageInteractor = async ( subject, toSection, toUserId, - }: { - attachments: any; - docketNumber: string; - message: string; - parentMessageId: string; - subject: string; - toSection: string; - toUserId: string; - }, -) => { + }: ReplyMessageType, +): Promise => { return await replyToMessage(applicationContext, { attachments, docketNumber, diff --git a/shared/src/business/useCases/messages/replyToMessageInteractor.test.ts b/shared/src/business/useCases/messages/replyToMessageInteractor.test.ts index cc9a14437fc..5558ce3bb63 100644 --- a/shared/src/business/useCases/messages/replyToMessageInteractor.test.ts +++ b/shared/src/business/useCases/messages/replyToMessageInteractor.test.ts @@ -8,6 +8,15 @@ import { applicationContext } from '../../test/createTestApplicationContext'; import { replyToMessageInteractor } from './replyToMessageInteractor'; describe('replyToMessageInteractor', () => { + const mockAttachments = [ + { + documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + }, + { + documentId: 'b1130321-0a69-43bc-b3eb-64a18f079873', + }, + ]; + it('throws unauthorized for a user without MESSAGES permission', async () => { applicationContext.getCurrentUser.mockReturnValue({ role: ROLES.petitioner, @@ -16,11 +25,7 @@ describe('replyToMessageInteractor', () => { await expect( replyToMessageInteractor(applicationContext, { - attachments: [ - { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', - }, - ], + attachments: mockAttachments, docketNumber: '101-20', message: "How's it going?", parentMessageId: '62ea7e6e-8101-4e4b-9bbd-932b149c86c3', @@ -33,11 +38,6 @@ describe('replyToMessageInteractor', () => { it('creates the message reply and marks the parent message as replied to', async () => { const messageData = { - attachments: [ - { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', - }, - ], docketNumber: '101-20', message: "How's it going?", parentMessageId: '62ea7e6e-8101-4e4b-9bbd-932b149c86c3', @@ -75,6 +75,7 @@ describe('replyToMessageInteractor', () => { await replyToMessageInteractor(applicationContext, { ...messageData, + attachments: mockAttachments, }); expect( @@ -85,6 +86,7 @@ describe('replyToMessageInteractor', () => { .message, ).toMatchObject({ ...messageData, + attachments: mockAttachments, caseStatus: CASE_STATUS_TYPES.generalDocket, caseTitle: 'Guy Fieri', docketNumber: '101-20', diff --git a/shared/src/business/useCases/messages/replyToMessageInteractor.ts b/shared/src/business/useCases/messages/replyToMessageInteractor.ts index 026110b6d68..2e64090dd90 100644 --- a/shared/src/business/useCases/messages/replyToMessageInteractor.ts +++ b/shared/src/business/useCases/messages/replyToMessageInteractor.ts @@ -4,22 +4,9 @@ import { ROLE_PERMISSIONS, isAuthorized, } from '../../../authorization/authorizationClientService'; +import { ReplyMessageType } from '@shared/business/useCases/messages/createMessageInteractor'; import { UnauthorizedError } from '../../../../../web-api/src/errors/errors'; -/** - * calls persistence methods to create a reply state for a message - * - * @param {object} applicationContext the application context - * @param {object} providers the providers object - * @param {array} providers.attachments array of objects containing documentId and documentTitle - * @param {string} providers.docketNumber the docket number of the case - * @param {string} providers.message the message text - * @param {string} providers.parentMessageId the id of the parent message for the thread - * @param {string} providers.subject the message subject - * @param {string} providers.toSection the section of the user receiving the message - * @param {string} providers.toUserId the user id of the user receiving the message - * @returns {object} validated raw message object - */ export const replyToMessage = async ( applicationContext: IApplicationContext, { @@ -30,16 +17,8 @@ export const replyToMessage = async ( subject, toSection, toUserId, - }: { - attachments: any; - docketNumber: string; - message: string; - parentMessageId: string; - subject: string; - toSection: string; - toUserId: string; - }, -) => { + }: ReplyMessageType, +): Promise => { const authorizedUser = applicationContext.getCurrentUser(); if (!isAuthorized(authorizedUser, ROLE_PERMISSIONS.SEND_RECEIVE_MESSAGES)) { @@ -94,20 +73,6 @@ export const replyToMessage = async ( return validatedRawMessage; }; -/** - * replies to a message - * - * @param {object} applicationContext the application context - * @param {object} providers the providers object - * @param {array} providers.attachments array of objects containing documentId and documentTitle - * @param {string} providers.docketNumber the docket number of the case - * @param {string} providers.message the message text - * @param {string} providers.parentMessageId the id of the parent message for the thread - * @param {string} providers.subject the message subject - * @param {string} providers.toSection the section of the user receiving the message - * @param {string} providers.toUserId the user id of the user receiving the message - * @returns {object} the message - */ export const replyToMessageInteractor = ( applicationContext: IApplicationContext, { @@ -118,16 +83,8 @@ export const replyToMessageInteractor = ( subject, toSection, toUserId, - }: { - attachments: any; - docketNumber: string; - message: string; - parentMessageId: string; - subject: string; - toSection: string; - toUserId: string; - }, -) => { + }: ReplyMessageType, +): Promise => { return replyToMessage(applicationContext, { attachments, docketNumber, diff --git a/shared/src/business/utilities/DateHandler.ts b/shared/src/business/utilities/DateHandler.ts index 043e83a76f9..015e4505d98 100644 --- a/shared/src/business/utilities/DateHandler.ts +++ b/shared/src/business/utilities/DateHandler.ts @@ -31,6 +31,7 @@ export const FORMATS = { } as const; const FORMATS1 = Object.values(FORMATS); export type TimeFormats = (typeof FORMATS1)[number]; +export type TimeFormatNames = keyof typeof FORMATS; export const PATTERNS = { 'H:MM': /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/, // hour can be specified with either one OR two digits. @@ -240,7 +241,7 @@ export const createISODateStringFromObject = options => { */ export const formatDateString = ( dateString, - formatArg: TimeFormats = FORMATS.ISO, + formatArg: TimeFormatNames | TimeFormats = FORMATS.ISO, ) => { if (!dateString) return; let formatString = FORMATS[formatArg] || formatArg; diff --git a/shared/src/business/utilities/getFormattedCaseDetail.test.ts b/shared/src/business/utilities/getFormattedCaseDetail.test.ts index 07e93a7dafe..e094837f665 100644 --- a/shared/src/business/utilities/getFormattedCaseDetail.test.ts +++ b/shared/src/business/utilities/getFormattedCaseDetail.test.ts @@ -491,6 +491,7 @@ describe('getFormattedCaseDetail', () => { const result = getFormattedCaseDetail({ applicationContext, caseDetail: { + ...MOCK_CASE, docketEntries: [ { docketEntryId: 'd-1-2-3', @@ -526,6 +527,7 @@ describe('getFormattedCaseDetail', () => { const result = getFormattedCaseDetail({ applicationContext, caseDetail: { + ...MOCK_CASE, petitionPaymentDate: '2019-03-01T21:40:46.415Z', petitionPaymentMethod: 'check', petitionPaymentStatus: PAYMENT_STATUS.PAID, @@ -539,6 +541,7 @@ describe('getFormattedCaseDetail', () => { const result = getFormattedCaseDetail({ applicationContext, caseDetail: { + ...MOCK_CASE, petitionPaymentStatus: PAYMENT_STATUS.WAIVED, petitionPaymentWaivedDate: '2019-03-01T21:40:46.415Z', }, @@ -550,7 +553,10 @@ describe('getFormattedCaseDetail', () => { it('should format filing fee string for an unpaid petition fee', () => { const result = getFormattedCaseDetail({ applicationContext, - caseDetail: { petitionPaymentStatus: PAYMENT_STATUS.UNPAID }, + caseDetail: { + ...MOCK_CASE, + petitionPaymentStatus: PAYMENT_STATUS.UNPAID, + }, }); expect(result.filingFee).toEqual(`${PAYMENT_STATUS.UNPAID} `); diff --git a/shared/src/business/utilities/getFormattedCaseDetail.ts b/shared/src/business/utilities/getFormattedCaseDetail.ts index 1a8d8323755..b1d9b6118dd 100644 --- a/shared/src/business/utilities/getFormattedCaseDetail.ts +++ b/shared/src/business/utilities/getFormattedCaseDetail.ts @@ -10,6 +10,7 @@ import { UNSERVABLE_EVENT_CODES, } from '../entities/EntityConstants'; import { Case } from '../entities/cases/Case'; +import { ClientApplicationContext } from '@web-client/applicationContext'; import { DocketEntry } from '../entities/DocketEntry'; import { FORMATS, @@ -498,6 +499,10 @@ export const getFormattedCaseDetail = ({ applicationContext, caseDetail, docketRecordSort, +}: { + applicationContext: ClientApplicationContext; + caseDetail: RawCase; + docketRecordSort?: string; }) => { const result = { ...applicationContext diff --git a/shared/src/proxies/messages/createMessageProxy.ts b/shared/src/proxies/messages/createMessageProxy.ts index 0851fe12475..655867d2c31 100644 --- a/shared/src/proxies/messages/createMessageProxy.ts +++ b/shared/src/proxies/messages/createMessageProxy.ts @@ -1,20 +1,17 @@ +import { ClientApplicationContext } from '@web-client/applicationContext'; +import { MessageWithMetaData } from '@shared/business/useCases/messages/createMessageInteractor'; import { post } from '../requests'; -/** - * createMessageInteractor - * - * @param {object} applicationContext the application context - * @param {object} providers the providers object - * @param {string} providers.docketNumber the docket number of the case - * @param {string} providers.message the message text - * @param {string} providers.subject the message subject - * @param {string} providers.toSection the section of the user receiving the message - * @param {string} providers.toUserId the user id of the user receiving the message - * @returns {Promise<*>} the promise of the api call - */ export const createMessageInteractor = ( - applicationContext, - { attachments, docketNumber, message, subject, toSection, toUserId }, + applicationContext: ClientApplicationContext, + { + attachments, + docketNumber, + message, + subject, + toSection, + toUserId, + }: MessageWithMetaData, ) => { return post({ applicationContext, diff --git a/shared/src/proxies/messages/forwardMessageProxy.ts b/shared/src/proxies/messages/forwardMessageProxy.ts index 62962597c11..aaa9752805c 100644 --- a/shared/src/proxies/messages/forwardMessageProxy.ts +++ b/shared/src/proxies/messages/forwardMessageProxy.ts @@ -1,21 +1,9 @@ +import { ClientApplicationContext } from '@web-client/applicationContext'; +import { ReplyMessageType } from '@shared/business/useCases/messages/createMessageInteractor'; import { post } from '../requests'; -/** - * forwardMessageInteractor - * - * @param {object} applicationContext the application context - * @param {object} providers the providers object - * @param {array} providers.attachments array attachments on the message - * @param {string} providers.docketNumber the docket number of the case - * @param {string} providers.message the message text - * @param {string} providers.parentMessageId the id of the parent message for the thread - * @param {string} providers.subject the message subject - * @param {string} providers.toSection the section of the user receiving the message - * @param {string} providers.toUserId the user id of the user receiving the message - * @returns {Promise<*>} the promise of the api call - */ export const forwardMessageInteractor = ( - applicationContext, + applicationContext: ClientApplicationContext, { attachments, docketNumber, @@ -24,7 +12,7 @@ export const forwardMessageInteractor = ( subject, toSection, toUserId, - }, + }: ReplyMessageType, ) => { return post({ applicationContext, diff --git a/shared/src/proxies/messages/replyToMessageProxy.ts b/shared/src/proxies/messages/replyToMessageProxy.ts index e985691bdc8..61a1e959221 100644 --- a/shared/src/proxies/messages/replyToMessageProxy.ts +++ b/shared/src/proxies/messages/replyToMessageProxy.ts @@ -1,21 +1,9 @@ +import { ClientApplicationContext } from '@web-client/applicationContext'; +import { ReplyMessageType } from '@shared/business/useCases/messages/createMessageInteractor'; import { post } from '../requests'; -/** - * replyToMessageInteractor - * - * @param {object} applicationContext the application context - * @param {object} providers the providers object - * @param {array} providers.attachments array attachments on the message - * @param {string} providers.docketNumber the docket number of the case - * @param {string} providers.message the message text - * @param {string} providers.parentMessageId the id of the parent message for the thread - * @param {string} providers.subject the message subject - * @param {string} providers.toSection the section of the user receiving the message - * @param {string} providers.toUserId the user id of the user receiving the message - * @returns {Promise<*>} the promise of the api call - */ export const replyToMessageInteractor = ( - applicationContext, + applicationContext: ClientApplicationContext, { attachments, docketNumber, @@ -24,7 +12,7 @@ export const replyToMessageInteractor = ( subject, toSection, toUserId, - }, + }: ReplyMessageType, ) => { return post({ applicationContext, diff --git a/web-api/src/persistence/elasticsearch/getCountOfConsolidedCases.ts b/web-api/src/persistence/elasticsearch/getCountOfConsolidedCases.ts index 09c89523674..d650a46bf15 100644 --- a/web-api/src/persistence/elasticsearch/getCountOfConsolidedCases.ts +++ b/web-api/src/persistence/elasticsearch/getCountOfConsolidedCases.ts @@ -21,6 +21,5 @@ export const getCountOfConsolidedCases = async ({ }, }); - console.log(results); return results; }; diff --git a/web-client/integration-tests/correspondenceJourney.test.ts b/web-client/integration-tests/correspondenceJourney.test.ts index 73e98cc52b0..2efde6cb0ba 100644 --- a/web-client/integration-tests/correspondenceJourney.test.ts +++ b/web-client/integration-tests/correspondenceJourney.test.ts @@ -29,7 +29,7 @@ describe('Adds correspondence to a case', () => { }); }); - describe('docket clerk adds two correspondence. deletes only the first one', () => { + describe('docket clerk adds two correspondences and deletes only the first one', () => { loginAs(cerebralTest, 'docketclerk@example.com'); userNavigatesToAddCorrespondence(cerebralTest, 'DocketClerk'); userAddsCorrespondence( @@ -58,7 +58,6 @@ describe('Adds correspondence to a case', () => { docketClerkDeletesCorrespondence( cerebralTest, `${firstCorrespondenceTitle} dc`, - 'DocketClerk', ); }); diff --git a/web-client/integration-tests/docketClerkServesCourtIssuedDocumentOnLeadCaseFromMessageDetail.test.ts b/web-client/integration-tests/docketClerkServesCourtIssuedDocumentOnLeadCaseFromMessageDetail.test.ts index dad143a85d9..c3e80f6ae2a 100644 --- a/web-client/integration-tests/docketClerkServesCourtIssuedDocumentOnLeadCaseFromMessageDetail.test.ts +++ b/web-client/integration-tests/docketClerkServesCourtIssuedDocumentOnLeadCaseFromMessageDetail.test.ts @@ -149,6 +149,7 @@ describe('Docket Clerk Serves Paper Filed Document On Lead Case From Message Det ); await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: cerebralTest.draftDocument.docketEntryId, }); diff --git a/web-client/integration-tests/docketClerkServesPaperFiledDocumentOnLeadCaseFromMessageDetail.test.ts b/web-client/integration-tests/docketClerkServesPaperFiledDocumentOnLeadCaseFromMessageDetail.test.ts index edd3fafce80..eab5d25f4d0 100644 --- a/web-client/integration-tests/docketClerkServesPaperFiledDocumentOnLeadCaseFromMessageDetail.test.ts +++ b/web-client/integration-tests/docketClerkServesPaperFiledDocumentOnLeadCaseFromMessageDetail.test.ts @@ -150,11 +150,13 @@ describe('Docket Clerk Serves Paper Filed Document On Lead Case From Message Det ); await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: cerebralTest.docketEntryId, }); cerebralTest.testMessageSubject = motionForLeaveToFileCaseMessageForm.subject; + for (const [key, value] of Object.entries( motionForLeaveToFileCaseMessageForm, )) { diff --git a/web-client/integration-tests/journey/createNewMessageOnCase.ts b/web-client/integration-tests/journey/createNewMessageOnCase.ts index 19aef574f47..badc3814a44 100644 --- a/web-client/integration-tests/journey/createNewMessageOnCase.ts +++ b/web-client/integration-tests/journey/createNewMessageOnCase.ts @@ -57,6 +57,7 @@ export const createNewMessageOnCase = ( cerebralTest.testMessageDocumentId = messageDocument.docketEntryId; await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: cerebralTest.testMessageDocumentId, }); diff --git a/web-client/integration-tests/journey/docketClerkCreatesMessageWithCorrespondence.ts b/web-client/integration-tests/journey/docketClerkCreatesMessageWithCorrespondence.ts index c6f353a70b6..75480de53a2 100644 --- a/web-client/integration-tests/journey/docketClerkCreatesMessageWithCorrespondence.ts +++ b/web-client/integration-tests/journey/docketClerkCreatesMessageWithCorrespondence.ts @@ -39,6 +39,7 @@ export const docketClerkCreatesMessageWithCorrespondence = cerebralTest => { ); await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: correspondence.correspondenceId, }); diff --git a/web-client/integration-tests/journey/petitionsClerkCreatesMessageToChambers.ts b/web-client/integration-tests/journey/petitionsClerkCreatesMessageToChambers.ts index 8c91295a66b..c1b9d00fa64 100644 --- a/web-client/integration-tests/journey/petitionsClerkCreatesMessageToChambers.ts +++ b/web-client/integration-tests/journey/petitionsClerkCreatesMessageToChambers.ts @@ -40,6 +40,7 @@ export const petitionsClerkCreatesMessageToChambers = cerebralTest => { cerebralTest.testMessageDocumentId = messageDocument.docketEntryId; await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: messageDocument.docketEntryId, }); diff --git a/web-client/integration-tests/journey/petitionsClerkCreatesNewMessageOnCaseWithMaxAttachments.ts b/web-client/integration-tests/journey/petitionsClerkCreatesNewMessageOnCaseWithMaxAttachments.ts index c315e0783e0..f02fc43c8e4 100644 --- a/web-client/integration-tests/journey/petitionsClerkCreatesNewMessageOnCaseWithMaxAttachments.ts +++ b/web-client/integration-tests/journey/petitionsClerkCreatesNewMessageOnCaseWithMaxAttachments.ts @@ -44,6 +44,7 @@ export const petitionsClerkCreatesNewMessageOnCaseWithMaxAttachments = cerebralTest.testMessageDocumentId = messageDocument.docketEntryId; await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: cerebralTest.testMessageDocumentId, }); @@ -57,6 +58,7 @@ export const petitionsClerkCreatesNewMessageOnCaseWithMaxAttachments = await cerebralTest.runSequence( 'updateMessageModalAttachmentsSequence', { + action: 'add', documentId: cerebralTest.testMessageDocumentId, }, ); diff --git a/web-client/integration-tests/journey/petitionsClerkForwardsMessageWithAttachment.ts b/web-client/integration-tests/journey/petitionsClerkForwardsMessageWithAttachment.ts index 4cd68f27067..3d79f023c91 100644 --- a/web-client/integration-tests/journey/petitionsClerkForwardsMessageWithAttachment.ts +++ b/web-client/integration-tests/journey/petitionsClerkForwardsMessageWithAttachment.ts @@ -56,6 +56,7 @@ export const petitionsClerkForwardsMessageWithAttachment = cerebralTest => { cerebralTest.testMessageDocumentId = messageDocument.docketEntryId; await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: messageDocument.docketEntryId, }); diff --git a/web-client/integration-tests/journey/userSendsMessage.ts b/web-client/integration-tests/journey/userSendsMessage.ts index e1602ce24b8..201a5653cdb 100644 --- a/web-client/integration-tests/journey/userSendsMessage.ts +++ b/web-client/integration-tests/journey/userSendsMessage.ts @@ -47,6 +47,7 @@ export const userSendsMessage = ( cerebralTest.testMessageDocumentId = messageDocument.docketEntryId; await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: messageDocument.docketEntryId, }); diff --git a/web-client/integration-tests/messagesJourney.test.ts b/web-client/integration-tests/messagesJourney.test.ts index cb6c544c114..a6afd3dc2fe 100644 --- a/web-client/integration-tests/messagesJourney.test.ts +++ b/web-client/integration-tests/messagesJourney.test.ts @@ -8,7 +8,12 @@ import { docketClerkRemovesSignatureFromMessage } from './journey/docketClerkRem import { docketClerkUpdatesCaseStatusToReadyForTrial } from './journey/docketClerkUpdatesCaseStatusToReadyForTrial'; import { docketClerkViewsCompletedMessagesOnCaseDetail } from './journey/docketClerkViewsCompletedMessagesOnCaseDetail'; import { docketClerkViewsForwardedMessageInInbox } from './journey/docketClerkViewsForwardedMessageInInbox'; -import { loginAs, setupTest, uploadPetition } from './helpers'; +import { + loginAs, + refreshElasticsearchIndex, + setupTest, + uploadPetition, +} from './helpers'; import { petitionsClerk1CreatesNoticeFromMessageDetail } from './journey/petitionsClerk1CreatesNoticeFromMessageDetail'; import { petitionsClerk1RepliesToMessage } from './journey/petitionsClerk1RepliesToMessage'; import { petitionsClerk1VerifiesCaseStatusOnMessage } from './journey/petitionsClerk1VerifiesCaseStatusOnMessage'; @@ -166,6 +171,7 @@ describe('messages journey', () => { ]); await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', documentId: docketEntryWithLongTitle.docketEntryId, }); @@ -176,4 +182,70 @@ describe('messages journey', () => { await cerebralTest.runSequence('clearModalFormSequence'); }); + + it('attaches a document to a message and adds an attachment, but changes mind and removes it', async () => { + const testMessageSubject = 'once more into the breach'; + await cerebralTest.runSequence('gotoCaseDetailSequence', { + docketNumber: cerebralTest.docketNumber, + }); + + await cerebralTest.runSequence('openCreateMessageModalSequence'); + + await cerebralTest.runSequence( + 'updateSectionInCreateMessageModalSequence', + { + key: 'toSection', + value: PETITIONS_SECTION, + }, + ); + + await cerebralTest.runSequence('updateModalFormValueSequence', { + key: 'toUserId', + value: '4805d1ab-18d0-43ec-bafb-654e83405416', + }); + + const currentDocketEntries = cerebralTest.getState( + 'caseDetail.docketEntries', + ); + + await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'add', + documentId: currentDocketEntries[0].docketEntryId, + }); + + await cerebralTest.runSequence('updateMessageModalAttachmentsSequence', { + action: 'remove', + documentId: currentDocketEntries[0].docketEntryId, + }); + + await cerebralTest.runSequence('updateModalFormValueSequence', { + key: 'message', + value: testMessageSubject, + }); + + await cerebralTest.runSequence('updateModalFormValueSequence', { + key: 'subject', + value: testMessageSubject, + }); + + await cerebralTest.runSequence('createMessageSequence'); + + expect(cerebralTest.getState('validationErrors')).toEqual({}); + + await refreshElasticsearchIndex(); + + await cerebralTest.runSequence('gotoMessagesSequence', { + box: 'outbox', + queue: 'my', + }); + + const messages = cerebralTest.getState('messages'); + + const foundMessage = messages.find( + message => message.subject === testMessageSubject, + ); + + expect(foundMessage).toBeDefined(); + expect(foundMessage.attachments).toEqual([]); + }); }); diff --git a/web-client/src/business/chambers/getJudgesChambers.ts b/web-client/src/business/chambers/getJudgesChambers.ts index cb0463823f5..d8fd6f04e66 100644 --- a/web-client/src/business/chambers/getJudgesChambers.ts +++ b/web-client/src/business/chambers/getJudgesChambers.ts @@ -16,11 +16,6 @@ const JUDGES_CHAMBERS = { label: 'Carluzzo’s Chambers', section: 'carluzzosChambers', }, - CHOIS_CHAMBERS_SECTION: { - judgeFullName: 'Eunkyong Choi', - label: 'Choi’s Chambers', - section: 'choisChambers', - }, COHENS_CHAMBERS_SECTION: { judgeFullName: 'Mary Ann Cohen', label: 'Cohen’s Chambers', @@ -41,6 +36,11 @@ const JUDGES_CHAMBERS = { label: 'Foley’s Chambers', section: 'foleysChambers', }, + FRIEDS_CHAMBERS_SECTION: { + judgeFullName: 'Zachary S. Fried', + label: 'Fried’s Chambers', + section: 'friedsChambers', + }, GALES_CHAMBERS_SECTION: { judgeFullName: 'Joseph H. Gale', label: 'Gale’s Chambers', @@ -136,6 +136,11 @@ const JUDGES_CHAMBERS = { label: 'Ruwe’s Chambers', section: 'ruwesChambers', }, + SIEGELS_CHAMBERS_SECTION: { + judgeFullName: 'Jennifer E. Siegel', + label: 'Siegel’s Chambers', + section: 'siegelsChambers', + }, THORNTONS_CHAMBERS_SECTION: { judgeFullName: 'Michael B. Thornton', label: 'Thornton’s Chambers', diff --git a/web-client/src/presenter/actions/CaseDetail/createMessageAction.test.ts b/web-client/src/presenter/actions/CaseDetail/createMessageAction.test.ts index c5ea542634d..b8a5adff4e7 100644 --- a/web-client/src/presenter/actions/CaseDetail/createMessageAction.test.ts +++ b/web-client/src/presenter/actions/CaseDetail/createMessageAction.test.ts @@ -9,6 +9,9 @@ describe('createMessageAction', () => { }); it('should call createMessageInteractor with the expected parameters and return the alertSuccess', async () => { + const docIdOne = 'b1130321-0a76-43bc-b3eb-64a18f079873'; + const docIdTwo = 'b100000-0a76-43bc-b3eb-64a18f079873'; + const result = await runAction(createMessageAction, { modules: { presenter, @@ -21,10 +24,16 @@ describe('createMessageAction', () => { form: { attachments: [ { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + documentId: docIdOne, documentTitle: 'Petition', }, ], + draftAttachments: [ + { + documentId: docIdTwo, + documentTitle: 'Petition Title', + }, + ], message: 'You there!', subject: 'Hey!', }, @@ -40,9 +49,13 @@ describe('createMessageAction', () => { ).toMatchObject({ attachments: [ { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + documentId: docIdOne, documentTitle: 'Petition', }, + { + documentId: docIdTwo, + documentTitle: 'Petition Title', + }, ], docketNumber: '101-20', message: 'You there!', diff --git a/web-client/src/presenter/actions/CaseDetail/createMessageAction.ts b/web-client/src/presenter/actions/CaseDetail/createMessageAction.ts index e11091b5965..ebe35c1e9e2 100644 --- a/web-client/src/presenter/actions/CaseDetail/createMessageAction.ts +++ b/web-client/src/presenter/actions/CaseDetail/createMessageAction.ts @@ -13,6 +13,7 @@ export const createMessageAction = async ({ .createMessageInteractor(applicationContext, { docketNumber, ...form, + attachments: [...form.attachments, ...form.draftAttachments], }); return { diff --git a/web-client/src/presenter/actions/CaseDetail/forwardMessageAction.test.ts b/web-client/src/presenter/actions/CaseDetail/forwardMessageAction.test.ts index 70419096d94..9fe3397d5de 100644 --- a/web-client/src/presenter/actions/CaseDetail/forwardMessageAction.test.ts +++ b/web-client/src/presenter/actions/CaseDetail/forwardMessageAction.test.ts @@ -4,8 +4,18 @@ import { presenter } from '../../presenter-mock'; import { runAction } from '@web-client/presenter/test.cerebral'; describe('forwardMessageAction', () => { + const forwardedDocOne = '546ea14f-833f-4576-a547-8ceb7f6282a2'; + const forwardedDocTwo = 'eab4fc75-ef58-4966-a043-8a83e9a61391'; + const firstAttachedMessageId = 'b1130321-0a76-43bc-b3eb-64a18f079873'; + + const selectedDocumentIdOne = 'b1135321-0a76-43bc-b3eb-64a18f55555'; beforeAll(() => { applicationContext.getUseCases().forwardMessageInteractor.mockReturnValue({ + attachments: [ + { documentId: forwardedDocOne }, + { documentId: forwardedDocTwo }, + { documentId: firstAttachedMessageId }, + ], docketNumber: '123-45', parentMessageId: '123', }); @@ -26,10 +36,16 @@ describe('forwardMessageAction', () => { form: { attachments: [ { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + documentId: firstAttachedMessageId, documentTitle: 'Petition', }, ], + draftAttachments: [ + { + documentId: selectedDocumentIdOne, + documentTitle: 'Petition Two', + }, + ], message: 'You there!', parentMessageId: '499d51ae-f118-4eb6-bd0e-f2c351df8f06', subject: 'Hey!', @@ -47,9 +63,13 @@ describe('forwardMessageAction', () => { ).toMatchObject({ attachments: [ { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + documentId: firstAttachedMessageId, documentTitle: 'Petition', }, + { + documentId: selectedDocumentIdOne, + documentTitle: 'Petition Two', + }, ], docketNumber: '101-20', message: 'You there!', @@ -60,7 +80,7 @@ describe('forwardMessageAction', () => { expect(result.output).toHaveProperty('parentMessageId'); expect(result.output).toMatchObject({ messageViewerDocumentToDisplay: { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + documentId: firstAttachedMessageId, }, }); }); diff --git a/web-client/src/presenter/actions/CaseDetail/forwardMessageAction.ts b/web-client/src/presenter/actions/CaseDetail/forwardMessageAction.ts index 740f73fa5ac..e7446759c5b 100644 --- a/web-client/src/presenter/actions/CaseDetail/forwardMessageAction.ts +++ b/web-client/src/presenter/actions/CaseDetail/forwardMessageAction.ts @@ -1,12 +1,5 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * forwards the message - * @param {object} providers the providers object - * @param {object} providers.applicationContext the application context - * @param {Function} providers.get the cerebral get function - * @returns {object} contains the alert success message - */ export const forwardMessageAction = async ({ applicationContext, get, @@ -15,17 +8,20 @@ export const forwardMessageAction = async ({ const docketNumber = get(state.caseDetail.docketNumber); + const computedAttachments = [...form.attachments, ...form.draftAttachments]; + const { parentMessageId } = await applicationContext .getUseCases() .forwardMessageInteractor(applicationContext, { docketNumber, ...form, + attachments: computedAttachments, }); let messageViewerDocumentToDisplay; - if (form.attachments.length) { + if (computedAttachments.length) { messageViewerDocumentToDisplay = { - documentId: form.attachments[0].documentId, + documentId: computedAttachments[0].documentId, }; } diff --git a/web-client/src/presenter/actions/CaseDetail/replyToMessageAction.test.ts b/web-client/src/presenter/actions/CaseDetail/replyToMessageAction.test.ts index 5e525373738..ab2d0268c9b 100644 --- a/web-client/src/presenter/actions/CaseDetail/replyToMessageAction.test.ts +++ b/web-client/src/presenter/actions/CaseDetail/replyToMessageAction.test.ts @@ -4,8 +4,20 @@ import { replyToMessageAction } from './replyToMessageAction'; import { runAction } from '@web-client/presenter/test.cerebral'; describe('replyToMessageAction', () => { + const forwardedDocOne = '546ea14f-833f-4576-a547-8ceb7f6282a2'; + const forwardedDocTwo = 'eab4fc75-ef58-4966-a043-8a83e9a61391'; + + const firstAttachedMessageId = 'b1130321-0a76-43bc-b3eb-64a18f079873'; + + const selectedDocumentIdOne = 'b1135321-0a76-43bc-b3eb-64a18f55555'; + beforeAll(() => { applicationContext.getUseCases().replyToMessageInteractor.mockReturnValue({ + attachments: [ + { documentId: forwardedDocOne }, + { documentId: forwardedDocTwo }, + { documentId: firstAttachedMessageId }, + ], docketNumber: '123-45', parentMessageId: '123', }); @@ -26,10 +38,16 @@ describe('replyToMessageAction', () => { form: { attachments: [ { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + documentId: firstAttachedMessageId, documentTitle: 'Petition', }, ], + draftAttachments: [ + { + documentId: selectedDocumentIdOne, + documentTitle: 'Petition Title', + }, + ], message: 'You there!', parentMessageId: '499d51ae-f118-4eb6-bd0e-f2c351df8f06', subject: 'Hey!', @@ -47,9 +65,13 @@ describe('replyToMessageAction', () => { ).toMatchObject({ attachments: [ { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + documentId: firstAttachedMessageId, documentTitle: 'Petition', }, + { + documentId: selectedDocumentIdOne, + documentTitle: 'Petition Title', + }, ], docketNumber: '123-45', message: 'You there!', @@ -60,7 +82,7 @@ describe('replyToMessageAction', () => { expect(result.output).toHaveProperty('parentMessageId'); expect(result.output).toMatchObject({ messageViewerDocumentToDisplay: { - documentId: 'b1130321-0a76-43bc-b3eb-64a18f079873', + documentId: firstAttachedMessageId, }, }); }); diff --git a/web-client/src/presenter/actions/CaseDetail/replyToMessageAction.ts b/web-client/src/presenter/actions/CaseDetail/replyToMessageAction.ts index d635db7ba49..c04d0b39ec2 100644 --- a/web-client/src/presenter/actions/CaseDetail/replyToMessageAction.ts +++ b/web-client/src/presenter/actions/CaseDetail/replyToMessageAction.ts @@ -1,12 +1,5 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * replies to the message - * @param {object} providers the providers object - * @param {object} providers.applicationContext the application context - * @param {Function} providers.get the cerebral get function - * @returns {object} contains the alert success message and parent message ID - */ export const replyToMessageAction = async ({ applicationContext, get, @@ -15,17 +8,20 @@ export const replyToMessageAction = async ({ const docketNumber = get(state.caseDetail.docketNumber); + const computedAttachments = [...form.attachments, ...form.draftAttachments]; + const { parentMessageId } = await applicationContext .getUseCases() .replyToMessageInteractor(applicationContext, { docketNumber, ...form, + attachments: computedAttachments, }); let messageViewerDocumentToDisplay; - if (form.attachments.length) { + if (computedAttachments.length) { messageViewerDocumentToDisplay = { - documentId: form.attachments[0].documentId, + documentId: computedAttachments[0].documentId, }; } diff --git a/web-client/src/presenter/actions/WorkItem/setCreateMessageModalDialogModalStateAction.test.ts b/web-client/src/presenter/actions/WorkItem/setCreateMessageModalDialogModalStateAction.test.ts index df07a7835d2..78c11f8eef5 100644 --- a/web-client/src/presenter/actions/WorkItem/setCreateMessageModalDialogModalStateAction.test.ts +++ b/web-client/src/presenter/actions/WorkItem/setCreateMessageModalDialogModalStateAction.test.ts @@ -3,7 +3,7 @@ import { runAction } from '@web-client/presenter/test.cerebral'; import { setCreateMessageModalDialogModalStateAction } from './setCreateMessageModalDialogModalStateAction'; describe('setCreateMessageModalDialogModalStateAction', () => { - it('should set the modal docketNumber state', async () => { + it('should define the validationErrors, attachments, and draftAttachments in modal state', async () => { const result = await runAction( setCreateMessageModalDialogModalStateAction, { @@ -18,6 +18,7 @@ describe('setCreateMessageModalDialogModalStateAction', () => { expect(result.state.modal).toEqual({ form: { attachments: [], + draftAttachments: [], }, validationErrors: {}, }); diff --git a/web-client/src/presenter/actions/WorkItem/setCreateMessageModalDialogModalStateAction.ts b/web-client/src/presenter/actions/WorkItem/setCreateMessageModalDialogModalStateAction.ts index 76d0902d7bd..e69a4dc7a1c 100644 --- a/web-client/src/presenter/actions/WorkItem/setCreateMessageModalDialogModalStateAction.ts +++ b/web-client/src/presenter/actions/WorkItem/setCreateMessageModalDialogModalStateAction.ts @@ -1,16 +1,11 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * set the modal state - * - * @param {object} providers the providers object - * @param {object} providers.store the cerebral store function - */ export const setCreateMessageModalDialogModalStateAction = ({ store, }: ActionProps) => { store.set(state.modal.validationErrors, {}); store.set(state.modal.form, { attachments: [], + draftAttachments: [], }); }; diff --git a/web-client/src/presenter/actions/WorkItem/setForwardMessageModalDialogModalStateAction.test.ts b/web-client/src/presenter/actions/WorkItem/setForwardMessageModalDialogModalStateAction.test.ts index b78773c5d5b..193f9a6c44e 100644 --- a/web-client/src/presenter/actions/WorkItem/setForwardMessageModalDialogModalStateAction.test.ts +++ b/web-client/src/presenter/actions/WorkItem/setForwardMessageModalDialogModalStateAction.test.ts @@ -60,6 +60,7 @@ describe('setForwardMessageModalDialogModalStateAction', () => { documentTitle: 'Petition', }, ], + draftAttachments: [], from: 'test user 1', fromSection: PETITIONS_SECTION, fromUserId: '589002b0-dacd-4e84-874a-52d9898623c3', diff --git a/web-client/src/presenter/actions/WorkItem/setForwardMessageModalDialogModalStateAction.ts b/web-client/src/presenter/actions/WorkItem/setForwardMessageModalDialogModalStateAction.ts index 3e3e4317061..9be3daf8b64 100644 --- a/web-client/src/presenter/actions/WorkItem/setForwardMessageModalDialogModalStateAction.ts +++ b/web-client/src/presenter/actions/WorkItem/setForwardMessageModalDialogModalStateAction.ts @@ -1,13 +1,5 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * set the modal state - * @param {object} providers the providers object - * @param {object} providers.applicationContext the applicationContext - * @param {object} providers.get the cerebral get method - * @param {object} providers.props the cerebral props - * @param {object} providers.store the cerebral store - */ export const setForwardMessageModalDialogModalStateAction = ({ applicationContext, get, @@ -28,6 +20,7 @@ export const setForwardMessageModalDialogModalStateAction = ({ store.set(state.modal.form, { attachments: formattedAttachments, + draftAttachments: [], from: mostRecentMessage.from, fromSection: mostRecentMessage.fromSection, fromUserId: mostRecentMessage.fromUserId, diff --git a/web-client/src/presenter/actions/WorkItem/setReplyToMessageModalDialogModalStateAction.test.ts b/web-client/src/presenter/actions/WorkItem/setReplyToMessageModalDialogModalStateAction.test.ts index 37bbfbfc708..060e03f7c34 100644 --- a/web-client/src/presenter/actions/WorkItem/setReplyToMessageModalDialogModalStateAction.test.ts +++ b/web-client/src/presenter/actions/WorkItem/setReplyToMessageModalDialogModalStateAction.test.ts @@ -60,6 +60,7 @@ describe('setReplyToMessageModalDialogModalStateAction', () => { documentTitle: 'Petition', }, ], + draftAttachments: [], parentMessageId: '530f9b43-4934-4b2f-9aa4-50dcbe8064fa', subject: 'the subject', to: 'test user 1', diff --git a/web-client/src/presenter/actions/WorkItem/setReplyToMessageModalDialogModalStateAction.ts b/web-client/src/presenter/actions/WorkItem/setReplyToMessageModalDialogModalStateAction.ts index cb475269a51..dfddd101094 100644 --- a/web-client/src/presenter/actions/WorkItem/setReplyToMessageModalDialogModalStateAction.ts +++ b/web-client/src/presenter/actions/WorkItem/setReplyToMessageModalDialogModalStateAction.ts @@ -1,13 +1,5 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * set the modal state - * @param {object} providers the providers object - * @param {object} providers.applicationContext the applicationContext - * @param {object} providers.get the cerebral get method - * @param {object} providers.props the cerebral props - * @param {object} providers.store the cerebral store - */ export const setReplyToMessageModalDialogModalStateAction = ({ applicationContext, get, @@ -28,6 +20,7 @@ export const setReplyToMessageModalDialogModalStateAction = ({ store.set(state.modal.form, { attachments: formattedAttachments, + draftAttachments: [], parentMessageId: mostRecentMessage.parentMessageId, subject: mostRecentMessage.subject, to: mostRecentMessage.from, diff --git a/web-client/src/presenter/actions/updateMessageModalAfterQCAction.test.ts b/web-client/src/presenter/actions/updateMessageModalAfterQCAction.test.ts index 4c0434a79bb..9d2de229e7d 100644 --- a/web-client/src/presenter/actions/updateMessageModalAfterQCAction.test.ts +++ b/web-client/src/presenter/actions/updateMessageModalAfterQCAction.test.ts @@ -65,4 +65,19 @@ describe('updateMessageModalAfterQCAction', () => { { documentId: mockDocketEntryId, documentTitle: mockDocumentTitle }, ]); }); + + it('set state.modal.form.draftAttachments to an empty array', async () => { + const result = await runAction(updateMessageModalAfterQCAction, { + modules: { presenter }, + state: { + docketEntryId: mockDocketEntryId, + form: { + documentTitle: mockDocumentTitle, + }, + modal: { form: undefined }, + }, + }); + + expect(result.state.modal.form.draftAttachments).toEqual([]); + }); }); diff --git a/web-client/src/presenter/actions/updateMessageModalAfterQCAction.ts b/web-client/src/presenter/actions/updateMessageModalAfterQCAction.ts index 425d4cec96a..2c8940c6475 100644 --- a/web-client/src/presenter/actions/updateMessageModalAfterQCAction.ts +++ b/web-client/src/presenter/actions/updateMessageModalAfterQCAction.ts @@ -1,11 +1,5 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * updates the message form data's attachments field based on the document being QCd - * @param {object} providers the providers object - * @param {object} providers.get the get function to retrieve values from state - * @param {object} providers.store the cerebral store object - */ export const updateMessageModalAfterQCAction = ({ applicationContext, get, @@ -27,4 +21,6 @@ export const updateMessageModalAfterQCAction = ({ documentTitle, }, ]); + + store.set(state.modal.form.draftAttachments, []); }; diff --git a/web-client/src/presenter/actions/updateMessageModalAttachmentsAction.test.ts b/web-client/src/presenter/actions/updateMessageModalAttachmentsAction.test.ts index bf2b7bb8cc3..6062511c7b5 100644 --- a/web-client/src/presenter/actions/updateMessageModalAttachmentsAction.test.ts +++ b/web-client/src/presenter/actions/updateMessageModalAttachmentsAction.test.ts @@ -30,10 +30,11 @@ describe('updateMessageModalAttachmentsAction', () => { presenter.providers.applicationContext = applicationContext; }); - it('appends the given document meta from props to the form.modal.attachments array', async () => { + it('appends the given document meta in props to the form.modal.attachments array', async () => { const result = await runAction(updateMessageModalAttachmentsAction, { modules: { presenter }, props: { + action: 'add', documentId: '123', }, state: { @@ -41,20 +42,24 @@ describe('updateMessageModalAttachmentsAction', () => { modal: { form: { attachments: [], + draftAttachments: [], }, }, }, }); - expect(result.state.modal.form.attachments).toEqual([ + expect(result.state.modal.form.attachments).toEqual([]); + + expect(result.state.modal.form.draftAttachments).toEqual([ { documentId: '123', documentTitle: 'Petition' }, ]); }); - it('appends the given document meta from state to the form.modal.attachments array', async () => { + it('should not change draftAttachments when the action is not add or remove', async () => { const result = await runAction(updateMessageModalAttachmentsAction, { modules: { presenter }, props: { + action: 'something', documentId: '123', }, state: { @@ -62,41 +67,46 @@ describe('updateMessageModalAttachmentsAction', () => { modal: { form: { attachments: [], + draftAttachments: [], }, }, }, }); - expect(result.state.modal.form.attachments).toEqual([ - { documentId: '123', documentTitle: 'Petition' }, - ]); + expect(result.state.modal.form.attachments).toEqual([]); + expect(result.state.modal.form.draftAttachments).toEqual([]); }); - it('can return case correspondence from the available documents', async () => { + it('removes the given document meta in props from the form.modal.attachments array', async () => { const result = await runAction(updateMessageModalAttachmentsAction, { modules: { presenter }, props: { - documentId: '234', // correspondence doc + action: 'remove', + documentId: '123', }, state: { caseDetail, modal: { form: { attachments: [], + draftAttachments: [ + { documentId: '123', documentTitle: 'Petition' }, + ], }, }, }, }); - expect(result.state.modal.form.attachments).toEqual([ - { documentId: '234', documentTitle: 'Test Correspondence' }, - ]); + expect(result.state.modal.form.attachments).toEqual([]); + + expect(result.state.modal.form.draftAttachments).toEqual([]); }); it('does not modify the array if no documentId is given', async () => { const result = await runAction(updateMessageModalAttachmentsAction, { modules: { presenter }, props: { + action: 'add', documentId: '', documentTitle: '', }, @@ -105,18 +115,21 @@ describe('updateMessageModalAttachmentsAction', () => { modal: { form: { attachments: [], + draftAttachments: [], }, }, }, }); expect(result.state.modal.form.attachments).toEqual([]); + expect(result.state.modal.form.draftAttachments).toEqual([]); }); it('sets the form subject field if this is the first attachment to be added', async () => { const result = await runAction(updateMessageModalAttachmentsAction, { modules: { presenter }, props: { + action: 'add', documentId: '123', }, state: { @@ -124,6 +137,7 @@ describe('updateMessageModalAttachmentsAction', () => { modal: { form: { attachments: [], + draftAttachments: [], }, }, }, @@ -132,46 +146,110 @@ describe('updateMessageModalAttachmentsAction', () => { expect(result.state.modal.form.subject).toEqual('Petition'); }); - it('truncates the document title to 250 characters when updating the subject field', async () => { + it('not change form subject field if there is already an attachment', async () => { const result = await runAction(updateMessageModalAttachmentsAction, { modules: { presenter }, props: { + action: 'add', documentId: '345', }, + state: { + caseDetail, + modal: { + form: { + attachments: [ + { + docketEntryId: '123', + documentType: 'Petition', + }, + ], + draftAttachments: [], + subject: 'Petition', + }, + }, + }, + }); + + expect(result.state.modal.form.subject).toEqual('Petition'); + }); + + it('not change form subject field if there is already a draft attachment', async () => { + const result = await runAction(updateMessageModalAttachmentsAction, { + modules: { presenter }, + props: { + action: 'add', + documentId: '123', + }, state: { caseDetail, modal: { form: { attachments: [], + draftAttachments: [ + { + docketEntryId: '456', + documentType: 'New Petition', + }, + ], + subject: 'New Petition', }, }, }, }); - expect( - result.state.modal.form.attachments[0].documentTitle.length, - ).toBeGreaterThan(250); - expect(result.state.modal.form.subject.length).toEqual(250); + expect(result.state.modal.form.subject).toEqual('New Petition'); }); - it('does NOT set the form subject field if this is NOT the first attachment to be added', async () => { + it('not change form subject field if all draft attachments are removed', async () => { const result = await runAction(updateMessageModalAttachmentsAction, { modules: { presenter }, props: { + action: 'remove', documentId: '123', }, state: { caseDetail, modal: { form: { - attachments: [{}], // already contains one attachment - subject: 'Testing', + attachments: [], + draftAttachments: [ + { + docketEntryId: '123', + documentTitle: 'Petition', + documentType: 'New Petition', + }, + ], + subject: 'Petition', }, }, }, }); - expect(result.state.modal.form.subject).toEqual('Testing'); + expect(result.state.modal.form.subject).toEqual('Petition'); + }); + + it('truncates the document title to 250 characters when updating the subject field', async () => { + const result = await runAction(updateMessageModalAttachmentsAction, { + modules: { presenter }, + props: { + action: 'add', + documentId: '345', + }, + state: { + caseDetail, + modal: { + form: { + attachments: [], + draftAttachments: [], + }, + }, + }, + }); + + expect( + result.state.modal.form.draftAttachments[0].documentTitle.length, + ).toBeGreaterThan(250); + expect(result.state.modal.form.subject.length).toEqual(250); }); it('calls getDescriptionDisplay and returns a generated document title', async () => { @@ -183,6 +261,7 @@ describe('updateMessageModalAttachmentsAction', () => { const { state } = await runAction(updateMessageModalAttachmentsAction, { modules: { presenter }, props: { + action: 'add', documentId: '123', }, state: { @@ -190,6 +269,7 @@ describe('updateMessageModalAttachmentsAction', () => { modal: { form: { attachments: [{}], // already contains one attachment + draftAttachments: [], subject: 'Testing', }, }, @@ -202,7 +282,7 @@ describe('updateMessageModalAttachmentsAction', () => { expect( applicationContext.getUtilities().getDescriptionDisplay.mock.calls[0][0], ).toMatchObject({ docketEntryId: '123', documentType: 'Petition' }); - expect(state.modal.form.attachments[1].documentTitle).toEqual( + expect(state.modal.form.draftAttachments[0].documentTitle).toEqual( mockDocumentTitle, ); }); diff --git a/web-client/src/presenter/actions/updateMessageModalAttachmentsAction.ts b/web-client/src/presenter/actions/updateMessageModalAttachmentsAction.ts index 6df5bbca89c..229d86e9fbd 100644 --- a/web-client/src/presenter/actions/updateMessageModalAttachmentsAction.ts +++ b/web-client/src/presenter/actions/updateMessageModalAttachmentsAction.ts @@ -1,19 +1,12 @@ import { state } from '@web-client/presenter/app.cerebral'; -/** - * updates the current message form data's attachments field - * @param {object} providers the providers object - * @param {object} providers.get the get function to retrieve values from state - * @param {object} providers.props the cerebral props object - * @param {object} providers.store the cerebral store object - */ export const updateMessageModalAttachmentsAction = ({ applicationContext, get, props, store, }: ActionProps) => { - const { attachments } = get(state.modal.form); + const { attachments, draftAttachments } = get(state.modal.form); const caseDetail = get(state.caseDetail); const documentId = props.documentId || get(state.docketEntryId); @@ -29,16 +22,22 @@ export const updateMessageModalAttachmentsAction = ({ .getUtilities() .getDescriptionDisplay(document); - if (attachments.length === 0) { + if (attachments.length + draftAttachments.length === 0) { // This is the first attachment, so we should update the subject store.set(state.modal.form.subject, documentTitle.slice(0, 250)); } + if (props.action === 'add') { + draftAttachments.push({ + documentId, + documentTitle, + }); + } else if (props.action === 'remove') { + const foundIndex = draftAttachments.findIndex( + attachment => attachment.documentId == props.documentId, + ); + draftAttachments.splice(foundIndex, 1); + } - attachments.push({ - documentId, - documentTitle, - }); - - store.set(state.modal.form.attachments, attachments); + store.set(state.modal.form.draftAttachments, draftAttachments); } }; diff --git a/web-client/src/presenter/computeds/messageModalHelper.test.ts b/web-client/src/presenter/computeds/messageModalHelper.test.ts index 8493586002a..b6657b23919 100644 --- a/web-client/src/presenter/computeds/messageModalHelper.test.ts +++ b/web-client/src/presenter/computeds/messageModalHelper.test.ts @@ -22,7 +22,7 @@ describe('messageModalHelper', () => { const mockDocketEntryWithFileAttachedOnDocketRecord = { descriptionDisplay: 'Hello with additional info', - documentId: mockDocketEntryIdOnDocketRecord, + docketEntryId: mockDocketEntryIdOnDocketRecord, documentType: 'Petition', index: 1, isFileAttached: true, @@ -30,7 +30,7 @@ describe('messageModalHelper', () => { }; const mockDocketEntryWithFileAttachedOnDocketRecordAndNoDescription = { - documentId: mockDocketEntryIdAlsoOnDocketRecord, + docketEntryId: mockDocketEntryIdAlsoOnDocketRecord, documentTitle: 'Some Document', index: 2, isFileAttached: true, @@ -44,7 +44,7 @@ describe('messageModalHelper', () => { ]; const mockDraftDocketEntry = { - documentId: '345', + docketEntryId: '345', documentTitle: 'Order to do something', documentType: 'Order', isDraft: true, @@ -67,15 +67,20 @@ describe('messageModalHelper', () => { }, ]; - const baseState = { - caseDetail: {}, - modal: { - form: { - attachments: [], + let baseState; + + beforeEach(() => { + baseState = { + caseDetail: {}, + modal: { + form: { + attachments: [], + draftAttachments: [], + }, }, - }, - screenMetadata: {}, - }; + screenMetadata: {}, + }; + }); const messageModalHelper = withAppContextDecorator( messageModalHelperComputed, @@ -99,6 +104,7 @@ describe('messageModalHelper', () => { it('should set a title on each entry from the documentTitle or documentType', () => { applicationContext.getUtilities().getFormattedCaseDetail.mockReturnValue({ + correspondence: [{}], draftDocuments: mockDraftDocuments, formattedDocketEntries: [], }); @@ -119,30 +125,27 @@ describe('messageModalHelper', () => { }); describe('documents', () => { - it('should include only documents that are on the docket record', () => { + beforeAll(() => { applicationContext.getUtilities().getFormattedCaseDetail.mockReturnValue({ correspondence: [], draftDocuments: [], formattedDocketEntries: mockDocketEntries, }); + }); + it('should include only documents that are on the docket record', () => { const { documents } = runCompute(messageModalHelper, { state: baseState, }); expect(documents).toMatchObject([ - { documentId: mockDocketEntryIdOnDocketRecord }, - { documentId: mockDocketEntryIdAlsoOnDocketRecord }, + { docketEntryId: mockDocketEntryIdOnDocketRecord }, + { docketEntryId: mockDocketEntryIdAlsoOnDocketRecord }, ]); expect(documents.length).toEqual(2); }); it('should set a title on each entry from either the descriptionDisplay or documentType', () => { - applicationContext.getUtilities().getFormattedCaseDetail.mockReturnValue({ - draftDocuments: [], - formattedDocketEntries: mockDocketEntries, - }); - const { documents } = runCompute(messageModalHelper, { state: baseState, }); @@ -154,6 +157,47 @@ describe('messageModalHelper', () => { mockDocketEntryWithFileAttachedOnDocketRecordAndNoDescription.documentType, ); }); + + it('should should set isAlreadyAttached to true if the document has already been selected', () => { + baseState.modal.form.attachments = [ + { + documentId: + mockDocketEntryWithFileAttachedOnDocketRecord.docketEntryId, + }, + ]; + baseState.modal.form.draftAttachments = []; + + const { documents } = runCompute(messageModalHelper, { + state: baseState, + }); + expect(documents[0].isAlreadyAttached).toEqual(true); + }); + + it('should should set isAlreadyAttached to false if the document has not been selected', () => { + baseState.modal.form.attachments = []; + baseState.modal.form.draftAttachments = []; + + const { documents } = runCompute(messageModalHelper, { + state: baseState, + }); + expect(documents[0].isAlreadyAttached).toEqual(false); + }); + + it('should should set isAlreadyAttached to true if the draft attachment has already been selected', () => { + baseState.modal.form.draftAttachments = [ + { + documentId: + mockDocketEntryWithFileAttachedOnDocketRecord.docketEntryId, + }, + ]; + + baseState.modal.form.attachments = []; + + const { documents } = runCompute(messageModalHelper, { + state: baseState, + }); + expect(documents[0].isAlreadyAttached).toEqual(true); + }); }); describe('draftDocuments', () => { @@ -283,6 +327,7 @@ describe('messageModalHelper', () => { modal: { form: { attachments: [{}], // 1/2 documents attached + draftAttachments: [], }, }, screenMetadata: { @@ -306,6 +351,7 @@ describe('messageModalHelper', () => { modal: { form: { attachments: [{}], // 1/2 documents attached + draftAttachments: [], }, }, screenMetadata: { @@ -328,7 +374,8 @@ describe('messageModalHelper', () => { caseDetail: {}, modal: { form: { - attachments: [{}, {}], // 2/2 documents attached + attachments: [{}], + draftAttachments: [{}], // 2/2 documents attached }, }, screenMetadata: { @@ -354,6 +401,7 @@ describe('messageModalHelper', () => { modal: { form: { attachments: [{}], // 1/2 documents attached + draftAttachments: [], }, }, screenMetadata: {}, @@ -374,7 +422,8 @@ describe('messageModalHelper', () => { caseDetail: {}, modal: { form: { - attachments: [{}, {}], // 2/2 documents attached + attachments: [{}], + draftAttachments: [{}], // 2/2 documents attached }, }, screenMetadata: {}, @@ -401,6 +450,7 @@ describe('messageModalHelper', () => { modal: { form: { attachments: [{}], + draftAttachments: [], }, }, screenMetadata: {}, @@ -437,6 +487,7 @@ describe('messageModalHelper', () => { modal: { form: { attachments: [{}, {}], // 2/2 documents attached + draftAttachments: [], }, }, screenMetadata: {}, @@ -461,6 +512,7 @@ describe('messageModalHelper', () => { modal: { form: { attachments: [{}], + draftAttachments: [], }, }, screenMetadata: {}, diff --git a/web-client/src/presenter/computeds/messageModalHelper.ts b/web-client/src/presenter/computeds/messageModalHelper.ts index 8eaf43393ed..2a52502065a 100644 --- a/web-client/src/presenter/computeds/messageModalHelper.ts +++ b/web-client/src/presenter/computeds/messageModalHelper.ts @@ -19,25 +19,44 @@ export const messageModalHelper = ( const caseDetail = get(state.caseDetail); const screenMetadata = get(state.screenMetadata); const attachments = get(state.modal.form.attachments); + const draftAttachments = get(state.modal.form.draftAttachments); + const currentAttachments = [...attachments, ...draftAttachments]; + + const computeIsAlreadyAttached = doc => + currentAttachments.some( + attachment => attachment.documentId === doc.docketEntryId, + ); const { correspondence, draftDocuments, formattedDocketEntries } = applicationContext .getUtilities() .getFormattedCaseDetail({ applicationContext, caseDetail }); - const documents: RawDocketEntry[] = []; - formattedDocketEntries.forEach(entry => { + const documents: (RawDocketEntry & { + isAlreadyAttached: boolean; + title: string; + })[] = []; + for (let entry of formattedDocketEntries) { if (entry.isFileAttached && entry.isOnDocketRecord) { entry.title = entry.descriptionDisplay || entry.documentType; + entry.isAlreadyAttached = computeIsAlreadyAttached(entry); + documents.push(entry); } - }); + } - draftDocuments.forEach(entry => { + for (let entry of draftDocuments) { entry.title = entry.documentTitle || entry.documentType; - }); + entry.isAlreadyAttached = computeIsAlreadyAttached(entry); + } + + for (let corr of correspondence) { + corr.isAlreadyAttached = currentAttachments.some( + attachment => attachment.docketEntryId === corr.correspondenceId, + ); + } - const currentAttachmentCount = attachments.length; + const currentAttachmentCount = currentAttachments.length; const canAddDocument = currentAttachmentCount < CASE_MESSAGE_DOCUMENT_ATTACHMENT_LIMIT; const shouldShowAddDocumentForm = @@ -84,6 +103,6 @@ export const messageModalHelper = ( sectionListWithoutSupervisorRole, showAddDocumentForm: canAddDocument && shouldShowAddDocumentForm, showAddMoreDocumentsButton: canAddDocument && !shouldShowAddDocumentForm, - showMessageAttachments: attachments.length > 0, + showMessageAttachments: currentAttachmentCount > 0, }; }; diff --git a/web-client/src/styles/forms.scss b/web-client/src/styles/forms.scss index b430f8b2930..cd13500be25 100644 --- a/web-client/src/styles/forms.scss +++ b/web-client/src/styles/forms.scss @@ -625,3 +625,7 @@ label.ustc-upload { margin-bottom: 35px; margin-left: -1.25rem; } + +.ustc-message-modal-text-area { + resize: vertical; +} diff --git a/web-client/src/views/Messages/CreateMessageModalDialog.tsx b/web-client/src/views/Messages/CreateMessageModalDialog.tsx index 054a5c59ee4..2dc01b46629 100644 --- a/web-client/src/views/Messages/CreateMessageModalDialog.tsx +++ b/web-client/src/views/Messages/CreateMessageModalDialog.tsx @@ -157,7 +157,7 @@ export const CreateMessageModalDialog = connect( Add message