From 7158db2f5e9a0c5e1a7ab85abd7e9d559b9817a0 Mon Sep 17 00:00:00 2001 From: Tony Valle <79843014+superskip@users.noreply.github.com> Date: Thu, 26 Oct 2023 21:41:28 +0200 Subject: [PATCH] refactor: [TECH-1657] standardize format of redux orgunits (#3436) --- .../WidgetsForEnrollmentAddEventPage.feature | 5 +- .../WidgetsForEnrollmentDashboard.feature | 5 +- .../WidgetsForEnrollmentEditEvent.feature | 5 +- .../rules-engine/src/rulesEngine.types.js | 4 +- .../EnrollmentRegistrationEntry.container.js | 4 +- .../NewEventDataEntryWrapper.component.js | 4 +- .../TeiRegistrationEntry.component.js | 16 +++--- ...rackedEntityInstanceDataEntry.component.js | 8 +-- .../LockedSelector/LockedSelector.actions.js | 3 +- .../LockedSelector/LockedSelector.epics.js | 32 +++++------- .../OrgUnitFetcher/OrgUnitFetcher.actions.js | 3 +- .../OrgUnitFetcher.component.js | 8 +-- .../OrgUnitFetcher/OrgUnitFetcher.epics.js | 19 +++---- .../EnrollmentPageDefault.container.js | 4 +- .../ProgramStageSelector.container.js | 4 +- .../RegistrationDataEntry.component.js | 8 +-- ...ataEntryTrackedEntityInstance.component.js | 4 +- .../EventDetailsSection.component.js | 4 +- .../Pages/ViewEvent/epics/viewEvent.epics.js | 47 +++++++++--------- .../PossibleDuplicatesDialog/useDuplicates.js | 4 +- .../actions/QuickSelector.actions.js | 4 -- .../SingleLockedSelect.component.js | 8 ++- .../OrgUnitFetcher.component.js | 17 ++----- .../WidgetEventEdit.container.js | 14 ++++-- .../dataQueries/useOrganisationUnit.js | 5 +- src/core_modules/capture-core/hooks/index.js | 1 - .../capture-core/hooks/useCurrentOrgUnitId.js | 5 ++ .../hooks/useCurrentOrgUnitInfo.js | 19 ------- .../hooks/useRulesEngineOrgUnit.js | 33 ------------- .../coreOrgUnit/coreOrgUnit.actions.js | 14 ++++++ .../coreOrgUnit/coreOrgUnit.types.js | 20 ++++++++ .../coreOrgUnit/fetchCoreOrgUnit.js} | 12 +++-- .../coreOrgUnit/getCoreOrgUnit.epics.js | 29 +++++++++++ .../metadataRetrieval/coreOrgUnit/index.js | 5 ++ .../coreOrgUnit/useCoreOrgUnit.js | 49 +++++++++++++++++++ .../organisationUnits.reducerDescription.js | 24 ++------- src/epics/trackerCapture.epics.js | 4 ++ 37 files changed, 254 insertions(+), 200 deletions(-) create mode 100644 src/core_modules/capture-core/hooks/useCurrentOrgUnitId.js delete mode 100644 src/core_modules/capture-core/hooks/useCurrentOrgUnitInfo.js delete mode 100644 src/core_modules/capture-core/hooks/useRulesEngineOrgUnit.js create mode 100644 src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/coreOrgUnit.actions.js create mode 100644 src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/coreOrgUnit.types.js rename src/core_modules/capture-core/{rules/getRulesEngineOrgUnit.js => metadataRetrieval/coreOrgUnit/fetchCoreOrgUnit.js} (53%) create mode 100644 src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/getCoreOrgUnit.epics.js create mode 100644 src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/index.js create mode 100644 src/core_modules/capture-core/metadataRetrieval/coreOrgUnit/useCoreOrgUnit.js diff --git a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentAddEventPage.feature b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentAddEventPage.feature index f5db1e30e2..bcdfb2ff8a 100644 --- a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentAddEventPage.feature +++ b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentAddEventPage.feature @@ -16,13 +16,16 @@ Feature: The user interacts with the widgets on the enrollment add event page Scenario: User can close the Enrollment Widget Given you land on the enrollment add event page by having typed #/enrollmentEventNew?programId=IpHINAT79UW&orgUnitId=DiszpKrYNg8&teiId=EaOyKGOIGRp&enrollmentId=wBU0RAsYjKE&stageId=A03MvHHogjR + And the enrollment widget should be opened When you click the enrollment widget toggle open close button Then the enrollment widget should be closed Scenario: User can close and reopen the Enrollment Widget Given you land on the enrollment add event page by having typed #/enrollmentEventNew?programId=IpHINAT79UW&orgUnitId=DiszpKrYNg8&teiId=EaOyKGOIGRp&enrollmentId=wBU0RAsYjKE&stageId=A03MvHHogjR + And the enrollment widget should be opened + When you click the enrollment widget toggle open close button + Then the enrollment widget should be closed When you click the enrollment widget toggle open close button - And you click the enrollment widget toggle open close button Then the enrollment widget should be opened Scenario: User can see the enrollment details diff --git a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentDashboard.feature b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentDashboard.feature index c71f98ef99..89af2a7ea9 100644 --- a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentDashboard.feature +++ b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentDashboard.feature @@ -48,13 +48,16 @@ Feature: The user interacts with the widgets on the enrollment dashboard Scenario: User can close the Enrollment Widget Given you land on the enrollment dashboard page by having typed #/enrollment?enrollmentId=wBU0RAsYjKE + And the enrollment widget should be opened When you click the enrollment widget toggle open close button Then the enrollment widget should be closed Scenario: User can close and reopen the Enrollment Widget Given you land on the enrollment dashboard page by having typed #/enrollment?enrollmentId=wBU0RAsYjKE + And the enrollment widget should be opened + When you click the enrollment widget toggle open close button + Then the enrollment widget should be closed When you click the enrollment widget toggle open close button - And you click the enrollment widget toggle open close button Then the enrollment widget should be opened Scenario: User can see the enrollment details diff --git a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentEditEvent.feature b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentEditEvent.feature index 1f551735a3..c3add0d727 100644 --- a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentEditEvent.feature +++ b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentEditEvent.feature @@ -16,13 +16,16 @@ Feature: The user interacts with the widgets on the enrollment edit event Scenario: User can close the Enrollment Widget Given you land on the enrollment edit event page by having typed /#/enrollmentEventEdit?eventId=XGLkLlOXgmE&orgUnitId=DiszpKrYNg8 + And the enrollment widget should be opened When you click the enrollment widget toggle open close button Then the enrollment widget should be closed Scenario: User can close and reopen the Enrollment Widget Given you land on the enrollment edit event page by having typed /#/enrollmentEventEdit?eventId=XGLkLlOXgmE&orgUnitId=DiszpKrYNg8 + And the enrollment widget should be opened + When you click the enrollment widget toggle open close button + Then the enrollment widget should be closed When you click the enrollment widget toggle open close button - And you click the enrollment widget toggle open close button Then the enrollment widget should be opened Scenario: User can see the enrollment details diff --git a/packages/rules-engine/src/rulesEngine.types.js b/packages/rules-engine/src/rulesEngine.types.js index decb2154a0..3f1d422303 100644 --- a/packages/rules-engine/src/rulesEngine.types.js +++ b/packages/rules-engine/src/rulesEngine.types.js @@ -141,12 +141,12 @@ export type OrgUnitGroup = $ReadOnly<{| code: string, |}>; -export type OrgUnit = $ReadOnly<{| +export type OrgUnit = $ReadOnly<{ id: string, name: string, code: string, groups: Array, -|}>; +}>; export type RulesEngineInput = {| programRulesContainer: ProgramRulesContainer, diff --git a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.container.js b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.container.js index e16304cf87..2da9aba5b1 100644 --- a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.container.js +++ b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.container.js @@ -5,7 +5,7 @@ import { useSelector } from 'react-redux'; import { EnrollmentRegistrationEntryComponent } from './EnrollmentRegistrationEntry.component'; import type { OwnProps } from './EnrollmentRegistrationEntry.types'; import { useLifecycle } from './hooks'; -import { useRulesEngineOrgUnit } from '../../../hooks'; +import { useCoreOrgUnit } from '../../../metadataRetrieval/coreOrgUnit'; import { dataEntryHasChanges } from '../../DataEntry/common/dataEntryHasChanges'; import { useBuildEnrollmentPayload, @@ -21,7 +21,7 @@ export const EnrollmentRegistrationEntry: ComponentType = ({ onSave, ...passOnProps }) => { - const { orgUnit, error } = useRulesEngineOrgUnit(orgUnitId); + const { orgUnit, error } = useCoreOrgUnit(orgUnitId); const { ready, skipDuplicateCheck, diff --git a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/NewEventDataEntryWrapper.component.js b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/NewEventDataEntryWrapper.component.js index 97503017e5..14e74ad609 100644 --- a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/NewEventDataEntryWrapper.component.js +++ b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/NewEventDataEntryWrapper.component.js @@ -7,7 +7,7 @@ import { DataEntry } from './DataEntry/DataEntry.container'; import { EventsList } from './RecentlyAddedEventsList/RecentlyAddedEventsList.container'; import { useScopeTitleText } from '../../../../hooks/useScopeTitleText'; import { useCurrentProgramInfo } from '../../../../hooks/useCurrentProgramInfo'; -import { useRulesEngineOrgUnit } from '../../../../hooks/useRulesEngineOrgUnit'; +import { useCoreOrgUnit } from '../../../../metadataRetrieval/coreOrgUnit'; import { useLocationQuery } from '../../../../utils/routing'; import { useRulesEngine } from './useRulesEngine'; import type { PlainProps } from './NewEventDataEntryWrapper.types'; @@ -48,7 +48,7 @@ const NewEventDataEntryWrapperPlain = ({ }: PlainProps) => { const { id: programId } = useCurrentProgramInfo(); const orgUnitId = useLocationQuery().orgUnitId; - const { orgUnit, error } = useRulesEngineOrgUnit(orgUnitId); + const { orgUnit, error } = useCoreOrgUnit(orgUnitId); const rulesReady = useRulesEngine({ programId, orgUnit, formFoundation }); const titleText = useScopeTitleText(programId); diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.component.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.component.js index 1a8e11bd4c..7b61054364 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.component.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.component.js @@ -8,7 +8,8 @@ import { useHistory } from 'react-router-dom'; import { useScopeInfo } from '../../../hooks/useScopeInfo'; import { scopeTypes } from '../../../metaData'; import { TrackedEntityInstanceDataEntry } from '../TrackedEntityInstance'; -import { useCurrentOrgUnitInfo } from '../../../hooks/useCurrentOrgUnitInfo'; +import { useCurrentOrgUnitId } from '../../../hooks/useCurrentOrgUnitId'; +import { useCoreOrgUnit } from '../../../metadataRetrieval/coreOrgUnit'; import type { Props, PlainProps } from './TeiRegistrationEntry.types'; import { DiscardDialog } from '../../Dialogs/DiscardDialog.component'; import { withSaveHandler } from '../../DataEntry'; @@ -54,7 +55,9 @@ const TeiRegistrationEntryPlain = const [showWarning, setShowWarning] = useState(false); const { scopeType } = useScopeInfo(selectedScopeId); const { formId, formFoundation } = useMetadataForRegistrationForm({ selectedScopeId }); - const orgUnit = useCurrentOrgUnitInfo(); + const orgUnitId = useCurrentOrgUnitId(); + const { orgUnit } = useCoreOrgUnit(orgUnitId); // Tony: [DHIS2-15814] Change this to new hook + const orgUnitName = orgUnit ? orgUnit.name : ''; const handleOnCancel = () => { if (!isUserInteractionInProgress) { @@ -68,9 +71,9 @@ const TeiRegistrationEntryPlain = const url = scopeType === scopeTypes.TRACKER_PROGRAM ? - buildUrlQueryString({ programId: selectedScopeId, orgUnitId: orgUnit.id }) + buildUrlQueryString({ programId: selectedScopeId, orgUnitId }) : - buildUrlQueryString({ orgUnitId: orgUnit.id }); + buildUrlQueryString({ orgUnitId }); return push(`/?${url}`); }; @@ -79,9 +82,8 @@ const TeiRegistrationEntryPlain = { scopeType === scopeTypes.TRACKED_ENTITY_TYPE && formId && <> - {/* $FlowFixMe */} - {translatedTextWithStylesForTei(trackedEntityName.toLowerCase(), orgUnit.name)} + {translatedTextWithStylesForTei(trackedEntityName.toLowerCase(), orgUnitName)} { } type PreTeiDataEntryProps = { - orgUnit: Object, + orgUnitId: string, trackedEntityTypeId: string, onUpdateField: Function, onStartAsyncUpdateField: Function, @@ -52,17 +52,17 @@ type PreTeiDataEntryProps = { export class PreTeiDataEntry extends React.Component { getValidationContext = () => { - const { orgUnit, onGetUnsavedAttributeValues, trackedEntityTypeId } = this.props; + const { orgUnitId, onGetUnsavedAttributeValues, trackedEntityTypeId } = this.props; return { trackedEntityTypeId, - orgUnitId: orgUnit.id, + orgUnitId, onGetUnsavedAttributeValues, }; } render() { const { - orgUnit, + orgUnitId, trackedEntityTypeId, onUpdateField, onStartAsyncUpdateField, diff --git a/src/core_modules/capture-core/components/LockedSelector/LockedSelector.actions.js b/src/core_modules/capture-core/components/LockedSelector/LockedSelector.actions.js index a91ec8b952..d7e395e289 100644 --- a/src/core_modules/capture-core/components/LockedSelector/LockedSelector.actions.js +++ b/src/core_modules/capture-core/components/LockedSelector/LockedSelector.actions.js @@ -1,5 +1,6 @@ // @flow import { actionCreator } from '../../actions/actions.utils'; +import type { CoreOrgUnit } from '../../metadataRetrieval/coreOrgUnit'; export const lockedSelectorActionTypes = { LOADING_START: 'LockedSelector.Loading', @@ -17,7 +18,7 @@ export const lockedSelectorActionTypes = { export const updateSelectionsFromUrl = (data: Object) => actionCreator(lockedSelectorActionTypes.FROM_URL_UPDATE)(data); export const validSelectionsFromUrl = () => actionCreator(lockedSelectorActionTypes.FROM_URL_CURRENT_SELECTIONS_VALID)(); export const invalidSelectionsFromUrl = (error: string) => actionCreator(lockedSelectorActionTypes.FROM_URL_CURRENT_SELECTIONS_INVALID)({ error }); -export const setCurrentOrgUnitBasedOnUrl = (orgUnit: Object) => actionCreator(lockedSelectorActionTypes.FETCH_ORG_UNIT_SUCCESS)(orgUnit); +export const setCurrentOrgUnitBasedOnUrl = (orgUnit: CoreOrgUnit) => actionCreator(lockedSelectorActionTypes.FETCH_ORG_UNIT_SUCCESS)(orgUnit); export const startLoading = () => actionCreator(lockedSelectorActionTypes.LOADING_START)(); export const completeUrlUpdate = () => actionCreator(lockedSelectorActionTypes.FROM_URL_UPDATE_COMPLETE)(); export const errorRetrievingOrgUnitBasedOnUrl = (error: string) => actionCreator(lockedSelectorActionTypes.FETCH_ORG_UNIT_ERROR)({ error }); diff --git a/src/core_modules/capture-core/components/LockedSelector/LockedSelector.epics.js b/src/core_modules/capture-core/components/LockedSelector/LockedSelector.epics.js index ba5a8d7032..ad4329db43 100644 --- a/src/core_modules/capture-core/components/LockedSelector/LockedSelector.epics.js +++ b/src/core_modules/capture-core/components/LockedSelector/LockedSelector.epics.js @@ -1,8 +1,8 @@ // @flow import i18n from '@dhis2/d2-i18n'; import { ofType } from 'redux-observable'; -import { catchError, filter, flatMap, map, startWith, switchMap } from 'rxjs/operators'; -import { from, of } from 'rxjs'; +import { filter, map, concatMap } from 'rxjs/operators'; +import { of } from 'rxjs'; import { lockedSelectorActionTypes, invalidSelectionsFromUrl, @@ -16,32 +16,25 @@ import { import { programCollection } from '../../metaDataMemoryStores'; import { getLocationPathname, pageFetchesOrgUnitUsingTheOldWay } from '../../utils/url'; import { getLocationQuery } from '../../utils/routing'; +import { getCoreOrgUnit } from '../../metadataRetrieval/coreOrgUnit'; -const orgUnitsQuery = id => ({ resource: 'organisationUnits', id }); - -export const getOrgUnitDataBasedOnUrlUpdateEpic = ( - action$: InputObservable, - store: ReduxStore, - { querySingleResource }: ApiUtils) => +export const getOrgUnitDataBasedOnUrlUpdateEpic = (action$: InputObservable, store: ReduxStore) => action$.pipe( ofType(lockedSelectorActionTypes.FROM_URL_UPDATE), filter(action => action.payload.nextProps.orgUnitId), - switchMap((action) => { + concatMap((action) => { const { organisationUnits } = store.value; const { orgUnitId } = action.payload.nextProps; if (organisationUnits[orgUnitId]) { return of(completeUrlUpdate()); } - return from(querySingleResource(orgUnitsQuery(action.payload.nextProps.orgUnitId))) - .pipe( - flatMap(response => - of(setCurrentOrgUnitBasedOnUrl({ id: response.id, name: response.displayName, code: response.code }))), - catchError(() => - of(errorRetrievingOrgUnitBasedOnUrl(i18n.t('Could not get organisation unit')))), - startWith(startLoading()), - ); - }, - )); + return of(startLoading(), getCoreOrgUnit({ + orgUnitId, + onSuccess: setCurrentOrgUnitBasedOnUrl, + onError: () => errorRetrievingOrgUnitBasedOnUrl(i18n.t('Could not get organisation unit')), + })); + }), + ); export const setOrgUnitDataEmptyBasedOnUrlUpdateEpic = (action$: InputObservable) => action$.pipe( @@ -76,4 +69,3 @@ export const validateSelectionsBasedOnUrlUpdateEpic = (action$: InputObservable) return validSelectionsFromUrl(); })); - diff --git a/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.actions.js b/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.actions.js index 260ad0c4ae..806b384742 100644 --- a/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.actions.js +++ b/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.actions.js @@ -1,6 +1,7 @@ // @flow import { actionCreator } from '../../actions/actions.utils'; +import type { CoreOrgUnit } from '../../metadataRetrieval/coreOrgUnit'; export const actionTypes = { FETCH_ORG_UNIT: 'OrgUnitFetcher.FetchOrgUnit', @@ -11,6 +12,6 @@ export const actionTypes = { export const fetchOrgUnit = (orgUnitId: string) => actionCreator(actionTypes.FETCH_ORG_UNIT)({ orgUnitId }); -export const setCurrentOrgUnit = (orgUnit: Object) => actionCreator(actionTypes.FETCH_ORG_UNIT_SUCCESS)(orgUnit); +export const setCurrentOrgUnit = (orgUnit: CoreOrgUnit) => actionCreator(actionTypes.FETCH_ORG_UNIT_SUCCESS)(orgUnit); export const errorRetrievingOrgUnit = () => actionCreator(actionTypes.FETCH_ORG_UNIT_FAILURE)(); diff --git a/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.component.js b/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.component.js index 51f7bb0d70..199c96f6ce 100644 --- a/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.component.js +++ b/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.component.js @@ -6,13 +6,7 @@ import { fetchOrgUnit } from './OrgUnitFetcher.actions'; export const OrgUnitFetcher = (({ orgUnitId, children, error }: Object) => { const dispatch = useDispatch(); - const { orgUnit } = useSelector( - ({ - organisationUnits, - }) => ({ - orgUnit: organisationUnits[orgUnitId], - }), - ); + const orgUnit = useSelector(({ organisationUnits }) => organisationUnits[orgUnitId]); useEffect(() => { if (!orgUnit && orgUnitId) { diff --git a/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.epics.js b/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.epics.js index 1c36e942d1..f82ba69dc0 100644 --- a/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.epics.js +++ b/src/core_modules/capture-core/components/OrgUnitFetcher/OrgUnitFetcher.epics.js @@ -1,17 +1,14 @@ // @flow import { ofType } from 'redux-observable'; -import { catchError, map, switchMap } from 'rxjs/operators'; -import { from, of } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { getCoreOrgUnit } from '../../metadataRetrieval/coreOrgUnit'; import { actionTypes, setCurrentOrgUnit, errorRetrievingOrgUnit } from './OrgUnitFetcher.actions'; - -const orgUnitsQuery = id => ({ resource: `organisationUnits/${id}` }); - -export const orgUnitFetcherEpic = (action$: InputObservable, _: ReduxStore, { querySingleResource }: ApiUtils, -) => action$.pipe( +export const orgUnitFetcherEpic = (action$: InputObservable) => action$.pipe( ofType(actionTypes.FETCH_ORG_UNIT), - switchMap(({ payload: { orgUnitId } }) => from(querySingleResource(orgUnitsQuery(orgUnitId))) - .pipe(map(({ id, displayName: name }) => setCurrentOrgUnit({ id, name })))) - , - catchError(() => of(errorRetrievingOrgUnit())), + map(({ payload: { orgUnitId } }) => getCoreOrgUnit({ + orgUnitId, + onSuccess: orgUnit => setCurrentOrgUnit(orgUnit), + onError: errorRetrievingOrgUnit, + })), ); diff --git a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentPageDefault.container.js b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentPageDefault.container.js index d7f3ccdf85..9e37366cad 100644 --- a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentPageDefault.container.js +++ b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentPageDefault.container.js @@ -19,7 +19,7 @@ import { updateTeiDisplayName, } from '../EnrollmentPage.actions'; import { useTrackerProgram } from '../../../../hooks/useTrackerProgram'; -import { useRulesEngineOrgUnit } from '../../../../hooks/useRulesEngineOrgUnit'; +import { useCoreOrgUnit } from '../../../../metadataRetrieval/coreOrgUnit'; import { EnrollmentPageDefaultComponent } from './EnrollmentPageDefault.component'; import { useProgramMetadata, @@ -34,7 +34,7 @@ export const EnrollmentPageDefault = () => { const history = useHistory(); const dispatch = useDispatch(); const { enrollmentId, programId, teiId, orgUnitId } = useLocationQuery(); - const { orgUnit, error } = useRulesEngineOrgUnit(orgUnitId); + const { orgUnit, error } = useCoreOrgUnit(orgUnitId); const { onLinkedRecordClick } = useLinkedRecordClick(); const program = useTrackerProgram(programId); diff --git a/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/ProgramStageSelector/ProgramStageSelector.container.js b/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/ProgramStageSelector/ProgramStageSelector.container.js index 1bd16b7a80..d0356732ac 100644 --- a/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/ProgramStageSelector/ProgramStageSelector.container.js +++ b/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/ProgramStageSelector/ProgramStageSelector.container.js @@ -10,7 +10,7 @@ import { useCommonEnrollmentDomainData, useRuleEffects } from '../../common/Enro import type { Props } from './ProgramStageSelector.types'; import { useProgramFromIndexedDB } from '../../../../utils/cachedDataHooks/useProgramFromIndexedDB'; import { useLocationQuery, buildUrlQueryString } from '../../../../utils/routing'; -import { useRulesEngineOrgUnit } from '../../../../hooks/useRulesEngineOrgUnit'; +import { useCoreOrgUnit } from '../../../../metadataRetrieval/coreOrgUnit'; import { useTrackerProgram } from '../../../../hooks/useTrackerProgram'; @@ -24,7 +24,7 @@ export const ProgramStageSelector = ({ programId, orgUnitId, teiId, enrollmentId isError: programError, } = useProgramFromIndexedDB(programId); - const { orgUnit } = useRulesEngineOrgUnit(orgUnitId); + const { orgUnit } = useCoreOrgUnit(orgUnitId); const programRules = useTrackerProgram(programId); const ruleEffects = useRuleEffects({ diff --git a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.component.js b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.component.js index d5d956f29d..af18875d9d 100644 --- a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.component.js +++ b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.component.js @@ -15,7 +15,7 @@ import { ResultsPageSizeContext } from '../../shared-contexts'; import { navigateToEnrollmentOverview } from '../../../../actions/navigateToEnrollmentOverview/navigateToEnrollmentOverview.actions'; import { useLocationQuery } from '../../../../utils/routing'; import { EnrollmentRegistrationEntryWrapper } from '../EnrollmentRegistrationEntryWrapper.component'; -import { useCurrentOrgUnitInfo } from '../../../../hooks/useCurrentOrgUnitInfo'; +import { useCurrentOrgUnitId } from '../../../../hooks/useCurrentOrgUnitId'; const getStyles = ({ typography }) => ({ container: { @@ -97,7 +97,7 @@ const RegistrationDataEntryPlain = ({ const { resultsPageSize } = useContext(ResultsPageSizeContext); const { scopeType, programName, trackedEntityName } = useScopeInfo(selectedScopeId); const titleText = useScopeTitleText(selectedScopeId); - const { id: reduxOrgUnitId } = useCurrentOrgUnitInfo(); + const currentOrgUnitId = useCurrentOrgUnitId(); const handleRegistrationScopeSelection = (id) => { setScopeId(id); @@ -176,7 +176,7 @@ const RegistrationDataEntryPlain = ({ { - const { id: orgUnitId } = useCurrentOrgUnitInfo(); + const orgUnitId = useCurrentOrgUnitId(); const fieldOptions = { theme, fieldLabelMediaBasedClass: teiClasses.fieldLabelMediaBased }; const { trackedEntityType } = teiRegistrationMetadata || {}; const trackedEntityTypeNameLC = trackedEntityType.name.toLocaleLowerCase(); diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/EventDetailsSection/EventDetailsSection.component.js b/src/core_modules/capture-core/components/Pages/ViewEvent/EventDetailsSection/EventDetailsSection.component.js index 4416248dcf..31da7bdbd4 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/EventDetailsSection/EventDetailsSection.component.js +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/EventDetailsSection/EventDetailsSection.component.js @@ -11,7 +11,7 @@ import { ViewEventSectionHeader } from '../Section/ViewEventSectionHeader.compon import { EditEventDataEntry } from '../../../WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.container'; import { ViewEventDataEntry } from '../../../WidgetEventEdit/ViewEventDataEntry/ViewEventDataEntry.container'; import type { ProgramStage } from '../../../../metaData'; -import { useRulesEngineOrgUnit } from '../../../../hooks/useRulesEngineOrgUnit'; +import { useCoreOrgUnit } from '../../../../metadataRetrieval/coreOrgUnit'; import { NoticeBox } from '../../../NoticeBox'; const getStyles = () => ({ @@ -60,7 +60,7 @@ const EventDetailsSectionPlain = (props: Props) => { eventAccess, ...passOnProps } = props; const orgUnitId = useSelector(({ viewEventPage }) => viewEventPage.loadedValues?.orgUnit?.id); - const { orgUnit, error } = useRulesEngineOrgUnit(orgUnitId); + const { orgUnit, error } = useCoreOrgUnit(orgUnitId); if (error) { return error.errorComponent; diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/epics/viewEvent.epics.js b/src/core_modules/capture-core/components/Pages/ViewEvent/epics/viewEvent.epics.js index 91c84cced6..b39483080b 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/epics/viewEvent.epics.js +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/epics/viewEvent.epics.js @@ -4,8 +4,7 @@ import { ofType } from 'redux-observable'; import { map, switchMap } from 'rxjs/operators'; import i18n from '@dhis2/d2-i18n'; import { errorCreator } from 'capture-core-utils'; -import { getRulesEngineOrgUnit } from 'capture-core/rules/getRulesEngineOrgUnit'; -import { getAssociatedOrgUnitGroups } from 'capture-core/MetaDataStoreUtils/getAssociatedOrgUnitGroups'; +import { getCoreOrgUnit } from 'capture-core/metadataRetrieval/coreOrgUnit'; import { isSelectionsEqual } from '../../../App/isSelectionsEqual'; import { getErrorMessageAndDetails } from '../../../../utils/errors/getErrorMessageAndDetails'; @@ -39,18 +38,24 @@ export const getEventOpeningFromEventListEpic = ( action$.pipe( ofType(eventWorkingListsActionTypes.VIEW_EVENT_PAGE_OPEN), switchMap(({ payload: { eventId } }) => getEvent(eventId, absoluteApiPath, querySingleResource) - .then(eventContainer => - (eventContainer - ? Promise.all( - [eventContainer, getRulesEngineOrgUnit(eventContainer.event.orgUnitId, querySingleResource)], - ) - : [])) - .then(([eventContainer, orgUnit]) => { + .then((eventContainer) => { if (!eventContainer) { return openViewEventPageFailed( i18n.t('Event could not be loaded. Are you sure it exists?')); } - return startOpenEventForView(eventContainer, orgUnit); + return getCoreOrgUnit({ + orgUnitId: eventContainer.event.orgUnitId, + onSuccess: orgUnit => startOpenEventForView(eventContainer, orgUnit), + onError: (error) => { + const { message, details } = getErrorMessageAndDetails(error); + log.error( + errorCreator( + message || + i18n.t('Organisation unit could not be loaded'))(details)); + return openViewEventPageFailed( + i18n.t('Could not get organisation unit')); + }, + }); }) .catch((error) => { const { message, details } = getErrorMessageAndDetails(error); @@ -95,28 +100,22 @@ export const getEventFromUrlEpic = ( }); })); -export const getOrgUnitOnUrlUpdateEpic = (action$: InputObservable, _: ReduxStore, { querySingleResource }: ApiUtils) => +export const getOrgUnitOnUrlUpdateEpic = (action$: InputObservable) => action$.pipe( ofType(viewEventActionTypes.EVENT_FROM_URL_RETRIEVED), - switchMap((action) => { + map((action) => { const eventContainer = action.payload.eventContainer; - // change from organisationUnitGroups -> groups - return Promise.all( - [ - querySingleResource({ resource: `organisationUnits/${eventContainer.event.orgUnitId}` }), - getAssociatedOrgUnitGroups(eventContainer.event.orgUnitId), - ]) - .then(([orgUnit, groups]) => { - orgUnit.groups = groups; - return orgUnitRetrievedOnUrlUpdate(orgUnit, eventContainer); - }) - .catch((error) => { + return getCoreOrgUnit({ + orgUnitId: eventContainer.event.orgUnitId, + onSuccess: orgUnit => orgUnitRetrievedOnUrlUpdate(orgUnit, eventContainer), + onError: (error) => { const { message, details } = getErrorMessageAndDetails(error); log.error(errorCreator( message || i18n.t('Organisation unit could not be loaded'))(details)); return orgUnitCouldNotBeRetrievedOnUrlUpdate(eventContainer); - }); + }, + }); })); export const openViewPageLocationChangeEpic = (action$: InputObservable, _: ReduxStore, { history }: ApiUtils) => diff --git a/src/core_modules/capture-core/components/PossibleDuplicatesDialog/useDuplicates.js b/src/core_modules/capture-core/components/PossibleDuplicatesDialog/useDuplicates.js index 049dfa7a50..15f7035c2c 100644 --- a/src/core_modules/capture-core/components/PossibleDuplicatesDialog/useDuplicates.js +++ b/src/core_modules/capture-core/components/PossibleDuplicatesDialog/useDuplicates.js @@ -1,7 +1,7 @@ // @flow import { useDispatch } from 'react-redux'; import { useCallback, useContext } from 'react'; -import { useCurrentOrgUnitInfo } from '../../hooks/useCurrentOrgUnitInfo'; +import { useCurrentOrgUnitId } from '../../hooks/useCurrentOrgUnitId'; import { changePage, reviewDuplicates } from './possibleDuplicatesDialog.actions'; import { ResultsPageSizeContext } from '../Pages/shared-contexts'; import { useScopeInfo } from '../../hooks/useScopeInfo'; @@ -10,7 +10,7 @@ export const useDuplicates = (dataEntryId: string, selectedScopeId: string) => { const { resultsPageSize } = useContext(ResultsPageSizeContext); const dispatch = useDispatch(); const { scopeType } = useScopeInfo(selectedScopeId); - const { id: orgUnitId } = useCurrentOrgUnitInfo(); + const orgUnitId = useCurrentOrgUnitId(); const dispatchOnReviewDuplicates = useCallback( () => { dispatch( diff --git a/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/actions/QuickSelector.actions.js b/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/actions/QuickSelector.actions.js index 184bda91b2..214f58bb4b 100644 --- a/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/actions/QuickSelector.actions.js +++ b/src/core_modules/capture-core/components/ScopeSelector/QuickSelector/actions/QuickSelector.actions.js @@ -3,7 +3,6 @@ import { actionCreator } from '../../../../actions/actions.utils'; export const actionTypes = { SET_ORG_UNIT_ID: 'setOrgUnitId', - STORE_ORG_UNIT_OBJECT: 'storeOrgUnitObject', SET_PROGRAM_ID: 'setProgramId', SET_CATEGORY_ID: 'setCategoryId', RESET_CATEGORY_SELECTIONS: 'resetCategorySelections', @@ -15,9 +14,6 @@ export const actionTypes = { export const setOrgUnitId = (orgUnitId: string) => actionCreator(actionTypes.SET_ORG_UNIT_ID)(orgUnitId); -export const storeOrgUnitObject = - (orgUnitObject: Object) => actionCreator(actionTypes.STORE_ORG_UNIT_OBJECT)(orgUnitObject); - export const setProgramId = (programId: string) => actionCreator(actionTypes.SET_PROGRAM_ID)(programId); diff --git a/src/core_modules/capture-core/components/ScopeSelector/SingleLockedSelect/SingleLockedSelect.component.js b/src/core_modules/capture-core/components/ScopeSelector/SingleLockedSelect/SingleLockedSelect.component.js index 46ac687c8c..6876a09fc9 100644 --- a/src/core_modules/capture-core/components/ScopeSelector/SingleLockedSelect/SingleLockedSelect.component.js +++ b/src/core_modules/capture-core/components/ScopeSelector/SingleLockedSelect/SingleLockedSelect.component.js @@ -14,7 +14,7 @@ import type { Icon } from '../../../metaData'; type Props = {| isUserInteractionInProgress?: boolean, - options: Array<{| label: string, value: any, icon?: Icon |}>, + options: Array