diff --git a/cypress/e2e/EnrollmentAddEventPage/ProgramStageSelector/ProgramStageSelector.feature b/cypress/e2e/EnrollmentAddEventPage/ProgramStageSelector/ProgramStageSelector.feature
index 0e93937044..da55e54d74 100644
--- a/cypress/e2e/EnrollmentAddEventPage/ProgramStageSelector/ProgramStageSelector.feature
+++ b/cypress/e2e/EnrollmentAddEventPage/ProgramStageSelector/ProgramStageSelector.feature
@@ -19,4 +19,4 @@ Feature: Program stage selector when navigating to EnrollmentEventNew without st
@user:trackerAutoTestRestricted
Scenario: Stages buttons should not be displayed when no data write access
Given user lands on the Enrollment dashboard page by typing #/enrollmentEventNew?enrollmentId=X7g83OFRALm&orgUnitId=DiszpKrYNg8&programId=WSGAb5XwJ3Y&teiId=YsKjdOcl9Cd
- Then the New event quick action button is disabled
+ Then the quick actions widget is not visible
diff --git a/cypress/e2e/EnrollmentAddEventPage/ProgramStageSelector/ProgramStageSelector.js b/cypress/e2e/EnrollmentAddEventPage/ProgramStageSelector/ProgramStageSelector.js
index c28e147c37..7b3ef8265c 100644
--- a/cypress/e2e/EnrollmentAddEventPage/ProgramStageSelector/ProgramStageSelector.js
+++ b/cypress/e2e/EnrollmentAddEventPage/ProgramStageSelector/ProgramStageSelector.js
@@ -33,6 +33,6 @@ Then('only three program stages are displayed in the stage selector widget', ()
cy.get('[data-test=program-stage-selector-button]').should('have.length', 3);
});
-Then('the New event quick action button is disabled', () => {
- cy.get('[data-test=quick-action-button-report]').should('be.disabled');
+Then('the quick actions widget is not visible', () => {
+ cy.get('[data-test=quick-action-button-container]').should('not.exist');
});
diff --git a/cypress/e2e/EnrollmentEditEventPage/EnrollmentEditEventPageForm/EnrollmentEditEventPageForm.feature b/cypress/e2e/EnrollmentEditEventPage/EnrollmentEditEventPageForm/EnrollmentEditEventPageForm.feature
index b0eb978b21..7a0fe7295d 100644
--- a/cypress/e2e/EnrollmentEditEventPage/EnrollmentEditEventPageForm/EnrollmentEditEventPageForm.feature
+++ b/cypress/e2e/EnrollmentEditEventPage/EnrollmentEditEventPageForm/EnrollmentEditEventPageForm.feature
@@ -103,10 +103,10 @@ Scenario: User can see disabled scheduled date for active 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
+Scenario: The edit button is hidden for users with read-only access
Given you land on the enrollment event page with selected Person by having typed /#/enrollmentEventEdit?eventId=nUVwTLuQ6FT&orgUnitId=DiszpKrYNg8
And the view enrollment event form is in view mode
- Then the edit button should be disabled
+ Then the edit button should not be visible
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
diff --git a/cypress/e2e/EnrollmentEditEventPage/EnrollmentEditEventPageForm/EnrollmentEditEventPageForm.js b/cypress/e2e/EnrollmentEditEventPage/EnrollmentEditEventPageForm/EnrollmentEditEventPageForm.js
index 7bc499c242..4d6bb465b8 100644
--- a/cypress/e2e/EnrollmentEditEventPage/EnrollmentEditEventPageForm/EnrollmentEditEventPageForm.js
+++ b/cypress/e2e/EnrollmentEditEventPage/EnrollmentEditEventPageForm/EnrollmentEditEventPageForm.js
@@ -207,10 +207,10 @@ And('you open the Birth stage event', () => {
});
});
-Then('the edit button should be disabled', () => {
+Then('the edit button should not be visible', () => {
cy.get('[data-test="widget-enrollment-event"]')
.find('[data-test="widget-enrollment-event-edit-button"]')
- .should('be.disabled');
+ .should('not.exist');
});
And('the add event form is displayed', () => {
diff --git a/cypress/e2e/EnrollmentPage/EnrollmentQuickActions/EnrollmentQuickActions.feature b/cypress/e2e/EnrollmentPage/EnrollmentQuickActions/EnrollmentQuickActions.feature
index ea20b12fea..2e60db7c13 100644
--- a/cypress/e2e/EnrollmentPage/EnrollmentQuickActions/EnrollmentQuickActions.feature
+++ b/cypress/e2e/EnrollmentPage/EnrollmentQuickActions/EnrollmentQuickActions.feature
@@ -14,7 +14,7 @@ Feature: User interacts with the quick actions-menu
Then you should be navigated to the schedule tab
@user:trackerAutoTestRestricted
- Scenario: The create new quick actions button should be disabled if no available stages
+ Scenario: The quick actions widget is hidden for users with read-only access
Given you open the enrollment page by typing #enrollment?enrollmentId=WKPoiZxZxNG&orgUnitId=DiszpKrYNg8&programId=WSGAb5XwJ3Y&teiId=PgmUFEQYZdt
- Then the quick action buttons should be disabled
+ Then the quick action buttons should not be visible
diff --git a/cypress/e2e/EnrollmentPage/EnrollmentQuickActions/EnrollmentQuickActions.js b/cypress/e2e/EnrollmentPage/EnrollmentQuickActions/EnrollmentQuickActions.js
index ff2c76281f..7aa0657aa8 100644
--- a/cypress/e2e/EnrollmentPage/EnrollmentQuickActions/EnrollmentQuickActions.js
+++ b/cypress/e2e/EnrollmentPage/EnrollmentQuickActions/EnrollmentQuickActions.js
@@ -34,8 +34,7 @@ Then('the buttons should be disabled', () => {
});
});
-Then('the quick action buttons should be disabled', () => {
- cy.get('[data-test="quick-action-button-container"]')
- .find('button')
- .should('be.disabled');
+Then('the quick action buttons should not be visible', () => {
+ cy.get('[data-test="enrollment-overview-page"]').should('exist');
+ cy.get('[data-test="quick-action-button-container"]').should('not.exist');
});
diff --git a/cypress/e2e/EnrollmentPage/StagesAndEventsWidget/StagesAndEventsWidget.feature b/cypress/e2e/EnrollmentPage/StagesAndEventsWidget/StagesAndEventsWidget.feature
index a18e595f6b..2c4a7fa670 100644
--- a/cypress/e2e/EnrollmentPage/StagesAndEventsWidget/StagesAndEventsWidget.feature
+++ b/cypress/e2e/EnrollmentPage/StagesAndEventsWidget/StagesAndEventsWidget.feature
@@ -83,6 +83,6 @@ Feature: User interacts with Stages and Events Widget
Then the Care at birth program stage should be hidden
@user:trackerAutoTestRestricted
- Scenario: Create new event button is disabled if no data write access
+ Scenario: Create new event buttons are hidden for users with read-only access
Given you open the enrollment page by typing #enrollment?enrollmentId=WKPoiZxZxNG&orgUnitId=DiszpKrYNg8&programId=WSGAb5XwJ3Y&teiId=PgmUFEQYZdt
- Then you should see the disabled button New Previous deliveries event
+ Then create new event button should not be visible
diff --git a/cypress/e2e/EnrollmentPage/StagesAndEventsWidget/StagesAndEventsWidget.js b/cypress/e2e/EnrollmentPage/StagesAndEventsWidget/StagesAndEventsWidget.js
index 1966adca4a..2575432141 100644
--- a/cypress/e2e/EnrollmentPage/StagesAndEventsWidget/StagesAndEventsWidget.js
+++ b/cypress/e2e/EnrollmentPage/StagesAndEventsWidget/StagesAndEventsWidget.js
@@ -186,6 +186,11 @@ Then(/^you should see the disabled button (.*)$/, (stageName) => {
.should('be.disabled');
});
+Then('create new event button should not be visible', () => {
+ cy.get('[data-test="stages-and-events-widget"]').should('exist');
+ cy.get('[data-test="create-new-button"]').should('not.exist');
+});
+
Then('the Care at birth program stage should be hidden', () => {
cy.contains('[data-test="stages-and-events-widget"]', 'Postpartum care visit').should('exist');
cy.contains('[data-test="stages-and-events-widget"]', 'Care at birth').should('not.exist');
diff --git a/cypress/e2e/WidgetsForEnrollmentPages/WidgetEnrollment/index.js b/cypress/e2e/WidgetsForEnrollmentPages/WidgetEnrollment/index.js
index a2bd1da20a..943619c0cd 100644
--- a/cypress/e2e/WidgetsForEnrollmentPages/WidgetEnrollment/index.js
+++ b/cypress/e2e/WidgetsForEnrollmentPages/WidgetEnrollment/index.js
@@ -60,6 +60,18 @@ Then('the enrollment widget should be opened', () => {
});
});
+Then('the enrollment actions button is not visible', () => {
+ cy.get('[data-test="widget-enrollment"]').within(() => {
+ cy.get('[data-test="widget-enrollment-actions-button"]').should('not.exist');
+ });
+});
+
+Then('the enrollment date edit buttons are not visible', () => {
+ cy.get('[data-test="widget-enrollment"]').within(() => {
+ cy.get('[data-test="widget-enrollment-icon-edit-date"]').should('not.exist');
+ });
+});
+
Then('the user sees the enrollment date', () => {
cy.get('[data-test="widget-enrollment-enrollment-date"]').within(() => {
cy.get('[data-test="widget-enrollment-icon-calendar"]').should('exist');
diff --git a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentAddEventPage/WidgetsForEnrollmentAddEventPage.feature b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentAddEventPage/WidgetsForEnrollmentAddEventPage.feature
index f4dfa1cc08..edb46a6ca5 100644
--- a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentAddEventPage/WidgetsForEnrollmentAddEventPage.feature
+++ b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentAddEventPage/WidgetsForEnrollmentAddEventPage.feature
@@ -38,12 +38,11 @@ Feature: The user interacts with the widgets on the enrollment add event page
And the user sees the owner organisation unit
And the user sees the last update date
- Scenario: User can open the delete modal
+ Scenario: The enrollment widget is in read-only mode
Given you land on the enrollment add event page by having typed #/enrollmentEventNew?programId=IpHINAT79UW&orgUnitId=DiszpKrYNg8&teiId=EaOyKGOIGRp&enrollmentId=wBU0RAsYjKE&stageId=A03MvHHogjR
Then the enrollment widget should be opened
- When the user opens the enrollment actions menu
- And the user clicks on the delete action
- Then the user sees the delete enrollment modal
+ And the enrollment actions button is not visible
+ And the enrollment date edit buttons are not visible
Scenario: User switch tab in add event page
Given you land on the enrollment add event page by having typed #/enrollmentEventNew?programId=IpHINAT79UW&orgUnitId=DiszpKrYNg8&teiId=EaOyKGOIGRp&enrollmentId=wBU0RAsYjKE&stageId=A03MvHHogjR
diff --git a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentEditEvent/WidgetsForEnrollmentEditEvent.feature b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentEditEvent/WidgetsForEnrollmentEditEvent.feature
index 2603f14633..896acfb495 100644
--- a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentEditEvent/WidgetsForEnrollmentEditEvent.feature
+++ b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEnrollmentEditEvent/WidgetsForEnrollmentEditEvent.feature
@@ -38,12 +38,11 @@ Feature: The user interacts with the widgets on the enrollment edit event
And the user sees the owner organisation unit
And the user sees the last update date
- Scenario: User can open the delete modal
+ Scenario: The enrollment widget is in read-only mode
Given you land on the enrollment edit event page by having typed /#/enrollmentEventEdit?eventId=XGLkLlOXgmE&orgUnitId=DiszpKrYNg8
Then the enrollment widget should be opened
- When the user opens the enrollment actions menu
- And the user clicks on the delete action
- Then the user sees the delete enrollment modal
+ And the enrollment actions button is not visible
+ And the enrollment date edit buttons are not visible
Scenario: User can add note on edit event page view mode
Given you land on the enrollment edit event page by having typed /#/enrollmentEventEdit?eventId=XGLkLlOXgmE&orgUnitId=DiszpKrYNg8
@@ -72,13 +71,11 @@ Feature: The user interacts with the widgets on the enrollment edit event
When you remove the assigned user
Then the event has no assignd user
- Scenario: User can complete the enrollment and the active events
+ Scenario: The enrollment widget is in read-only mode on enrollment event page
Given you land on the enrollment edit event page by having typed #/enrollmentEventEdit?eventId=PyXThVzWJzL&orgUnitId=RzgSFJ9E46G
And the enrollment widget should be opened
- And the user sees the enrollment status and the Baby Postnatal event status is active
- And the user opens the enrollment actions menu
- When the user completes the enrollment and the active events
- Then the user sees the enrollment status and the Baby Postnatal event status is completed
+ Then the enrollment actions button is not visible
+ And the enrollment date edit buttons are not visible
Scenario: User can see the enrollment minimap
Given you land on the enrollment edit event page by having typed #/enrollmentEventEdit?eventId=W1uHdJEjZUI&orgUnitId=DiszpKrYNg8
diff --git a/i18n/en.pot b/i18n/en.pot
index 58ea419d37..beeca74ad7 100644
--- a/i18n/en.pot
+++ b/i18n/en.pot
@@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-"POT-Creation-Date: 2026-05-26T07:35:44.230Z\n"
-"PO-Revision-Date: 2026-05-26T07:35:44.230Z\n"
+"POT-Creation-Date: 2026-05-24T11:43:30.545Z\n"
+"PO-Revision-Date: 2026-05-24T11:43:30.545Z\n"
msgid "The application could not be loaded."
msgstr "The application could not be loaded."
@@ -1071,6 +1071,36 @@ msgstr "Possible duplicates found"
msgid "An error occurred loading possible duplicates"
msgstr "An error occurred loading possible duplicates"
+msgid "You only have view access to this enrollment"
+msgstr "You only have view access to this enrollment"
+
+msgid "You only have view access to this program"
+msgstr "You only have view access to this program"
+
+msgid "You only have view access to this {{trackedEntityName}}"
+msgstr "You only have view access to this {{trackedEntityName}}"
+
+msgid "You only have view access to this tracked entity type"
+msgstr "You only have view access to this tracked entity type"
+
+msgid "You only have view access to these program stages"
+msgstr "You only have view access to these program stages"
+
+msgid "You only have view access to this program stage"
+msgstr "You only have view access to this program stage"
+
+msgid "This event is outside the valid editing period"
+msgstr "This event is outside the valid editing period"
+
+msgid "This event has been completed"
+msgstr "This event has been completed"
+
+msgid "View only - {{message}}"
+msgstr "View only - {{message}}"
+
+msgid "View only"
+msgstr "View only"
+
msgid "You don't have access to delete this relationship"
msgstr "You don't have access to delete this relationship"
@@ -1311,9 +1341,6 @@ msgstr "Unsaved changes"
msgid "Continue data entry"
msgstr "Continue data entry"
-msgid "You do not have access to modify this enrollment"
-msgstr "You do not have access to modify this enrollment"
-
msgid "Enrollment actions"
msgstr "Enrollment actions"
@@ -1512,9 +1539,6 @@ msgstr "No polygon captured"
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 "Notes about this event"
msgstr "Notes about this event"
@@ -1593,14 +1617,17 @@ msgstr "Save note"
msgid "Edit {{trackedEntityName}}"
msgstr "Edit {{trackedEntityName}}"
+msgid "Save changes"
+msgstr "Save changes"
+
msgid "Change information about this {{trackedEntityName}} here."
msgstr "Change information about this {{trackedEntityName}} here."
msgid "Information about this enrollment can be edited in the Enrollment widget."
msgstr "Information about this enrollment can be edited in the Enrollment widget."
-msgid "Save changes"
-msgstr "Save changes"
+msgid "{{trackedEntityName}} profile"
+msgstr "{{trackedEntityName}} profile"
msgid "Profile"
msgstr "Profile"
@@ -1641,6 +1668,9 @@ msgstr "There was a problem deleting the {{trackedEntityTypeName}}"
msgid "Yes, delete {{trackedEntityTypeName}}"
msgstr "Yes, delete {{trackedEntityTypeName}}"
+msgid "View profile"
+msgstr "View profile"
+
msgid "Profile widget could not be loaded. Please try again later"
msgstr "Profile widget could not be loaded. Please try again later"
@@ -1701,9 +1731,6 @@ msgstr "Please enter a date"
msgid "Please select a valid event"
msgstr "Please select a valid event"
-msgid "You do not have access to create events in this stage"
-msgstr "You do not have access to create events in this stage"
-
msgid "This stage can only have one event"
msgstr "This stage can only have one event"
@@ -1751,6 +1778,9 @@ msgstr "{{ overdueEvents }} overdue"
msgid "{{ scheduledEvents }} scheduled"
msgstr "{{ scheduledEvents }} scheduled"
+msgid "No stages found in this program"
+msgstr "No stages found in this program"
+
msgid "Stages and Events"
msgstr "Stages and Events"
@@ -1891,6 +1921,9 @@ msgstr "An error occurred while deleting the relationship."
msgid "To open this relationship, please wait until saving is complete"
msgstr "To open this relationship, please wait until saving is complete"
+msgid "This enrollment doesn't have any relationships"
+msgstr "This enrollment doesn't have any relationships"
+
msgid "Type"
msgstr "Type"
diff --git a/src/core_modules/capture-core/components/DataEntry/DataEntry.component.tsx b/src/core_modules/capture-core/components/DataEntry/DataEntry.component.tsx
index f6c9003adc..7e23cda0b4 100644
--- a/src/core_modules/capture-core/components/DataEntry/DataEntry.component.tsx
+++ b/src/core_modules/capture-core/components/DataEntry/DataEntry.component.tsx
@@ -142,6 +142,7 @@ export type DataEntryOutputProps = {
onGetValidationContext?: () => any,
orgUnitId?: string,
pluginContext?: PluginContext,
+ viewMode?: boolean,
};
type OwnProps = DataEntryOutputProps & {
diff --git a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentPageDefault.container.tsx b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentPageDefault.container.tsx
index 4189a37995..ea486c8df5 100644
--- a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentPageDefault.container.tsx
+++ b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentPageDefault.container.tsx
@@ -8,6 +8,7 @@ import { useTimeZoneConversion } from '@dhis2/app-runtime';
import type { ApiEnrollmentEvent } from 'capture-core-utils/types/api-types';
import {
commitEnrollmentAndEvents,
+ EnrollmentAccessProvider,
rollbackEnrollmentAndEvents,
showEnrollmentError,
updateEnrollmentAndEvents,
@@ -191,42 +192,43 @@ export const EnrollmentPageDefault = () => {
}
return (
-
+
+
+
);
};
diff --git a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentQuickActions/EnrollmentQuickActions.component.tsx b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentQuickActions/EnrollmentQuickActions.component.tsx
index 3ce36927d4..6bb4b27e7d 100644
--- a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentQuickActions/EnrollmentQuickActions.component.tsx
+++ b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentQuickActions/EnrollmentQuickActions.component.tsx
@@ -7,6 +7,7 @@ import { Widget } from '../../../../Widget';
import { QuickActionButton } from './QuickActionButton/QuickActionButton';
import { tabMode } from '../../../EnrollmentAddEvent/NewEventWorkspace/newEventWorkspace.constants';
import { useNavigate, buildUrlQueryString, useLocationQuery } from '../../../../../utils/routing';
+import { useEnrollmentAccessContext } from '../../../common/EnrollmentOverviewDomain/EnrollmentAccessContext';
import { OwnProps, ProgramStage, EventCount } from './EnrollmentQuickActions.types';
const styles = {
@@ -28,6 +29,7 @@ const EnrollmentQuickActionsComponentPlain = ({
const [open, setOpen] = useState(true);
const { navigate } = useNavigate();
const { enrollmentId, programId, teiId, orgUnitId } = useLocationQuery();
+ const { anyStageWriteAccess } = useEnrollmentAccessContext();
const stagesWithEventCount = useMemo(() => stages.map((stage) => {
const mutatedStage = { ...stage };
@@ -61,6 +63,8 @@ const EnrollmentQuickActionsComponentPlain = ({
const ready: boolean = events !== undefined && stages !== undefined;
+ if (!anyStageWriteAccess) return null;
+
return (
= ({ typography }: any) => ({
container: {
@@ -67,28 +69,33 @@ const EnrollmentAddEventPagePain = ({
return null;
}
return (
-