Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [DHIS2-18746][DHIS2-18903] Show org. unit in edit event form #3949

Merged
Merged
1 change: 1 addition & 0 deletions packages/rules-engine/src/rulesEngine.types.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export type OrgUnitGroup = $ReadOnly<{|
export type OrgUnit = $ReadOnly<{
id: string,
name: string,
path?: string,
code: string,
groups: Array<OrgUnitGroup>,
}>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const TopBar = ({
onResetOrgUnitId={() => resetOrgUnitId()}
isUserInteractionInProgress={isUserInteractionInProgress}
onStartAgain={() => reset()}
isReadOnly={mode === dataEntryKeys.EDIT}
>
<SingleLockedSelect
displayOnly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@ import {
resetCategoryOption,
resetAllCategoryOptions,
} from './ViewEventPage.actions';

import { TopBarActions } from '../../TopBarActions';

type TopBarProps = {
isUserInteractionInProgress: boolean,
programId?: string,
orgUnitId?: string,
selectedCategories?: any,
isReadOnly: boolean,
formIsOpen: boolean,
};

export const TopBar = ({
programId,
orgUnitId,
selectedCategories,
isReadOnly,
isUserInteractionInProgress,
formIsOpen,
}: TopBarProps) => {
Expand Down Expand Up @@ -63,6 +64,7 @@ export const TopBar = ({
isUserInteractionInProgress={isUserInteractionInProgress}
formIsOpen={formIsOpen}
onStartAgain={() => reset()}
isReadOnly={isReadOnly}
>
<TopBarActions
selectedProgramId={programId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import { inMemoryFileStore } from '../../DataEntry/file/inMemoryFileStore';
type Props = {
isUserInteractionInProgress: boolean,
showAddRelationship: boolean,
isReadOnly: boolean,
};

export const ViewEventPageComponent = ({ isUserInteractionInProgress, showAddRelationship }: Props) => {
export const ViewEventPageComponent = ({ isUserInteractionInProgress, showAddRelationship, isReadOnly }: Props) => {
const { serverVersion: { minor } } = useConfig();
useEffect(() => inMemoryFileStore.clear, []);

Expand All @@ -29,6 +30,7 @@ export const ViewEventPageComponent = ({ isUserInteractionInProgress, showAddRel
programId={programId}
orgUnitId={orgUnitId}
selectedCategories={selectedCategories}
isReadOnly={isReadOnly}
isUserInteractionInProgress={isUserInteractionInProgress}
formIsOpen
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { withLoadingIndicator, withErrorMessageHandler } from '../../../HOC';

const mapStateToProps = (state: ReduxState) => {
const eventDetailsSection = state.viewEventPage.eventDetailsSection || {};
const isReadOnly = eventDetailsSection.showEditEvent;
const isUserInteractionInProgress =
(state.currentSelections.complete && eventDetailsSection.showEditEvent)
?
Expand All @@ -17,6 +18,7 @@ const mapStateToProps = (state: ReduxState) => {
error: state.activePage.viewEventLoadError && state.activePage.viewEventLoadError.error,
ready: !state.activePage.lockedSelectorLoads,
isUserInteractionInProgress,
isReadOnly,
showAddRelationship: state.viewEventPage.showAddRelationship,
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import {
updateRulesEffects,
} from '../../../rules';
import { RenderFoundation, Program } from '../../../metaData';
import { getEventDateValidatorContainers } from './fieldValidators/eventDate.validatorContainersGetter';
import { getCategoryOptionsValidatorContainers } from './fieldValidators/categoryOptions.validatorContainersGetter';
import {
getEventDateValidatorContainers,
getOrgUnitValidatorContainers,
getCategoryOptionsValidatorContainers,
} from './fieldValidators';
import {
getConvertGeometryIn,
convertGeometryOut,
Expand Down Expand Up @@ -110,6 +113,11 @@ export const openEventForEditInDataEntry = ({
type: 'DATE',
validatorContainers: getEventDateValidatorContainers(),
},
{
id: 'orgUnit',
type: 'ORGANISATION_UNIT',
validatorContainers: getOrgUnitValidatorContainers(),
},
{
clientId: 'geometry',
dataEntryId: 'geometry',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { from } from 'rxjs';
import { ofType } from 'redux-observable';
import { map, switchMap } from 'rxjs/operators';
import { batchActions } from 'redux-batched-actions';
import type { OrgUnit } from '@dhis2/rules-engine-javascript';
import { rulesExecutedPostUpdateField } from '../../../DataEntry/actions/dataEntry.actions';
import {
batchActionTypes as editEventDataEntryBatchActionTypes,
Expand All @@ -26,13 +25,13 @@ import { getDataEntryKey } from '../../../DataEntry/common/getDataEntryKey';
import { prepareEnrollmentEventsForRulesEngine } from '../../../../events/prepareEnrollmentEvents';
import { getEnrollmentForRulesEngine, getAttributeValuesForRulesEngine } from '../../helpers';
import type { QuerySingleResource } from '../../../../utils/api';
import { getCoreOrgUnitFn, orgUnitFetched } from '../../../../metadataRetrieval/coreOrgUnit';

const runRulesForEditSingleEvent = async ({
store,
dataEntryId,
itemId,
uid,
orgUnit,
fieldData,
programId,
querySingleResource,
Expand All @@ -42,7 +41,6 @@ const runRulesForEditSingleEvent = async ({
itemId: string,
uid: string,
programId: string,
orgUnit: OrgUnit,
fieldData?: ?FieldData,
querySingleResource: QuerySingleResource
}) => {
Expand All @@ -66,6 +64,10 @@ const runRulesForEditSingleEvent = async ({
// $FlowFixMe
const currentEvent = { ...currentEventValues, ...currentEventMainData, eventId };

const { coreOrgUnit, cached } =
// $FlowFixMe
await getCoreOrgUnitFn(querySingleResource)(currentEvent.orgUnit?.id, store.value.organisationUnits);

let effects;
if (program instanceof TrackerProgram) {
const { enrollment, attributeValues } = state.enrollmentDomain;
Expand All @@ -82,7 +84,7 @@ const runRulesForEditSingleEvent = async ({
effects = getApplicableRuleEffectsForTrackerProgram({
program,
stage,
orgUnit,
orgUnit: coreOrgUnit,
currentEvent: { ...currentEvent, createdAt: apiCurrentEventOriginal.createdAt },
otherEvents: prepareEnrollmentEventsForRulesEngine(apiOtherEvents),
enrollmentData: getEnrollmentForRulesEngine(enrollment),
Expand All @@ -91,7 +93,7 @@ const runRulesForEditSingleEvent = async ({
} else {
effects = getApplicableRuleEffectsForEventProgram({
program,
orgUnit,
orgUnit: coreOrgUnit,
currentEvent,
});
}
Expand All @@ -105,6 +107,7 @@ const runRulesForEditSingleEvent = async ({
return batchActions([
updateRulesEffects(effectsWithValidations, formId),
rulesExecutedPostUpdateField(dataEntryId, itemId, uid),
...(coreOrgUnit && !cached ? [orgUnitFetched(coreOrgUnit)] : []),
],
editEventDataEntryBatchActionTypes.RULES_EFFECTS_ACTIONS_BATCH);
};
Expand All @@ -114,20 +117,19 @@ export const runRulesOnUpdateDataEntryFieldForEditSingleEventEpic = (
store: ReduxStore,
{ querySingleResource }: ApiUtils,
) =>
// $FlowSuppress
// $FlowSuppress
action$.pipe(
ofType(editEventDataEntryBatchActionTypes.UPDATE_DATA_ENTRY_FIELD_EDIT_SINGLE_EVENT_ACTION_BATCH),
map(actionBatch =>
actionBatch.payload.find(action => action.type === editEventDataEntryActionTypes.START_RUN_RULES_ON_UPDATE),
),
switchMap((action) => {
const { dataEntryId, itemId, uid, orgUnit, programId } = action.payload;
const { dataEntryId, itemId, uid, programId } = action.payload;
const runRulesForEditSingleEventPromise = runRulesForEditSingleEvent({
store,
dataEntryId,
itemId,
uid,
orgUnit,
programId,
querySingleResource,
});
Expand All @@ -139,7 +141,7 @@ export const runRulesOnUpdateFieldForEditSingleEventEpic = (
store: ReduxStore,
{ querySingleResource }: ApiUtils,
) =>
// $FlowSuppress
// $FlowSuppress
action$.pipe(
ofType(editEventDataEntryBatchActionTypes.UPDATE_FIELD_EDIT_SINGLE_EVENT_ACTION_BATCH),
map(actionBatch =>
Expand All @@ -153,7 +155,6 @@ export const runRulesOnUpdateFieldForEditSingleEventEpic = (
dataEntryId,
itemId,
uid,
orgUnit,
programId,
} = action.payload;
const fieldData: FieldData = {
Expand All @@ -166,7 +167,6 @@ export const runRulesOnUpdateFieldForEditSingleEventEpic = (
dataEntryId,
itemId,
uid,
orgUnit,
fieldData,
programId,
querySingleResource,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
withDefaultFieldContainer,
withDefaultShouldUpdateInterface,
VirtualizedSelectField,
SingleOrgUnitSelectField,
} from '../../FormFields/New';
import { statusTypes, translatedStatusTypes } from '../../../events/statusTypes';
import labelTypeClasses from '../DataEntry/dataEntryFieldLabels.module.css';
Expand All @@ -48,6 +49,7 @@ import {
withDataEntryFields,
} from '../../DataEntryDhis2Helpers/';
import type { UserFormField } from '../../FormFields/UserField';
import { getOrgUnitValidatorContainers } from '../DataEntry/fieldValidators';

const tabMode = Object.freeze({
REPORT: 'REPORT',
Expand Down Expand Up @@ -197,6 +199,47 @@ const buildScheduleDateSettingsFn = () => {
return scheduleDateSettings;
};

const buildOrgUnitSettingsFn = () => {
const orgUnitComponent =
withCalculateMessages(overrideMessagePropNames)(
withFocusSaver()(
withDefaultFieldContainer()(
withDefaultShouldUpdateInterface()(
withLabel({
onGetUseVerticalOrientation: (props: Object) => props.formHorizontal,
onGetCustomFieldLabeClass: (props: Object) =>
`${props.fieldOptions.fieldLabelMediaBasedClass} ${labelTypeClasses.dateLabel}`,
})(
withDisplayMessages()(
withInternalChangeHandler()(
withFilterProps(defaultFilterProps)(SingleOrgUnitSelectField),
),
),
),
),
),
),
);

const orgUnitSettings = {
getComponent: () => orgUnitComponent,
getComponentProps: (props: Object) => createComponentProps(props, {
width: props && props.formHorizontal ? 150 : 350,
label: i18n.t('Organisation unit'),
required: true,
}),
getPropName: () => 'orgUnit',
getValidatorContainers: () => getOrgUnitValidatorContainers(),
getMeta: () => ({
placement: placements.TOP,
section: dataEntrySectionNames.BASICINFO,
}),
};

return orgUnitSettings;
};


const pointComponent = withCalculateMessages(overrideMessagePropNames)(
withFocusSaver()(
withDefaultFieldContainer()(
Expand Down Expand Up @@ -359,7 +402,8 @@ const saveHandlerConfig = {
const AOCFieldBuilderHOC = withAOCFieldBuilder({})(withDataEntryFields(getCategoryOptionsSettingsFn())(DataEntry));
const CleanUpHOC = withCleanUp()(AOCFieldBuilderHOC);
const GeometryField = withDataEntryFieldIfApplicable(buildGeometrySettingsFn())(CleanUpHOC);
const ScheduleDateField = withDataEntryField(buildScheduleDateSettingsFn())(GeometryField);
const OrgUnitField = withDataEntryField(buildOrgUnitSettingsFn())(GeometryField);
const ScheduleDateField = withDataEntryField(buildScheduleDateSettingsFn())(OrgUnitField);
const ReportDateField = withDataEntryField(buildReportDateSettingsFn())(ScheduleDateField);
const SaveableDataEntry = withSaveHandler(saveHandlerConfig)(withMainButton()(ReportDateField));
const CancelableDataEntry = withCancelButton(getCancelOptions)(SaveableDataEntry);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export const saveEditedEventEpic = (action$: InputObservable, store: ReduxStore,
const serverData = {
events: [{
...mainDataServerValues,
orgUnit: mainDataServerValues.orgUnit.id,
attributeOptionCombo: undefined,
dataValues: formFoundation
.getElements()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ const buildOrgUnitSettingsFn = () => {
label: i18n.t('Organisation unit'),
valueConverter: value => dataElement.convertValue(value, valueConvertFn),
}),
getPropName: () => 'orgUnitId',
getPropName: () => 'orgUnit',
getMeta: () => ({
placement: placements.TOP,
section: dataEntrySectionNames.BASICINFO,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ export const loadViewEventDataEntry =
type: 'DATE',
validatorContainers: getEventDateValidatorContainers(),
},
{
id: 'orgUnitId',
type: 'ORGANISATION_UNIT',
validatorContainers: getOrgUnitValidatorContainers(),
},
{
id: 'scheduledAt',
type: 'DATE',
},
{
id: 'orgUnit',
type: 'ORGANISATION_UNIT',
validatorContainers: getOrgUnitValidatorContainers(),
},
{
clientId: 'geometry',
dataEntryId: 'geometry',
Expand Down Expand Up @@ -118,6 +118,11 @@ export const loadViewEventDataEntry =
dataEntryPropsToInclude.push(...Object.keys(attributeCategoryOptions).map(id => ({ id, type: 'TEXT' })));
}

const clientValuesForDataEntry = {
...eventContainer.event,
orgUnit: { id: orgUnit.id, name: orgUnit.name, path: orgUnit.path },
};

const extraProps = {
eventId: eventContainer.event.eventId,
};
Expand All @@ -126,7 +131,7 @@ export const loadViewEventDataEntry =
loadEditDataEntryAsync(
dataEntryId,
dataEntryKey,
eventContainer.event,
clientValuesForDataEntry,
eventContainer.values,
dataEntryPropsToInclude,
foundation,
Expand Down Expand Up @@ -163,7 +168,6 @@ export const loadViewEventDataEntry =
});
}
const filteredEffects = filterApplicableRuleEffects(effects, effectActions.ASSIGN_VALUE);

return [
...dataEntryActions,
updateRulesEffects(filteredEffects, formId),
Expand Down
Loading
Loading