Skip to content

Commit

Permalink
feat: interface for accessing organisationUnits
Browse files Browse the repository at this point in the history
  • Loading branch information
superskip committed Oct 17, 2023
1 parent 12060ed commit 3ca1205
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useDataQuery } from '@dhis2/app-runtime';
import log from 'loglevel';
import { errorCreator } from '../../capture-core-utils';

// Skips fetching if orgUnitId is falsy
export const useOrganisationUnit = (orgUnitId: string, fields?: string) => {
const [orgUnit, setOrgUnit] = useState();
const { error, loading, data, refetch, called } = useDataQuery(
Expand All @@ -24,7 +25,7 @@ export const useOrganisationUnit = (orgUnitId: string, fields?: string) => {
);

useEffect(() => {
refetch({ variables: { orgUnitId } });
orgUnitId && refetch({ variables: { orgUnitId } });
}, [refetch, orgUnitId]);

useEffect(() => {
Expand All @@ -35,7 +36,7 @@ export const useOrganisationUnit = (orgUnitId: string, fields?: string) => {

useEffect(() => {
const organisationUnit = data?.organisationUnits;
setOrgUnit(
orgUnitId && setOrgUnit(
(loading || !called || error) ?
undefined : {
id: orgUnitId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// @flow
import { getAssociatedOrgUnitGroups } from 'capture-core/MetaDataStoreUtils/getAssociatedOrgUnitGroups';
import type { ReduxOrgUnit } from './organisationUnits.types';
import type { QuerySingleResource } from '../../utils/api/api.types';

// Builds new ReduxOrgUnit by fetching data from the api and index db
export async function fetchReduxOrgUnit(
orgUnitId: string,
querySingleResource: QuerySingleResource,
): Promise<ReduxOrgUnit> {
return Promise.all([
querySingleResource({
resource: `organisationUnits/${orgUnitId}`,
params: {
fields: 'displayName,code,path',
},
}),
getAssociatedOrgUnitGroups(orgUnitId),
]).then(([orgUnit, groups]) => ({
id: orgUnitId,
name: orgUnit.displayName,
code: orgUnit.code,
path: orgUnit.path,
groups,
}));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// @flow
import { ofType } from 'redux-observable';
import { catchError, mergeMap, concatMap } from 'rxjs/operators';
import { from, of } from 'rxjs';
import { actionTypes, orgUnitFetched, type FetchOrgUnitPayload } from './organisationUnits.actions';
import { fetchReduxOrgUnit } from './fetchReduxOrgUnit';

export const getReduxOrgUnitEpic = (
action$: InputObservable,
store: ReduxStore,
{ querySingleResource }: ApiUtils,
) => action$.pipe(
ofType(actionTypes.GET_ORGUNIT),
concatMap((action: ReduxAction<FetchOrgUnitPayload, void>) => {
const { organisationUnits } = store.value;
const payload = action.payload;
if (organisationUnits[payload.orgUnitId]) {
return of(payload.onSuccess(organisationUnits[payload.orgUnitId]));
}
return from(fetchReduxOrgUnit(payload.orgUnitId, querySingleResource))
.pipe(
mergeMap(orgUnit =>
of(orgUnitFetched(orgUnit), payload.onSuccess(orgUnit))),
catchError(error =>
(payload.onError ? of(payload.onError(error)) : of({}))),
);
}),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// @flow
export { useReduxOrgUnit } from './useReduxOrgUnit';
export { getOrgUnit } from './organisationUnits.actions';
export { getReduxOrgUnitEpic } from './getReduxOrgUnit.epics';
export type { ReduxOrgUnit } from './organisationUnits.types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @flow
import { actionCreator } from '../../actions/actions.utils';
import type { ReduxOrgUnit } from './organisationUnits.types';

export const actionTypes = {
GET_ORGUNIT: 'organisationUnits.GetOrgUnit',
ORG_UNIT_FETCHED: 'organisationUnits.OrgUnitFetched',
};

type ActionCreator<T> = (payload: T) => ReduxAction<any, any>;

// Public
export type FetchOrgUnitPayload = {
orgUnitId: string,
onSuccess: ActionCreator<ReduxOrgUnit>,
onError?: ActionCreator<any>,
}
export const getOrgUnit = (payload: FetchOrgUnitPayload) => actionCreator(actionTypes.GET_ORGUNIT)(payload);

// Private
export const orgUnitFetched = (orgUnit: ReduxOrgUnit) => actionCreator(actionTypes.ORG_UNIT_FETCHED)(orgUnit);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// @flow
import type { OrgUnitGroup } from '@dhis2/rules-engine-javascript';

// Make sure rules engine OrgUnit is a subset of this!
export type ReduxOrgUnit = {|
id: string,
name: string, // this is the translated name (displayName)
code: string,
path: string,
groups: Array<OrgUnitGroup>,
|};
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// @flow
import React from 'react';
import i18n from '@dhis2/d2-i18n';
import { useSelector, useDispatch } from 'react-redux';
import { useOrgUnitGroups } from 'capture-core/hooks/useOrgUnitGroups';
import { useOrganisationUnit } from '../../dataQueries';
import { orgUnitFetched } from './organisationUnits.actions';
import { type ReduxOrgUnit } from './organisationUnits.types';

export function useReduxOrgUnit(orgUnitId: string): {
orgUnit?: ReduxOrgUnit,
error?: any,
} {
const dispatch = useDispatch();
const reduxOrgUnit = useSelector(({ organisationUnits }) => organisationUnits && organisationUnits[orgUnitId]);
const id = reduxOrgUnit ? undefined : orgUnitId;
// These hooks do no work when id is undefined
const { orgUnit, error } = useOrganisationUnit(id, 'displayName,code,path');
const { orgUnitGroups, error: groupError } = useOrgUnitGroups(id);

if (reduxOrgUnit) {
return { orgUnit: reduxOrgUnit };
}

if (error) {
return { error: { error, errorComponent } };
} else if (groupError) {
return { error: { groupError, errorComponent } };
}

if (orgUnit && orgUnitGroups) {
orgUnit.name = orgUnit.displayName;
orgUnit.groups = orgUnitGroups;
delete orgUnit.displayName;
dispatch(orgUnitFetched(orgUnit));
return { orgUnit };
}

return {};
}

const errorComponent = (
<div>
{i18n.t('organisation unit could not be retrieved. Please try again later.')}
</div>
);
4 changes: 4 additions & 0 deletions src/epics/trackerCapture.epics.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ import {
import {
orgUnitFetcherEpic,
} from '../core_modules/capture-core/components/OrgUnitFetcher';
import {
getReduxOrgUnitEpic,
} from '../core_modules/capture-core/redux/organisationUnits';

export const epics = combineEpics(
resetProgramAfterSettingOrgUnitIfApplicableEpic,
Expand Down Expand Up @@ -339,6 +342,7 @@ export const epics = combineEpics(
navigateToEnrollmentOverviewEpic,
scheduleEnrollmentEventEpic,
orgUnitFetcherEpic,
getReduxOrgUnitEpic,
updateTeiEpic,
updateTeiSucceededEpic,
updateTeiFailedEpic,
Expand Down

0 comments on commit 3ca1205

Please sign in to comment.