From 27df7bcd74b6236a6ec673bd01191854b2b9f1e1 Mon Sep 17 00:00:00 2001 From: Stephen Hand Date: Fri, 2 May 2025 17:23:12 +0100 Subject: [PATCH 1/2] Fix referencing for timelines to prevent issues with case search results going blank. Fix orphaned case check --- .../___tests__/components/case/Case.test.tsx | 3 +- .../___tests__/states/case/timeline.test.ts | 2 ++ .../src/components/case/CaseSection.tsx | 9 +++++- .../case/casePrint/CasePrintView.tsx | 30 ++++++++++++++----- .../case/timeline/FullTimelineView.tsx | 15 +++++++--- .../src/components/case/timeline/Timeline.tsx | 15 +++++++--- .../components/caseList/CaseListTableRow.tsx | 4 ++- .../components/search/CasePreview/index.tsx | 19 ++++++++++-- .../src/states/case/hooks/useCaseSections.ts | 4 ++- plugin-hrm-form/src/states/case/timeline.ts | 5 +++- .../src/states/contacts/reducer.ts | 4 +-- 11 files changed, 84 insertions(+), 26 deletions(-) diff --git a/plugin-hrm-form/src/___tests__/components/case/Case.test.tsx b/plugin-hrm-form/src/___tests__/components/case/Case.test.tsx index 1a87efaa7b..0e0e8c4244 100644 --- a/plugin-hrm-form/src/___tests__/components/case/Case.test.tsx +++ b/plugin-hrm-form/src/___tests__/components/case/Case.test.tsx @@ -87,7 +87,7 @@ describe('useState mocked', () => { expect(mockNewGetTimelineAction).toHaveBeenCalledWith(case1.connectedCase.id, sectionType, [sectionType], false, { limit: 100, offset: 0, - }); + }, `case-${case1.connectedCase.id}`); }); expect(mockNewGetTimelineAction).toHaveBeenCalledWith( @@ -96,6 +96,7 @@ describe('useState mocked', () => { expect.arrayContaining(['referral', 'note']), true, { limit: 5, offset: 0 }, + `case-${case1.connectedCase.id}`, ); }; diff --git a/plugin-hrm-form/src/___tests__/states/case/timeline.test.ts b/plugin-hrm-form/src/___tests__/states/case/timeline.test.ts index 0f372b24ac..068ef2334f 100644 --- a/plugin-hrm-form/src/___tests__/states/case/timeline.test.ts +++ b/plugin-hrm-form/src/___tests__/states/case/timeline.test.ts @@ -111,6 +111,7 @@ describe('newGetTimelineAsyncAction', () => { ['note', 'household'], true, SAMPLE_PAGINATION, + 'test-reference' ); expect(getCaseTimeline).toHaveBeenCalledWith(TEST_CASE_ID, ['note', 'household'], true, SAMPLE_PAGINATION); @@ -120,6 +121,7 @@ describe('newGetTimelineAsyncAction', () => { timelineId: TEST_TIMELINE_ID, caseId: TEST_CASE_ID, pagination: SAMPLE_PAGINATION, + reference: 'test-reference', }); }); diff --git a/plugin-hrm-form/src/components/case/CaseSection.tsx b/plugin-hrm-form/src/components/case/CaseSection.tsx index 8e29c4f64b..3fa6a5caad 100644 --- a/plugin-hrm-form/src/components/case/CaseSection.tsx +++ b/plugin-hrm-form/src/components/case/CaseSection.tsx @@ -65,7 +65,14 @@ const CaseSection: React.FC = ({ taskSid, canAdd, sectionType }) => { // eslint-disable-next-line no-console console.log(`Fetching ${sectionType} sections for case ${caseId}`); asyncDispatcher( - newGetTimelineAsyncAction(caseId, sectionType, [sectionType], false, { offset: 0, limit: MAX_SECTIONS }), + newGetTimelineAsyncAction( + caseId, + sectionType, + [sectionType], + false, + { offset: 0, limit: MAX_SECTIONS }, + `case-${caseId}`, + ), ); } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/plugin-hrm-form/src/components/case/casePrint/CasePrintView.tsx b/plugin-hrm-form/src/components/case/casePrint/CasePrintView.tsx index 9bfb733e4c..9e9ba51063 100644 --- a/plugin-hrm-form/src/components/case/casePrint/CasePrintView.tsx +++ b/plugin-hrm-form/src/components/case/casePrint/CasePrintView.tsx @@ -115,10 +115,17 @@ const CasePrintView: React.FC = ({ task }) => { useEffect(() => { if (!contactTimeline) { dispatch( - newGetTimelineAsyncAction(connectedCase.id, 'print-contacts', [], true, { - offset: 0, - limit: MAX_PRINTOUT_CONTACTS, - }), + newGetTimelineAsyncAction( + connectedCase.id, + 'print-contacts', + [], + true, + { + offset: 0, + limit: MAX_PRINTOUT_CONTACTS, + }, + `case-${connectedCase.id}`, + ), ); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -129,10 +136,17 @@ const CasePrintView: React.FC = ({ task }) => { useEffect( () => { dispatch( - newGetTimelineAsyncAction(connectedCase.id, sectionType, [sectionType], false, { - offset: 0, - limit: MAX_SECTIONS, - }), + newGetTimelineAsyncAction( + connectedCase.id, + sectionType, + [sectionType], + false, + { + offset: 0, + limit: MAX_SECTIONS, + }, + `case-${connectedCase.id}`, + ), ); }, // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/plugin-hrm-form/src/components/case/timeline/FullTimelineView.tsx b/plugin-hrm-form/src/components/case/timeline/FullTimelineView.tsx index ef7789d48c..aecdbd7c27 100644 --- a/plugin-hrm-form/src/components/case/timeline/FullTimelineView.tsx +++ b/plugin-hrm-form/src/components/case/timeline/FullTimelineView.tsx @@ -53,10 +53,17 @@ const mapDispatchToProps = (dispatch: Dispatch, { task }: MyProps) => { changeRoute({ route: 'case', subroute: 'timeline', caseId, page }, task.taskSid, ChangeRouteMode.Replace), ); dispatch( - newGetTimelineAsyncAction(caseId, 'prime-timeline', ['note', 'referral'], true, { - offset: page * TIMELINE_PAGE_SIZE, - limit: TIMELINE_PAGE_SIZE, - }), + newGetTimelineAsyncAction( + caseId, + 'prime-timeline', + ['note', 'referral'], + true, + { + offset: page * TIMELINE_PAGE_SIZE, + limit: TIMELINE_PAGE_SIZE, + }, + `case-${caseId}`, + ), ); }, }; diff --git a/plugin-hrm-form/src/components/case/timeline/Timeline.tsx b/plugin-hrm-form/src/components/case/timeline/Timeline.tsx index 2419125853..b7212625e0 100644 --- a/plugin-hrm-form/src/components/case/timeline/Timeline.tsx +++ b/plugin-hrm-form/src/components/case/timeline/Timeline.tsx @@ -92,10 +92,17 @@ const Timeline: React.FC = ({ if (caseId) { console.log(`Fetching main timeline sections for case ${caseId}`); asyncDispatch(dispatch)( - newGetTimelineAsyncAction(caseId, timelineId, timelineCaseSectionTypes, true, { - offset: page * pageSize, - limit: pageSize, - }), + newGetTimelineAsyncAction( + caseId, + timelineId, + timelineCaseSectionTypes, + true, + { + offset: page * pageSize, + limit: pageSize, + }, + `case-${caseId}`, + ), ); } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/plugin-hrm-form/src/components/caseList/CaseListTableRow.tsx b/plugin-hrm-form/src/components/caseList/CaseListTableRow.tsx index e2cf23c33a..2bfa38f348 100644 --- a/plugin-hrm-form/src/components/caseList/CaseListTableRow.tsx +++ b/plugin-hrm-form/src/components/caseList/CaseListTableRow.tsx @@ -95,7 +95,9 @@ const CaseListTableRow: React.FC = ({ caseId, handleClickViewCase }) => { useEffect(() => { if (!timelineCategories) { - dispatch(newGetTimelineAsyncAction(caseId, CONTACTS_TIMELINE_ID, [], true, { offset: 0, limit: 10000 })); + dispatch( + newGetTimelineAsyncAction(caseId, CONTACTS_TIMELINE_ID, [], true, { offset: 0, limit: 10000 }, `case-list`), + ); } }, [timelineCategories, caseId, dispatch]); diff --git a/plugin-hrm-form/src/components/search/CasePreview/index.tsx b/plugin-hrm-form/src/components/search/CasePreview/index.tsx index 3b1ae0bd4d..f521c311e8 100644 --- a/plugin-hrm-form/src/components/search/CasePreview/index.tsx +++ b/plugin-hrm-form/src/components/search/CasePreview/index.tsx @@ -39,6 +39,7 @@ import { newGetTimelineAsyncAction, selectCaseLabel, selectTimelineContactCategories, + selectTimelineCount, } from '../../../states/case/timeline'; type Props = { @@ -60,6 +61,9 @@ const CasePreview: React.FC = ({ currentCase, onClickViewCase, counselors const timelineCategories = useSelector((state: RootState) => selectTimelineContactCategories(state, currentCase.id, CONTACTS_TIMELINE_ID), ); + const contactCount = useSelector((state: RootState) => + selectTimelineCount(state, currentCase.id, CONTACTS_TIMELINE_ID), + ); const caseLabel = useSelector((state: RootState) => selectCaseLabel(state, currentCase.id, CONTACTS_TIMELINE_ID, { substituteForId: false, @@ -71,15 +75,24 @@ const CasePreview: React.FC = ({ currentCase, onClickViewCase, counselors useEffect(() => { if (!timelineCategories) { - dispatch(newGetTimelineAsyncAction(currentCase.id, CONTACTS_TIMELINE_ID, [], true, { offset: 0, limit: 10000 })); + dispatch( + newGetTimelineAsyncAction( + currentCase.id, + CONTACTS_TIMELINE_ID, + [], + true, + { offset: 0, limit: 10000 }, + `search-${task.taskSid}`, + ), + ); } - }, [timelineCategories, currentCase.id, dispatch]); + }, [timelineCategories, currentCase.id, dispatch, task.taskSid]); const { id, createdAt, status, info, twilioWorkerId } = currentCase; const updatedAtObj = getUpdatedDate(currentCase); const followUpDateObj = info.followUpDate ? new Date(info.followUpDate) : undefined; const { definitionVersion: versionId } = info; - const orphanedCase = !timelineCategories; + const orphanedCase = contactCount === 0; const summary = info?.summary; const counselor = counselorsHash[twilioWorkerId]; diff --git a/plugin-hrm-form/src/states/case/hooks/useCaseSections.ts b/plugin-hrm-form/src/states/case/hooks/useCaseSections.ts index 9cf05c55d2..c2e1174527 100644 --- a/plugin-hrm-form/src/states/case/hooks/useCaseSections.ts +++ b/plugin-hrm-form/src/states/case/hooks/useCaseSections.ts @@ -52,7 +52,9 @@ const useCaseSectionsLoader = ({ return; } - asyncDispatch(dispatch)(newGetTimelineAsyncAction(caseId, sectionType, [sectionType], false, { offset, limit })); + asyncDispatch(dispatch)( + newGetTimelineAsyncAction(caseId, sectionType, [sectionType], false, { offset, limit }, `case-${caseId}`), + ); }, [caseId, dispatch, limit, offset, sectionType]); const safeToLoad = Boolean(caseId) && exists; diff --git a/plugin-hrm-form/src/states/case/timeline.ts b/plugin-hrm-form/src/states/case/timeline.ts index c4f46624ec..4c1fb92fcd 100644 --- a/plugin-hrm-form/src/states/case/timeline.ts +++ b/plugin-hrm-form/src/states/case/timeline.ts @@ -47,17 +47,20 @@ export const newGetTimelineAsyncAction = createAsyncAction( sectionTypes: string[], includeContacts: boolean, pagination: PaginationSettings, + reference: string, ): Promise<{ timelineResult: TimelineResult; caseId: Case['id']; timelineId: string; pagination: PaginationSettings; + reference: string; }> => { return { timelineResult: await getCaseTimeline(caseId, sectionTypes, includeContacts, pagination), caseId, timelineId, pagination, + reference, }; }, ); @@ -211,5 +214,5 @@ export const selectCaseLabel = ( return contactLabelFromHrmContact(def, firstContact.activity, contactLabelOptions); } } - return undefined; + return contactLabelOptions?.placeholder ?? ''; }; diff --git a/plugin-hrm-form/src/states/contacts/reducer.ts b/plugin-hrm-form/src/states/contacts/reducer.ts index deabcd47a6..159517c7c0 100644 --- a/plugin-hrm-form/src/states/contacts/reducer.ts +++ b/plugin-hrm-form/src/states/contacts/reducer.ts @@ -258,9 +258,9 @@ export function reduce( return loadContactListIntoState(state, rootState.configuration, action.searchResult.contacts, `${action.taskId}-search-contact`); } case GET_CASE_TIMELINE_ACTION_FULFILLED: { - const { payload: { caseId, timelineResult: { activities } } } = action; + const { payload: { timelineResult: { activities }, reference } } = action; const contacts = activities.filter(isContactTimelineActivity).map(({ activity })=> activity); - return loadContactListIntoState(state, rootState.configuration, contacts, `case-${caseId}`, false); + return loadContactListIntoState(state, rootState.configuration, contacts, reference, false); } case CREATE_CASE_ACTION_FULFILLED: { const { payload: { connectedContact } } = action as CreateCaseAsyncActionFulfilled; From f3c052847221c02cf655a746ce082711d02416b3 Mon Sep 17 00:00:00 2001 From: Stephen Hand Date: Fri, 2 May 2025 17:47:00 +0100 Subject: [PATCH 2/2] Linter --- .../___tests__/components/case/Case.test.tsx | 19 +++++++++++-------- .../___tests__/states/case/timeline.test.ts | 11 +++++++++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/plugin-hrm-form/src/___tests__/components/case/Case.test.tsx b/plugin-hrm-form/src/___tests__/components/case/Case.test.tsx index 0e0e8c4244..d58e7161a5 100644 --- a/plugin-hrm-form/src/___tests__/components/case/Case.test.tsx +++ b/plugin-hrm-form/src/___tests__/components/case/Case.test.tsx @@ -84,10 +84,17 @@ beforeEach(() => { describe('useState mocked', () => { const verifyTimelineActions = () => { ['household', 'incident', 'perpetrator'].forEach(sectionType => { - expect(mockNewGetTimelineAction).toHaveBeenCalledWith(case1.connectedCase.id, sectionType, [sectionType], false, { - limit: 100, - offset: 0, - }, `case-${case1.connectedCase.id}`); + expect(mockNewGetTimelineAction).toHaveBeenCalledWith( + case1.connectedCase.id, + sectionType, + [sectionType], + false, + { + limit: 100, + offset: 0, + }, + `case-${case1.connectedCase.id}`, + ); }); expect(mockNewGetTimelineAction).toHaveBeenCalledWith( @@ -137,12 +144,8 @@ describe('useState mocked', () => { twilioWorkerId: WORKER_SID, status: 'open', info: { definitionVersion: DefinitionVersionId.v1 }, - categories: {}, accountSid: 'AC-accountSid', helpline: 'helpline', - firstContact: { - id: 'contact1', - } as Contact, }, availableStatusTransitions: [], references: new Set(['x']), diff --git a/plugin-hrm-form/src/___tests__/states/case/timeline.test.ts b/plugin-hrm-form/src/___tests__/states/case/timeline.test.ts index 068ef2334f..5146d7e0b3 100644 --- a/plugin-hrm-form/src/___tests__/states/case/timeline.test.ts +++ b/plugin-hrm-form/src/___tests__/states/case/timeline.test.ts @@ -111,7 +111,7 @@ describe('newGetTimelineAsyncAction', () => { ['note', 'household'], true, SAMPLE_PAGINATION, - 'test-reference' + 'test-reference', ); expect(getCaseTimeline).toHaveBeenCalledWith(TEST_CASE_ID, ['note', 'household'], true, SAMPLE_PAGINATION); @@ -199,7 +199,14 @@ describe('newGetTimelineAsyncAction', () => { } = getState() as HrmState; mockGetCaseTimeline.mockResolvedValue(apiResponse); await ((dispatch( - newGetTimelineAsyncAction(TEST_CASE_ID, TEST_TIMELINE_ID, ['note', 'household'], true, pagination), + newGetTimelineAsyncAction( + TEST_CASE_ID, + TEST_TIMELINE_ID, + ['note', 'household'], + true, + pagination, + 'test-reference', + ), ) as unknown) as PromiseLike); const { connectedCase: {