diff --git a/packages/card-support/src/components/DownloadClientData/index.tsx b/packages/card-support/src/components/DownloadClientData/index.tsx index 14791324c..b968c7fd3 100644 --- a/packages/card-support/src/components/DownloadClientData/index.tsx +++ b/packages/card-support/src/components/DownloadClientData/index.tsx @@ -167,7 +167,7 @@ const DownloadClientData: React.FC = (props: DownloadCl opensrpServiceClass, locationHierarchies, setSubmitting - ); + ).catch(() => sendErrorNotification(lang.ERROR_OCCURRED)); }} > diff --git a/packages/card-support/src/components/DownloadClientData/tests/fixtures.ts b/packages/card-support/src/components/DownloadClientData/tests/fixtures.ts index 2a76db570..abcde3054 100644 --- a/packages/card-support/src/components/DownloadClientData/tests/fixtures.ts +++ b/packages/card-support/src/components/DownloadClientData/tests/fixtures.ts @@ -193,7 +193,32 @@ export const locationHierarchy = { }, }, }, - parentChildren: {}, + parentChildren: { + '70589012-899c-401d-85a1-13fabce26aab': [ + '325b9549-80fa-4dd0-9cf8-f0538cbebb18', + 'e2b4a441-21b5-4d03-816b-09d45b17cad7', + '72f8ae88-58c9-40b4-863a-1c7bc6549a8b', + '52c10f07-6653-470d-9fee-14b0bb111c2a', + 'd309898b-3925-494f-a30c-689222d3fcce', + 'dbacb5dc-c8a3-439d-b407-13ffd570b9ef', + '27400130-8127-4f54-b14f-e26f20ecae14', + '14e83edc-5a54-44f5-816e-c96c61b5d911', + '9c183088-e498-4183-af41-b29bd32d94b6', + '66c88197-8281-4eb4-ae2e-4a89ae8419ed', + ], + 'e447d5bb-8d42-4be4-b91d-b8d185cf81a6': ['1018b255-0889-492c-b5dd-31a50cb3db4d'], + 'e5631d3e-70c3-4083-ac17-46f9467c6dd5': ['5d99a60e-126e-4c40-b5ce-439f920de090'], + '7a663f5e-2619-4a2d-a7df-7250263f47d2': ['9a0e7727-b011-458f-832a-61108b2fe381'], + '18b3841b-b5b1-4971-93d0-d36ac20c4565': ['70589012-899c-401d-85a1-13fabce26aab'], + 'fee237ef-75e8-4ada-b15f-6d1a92633f33': ['e5631d3e-70c3-4083-ac17-46f9467c6dd5'], + '16c58ef5-3b19-4ec2-ba9c-aefac3d08a66': ['e447d5bb-8d42-4be4-b91d-b8d185cf81a6'], + 'ede2c7cf-331e-497e-9c7f-2f914d734604': [ + '18b3841b-b5b1-4971-93d0-d36ac20c4565', + 'fee237ef-75e8-4ada-b15f-6d1a92633f33', + '16c58ef5-3b19-4ec2-ba9c-aefac3d08a66', + '7a663f5e-2619-4a2d-a7df-7250263f47d2', + ], + }, }, }; diff --git a/packages/card-support/src/components/DownloadClientData/tests/index.test.tsx b/packages/card-support/src/components/DownloadClientData/tests/index.test.tsx index 46c702e9e..1500fe5b9 100644 --- a/packages/card-support/src/components/DownloadClientData/tests/index.test.tsx +++ b/packages/card-support/src/components/DownloadClientData/tests/index.test.tsx @@ -235,6 +235,7 @@ describe('components/DownloadClientData', () => { it('downloads csv correctly', async () => { fetch.mockOnce(JSON.stringify(fixtures.sampleTeamAssignment)); fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); + fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); fetch.mockOnce(JSON.stringify([fixtures.mother, fixtures.child1, fixtures.child2])); const queryClient = new QueryClient(); @@ -276,7 +277,8 @@ describe('components/DownloadClientData', () => { expect(fetch.mock.calls.map((res) => res[0])).toEqual([ 'https://unicef-tunisia-stage.smartregister.org/opensrp/security/authenticate', 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7?is_jurisdiction=true', - 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=e2b4a441-21b5-4d03-816b-09d45b17cad7&attribute=card_status:needs_card', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=325b9549-80fa-4dd0-9cf8-f0538cbebb18,e2b4a441-21b5-4d03-816b-09d45b17cad7,72f8ae88-58c9-40b4-863a-1c7bc6549a8b,52c10f07-6653-470d-9fee-14b0bb111c2a,d309898b-3925-494f-a30c-689222d3fcce,dbacb5dc-c8a3-439d-b407-13ffd570b9ef,27400130-8127-4f54-b14f-e26f20ecae14,14e83edc-5a54-44f5-816e-c96c61b5d911,9c183088-e498-4183-af41-b29bd32d94b6,66c88197-8281-4eb4-ae2e-4a89ae8419ed,1018b255-0889-492c-b5dd-31a50cb3db4d,5d99a60e-126e-4c40-b5ce-439f920de090,9a0e7727-b011-458f-832a-61108b2fe381,70589012-899c-401d-85a1-13fabce26aab,e5631d3e-70c3-4083-ac17-46f9467c6dd5,e447d5bb-8d42-4be4-b91d-b8d185cf81a6,18b3841b-b5b1-4971-93d0-d36ac20c4565,fee237ef-75e8-4ada-b15f-6d1a92633f33,16c58ef5-3b19-4ec2-ba9c-aefac3d08a66,7a663f5e-2619-4a2d-a7df-7250263f47d2,e2b4a441-21b5-4d03-816b-09d45b17cad7&attribute=card_status:needs_card', ]); expect(papaparseMock).toBeCalledWith([fixtures.child1CsvEntry, fixtures.child2CsvEntry], { header: true, @@ -290,6 +292,7 @@ describe('components/DownloadClientData', () => { it('submits if card status is not entered', async () => { fetch.mockOnce(JSON.stringify(fixtures.sampleTeamAssignment)); fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); + fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); fetch.mockOnce(JSON.stringify([fixtures.mother, fixtures.child1, fixtures.child2])); const queryClient = new QueryClient(); @@ -329,7 +332,8 @@ describe('components/DownloadClientData', () => { expect(fetch.mock.calls.map((res) => res[0])).toEqual([ 'https://unicef-tunisia-stage.smartregister.org/opensrp/security/authenticate', 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7?is_jurisdiction=true', - 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=e2b4a441-21b5-4d03-816b-09d45b17cad7', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=325b9549-80fa-4dd0-9cf8-f0538cbebb18,e2b4a441-21b5-4d03-816b-09d45b17cad7,72f8ae88-58c9-40b4-863a-1c7bc6549a8b,52c10f07-6653-470d-9fee-14b0bb111c2a,d309898b-3925-494f-a30c-689222d3fcce,dbacb5dc-c8a3-439d-b407-13ffd570b9ef,27400130-8127-4f54-b14f-e26f20ecae14,14e83edc-5a54-44f5-816e-c96c61b5d911,9c183088-e498-4183-af41-b29bd32d94b6,66c88197-8281-4eb4-ae2e-4a89ae8419ed,1018b255-0889-492c-b5dd-31a50cb3db4d,5d99a60e-126e-4c40-b5ce-439f920de090,9a0e7727-b011-458f-832a-61108b2fe381,70589012-899c-401d-85a1-13fabce26aab,e5631d3e-70c3-4083-ac17-46f9467c6dd5,e447d5bb-8d42-4be4-b91d-b8d185cf81a6,18b3841b-b5b1-4971-93d0-d36ac20c4565,fee237ef-75e8-4ada-b15f-6d1a92633f33,16c58ef5-3b19-4ec2-ba9c-aefac3d08a66,7a663f5e-2619-4a2d-a7df-7250263f47d2,e2b4a441-21b5-4d03-816b-09d45b17cad7', ]); expect(papaparseMock).toBeCalledWith([fixtures.child1CsvEntry, fixtures.child2CsvEntry], { header: true, @@ -339,6 +343,7 @@ describe('components/DownloadClientData', () => { it('uses the default location id if location not selected', async () => { fetch.mockOnce(JSON.stringify(fixtures.sampleTeamAssignment)); fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); + fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); fetch.mockOnce(JSON.stringify([fixtures.mother, fixtures.child1, fixtures.child2])); const queryClient = new QueryClient(); @@ -377,7 +382,8 @@ describe('components/DownloadClientData', () => { expect(fetch.mock.calls.map((res) => res[0])).toEqual([ 'https://unicef-tunisia-stage.smartregister.org/opensrp/security/authenticate', 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7?is_jurisdiction=true', - 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=e2b4a441-21b5-4d03-816b-09d45b17cad7&attribute=card_status:needs_card', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=325b9549-80fa-4dd0-9cf8-f0538cbebb18,e2b4a441-21b5-4d03-816b-09d45b17cad7,72f8ae88-58c9-40b4-863a-1c7bc6549a8b,52c10f07-6653-470d-9fee-14b0bb111c2a,d309898b-3925-494f-a30c-689222d3fcce,dbacb5dc-c8a3-439d-b407-13ffd570b9ef,27400130-8127-4f54-b14f-e26f20ecae14,14e83edc-5a54-44f5-816e-c96c61b5d911,9c183088-e498-4183-af41-b29bd32d94b6,66c88197-8281-4eb4-ae2e-4a89ae8419ed,1018b255-0889-492c-b5dd-31a50cb3db4d,5d99a60e-126e-4c40-b5ce-439f920de090,9a0e7727-b011-458f-832a-61108b2fe381,70589012-899c-401d-85a1-13fabce26aab,e5631d3e-70c3-4083-ac17-46f9467c6dd5,e447d5bb-8d42-4be4-b91d-b8d185cf81a6,18b3841b-b5b1-4971-93d0-d36ac20c4565,fee237ef-75e8-4ada-b15f-6d1a92633f33,16c58ef5-3b19-4ec2-ba9c-aefac3d08a66,7a663f5e-2619-4a2d-a7df-7250263f47d2,e2b4a441-21b5-4d03-816b-09d45b17cad7&attribute=card_status:needs_card', ]); expect(papaparseMock).toBeCalledWith([fixtures.child1CsvEntry, fixtures.child2CsvEntry], { header: true, @@ -386,8 +392,7 @@ describe('components/DownloadClientData', () => { it('handles fetch error when fetching user data - team assignments', async () => { fetch.mockRejectOnce(() => Promise.reject('API is down')); - fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); - fetch.mockOnce(JSON.stringify([fixtures.mother, fixtures.child1, fixtures.child2])); + const notificationErrorMock = jest.spyOn(notifications, 'sendErrorNotification'); // turn retries off - makes fetch fail on first try @@ -422,7 +427,7 @@ describe('components/DownloadClientData', () => { it('handles fetch error when fetching user location hierarchy', async () => { fetch.mockOnce(JSON.stringify(fixtures.sampleTeamAssignment)); fetch.mockRejectOnce(() => Promise.reject('API is down')); - fetch.mockOnce(JSON.stringify([fixtures.mother, fixtures.child1, fixtures.child2])); + const notificationErrorMock = jest.spyOn(notifications, 'sendErrorNotification'); // turn retries off - makes fetch fail on first try diff --git a/packages/card-support/src/components/DownloadClientData/tests/utils.test.tsx b/packages/card-support/src/components/DownloadClientData/tests/utils.test.tsx index 17cbdce30..ab997d9d1 100644 --- a/packages/card-support/src/components/DownloadClientData/tests/utils.test.tsx +++ b/packages/card-support/src/components/DownloadClientData/tests/utils.test.tsx @@ -16,8 +16,10 @@ import { act } from 'react-dom/test-utils'; import flushPromises from 'flush-promises'; import * as notifications from '@opensrp/notifications'; import lang from '../../../lang'; +import * as functions from '../utils'; /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/camelcase */ +/* eslint-disable @typescript-eslint/no-empty-function */ jest.mock('@opensrp/notifications', () => ({ __esModule: true, @@ -145,6 +147,7 @@ describe('components/DownloadClientData/utils/submitForm', () => { const setSubmittingMock = jest.fn(); it('submits the form correctly', async () => { + fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); fetch.mockResponse(JSON.stringify([fixtures.mother, fixtures.child1, fixtures.child2])); submitForm( @@ -154,23 +157,16 @@ describe('components/DownloadClientData/utils/submitForm', () => { OpenSRPService, fixtures.locations, setSubmittingMock - ); + ).catch(() => {}); await act(async () => { await flushPromises(); }); expect(setSubmittingMock.mock.calls[0][0]).toEqual(true); - expect(fetch.mock.calls[0]).toEqual([ - `https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=${clientLocation}&attribute=card_status:${cardStatus}`, - { - headers: { - accept: 'application/json', - authorization: 'Bearer hunter2', - 'content-type': 'application/json;charset=UTF-8', - }, - method: 'GET', - }, + expect(fetch.mock.calls.map((res) => res[0])).toEqual([ + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=325b9549-80fa-4dd0-9cf8-f0538cbebb18,e2b4a441-21b5-4d03-816b-09d45b17cad7,72f8ae88-58c9-40b4-863a-1c7bc6549a8b,52c10f07-6653-470d-9fee-14b0bb111c2a,d309898b-3925-494f-a30c-689222d3fcce,dbacb5dc-c8a3-439d-b407-13ffd570b9ef,27400130-8127-4f54-b14f-e26f20ecae14,14e83edc-5a54-44f5-816e-c96c61b5d911,9c183088-e498-4183-af41-b29bd32d94b6,66c88197-8281-4eb4-ae2e-4a89ae8419ed,1018b255-0889-492c-b5dd-31a50cb3db4d,5d99a60e-126e-4c40-b5ce-439f920de090,9a0e7727-b011-458f-832a-61108b2fe381,70589012-899c-401d-85a1-13fabce26aab,e5631d3e-70c3-4083-ac17-46f9467c6dd5,e447d5bb-8d42-4be4-b91d-b8d185cf81a6,18b3841b-b5b1-4971-93d0-d36ac20c4565,fee237ef-75e8-4ada-b15f-6d1a92633f33,16c58ef5-3b19-4ec2-ba9c-aefac3d08a66,7a663f5e-2619-4a2d-a7df-7250263f47d2,e2b4a441-21b5-4d03-816b-09d45b17cad7&attribute=card_status:needs_card', ]); expect(setSubmittingMock.mock.calls[1][0]).toEqual(false); @@ -183,8 +179,63 @@ describe('components/DownloadClientData/utils/submitForm', () => { ); }); + it('handles error if fetching Nested Location Ids fails', async () => { + fetch.mockReject(() => Promise.reject('API is down')); + fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); + + const notificationErrorMock = jest.spyOn(notifications, 'sendErrorNotification'); + + submitForm( + values, + accessToken, + opensrpBaseURL, + OpenSRPService, + fixtures.locations, + setSubmittingMock + ).catch(() => {}); + + await act(async () => { + await flushPromises(); + }); + expect(setSubmittingMock.mock.calls[0][0]).toEqual(true); + expect(fetch.mock.calls.map((res) => res[0])).toEqual([ + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=325b9549-80fa-4dd0-9cf8-f0538cbebb18,e2b4a441-21b5-4d03-816b-09d45b17cad7,72f8ae88-58c9-40b4-863a-1c7bc6549a8b,52c10f07-6653-470d-9fee-14b0bb111c2a,d309898b-3925-494f-a30c-689222d3fcce,dbacb5dc-c8a3-439d-b407-13ffd570b9ef,27400130-8127-4f54-b14f-e26f20ecae14,14e83edc-5a54-44f5-816e-c96c61b5d911,9c183088-e498-4183-af41-b29bd32d94b6,66c88197-8281-4eb4-ae2e-4a89ae8419ed,1018b255-0889-492c-b5dd-31a50cb3db4d,5d99a60e-126e-4c40-b5ce-439f920de090,9a0e7727-b011-458f-832a-61108b2fe381,70589012-899c-401d-85a1-13fabce26aab,e5631d3e-70c3-4083-ac17-46f9467c6dd5,e447d5bb-8d42-4be4-b91d-b8d185cf81a6,18b3841b-b5b1-4971-93d0-d36ac20c4565,fee237ef-75e8-4ada-b15f-6d1a92633f33,16c58ef5-3b19-4ec2-ba9c-aefac3d08a66,7a663f5e-2619-4a2d-a7df-7250263f47d2,e2b4a441-21b5-4d03-816b-09d45b17cad7&attribute=card_status:needs_card', + ]); + expect(setSubmittingMock.mock.calls[1][0]).toEqual(false); + expect(papaparseMock).not.toHaveBeenCalled(); + expect(notificationErrorMock).toHaveBeenCalledWith(lang.ERROR_OCCURRED); + }); + + it('handles error if submit form fails', async () => { + fetch.mockReject(() => Promise.reject('API is down')); + fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); + + const mockRejectFn = jest.fn(); + jest.spyOn(functions, 'submitForm').mockRejectedValueOnce(() => Promise.reject('API is down')); + + submitForm( + values, + accessToken, + opensrpBaseURL, + OpenSRPService, + fixtures.locations, + setSubmittingMock + ).catch(() => { + mockRejectFn(); + }); + + await act(async () => { + await flushPromises(); + }); + + expect(mockRejectFn).toHaveBeenCalled(); + }); + it('handles error if submission fails', async () => { + fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); fetch.mockReject(() => Promise.reject('API is down')); + const notificationErrorMock = jest.spyOn(notifications, 'sendErrorNotification'); submitForm( @@ -194,21 +245,15 @@ describe('components/DownloadClientData/utils/submitForm', () => { OpenSRPService, fixtures.locations, setSubmittingMock - ); + ).catch(() => {}); + await act(async () => { await flushPromises(); }); expect(setSubmittingMock.mock.calls[0][0]).toEqual(true); - expect(fetch.mock.calls[0]).toEqual([ - `https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=${clientLocation}&attribute=card_status:${cardStatus}`, - { - headers: { - accept: 'application/json', - authorization: 'Bearer hunter2', - 'content-type': 'application/json;charset=UTF-8', - }, - method: 'GET', - }, + expect(fetch.mock.calls.map((res) => res[0])).toEqual([ + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=325b9549-80fa-4dd0-9cf8-f0538cbebb18,e2b4a441-21b5-4d03-816b-09d45b17cad7,72f8ae88-58c9-40b4-863a-1c7bc6549a8b,52c10f07-6653-470d-9fee-14b0bb111c2a,d309898b-3925-494f-a30c-689222d3fcce,dbacb5dc-c8a3-439d-b407-13ffd570b9ef,27400130-8127-4f54-b14f-e26f20ecae14,14e83edc-5a54-44f5-816e-c96c61b5d911,9c183088-e498-4183-af41-b29bd32d94b6,66c88197-8281-4eb4-ae2e-4a89ae8419ed,1018b255-0889-492c-b5dd-31a50cb3db4d,5d99a60e-126e-4c40-b5ce-439f920de090,9a0e7727-b011-458f-832a-61108b2fe381,70589012-899c-401d-85a1-13fabce26aab,e5631d3e-70c3-4083-ac17-46f9467c6dd5,e447d5bb-8d42-4be4-b91d-b8d185cf81a6,18b3841b-b5b1-4971-93d0-d36ac20c4565,fee237ef-75e8-4ada-b15f-6d1a92633f33,16c58ef5-3b19-4ec2-ba9c-aefac3d08a66,7a663f5e-2619-4a2d-a7df-7250263f47d2,e2b4a441-21b5-4d03-816b-09d45b17cad7&attribute=card_status:needs_card', ]); expect(setSubmittingMock.mock.calls[1][0]).toEqual(false); expect(papaparseMock).not.toHaveBeenCalled(); @@ -216,6 +261,7 @@ describe('components/DownloadClientData/utils/submitForm', () => { }); it('calls API correctly if card status is empty', async () => { + fetch.mockOnce(JSON.stringify(fixtures.locationHierarchy)); fetch.mockResponse(JSON.stringify([fixtures.mother, fixtures.child1, fixtures.child2])); submitForm( @@ -228,21 +274,15 @@ describe('components/DownloadClientData/utils/submitForm', () => { OpenSRPService, fixtures.locations, setSubmittingMock - ); + ).catch(() => {}); + await act(async () => { await flushPromises(); }); expect(setSubmittingMock.mock.calls[0][0]).toEqual(true); - expect(fetch.mock.calls[0]).toEqual([ - `https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=${clientLocation}`, - { - headers: { - accept: 'application/json', - authorization: 'Bearer hunter2', - 'content-type': 'application/json;charset=UTF-8', - }, - method: 'GET', - }, + expect(fetch.mock.calls.map((res) => res[0])).toEqual([ + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/location/hierarchy/e2b4a441-21b5-4d03-816b-09d45b17cad7', + 'https://unicef-tunisia-stage.smartregister.org/opensrp/rest/client/search?locationIds=325b9549-80fa-4dd0-9cf8-f0538cbebb18,e2b4a441-21b5-4d03-816b-09d45b17cad7,72f8ae88-58c9-40b4-863a-1c7bc6549a8b,52c10f07-6653-470d-9fee-14b0bb111c2a,d309898b-3925-494f-a30c-689222d3fcce,dbacb5dc-c8a3-439d-b407-13ffd570b9ef,27400130-8127-4f54-b14f-e26f20ecae14,14e83edc-5a54-44f5-816e-c96c61b5d911,9c183088-e498-4183-af41-b29bd32d94b6,66c88197-8281-4eb4-ae2e-4a89ae8419ed,1018b255-0889-492c-b5dd-31a50cb3db4d,5d99a60e-126e-4c40-b5ce-439f920de090,9a0e7727-b011-458f-832a-61108b2fe381,70589012-899c-401d-85a1-13fabce26aab,e5631d3e-70c3-4083-ac17-46f9467c6dd5,e447d5bb-8d42-4be4-b91d-b8d185cf81a6,18b3841b-b5b1-4971-93d0-d36ac20c4565,fee237ef-75e8-4ada-b15f-6d1a92633f33,16c58ef5-3b19-4ec2-ba9c-aefac3d08a66,7a663f5e-2619-4a2d-a7df-7250263f47d2,e2b4a441-21b5-4d03-816b-09d45b17cad7', ]); expect(setSubmittingMock.mock.calls[1][0]).toEqual(false); expect(papaparseMock).toBeCalledWith([fixtures.child1CsvEntry, fixtures.child2CsvEntry], { @@ -262,7 +302,8 @@ describe('components/DownloadClientData/utils/submitForm', () => { OpenSRPService, fixtures.locations, setSubmittingMock - ); + ).catch(() => {}); + await act(async () => { await flushPromises(); }); @@ -285,7 +326,7 @@ describe('components/DownloadClientData/utils/submitForm', () => { OpenSRPService, fixtures.locations, setSubmittingMock - ); + ).catch(() => {}); await act(async () => { await flushPromises(); @@ -298,6 +339,7 @@ describe('components/DownloadClientData/utils/submitForm', () => { it('filters correctly if registration date does not meet range', async () => { fetch.mockResponse(JSON.stringify([fixtures.mother, fixtures.child1, fixtures.child2])); + submitForm( { ...values, @@ -308,7 +350,7 @@ describe('components/DownloadClientData/utils/submitForm', () => { OpenSRPService, fixtures.locations, setSubmittingMock - ); + ).catch(() => {}); await act(async () => { await flushPromises(); @@ -332,7 +374,8 @@ describe('components/DownloadClientData/utils/submitForm', () => { OpenSRPService, fixtures.locations, setSubmittingMock - ); + ).catch(() => {}); + await act(async () => { await flushPromises(); }); @@ -354,7 +397,8 @@ describe('components/DownloadClientData/utils/submitForm', () => { OpenSRPService, fixtures.locations, setSubmittingMock - ); + ).catch(() => {}); + await act(async () => { await flushPromises(); }); diff --git a/packages/card-support/src/components/DownloadClientData/utils.tsx b/packages/card-support/src/components/DownloadClientData/utils.tsx index b03c7d326..e71c6ad5f 100644 --- a/packages/card-support/src/components/DownloadClientData/utils.tsx +++ b/packages/card-support/src/components/DownloadClientData/utils.tsx @@ -2,10 +2,14 @@ import Papaparse from 'papaparse'; import { OpenSRPService } from '@opensrp/server-service'; import { DownloadClientDataFormFields } from '../DownloadClientData'; import { Dispatch, SetStateAction } from 'react'; -import { OPENSRP_URL_CLIENT_SEARCH, APPLICATION_CSV } from '../../constants'; +import { + OPENSRP_URL_CLIENT_SEARCH, + APPLICATION_CSV, + OPENSRP_URL_LOCATION_HIERARCHY, +} from '../../constants'; import { Client } from '../../ducks/clients'; import { downloadFile } from '../../helpers/utils'; -import { ParsedHierarchyNode } from '@opensrp/location-management'; +import { ParsedHierarchyNode, RawOpenSRPHierarchy } from '@opensrp/location-management'; import { sendErrorNotification } from '@opensrp/notifications'; import { Dictionary } from '@onaio/utils'; import lang, { Lang } from '../../lang'; @@ -55,7 +59,7 @@ export const handleCardOrderDateChange = ( * @param setSubmitting - method to set form `isSubmitting` status * @param langObj - tthe lang object */ -export const submitForm = ( +export const submitForm = async ( values: DownloadClientDataFormFields, accessToken: string, opensrpBaseURL: string, @@ -63,7 +67,7 @@ export const submitForm = ( locations: ParsedHierarchyNode[], setSubmitting: (isSubmitting: boolean) => void, langObj: Lang = lang -): void => { +): Promise => { const { clientLocation, cardStatus, cardOrderDate } = values; if (!clientLocation) { @@ -71,12 +75,38 @@ export const submitForm = ( } setSubmitting(true); - const startDate = cardOrderDate[0]; - const endDate = cardOrderDate[1]; - const endPoint = `${OPENSRP_URL_CLIENT_SEARCH}`; - const serve = new serviceClass(accessToken, opensrpBaseURL, endPoint); + + // get location id's of all nested children of a selected jurisdiction + const fetchNestedLocationIds = async (clientLocationId: string) => { + const serve = new serviceClass(accessToken, opensrpBaseURL, OPENSRP_URL_LOCATION_HIERARCHY); + try { + const res: RawOpenSRPHierarchy = await serve.read(clientLocationId); + // parentChildren is an object with keys as parent location ids + // and values as arrays of children location ids + // each children location with children itself has an entry in the object + const nestedLocationIds = Object.values(res.locationsHierarchy.parentChildren); + const flatNestedLocationIds = nestedLocationIds.flat(); + // all keys (nested children location ids) are present as values of the primary location id values (clientLocationId) + // except the primary location id itself - thus the re-add + const flatNestedLocationIdsWithClientLocationId = [ + ...flatNestedLocationIds, + clientLocationId, + ]; + const stringifiedFlatNestedLocationIdsWithClientLocationId = flatNestedLocationIdsWithClientLocationId.join( + ',' + ); + return stringifiedFlatNestedLocationIdsWithClientLocationId; + } catch (_) { + sendErrorNotification(langObj.ERROR_OCCURRED); + return ''; + } + }; + + const nestedLocationIds = await fetchNestedLocationIds(clientLocation); + + // add all nested location ids (children of selected location) to the search params let params: Dictionary = { - locationIds: clientLocation, + locationIds: nestedLocationIds, }; if (cardStatus) { @@ -86,6 +116,10 @@ export const submitForm = ( }; } + const startDate = cardOrderDate[0]; + const endDate = cardOrderDate[1]; + const serve = new serviceClass(accessToken, opensrpBaseURL, OPENSRP_URL_CLIENT_SEARCH); + serve .list(params) .then((clients: Client[]) => {