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-11836] respect block entry form #3759

Merged
merged 9 commits into from
Aug 28, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ Scenario: User can see disabled scheduled date for active event
Then the user see the following text: Enrollment: Edit Event
Then the user see the schedule date field with tooltip: Scheduled date cannot be changed for Active events

@user:trackerAutoTestRestricted
Scenario: The user cannot enter edit mode for completed events
Given you land on the enrollment event page with selected Person by having typed /#/enrollmentEventEdit?eventId=nUVwTLuQ6FT&orgUnitId=DiszpKrYNg8
And the user see the following text: Enrollment: View Event
Then the edit button should be disabled

Scenario: User can edit the event and complete the enrollment
Given you land on the enrollment event page with selected Malaria Entity by having typed #/enrollmentEventEdit?eventId=MHR4Zj6KLz0&orgUnitId=DiszpKrYNg8
And the enrollment status is active
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,9 @@ And('you open the Birth stage event', () => {
});
});

Then('the edit button should be disabled', () => {
cy.get('[data-test="widget-enrollment-event"]')
.find('[data-test="dhis2-uicore-button"]')
.eq(1)
.should('be.disabled');
});
3 changes: 3 additions & 0 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,9 @@ msgstr "Scheduled date cannot be changed for {{ eventStatus }} events"
msgid "Event completed"
msgstr "Event completed"

msgid "The event cannot be edited after it has been completed"
msgstr "The event cannot be edited after it has been completed"

msgid "Back to all stages and events"
msgstr "Back to all stages and events"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import { OverflowButton } from '../Buttons';
import { EventChangelogWrapper } from './EventChangelogWrapper';
import { FEATURES, useFeature } from '../../../capture-core-utils';
import { inMemoryFileStore } from '../DataEntry/file/inMemoryFileStore';
import { eventStatuses } from './constants/status.const';
import { useAuthorities } from './hooks';

const styles = {
header: {
Expand Down Expand Up @@ -99,6 +101,14 @@ export const WidgetEventEditPlain = ({
const loadedValues = useSelector(({ viewEventPage }) => viewEventPage.loadedValues);

const eventAccess = getProgramEventAccess(programId, stageId);
const { canEditCompletedEvent } = useAuthorities();
const blockEntryForm = stage.blockEntryForm && !canEditCompletedEvent && eventStatus === eventStatuses.COMPLETED;
const disableEdit = !eventAccess?.write || blockEntryForm;

const tooltipContent = blockEntryForm ?
i18n.t('The event cannot be edited after it has been completed') :
i18n.t('You don\'t have access to edit this event');

const availableProgramStages = useAvailableProgramStages(stage, teiId, enrollmentId, programId);
const { programCategory } = useCategoryCombinations(programId);
if (error) {
Expand All @@ -117,14 +127,14 @@ export const WidgetEventEditPlain = ({
{currentPageMode === dataEntryKeys.VIEW && (
<div className={classes.menuActions}>
<ConditionalTooltip
content={i18n.t('You don\'t have access to edit this event')}
enabled={!eventAccess?.write}
content={tooltipContent}
enabled={disableEdit}
wrapperClassName={classes.tooltip}
>
<Button
small
secondary
disabled={!eventAccess?.write}
disabled={disableEdit}
icon={<IconEdit24 />}
onClick={() => dispatch(startShowEditEventDataEntry(orgUnit, programCategory))}
>
Expand Down Expand Up @@ -225,3 +235,4 @@ export const WidgetEventEditPlain = ({
) : <LoadingMaskElementCenter />;
};
export const WidgetEventEdit: ComponentType<ComponentProps> = withStyles(styles)(WidgetEventEditPlain);

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @flow

export const eventStatuses = Object.freeze({
ACTIVE: 'ACTIVE',
COMPLETED: 'COMPLETED',
VISITED: 'VISITED',
SCHEDULE: 'SCHEDULE',
OVERDUE: 'OVERDUE',
SKIPPED: 'SKIPPED',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// @flow
export { useAuthorities } from './useAuthorities';
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// @flow
import { useApiMetadataQuery } from 'capture-core/utils/reactQueryHelpers';

const auth = Object.freeze({
F_UNCOMPLETE_EVENT: 'F_UNCOMPLETE_EVENT',
ALL: 'ALL',
});

export const useAuthorities = () => {
const queryKey = ['authorities'];
const queryFn = {
resource: 'me.json',
params: {
fields: 'authorities',
},
};
const queryOptions = {
select: ({ authorities }) =>
authorities &&
authorities.some(authority => authority === auth.ALL || authority === auth.F_UNCOMPLETE_EVENT),
};
const { data } = useApiMetadataQuery<any>(queryKey, queryFn, queryOptions);

return {
canEditCompletedEvent: Boolean(data),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class ProgramStage {
_id: string;
_name: string;
_access: { data: { write: boolean } };
_blockEntryForm: boolean;
_untranslatedName: string;
_stageForm: RenderFoundation;
_relationshipTypes: Array<RelationshipType>;
Expand Down Expand Up @@ -41,6 +42,14 @@ export class ProgramStage {
this._stageForm = stageForm;
}

get blockEntryForm(): boolean {
return this._blockEntryForm;
}

set blockEntryForm(blockEntryForm: boolean) {
this._blockEntryForm = blockEntryForm;
}

get id(): string {
return this._id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ export class ProgramStageFactory {
_stage.generatedByEnrollmentDate = !!cachedProgramStage.generatedByEnrollmentDate;
_stage.reportDateToUse = cachedProgramStage.reportDateToUse;
_stage.minDaysFromStart = cachedProgramStage.minDaysFromStart;
_stage.blockEntryForm = !!cachedProgramStage.blockEntryForm;
_stage.repeatable = cachedProgramStage.repeatable;
_stage.stageForm = new RenderFoundation((_form) => {
_form.id = cachedProgramStage.id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const fieldsParam = 'id,displayName,displayShortName,description,programType,sty
'categoryCombo[id,displayName,isDefault,categories[id,displayName]],' +
'userRoles[id,displayName],' +
// eslint-disable-next-line max-len
'programStages[id,access,autoGenerateEvent,openAfterEnrollment,hideDueDate,allowGenerateNextVisit,remindCompleted,repeatable,generatedByEnrollmentDate,reportDateToUse,minDaysFromStart,name,displayName,description,displayExecutionDateLabel,displayDueDateLabel,formType,featureType,validationStrategy,enableUserAssignment,style,dataEntryForm[id,htmlCode]' +
'programStages[id,access,autoGenerateEvent,openAfterEnrollment,hideDueDate,allowGenerateNextVisit,remindCompleted,repeatable,generatedByEnrollmentDate,reportDateToUse,blockEntryForm,minDaysFromStart,name,displayName,description,displayExecutionDateLabel,displayDueDateLabel,formType,featureType,validationStrategy,enableUserAssignment,style,dataEntryForm[id,htmlCode]' +
'programStageSections[id,displayName,displayDescription,sortOrder,dataElements[id]],' +
// eslint-disable-next-line max-len
'programStageDataElements[compulsory,displayInReports,renderOptionsAsRadio,allowFutureDate,renderType[*],dataElement[id]]]' +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export type CachedDataEntryForm = {
export type CachedProgramStage = {
id: string,
access: Object,
blockEntryForm: boolean,
name: string,
displayName: string,
description: ?string,
Expand Down
Loading