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-13299][DHIS2-16291] Related Stages #3488

Merged
merged 23 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
daaf2da
feat: [DHIS2-13672] add referral actions to add event widget (#3032)
jasminenguyennn Dec 2, 2022
9d3459a
Merge remote-tracking branch 'origin/master' into DHIS2-13299-referrals
eirikhaugstulen Feb 9, 2023
53c1ca8
Merge remote-tracking branch 'origin/master' into DHIS2-13299-referrals
eirikhaugstulen Jun 20, 2023
175190c
feat: [DHIS2-14405] Schedule referral event in another orgUnit
eirikhaugstulen Jul 24, 2023
41f6069
Merge remote-tracking branch 'origin/master' into DHIS2-13299-referrals
eirikhaugstulen Oct 30, 2023
6cef430
feat: [DHIS2-15212][DHIS2-15214][DHIS2-15216] Referral widget actions…
eirikhaugstulen Dec 18, 2023
9914da2
Merge remote-tracking branch 'origin/master' into DHIS2-13299-referrals
eirikhaugstulen Dec 18, 2023
0b289ef
chore: rebrand widget as RelatedStageWidget
eirikhaugstulen Dec 18, 2023
02f702c
chore: rebrand widget as RelatedStageWidget
eirikhaugstulen Dec 18, 2023
b5de782
feat: implement changes from the design discussions
eirikhaugstulen Dec 19, 2023
51620eb
Merge remote-tracking branch 'origin/master' into eh/feat/DHIS2-16291…
eirikhaugstulen Jan 11, 2024
096b37f
feat: add clear selections button
eirikhaugstulen Jan 11, 2024
f72709c
Merge remote-tracking branch 'origin/master' into eh/feat/DHIS2-16291…
eirikhaugstulen Feb 28, 2024
f59794e
feat: rebrand from maldives
eirikhaugstulen Feb 28, 2024
7c1a443
Merge remote-tracking branch 'origin/master' into eh/feat/DHIS2-16291…
eirikhaugstulen Mar 4, 2024
1913d79
Merge remote-tracking branch 'origin/master' into eh/feat/DHIS2-16291…
eirikhaugstulen Mar 5, 2024
4269fd4
chore: merge conflicts
eirikhaugstulen Mar 10, 2024
b7675b8
Merge remote-tracking branch 'origin/master' into eh/feat/DHIS2-16291…
eirikhaugstulen Mar 11, 2024
5b2f329
feat: rewrite save & optimistic ui
eirikhaugstulen Mar 12, 2024
088b50b
Merge remote-tracking branch 'origin/master' into eh/feat/DHIS2-16291…
eirikhaugstulen Mar 15, 2024
7a20f20
feat: navigate on enrollment widget complete
eirikhaugstulen Mar 15, 2024
c02062d
fix: remove unused epics
eirikhaugstulen Mar 19, 2024
29a29ca
fix: remove filtration and flow
eirikhaugstulen Mar 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1442,6 +1442,37 @@ msgstr "{{trackedEntityTypeName}} profile"
msgid "tracked entity instance"
msgstr "tracked entity instance"

msgid "Link to an existing {{linkableStageLabel}}"
msgstr "Link to an existing {{linkableStageLabel}}"

msgid "Choose a {{linkableStageLabel}}"
msgstr "Choose a {{linkableStageLabel}}"

msgid "Ambiguous relationships, contact system administrator"
msgstr "Ambiguous relationships, contact system administrator"

msgid ""
"Enter {{linkableStageLabel}} details in the next step after completing this "
"{{currentStageLabel}}."
msgstr ""
"Enter {{linkableStageLabel}} details in the next step after completing this "
"{{currentStageLabel}}."

msgid "Enter details now"
msgstr "Enter details now"

msgid "Link to an existing"
msgstr "Link to an existing"

msgid "Scheduled date"
msgstr "Scheduled date"

msgid "Report date"
msgstr "Report date"

msgid "Please select a valid event"
msgstr "Please select a valid event"

msgid "New {{ eventName }} event"
msgstr "New {{ eventName }} event"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class IndexedDBAdapter {
});
}

static get(store, key, db, keyPath) {
static get(store, key, options, db, keyPath) {
return new Promise((resolve, reject) => {
let tx;
let catchError;
Expand All @@ -105,11 +105,13 @@ export class IndexedDBAdapter {
const request = objectStore.get(key);
request.onsuccess = (e) => {
const object = e.target.result;
const { project } = options || {};

if (isDefined(object)) {
object[keyPath] = key;
}
resultObject = object;

resultObject = project ? project(object) : object;
};
} catch (error) {
if (tx) {
Expand Down Expand Up @@ -392,8 +394,8 @@ export class IndexedDBAdapter {
});
}

get(store, key) {
return IndexedDBAdapter.get(store, key, this.db, this.keyPath);
get(store, key, options) {
return IndexedDBAdapter.get(store, key, options, this.db, this.keyPath);
}

// eslint-disable-next-line class-methods-use-this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export class StorageController {
}

// using async ensures that the the return value is wrapped in a promise
async get(store, key) {
async get(store, key, options) {
this.throwIfNotOpen();
this.throwIfStoreNotFound(store, 'get');

Expand All @@ -200,7 +200,7 @@ export class StorageController {
);
}

return this.adapter.get(store, key);
return this.adapter.get(store, key, options);
}

// using async ensures that the the return value is wrapped in a promise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type OrgUnitValue = {
path: string,
}

export const isValidOrgUnit = (value: OrgUnitValue) => {
export const isValidOrgUnit = (value: ?OrgUnitValue) => {
const valid = !!(value && value.id && value.name);
return valid;
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import { CompleteModal } from './CompleteModal';
import { statusTypes as eventStatuses } from '../../../../../events/statusTypes';
import { type RenderFoundation } from '../../../../../metaData';
import { addEventSaveTypes } from '../../../../WidgetEnrollmentEventNew/DataEntry/addEventSaveTypes';
import { actions as LinkModes } from '../../../../WidgetRelatedStages/constants';
import type { RelatedStageRefPayload } from '../../../../WidgetEnrollmentEventNew/Validated/validated.types';

type Props = {
onSave: (eventId: string, dataEntryId: string, formFoundation: RenderFoundation, saveType?: ?string) => void,
askCompleteEnrollmentOnEventComplete?: ?boolean,
isCompleted?: boolean,
eventId?: ?string,
formFoundation: RenderFoundation,
relatedStageRef: { current?: ?RelatedStageRefPayload },
onSaveAndCompleteEnrollment: (
eventId: string,
dataEntryId: string,
Expand All @@ -28,6 +31,7 @@ const getAskToCompleteEnrollment = (InnerComponent: ComponentType<any>) => (prop
isCompleted,
onSaveAndCompleteEnrollment,
eventId,
relatedStageRef,
...passOnProps
} = props;
const enrollment = useSelector(({ enrollmentDomain }) => enrollmentDomain?.enrollment);
Expand All @@ -54,8 +58,9 @@ const getAskToCompleteEnrollment = (InnerComponent: ComponentType<any>) => (prop
formFoundation: RenderFoundation,
saveType?: string,
) => {
const { linkMode } = relatedStageRef?.current?.getLinkedStageValues() ?? {};
eventDataToSave.current = { itemId, dataEntryId, formFoundation, saveType };
if (askCompleteEnrollmentOnEventComplete && (isCompleted || saveType === addEventSaveTypes.COMPLETE)) {
if (askCompleteEnrollmentOnEventComplete && (isCompleted || saveType === addEventSaveTypes.COMPLETE) && linkMode !== LinkModes.ENTER_DATA) {
setOpenCompleteModal(true);
} else {
onSave(itemId, dataEntryId, formFoundation, saveType);
Expand All @@ -66,6 +71,7 @@ const getAskToCompleteEnrollment = (InnerComponent: ComponentType<any>) => (prop
<>
<InnerComponent
{...passOnProps}
relatedStageRef={relatedStageRef}
askCompleteEnrollmentOnEventComplete={askCompleteEnrollmentOnEventComplete}
onSave={handleOnSave}
isCompleted={isCompleted}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { defaultDialogProps } from '../Dialogs/DiscardDialog.constants';

type Props = {
dataEntryHasChanges: boolean,
disabled: boolean,
onCancel: () => void,
}

Expand Down Expand Up @@ -36,6 +37,7 @@ export class CancelButtonComponent extends React.Component<Props, State> {
<div>
<Button
onClick={this.handleCancel}
disabled={this.props.disabled}
secondary
>
{ i18n.t('Cancel') }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const styles = theme => ({
verticalFormContainer: {
flexGrow: 10,
maxWidth: '100%',
marginBottom: spacers.dp12,
},
verticalFormInnerContainer: {
maxWidth: theme.typography.pxToRem(892),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CancelButton } from './CancelButton.container';
type Props = {
id: string,
onCancel: () => void,
cancelButtonIsDisabled?: boolean,
cancelButtonRef?: ?Function,
};

Expand All @@ -22,7 +23,7 @@ const getCancelButton = (InnerComponent: React.ComponentType<any>, optionsFn?: ?
getWrappedInstance = () => this.innerInstance;

render() {
const { onCancel, cancelButtonRef, ...passOnProps } = this.props;
const { onCancel, cancelButtonIsDisabled, cancelButtonRef, ...passOnProps } = this.props;
const options = (optionsFn && optionsFn(this.props)) || {};

return (
Expand All @@ -34,6 +35,7 @@ const getCancelButton = (InnerComponent: React.ComponentType<any>, optionsFn?: ?
id={this.props.id}
onCancel={onCancel}
options={options}
disabled={cancelButtonIsDisabled}
/>
}
{...passOnProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { withStyles } from '@material-ui/core';
import type { Props } from './dataSection.type';


const styles = {
const styles = theme => ({
sectionWrapper: {
border: `1px solid ${colors.grey300}`,
borderRadius: '3px',
marginBottom: spacersNum.dp16,
maxWidth: theme.typography.pxToRem(892),
},
sectionHeader: {
color: colors.grey900,
Expand All @@ -20,7 +21,7 @@ const styles = {
marginBottom: '8px',
width: 'fit-content',
},
};
});

const DataSectionPlain = ({ sectionName, children, classes, dataTest }: Props) => (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,92 @@ import {
addEnrollmentEventPageDefaultActionTypes,
} from './EnrollmentAddEventPageDefault/EnrollmentAddEventPageDefault.actions';
import {
commitEnrollmentEventWithoutId,
rollbackEnrollmentEventWithoutId,
addPersistedEnrollmentEvents,
commitEnrollmentEvents,
rollbackEnrollmentEvents,
saveFailed,
commitEnrollmentAndEvents,
rollbackEnrollmentAndEvents,
} from '../common/EnrollmentOverviewDomain/enrollment.actions';
import { actions as RelatedStageActions } from '../../WidgetRelatedStages/constants';
import { buildUrlQueryString } from '../../../utils/routing';

export const saveNewEventSucceededEpic = (action$: InputObservable) =>
const shouldNavigateWithRelatedStage = ({
linkMode,
linkedEventId,
linkedOrgUnitId,
history,
}) => {
if (linkMode && linkedEventId) {
if (linkMode === RelatedStageActions.ENTER_DATA) {
const navigate = () => history.push(`/enrollmentEventEdit?${buildUrlQueryString({
eventId: linkedEventId,
orgUnitId: linkedOrgUnitId,
})}`);
return { navigate };
}
}
return {};
};

export const saveNewEventSucceededEpic = (action$: InputObservable, state: ReduxStore, { history }: ApiUtils) =>
action$.pipe(
ofType(
addEnrollmentEventPageDefaultActionTypes.EVENT_SAVE_SUCCESS,
addEnrollmentEventPageDefaultActionTypes.EVENT_SCHEDULE_SUCCESS,
),
map((action) => {
const meta = action.meta;
const eventId = action.payload.bundleReport.typeReportMap.EVENT.objectReports[0].uid;
return commitEnrollmentEventWithoutId(meta.uid, eventId);
const actions = [];
const { enrollmentDomain } = state.value;
const eventsFromApi = action.payload.bundleReport.typeReportMap.EVENT.objectReports;
const { serverData: { events, enrollments } } = action.meta;
const serverDataEvents = events ?? enrollments[0].events;
const enrollmentEvents = enrollmentDomain.enrollment.events;

const { eventsToCommit, eventsToAdd } = serverDataEvents.reduce((acc, event) => {
const eventFromRedux = enrollmentEvents.find(e => e.event === event.event);

if (!eventFromRedux) {
acc.eventsToAdd.push(event);
} else if (eventFromRedux.pendingApiResponse) {
const eventToCommit = eventsFromApi.find(e => e.uid === event.event);
acc.eventsToCommit.push(eventToCommit);
}
return acc;
}, { eventsToCommit: [], eventsToAdd: [] });

if (eventsToAdd.length > 0) {
actions.push(
addPersistedEnrollmentEvents({ events: eventsToAdd }),
);
}

if (eventsToCommit.length > 0) {
actions.push(
commitEnrollmentEvents({ events: eventsToCommit }),
);
}

if (enrollmentDomain.eventSaveInProgress) {
const {
linkMode,
requestEventId,
linkedEventId,
linkedOrgUnitId,
} = enrollmentDomain.eventSaveInProgress;
const requestEvent = eventsFromApi.find(event => event.uid === requestEventId);

if (requestEvent) {
const { navigate } = shouldNavigateWithRelatedStage({
linkMode,
linkedEventId,
linkedOrgUnitId,
history,
});

navigate && navigate();
}
}

return batchActions(actions);
}),
);

Expand All @@ -33,30 +102,15 @@ export const saveNewEventFailedEpic = (action$: InputObservable) =>
addEnrollmentEventPageDefaultActionTypes.EVENT_SCHEDULE_ERROR,
),
map((action) => {
const meta = action.meta;
return batchActions([saveFailed(), rollbackEnrollmentEventWithoutId(meta.uid)]);
}),
);
const { serverData: { events, enrollments } } = action.meta;
const rollbackEvents = events ?? enrollments[0].events;

export const saveEventAndCompleteEnrollmentSucceededEpic = (action$: InputObservable) =>
action$.pipe(
ofType(addEnrollmentEventPageDefaultActionTypes.EVENT_SAVE_ENROLLMENT_COMPLETE_SUCCESS),
map((action) => {
const meta = action.meta;
// the bundleReport returns the events in the same order as the payload order. Therefore, we know that the first event is the newly added one.
const eventId = action.payload.bundleReport.typeReportMap.EVENT.objectReports[0].uid;
return commitEnrollmentAndEvents(meta.uid, eventId);
return batchActions([
saveFailed(),
rollbackEnrollmentEvents({
events: rollbackEvents,
}),
]);
}),
);

export const saveEventAndCompleteEnrollmentFailedEpic = (action$: InputObservable) =>
action$.pipe(
ofType(addEnrollmentEventPageDefaultActionTypes.EVENT_SAVE_ENROLLMENT_COMPLETE_ERROR),
map((action) => {
const meta = action.meta;
return batchActions(
[saveFailed(), rollbackEnrollmentAndEvents(meta.uid)],
'NewEvent.saveEventAndCompleteEnrollmentFailed',
);
}),
);
Loading
Loading