Skip to content

Commit

Permalink
feat: [DHIS2-14334] edit enrollment date (#3350)
Browse files Browse the repository at this point in the history
  • Loading branch information
superskip committed Oct 27, 2023
1 parent be652c2 commit 189c577
Show file tree
Hide file tree
Showing 24 changed files with 400 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ Then('the enrollment widget should be opened', () => {
});

Then('the user sees the enrollment date', () => {
cy.get('[data-test="widget-enrollment"]').within(() => {
cy.get('[data-test="widget-enrollment-enrollment-date"]').within(() => {
cy.get('[data-test="widget-enrollment-icon-calendar"]').should('exist');
cy.get('[data-test="widget-enrollment-enrollment-date"]')
.contains(`Date of enrollment ${getCurrentYear()}-08-01`)
cy.get('[data-test="widget-enrollment-date"]')
.contains(`Date of enrollment: ${getCurrentYear()}-08-01`)
.should('exist');
});
});

Then('the user sees the incident date', () => {
cy.get('[data-test="widget-enrollment"]').within(() => {
cy.get('[data-test="widget-enrollment-incident-date"]')
.contains(`Date of birth ${getCurrentYear()}-08-01`)
cy.get('[data-test="widget-enrollment-incident-date"]').within(() => {
cy.get('[data-test="widget-enrollment-date"]')
.contains(`Date of birth: ${getCurrentYear()}-08-01`)
.should('exist');
});
});
Expand Down
3 changes: 3 additions & 0 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,9 @@ msgstr "Remove mark for follow-up"
msgid "Mark for follow-up"
msgstr "Mark for follow-up"

msgid "Existing dates for auto-generated events will not be updated."
msgstr "Existing dates for auto-generated events will not be updated."

msgid "Enrollment date"
msgstr "Enrollment date"

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
},
"resolutions": {
"@babel/preset-react": "7.16.7",
"@js-temporal/polyfill": "0.4.3",
"core-js": "2.5.7"
},
"browserslist": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const enrollmentPageActionTypes = {

DELETE_ENROLLMENT: 'EnrollmentPage.DeleteEnrollment',
UPDATE_TEI_DISPLAY_NAME: 'EnrollmentPage.UpdateTeiDisplayName',
UPDATE_ENROLLMENT_DATE: 'EnrollmentPage.UpdateEnrollmentDate',
};

export const fetchEnrollmentPageInformation = () =>
Expand Down Expand Up @@ -73,3 +74,6 @@ export const updateTeiDisplayName = (teiDisplayName: string) =>
actionCreator(enrollmentPageActionTypes.UPDATE_TEI_DISPLAY_NAME)({
teiDisplayName,
});

export const updateEnrollmentDate = ({ enrollmentId, enrollmentDate }: { enrollmentId: string, enrollmentDate: string }) =>
actionCreator(enrollmentPageActionTypes.UPDATE_ENROLLMENT_DATE)({ enrollmentId, enrollmentDate });
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export const EnrollmentPageDefaultPlain = ({
classes,
onEventClick,
onUpdateTeiAttributeValues,
onUpdateEnrollmentDate,
onUpdateIncidentDate,
onEnrollmentError,
}: PlainProps) => (
<>
Expand Down Expand Up @@ -108,6 +110,8 @@ export const EnrollmentPageDefaultPlain = ({
programId={program.id}
onDelete={onDelete}
onAddNew={onAddNew}
onUpdateEnrollmentDate={onUpdateEnrollmentDate}
onUpdateIncidentDate={onUpdateIncidentDate}
onError={onEnrollmentError}
/>}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ import { useHistory } from 'react-router-dom';
import {
useCommonEnrollmentDomainData,
updateEnrollmentAttributeValues,
updateEnrollmentDate,
updateIncidentDate,
showEnrollmentError,
} from '../../common/EnrollmentOverviewDomain';
import {
updateEnrollmentDate as updateTopBarEnrollmentDate,
deleteEnrollment,
updateTeiDisplayName,
} from '../EnrollmentPage.actions';
import { useTrackerProgram } from '../../../../hooks/useTrackerProgram';
import { useRulesEngineOrgUnit } from '../../../../hooks/useRulesEngineOrgUnit';
import { EnrollmentPageDefaultComponent } from './EnrollmentPageDefault.component';
Expand All @@ -20,7 +27,6 @@ import {
useRuleEffects,
} from './hooks';
import { buildUrlQueryString, useLocationQuery } from '../../../../utils/routing';
import { deleteEnrollment, updateTeiDisplayName } from '../EnrollmentPage.actions';
import { useFilteredWidgetData } from './hooks/useFilteredWidgetData';

export const EnrollmentPageDefault = () => {
Expand Down Expand Up @@ -74,13 +80,23 @@ export const EnrollmentPageDefault = () => {
const onEventClick = (eventId: string) => {
history.push(`/enrollmentEventEdit?${buildUrlQueryString({ orgUnitId, eventId })}`);
};

const onUpdateTeiAttributeValues = useCallback((updatedAttributeValues, teiDisplayName) => {
dispatch(updateEnrollmentAttributeValues(updatedAttributeValues
.map(({ attribute, value }) => ({ id: attribute, value })),
));
dispatch(updateTeiDisplayName(teiDisplayName));
}, [dispatch]);

const onUpdateEnrollmentDate = useCallback((enrollmentDate) => {
dispatch(updateEnrollmentDate(enrollmentDate));
dispatch(updateTopBarEnrollmentDate({ enrollmentId, enrollmentDate }));
}, [dispatch, enrollmentId]);

const onUpdateIncidentDate = useCallback((incidentDate) => {
dispatch(updateIncidentDate(incidentDate));
}, [dispatch]);

const onAddNew = () => {
history.push(`/new?${buildUrlQueryString({ orgUnitId, programId, teiId })}`);
};
Expand All @@ -107,6 +123,8 @@ export const EnrollmentPageDefault = () => {
hideWidgets={hideWidgets}
onEventClick={onEventClick}
onUpdateTeiAttributeValues={onUpdateTeiAttributeValues}
onUpdateEnrollmentDate={onUpdateEnrollmentDate}
onUpdateIncidentDate={onUpdateIncidentDate}
onEnrollmentError={onEnrollmentError}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export type Props = {|
onCreateNew: (stageId: string) => void,
onEventClick: (eventId: string) => void,
onUpdateTeiAttributeValues: (attributes: Array<{ [key: string]: string }>, teiDisplayName: string) => void,
onUpdateEnrollmentDate: (enrollmentDate: string) => void,
onUpdateIncidentDate: (incidentDate: string) => void,
onEnrollmentError: (message: string) => void,
|};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ const EnrollmentAddEventPagePain = ({
teiId={teiId}
enrollmentId={enrollmentId}
programId={programId}
readOnlyMode
onDelete={onDelete}
onAddNew={onAddNew}
onError={onEnrollmentError}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ const EnrollmentEditEventPagePain = ({
teiId={teiId}
enrollmentId={enrollmentId}
programId={programId}
readOnlyMode
onDelete={onDelete}
onAddNew={onAddNew}
onError={onEnrollmentError}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { actionCreator } from '../../../../actions/actions.utils';

export const enrollmentSiteActionTypes = {
COMMON_ENROLLMENT_SITE_DATA_SET: 'EnrollmentSite.SetCommonData',
UPDATE_ENROLLMENT_DATE: 'Enrollment.UpdateEnrollmentDate',
UPDATE_INCIDENT_DATE: 'Enrollment.UpdateIncidentDate',
UPDATE_ENROLLMENT_EVENTS: 'Enrollment.UpdateEnrollmentEvents',
UPDATE_ENROLLMENT_EVENTS_WITHOUT_ID: 'Enrollment.UpdateEnrollmentEventsWithoutId',
UPDATE_ENROLLMENT_ATTRIBUTE_VALUES: 'Enrollment.UpdateEnrollmentAttributeValues',
Expand All @@ -18,6 +20,16 @@ export const enrollmentSiteActionTypes = {
export const setCommonEnrollmentSiteData = (enrollment: ApiEnrollment, attributeValues: ApiAttributeValues) =>
actionCreator(enrollmentSiteActionTypes.COMMON_ENROLLMENT_SITE_DATA_SET)({ enrollment, attributeValues });

export const updateEnrollmentDate = (enrollmentDate: string) =>
actionCreator(enrollmentSiteActionTypes.UPDATE_ENROLLMENT_DATE)({
enrollmentDate,
});

export const updateIncidentDate = (incidentDate: string) =>
actionCreator(enrollmentSiteActionTypes.UPDATE_INCIDENT_DATE)({
incidentDate,
});

export const updateEnrollmentEvents = (eventId: string, eventData: Object) =>
actionCreator(enrollmentSiteActionTypes.UPDATE_ENROLLMENT_EVENTS)({
eventId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
export type { HideWidgets, WidgetEffects } from './enrollmentOverviewDomain.types';
export {
enrollmentSiteActionTypes,
updateEnrollmentDate,
updateIncidentDate,
updateEnrollmentEvents,
commitEnrollmentEvent,
rollbackEnrollmentEvent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useDataMutation } from '@dhis2/app-runtime';
import React from 'react';
import { ActionsComponent } from './Actions.component';
import type { Props } from './actions.types';
import { processErrorReports } from '../processErrorReports';

const enrollmentUpdate = {
resource: 'tracker?async=false&importStrategy=UPDATE',
Expand All @@ -18,13 +19,6 @@ const enrollmentDelete = {
enrollments: [enrollment],
}),
};
const processErrorReports = (error) => {
// $FlowFixMe[prop-missing]
const errorReports = error?.details?.validationReport?.errorReports;
return errorReports?.length > 0
? errorReports.reduce((acc, errorReport) => `${acc} ${errorReport.message}`, '')
: error.message;
};

export const Actions = ({
enrollment = {},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// @flow
import React, { useState, useCallback } from 'react';
import moment from 'moment';
import {
Button,
CalendarInput,
IconCalendar16,
IconEdit16,
colors,
spacersNum,
} from '@dhis2/ui';
import i18n from '@dhis2/d2-i18n';
import { withStyles } from '@material-ui/core';
import { convertValue as convertValueClientToView } from '../../../converters/clientToView';
import { dataElementTypes } from '../../../metaData';

type Props = {
date: string,
dateLabel: string,
editEnabled: boolean,
displayAutoGeneratedEventWarning: boolean,
onSave: (string) => void,
...CssClasses,
}

const styles = {
editButton: {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
cursor: 'pointer',
border: 'none',
borderRadius: '3px',
background: 'transparent',
color: colors.grey600,
padding: 0,
marginLeft: '2px',
'&:focus': {
outline: 'none',
background: colors.grey200,
color: colors.grey800,
},
'&:hover': {
background: colors.grey200,
color: colors.grey800,
},
},
calendar: {
paddingTop: '6px',
},
inputField: {
maxWidth: '200px',
},
buttonStrip: {
display: 'flex',
gap: `${spacersNum.dp4}px`,
margin: `${spacersNum.dp4}px 0`,
},
note: {
fontSize: '12px',
color: colors.grey700,
},
};

const DateComponentPlain = ({
date,
dateLabel,
editEnabled,
displayAutoGeneratedEventWarning,
onSave,
classes,
}: Props) => {
const [editMode, setEditMode] = useState(false);
const [selectedDate, setSelectedDate] = useState();
const dateChangeHandler = useCallback(({ calendarDateString }) => {
setSelectedDate(calendarDateString);
}, [setSelectedDate]);
const displayDate = String(convertValueClientToView(date, dataElementTypes.DATE));

const onOpenEdit = () => {
// CalendarInput component only supports the YYYY-MM-DD format
setSelectedDate(moment(date).format('YYYY-MM-DD'));
setEditMode(true);
};
const saveHandler = () => {
// CalendarInput component only supports the YYYY-MM-DD format
if (selectedDate) {
const newDate = moment.utc(selectedDate, 'YYYY-MM-DD').format('YYYY-MM-DDTHH:mm:ss.SSS');
if (newDate !== date) {
onSave(newDate);
}
}
setEditMode(false);
};

return editMode ? (
<div data-test="widget-enrollment-date">
<div className={classes.inputField}>
<CalendarInput
calendar="gregory"
dense
className={classes.calendar}
label={dateLabel}
date={selectedDate}
onDateSelect={dateChangeHandler}
/>
</div>
<div className={classes.buttonStrip}>
<Button
primary
small
onClick={saveHandler}
>
{i18n.t('Save')}
</Button>
<Button
secondary
small
onClick={() => setEditMode(false)}
>
{i18n.t('Cancel')}
</Button>
</div>
{displayAutoGeneratedEventWarning && (
<div className={classes.note}>
{i18n.t('Existing dates for auto-generated events will not be updated.')}
</div>
)}
</div>
) : (
<div className={classes.row} data-test="widget-enrollment-date">
<span data-test="widget-enrollment-icon-calendar">
<IconCalendar16 color={colors.grey600} />
</span>
{dateLabel}{': '}
{displayDate}
{editEnabled &&
<button
className={classes.editButton}
data-test="widget-enrollment-icon-edit-date"
onClick={onOpenEdit}
>
<IconEdit16 />
</button>
}
</div>
);
};

export const Date = withStyles(styles)(DateComponentPlain);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// @flow
export { Date } from './Date.component';
Loading

0 comments on commit 189c577

Please sign in to comment.