From 4a6d4483748c52aae6db9e0b2260422644b5c53e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 10:00:30 +0200 Subject: [PATCH 01/11] chore(deps-dev): bump @dhis2/cli-app-scripts from 12.11.0 to 12.11.1 (#4588) Bumps [@dhis2/cli-app-scripts](https://github.com/dhis2/app-platform/tree/HEAD/cli) from 12.11.0 to 12.11.1. - [Release notes](https://github.com/dhis2/app-platform/releases) - [Changelog](https://github.com/dhis2/app-platform/blob/master/CHANGELOG.md) - [Commits](https://github.com/dhis2/app-platform/commits/v12.11.1/cli) --- updated-dependencies: - dependency-name: "@dhis2/cli-app-scripts" dependency-version: 12.11.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index a888c17cf9..4837347be3 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "@babel/preset-typescript": "^7.27.0", "@badeball/cypress-cucumber-preprocessor": "17.2.1", "@cypress/webpack-preprocessor": "^6.0.0", - "@dhis2/cli-app-scripts": "^12.11.0", + "@dhis2/cli-app-scripts": "^12.11.1", "@dhis2/cli-helpers-engine": "^3.2.1", "@dhis2/cli-style": "^10.7.10", "@dhis2/cli-utils-cypress": "^9.0.2", diff --git a/yarn.lock b/yarn.lock index 016bbe9e34..dd350d97af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2313,12 +2313,12 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2/app-adapter@12.11.0": - version "12.11.0" - resolved "https://registry.yarnpkg.com/@dhis2/app-adapter/-/app-adapter-12.11.0.tgz#bc76fd317c0b95b9a1498f4bc717622a8dd5be6a" - integrity sha512-XwAVGJtBMIq1tf3yIGYbsgUVn08W4021jo3E5mkIuTsds20q5hk3pt6KEQK21dlWIMPM0OYYvNdhFTTuXj9d2A== +"@dhis2/app-adapter@12.11.1": + version "12.11.1" + resolved "https://registry.yarnpkg.com/@dhis2/app-adapter/-/app-adapter-12.11.1.tgz#f12f3e2ed6eb4c572997ff04d6d8bfce61e24912" + integrity sha512-xPc/SfnQ4AsDknCoH6eEyzHW+cwLHA6fJmuvbBSjOs8rFUw0T/ZMOOSh9kcAb+/qmFpcFTRlnCQXwEnLkadgtg== dependencies: - "@dhis2/pwa" "12.11.0" + "@dhis2/pwa" "12.11.1" moment "^2.24.0" "@dhis2/app-runtime@^3.14.3", "@dhis2/app-runtime@^3.17.0": @@ -2379,15 +2379,15 @@ dependencies: prop-types "^15.7.2" -"@dhis2/app-shell@12.11.0": - version "12.11.0" - resolved "https://registry.yarnpkg.com/@dhis2/app-shell/-/app-shell-12.11.0.tgz#7535240ee60d5ba179989d10aaf2d8fe16b36ed3" - integrity sha512-b1wm7nC5cMpoprRfrC8/OOrDTe1+1im50cxwQwNIL2Q/8v0fwd14NSJzWbyxGL0To8S9tbK5ruZL+QllrWtGfg== +"@dhis2/app-shell@12.11.1": + version "12.11.1" + resolved "https://registry.yarnpkg.com/@dhis2/app-shell/-/app-shell-12.11.1.tgz#9b6e3ed97e1a2c1b7617e42fd5bc82eeb9480510" + integrity sha512-8Vbms2pE1GFCgJOuAafSZuLrOPOmpiqt5lcFvDlhBzXOLx2VDzM9BwTtGi8bm+kX4jrTFkDCTkxkvelRNonjvQ== dependencies: - "@dhis2/app-adapter" "12.11.0" + "@dhis2/app-adapter" "12.11.1" "@dhis2/app-runtime" "^3.14.3" "@dhis2/d2-i18n" "^1.2.0" - "@dhis2/pwa" "12.11.0" + "@dhis2/pwa" "12.11.1" "@dhis2/ui" "^10.9.2" classnames "^2.2.6" moment "^2.29.1" @@ -2398,10 +2398,10 @@ styled-jsx "^4.0.1" typeface-roboto "^0.0.75" -"@dhis2/cli-app-scripts@^12.11.0": - version "12.11.0" - resolved "https://registry.yarnpkg.com/@dhis2/cli-app-scripts/-/cli-app-scripts-12.11.0.tgz#cddecb6c6c3e2c40cdfbf6250ab3e0ecae7e3fb7" - integrity sha512-dBbnNS4tOzez1QIBoYfpS2wotWWTig29VSOT09zruqILyIpT6uQ8kWx2kF97Iq0tSfdIq5I5x8U4/yxdzO9Vfg== +"@dhis2/cli-app-scripts@^12.11.1": + version "12.11.1" + resolved "https://registry.yarnpkg.com/@dhis2/cli-app-scripts/-/cli-app-scripts-12.11.1.tgz#ca33d006a8743c35366864c8ac22e488680324e7" + integrity sha512-zgyiqR3UTo9bK2yDUFRDusNGPX1gKNShSIjou63RbWLKJ3tfPgxpXR9pX6D+wqeBwKYu/S+zuZziCjgyX6U0dA== dependencies: "@babel/core" "^7.27.4" "@babel/plugin-syntax-dynamic-import" "^7.8.3" @@ -2414,7 +2414,7 @@ "@babel/preset-env" "^7.27.2" "@babel/preset-react" "^7.0.0" "@babel/preset-typescript" "^7.27.1" - "@dhis2/app-shell" "12.11.0" + "@dhis2/app-shell" "12.11.1" "@dhis2/cli-helpers-engine" "^3.2.2" "@jest/core" "^27.0.6" "@pmmmwh/react-refresh-webpack-plugin" "^0.5.4" @@ -2574,10 +2574,10 @@ resolved "https://registry.yarnpkg.com/@dhis2/prop-types/-/prop-types-3.1.2.tgz#65b8ad2da8cd2f72bc8b951049a6c9d1b97af3e9" integrity sha512-eM0jjLOWvtXWqSFp5YC4DHFpkP8Y1D2eUwGV7MBWjni+o27oesVan+oT7WHeOeLdlAd4acRJrnaaAyB4Ck1wGQ== -"@dhis2/pwa@12.11.0": - version "12.11.0" - resolved "https://registry.yarnpkg.com/@dhis2/pwa/-/pwa-12.11.0.tgz#6600c91d2d9595fdf35243dce0ef714c6e414e15" - integrity sha512-ZcWHMBLzqW4TzvKQxsX+NALyKH9IEc/QvIIf5tR5pSdhIUPhy0WBtRdczgBfuUcBMtyNR+i9iORgnsUHA4Iefg== +"@dhis2/pwa@12.11.1": + version "12.11.1" + resolved "https://registry.yarnpkg.com/@dhis2/pwa/-/pwa-12.11.1.tgz#76448bbcbf0b2a347a04fe5524ac627bca1aa550" + integrity sha512-q1bIYrvF2R/peQp/bu8AZ6LsEOAYNHliJEGSr/0lczrrke61oHAk4WcYFATYRaUDlvRA1vxstRSSVsUWtB0qRA== dependencies: idb "^6.0.0" workbox-precaching "^7.1.0" From 1aeb6435db07102754ed89e4efc951950365fc46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 11:02:14 +0200 Subject: [PATCH 02/11] chore(deps-dev): bump @babel/eslint-parser from 7.28.0 to 7.28.6 (#4585) Bumps [@babel/eslint-parser](https://github.com/babel/babel/tree/HEAD/eslint/babel-eslint-parser) from 7.28.0 to 7.28.6. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.28.6/eslint/babel-eslint-parser) --- updated-dependencies: - dependency-name: "@babel/eslint-parser" dependency-version: 7.28.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4837347be3..327e6f0f12 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "devDependencies": { "@actions/core": "^3.0.0", "@babel/core": "^7.17.8", - "@babel/eslint-parser": "^7.19.1", + "@babel/eslint-parser": "^7.28.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.26.3", diff --git a/yarn.lock b/yarn.lock index dd350d97af..f5120eb76f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -90,10 +90,10 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/eslint-parser@^7.19.1": - version "7.28.0" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.28.0.tgz#c1b3fbba070f5bac32e3d02f244201add4afdd6e" - integrity sha512-N4ntErOlKvcbTt01rr5wj3y55xnIdx1ymrfIr8C2WnM1Y9glFgWaGDEULJIazOX3XM9NRzhfJ6zZnQ1sBNWU+w== +"@babel/eslint-parser@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.28.6.tgz#6a294a4add732ebe7ded8a8d2792dd03dd81dc3f" + integrity sha512-QGmsKi2PBO/MHSQk+AAgA9R6OHQr+VqnniFE0eMWZcVcfBZoA2dKn2hUsl3Csg/Plt9opRUWdY7//VXsrIlEiA== dependencies: "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" eslint-visitor-keys "^2.1.0" From ead5b8dd8affa291987e5e5b51d38ee9b3b62d17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 11:02:25 +0200 Subject: [PATCH 03/11] chore(deps): bump typeface-roboto from 0.0.75 to 1.1.13 (#4589) Bumps [typeface-roboto](https://github.com/KyleAMathews/typefaces) from 0.0.75 to 1.1.13. - [Commits](https://github.com/KyleAMathews/typefaces/compare/v0.0.75...v1.1.13) --- updated-dependencies: - dependency-name: typeface-roboto dependency-version: 1.1.13 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 327e6f0f12..8031650743 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "regenerator-runtime": "^0.14.1", "reselect": "^4.1.7", "rxjs": "^7.8.2", - "typeface-roboto": "^0.0.75", + "typeface-roboto": "^1.1.13", "uuid": "^9.0.0", "zod": "^3.24.4" }, diff --git a/yarn.lock b/yarn.lock index f5120eb76f..d67b1b4135 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14140,6 +14140,11 @@ typeface-roboto@^0.0.75: resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-0.0.75.tgz#98d5ba35ec234bbc7172374c8297277099cc712b" integrity sha512-VrR/IiH00Z1tFP4vDGfwZ1esNqTiDMchBEXYY9kilT6wRGgFoCAlgkEUMHb1E3mB0FsfZhv756IF0+R+SFPfdg== +typeface-roboto@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-1.1.13.tgz#9c4517cb91e311706c74823e857b4bac9a764ae5" + integrity sha512-YXvbd3a1QTREoD+FJoEkl0VQNJoEjewR2H11IjVv4bp6ahuIcw0yyw/3udC4vJkHw3T3cUh85FTg8eWef3pSaw== + typescript@^5.6.3, typescript@^5.8.2: version "5.8.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" From af21acd67c81195e66631ff49d7a40bac82a8ebe Mon Sep 17 00:00:00 2001 From: henrikmv Date: Thu, 28 May 2026 14:40:29 +0200 Subject: [PATCH 04/11] fix: revert feedbackbar changes --- .../FeedbackBar/FeedbackBar.component.tsx | 4 +- .../FeedbackBar/FeedbackBar.types.ts | 1 - .../feedback.reducerDescriptionGetter.ts | 156 +++++++++++------- 3 files changed, 95 insertions(+), 66 deletions(-) diff --git a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.tsx b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.tsx index bbf92a312c..d478dccaa7 100644 --- a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.tsx +++ b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.tsx @@ -24,7 +24,7 @@ const FeedbackBarComponentPlain = ({ feedback, onClose }: Props) => { return null; } - const { id, message, displayType, variant } = feedback; + const { message, displayType, variant } = feedback; const isAlertBarOpen = typeof message === 'string' && !displayType; const isDialogOpen = typeof message === 'object' && displayType === 'dialog'; const alertVariant = getAlertVariant(variant); @@ -33,7 +33,7 @@ const FeedbackBarComponentPlain = ({ feedback, onClose }: Props) => { <> {isAlertBarOpen && ( - + {message} )} diff --git a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.types.ts b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.types.ts index 55a54cb07d..f7acaada51 100644 --- a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.types.ts +++ b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.types.ts @@ -1,7 +1,6 @@ import { ReactNode } from 'react'; export type Feedback = { - id: string; message: string | { title: string; content: string }; action?: ReactNode; displayType?: 'alert' | 'dialog'; diff --git a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts index e5e4cd7d09..05e1db06d8 100644 --- a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts +++ b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts @@ -3,7 +3,6 @@ import log from 'loglevel'; import i18n from '@dhis2/d2-i18n'; import isString from 'd2-utilizr/lib/isString'; import isObject from 'd2-utilizr/lib/isObject'; -import uuid from 'd2-utilizr/lib/uuid'; import { errorCreator } from 'capture-core-utils'; import { createReducerDescription } from '../../trackerRedux/trackerReducer'; import { actionTypes as feedbackActionTypes } from '../../components/FeedbackBar/actions/feedback.actions'; @@ -45,19 +44,31 @@ type ErrorFeedbackInput = { action?: ReactNode, }; -const getErrorFeedback = ({ - message, - variant = 'critical', - action, -}: ErrorFeedbackInput) => ({ - id: uuid(), - message, - action, - feedbackType: 'ERROR' as const, - variant, -}); +function addErrorFeedback( + state: any, + { message, variant = alertVariants.critical as keyof typeof alertVariants, action }: ErrorFeedbackInput, +) { + return [ + ...state, + { + message, + action, + feedbackType: 'ERROR', + variant, + }, + ]; +} -const addErrorFeedback = (input: ErrorFeedbackInput) => [getErrorFeedback(input)]; +function getErrorFeedback( + { message, variant = alertVariants.critical as keyof typeof alertVariants, action }: ErrorFeedbackInput, +) { + return { + message, + action, + feedbackType: 'ERROR', + variant, + }; +} export const getFeedbackDesc = (appUpdaters: Updaters) => createReducerDescription({ ...appUpdaters, @@ -66,67 +77,86 @@ export const getFeedbackDesc = (appUpdaters: Updaters) => createReducerDescripti newState.shift(); return newState; }, - [dataEntryActionTypes.COMPLETE_EVENT_ERROR]: (_state, action) => - addErrorFeedback({ + [dataEntryActionTypes.COMPLETE_EVENT_ERROR]: (state, action) => + addErrorFeedback(state, { message: action.payload.error, action: action.payload.action, }), - [enrollmentActionTypes.ENROLLMENT_LOAD_FAILED]: (_state, action) => - addErrorFeedback(action.payload), - [workingListsCommonActionTypes.LIST_VIEW_INIT_ERROR]: (_state, action) => - addErrorFeedback(action.payload.errorMessage), - [newEventDataEntryActionTypes.SAVE_FAILED_FOR_NEW_EVENT_AFTER_RETURNED_TO_MAIN_PAGE]: (_state, action) => { + [enrollmentActionTypes.ENROLLMENT_LOAD_FAILED]: (state, action) => + addErrorFeedback(state, action.payload), + [workingListsCommonActionTypes.LIST_VIEW_INIT_ERROR]: (state, action) => + addErrorFeedback(state, action.payload.errorMessage), + [newEventDataEntryActionTypes.SAVE_FAILED_FOR_NEW_EVENT_AFTER_RETURNED_TO_MAIN_PAGE]: (state, action) => { const error = action.payload; const errorMessage = isString(error) ? error : error.message; const errorObject = isObject(error) ? error : null; log.error(errorCreator(errorMessage || 'Error saving event')(errorObject)); - return addErrorFeedback({ message: i18n.t('Could not save event') }); + const newState = [ + ...state, + getErrorFeedback({ message: i18n.t('Could not save event') }), + ]; + return newState; }, - [workingListsCommonActionTypes.LIST_UPDATE_ERROR]: (_state, action) => - addErrorFeedback({ message: action.payload.errorMessage }), - [eventWorkingListsActionTypes.EVENT_DELETE_ERROR]: () => - addErrorFeedback({ message: i18n.t('Could not delete event') }), - [workingListsCommonActionTypes.TEMPLATE_UPDATE_ERROR]: () => - addErrorFeedback({ message: i18n.t('Could not save working list') }), - [workingListsCommonActionTypes.TEMPLATE_ADD_ERROR]: () => - addErrorFeedback({ message: i18n.t('Could not add working list') }), - [workingListsCommonActionTypes.TEMPLATE_DELETE_ERROR]: () => - addErrorFeedback({ message: i18n.t('Could not delete working list') }), - [asyncHandlerActionTypes.ASYNC_UPDATE_FIELD_FAILED]: (_state, { payload }) => - addErrorFeedback({ message: payload.message }), - [newEventDataEntryActionTypes.SAVE_FAILED_FOR_NEW_EVENT_ADD_ANOTHER]: (_state, action) => { + [workingListsCommonActionTypes.LIST_UPDATE_ERROR]: (state, action) => [ + ...state, + getErrorFeedback({ message: action.payload.errorMessage }), + ], + [eventWorkingListsActionTypes.EVENT_DELETE_ERROR]: state => [ + ...state, + getErrorFeedback({ message: i18n.t('Could not delete event') }), + ], + + [workingListsCommonActionTypes.TEMPLATE_UPDATE_ERROR]: state => [ + ...state, + getErrorFeedback({ message: i18n.t('Could not save working list') }), + ], + [workingListsCommonActionTypes.TEMPLATE_ADD_ERROR]: state => [ + ...state, + getErrorFeedback({ message: i18n.t('Could not add working list') }), + ], + [workingListsCommonActionTypes.TEMPLATE_DELETE_ERROR]: state => [ + ...state, + getErrorFeedback({ message: i18n.t('Could not delete working list') }), + ], + [asyncHandlerActionTypes.ASYNC_UPDATE_FIELD_FAILED]: (state, { payload }) => + addErrorFeedback(state, { message: payload.message }), + [newEventDataEntryActionTypes.SAVE_FAILED_FOR_NEW_EVENT_ADD_ANOTHER]: (state, action) => { const error = action.payload; const errorMessage = isString(error) ? error : error.message; const errorObject = isObject(error) ? error : null; log.error(errorCreator(errorMessage || 'Error saving event')(errorObject)); - return addErrorFeedback({ message: i18n.t('Could not save event') }); + const newState = [ + ...state, + getErrorFeedback({ message: i18n.t('Could not save event') }), + ]; + return newState; }, - [dataEntryActionTypes.DATA_ENTRY_RELATIONSHIP_ALREADY_EXISTS]: (_state, action) => - addErrorFeedback({ message: action.payload.message }), - [viewEventNewRelationshipActionTypes.EVENT_RELATIONSHIP_ALREADY_EXISTS]: (_state, action) => - addErrorFeedback({ message: action.payload.message }), - [registrationSectionActionTypes.ORG_UNIT_SEARCH_FAILED]: () => - addErrorFeedback({ message: i18n.t('Organisation unit search failed.') }), - [registrationFormActionTypes.NEW_TRACKED_ENTITY_INSTANCE_SAVE_FAILED]: () => - addErrorFeedback({ message: i18n.t('Error saving tracked entity instance') }), - [registrationFormActionTypes.NEW_TRACKED_ENTITY_INSTANCE_WITH_ENROLLMENT_SAVE_FAILED]: () => - addErrorFeedback({ message: i18n.t('Error saving enrollment') }), - [enrollmentSiteActionTypes.SAVE_FAILED]: () => - addErrorFeedback({ message: i18n.t('Error saving the enrollment event') }), - [editEventActionTypes.DELETE_EVENT_DATA_ENTRY_FAILED]: () => - addErrorFeedback({ message: i18n.t('Error deleting the enrollment event') }), - [editEventDataEntryAction.SAVE_EDIT_EVENT_DATA_ENTRY_FAILED]: () => - addErrorFeedback({ message: i18n.t('Error editing the event, the changes made were not saved') }), - [enrollmentSiteActionTypes.ERROR_ENROLLMENT]: (_state, action) => - addErrorFeedback({ message: i18n.t(action.payload.message) }), - [viewEventActionTypes.ASSIGNEE_SAVE_FAILED]: () => - addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), - [enrollmentEditEventActionTypes.ASSIGNEE_SAVE_FAILED]: () => - addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), - [enrollmentNoteActionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT]: () => - addErrorFeedback({ message: i18n.t('Could not save enrollment note') }), - [eventNoteActionTypes.ADD_NOTE_FAILED_FOR_EVENT]: () => - addErrorFeedback({ message: i18n.t('Could not save event note') }), - [viewEventNotesActionTypes.SAVE_EVENT_NOTE_FAILED]: () => - addErrorFeedback({ message: i18n.t('Could not save event note') }), + [dataEntryActionTypes.DATA_ENTRY_RELATIONSHIP_ALREADY_EXISTS]: (state, action) => + addErrorFeedback(state, { message: action.payload.message }), + [viewEventNewRelationshipActionTypes.EVENT_RELATIONSHIP_ALREADY_EXISTS]: (state, action) => + addErrorFeedback(state, { message: action.payload.message }), + [registrationSectionActionTypes.ORG_UNIT_SEARCH_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Organisation unit search failed.') }), + [registrationFormActionTypes.NEW_TRACKED_ENTITY_INSTANCE_SAVE_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Error saving tracked entity instance') }), + [registrationFormActionTypes.NEW_TRACKED_ENTITY_INSTANCE_WITH_ENROLLMENT_SAVE_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Error saving enrollment') }), + [enrollmentSiteActionTypes.SAVE_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Error saving the enrollment event') }), + [editEventActionTypes.DELETE_EVENT_DATA_ENTRY_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Error deleting the enrollment event') }), + [editEventDataEntryAction.SAVE_EDIT_EVENT_DATA_ENTRY_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Error editing the event, the changes made were not saved') }), + [enrollmentSiteActionTypes.ERROR_ENROLLMENT]: (state, action) => + addErrorFeedback(state, { message: i18n.t(action.payload.message) }), + [viewEventActionTypes.ASSIGNEE_SAVE_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Error updating the Assignee') }), + [enrollmentEditEventActionTypes.ASSIGNEE_SAVE_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Error updating the Assignee') }), + [enrollmentNoteActionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT]: state => + addErrorFeedback(state, { message: i18n.t('Could not save enrollment note') }), + [eventNoteActionTypes.ADD_NOTE_FAILED_FOR_EVENT]: state => + addErrorFeedback(state, { message: i18n.t('Could not save event note') }), + [viewEventNotesActionTypes.SAVE_EVENT_NOTE_FAILED]: state => + addErrorFeedback(state, { message: i18n.t('Could not save event note') }), }, 'feedbacks', []); From d04c459e8f5782b45a723f96b1f82ee76bcd0ae7 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Thu, 28 May 2026 16:06:43 +0200 Subject: [PATCH 05/11] Merge branch 'hv/fix/DHIS2-21580_sequential-errors-are-not-shown-FeedbackBar' into hv/fix/DHIS2-21544_failed-saves-leave-stale-optimistic-enrollment-note-in-state --- i18n/en.pot | 4 +- .../ViewEvent/Notes/viewEventNotes.epics.ts | 2 +- .../ViewEventComponent/editEvent.actions.ts | 8 + .../ViewEventComponent/viewEvent.actions.ts | 8 + .../WidgetEnrollmentNote.actions.ts | 5 +- .../WidgetEnrollmentNote.epics.ts | 12 +- .../WidgetEnrollmentNote.types.ts | 1 - .../WidgetEventNote.actions.ts | 1 + .../WidgetEventNote/WidgetEventNote.epics.ts | 27 ++- .../WidgetEventNote/WidgetEventNote.types.ts | 13 +- .../enrollmentDomain.reducerDescription.ts | 11 +- .../descriptions/events.reducerDescription.ts | 16 ++ .../feedback.reducerDescriptionGetter.ts | 156 +++++++----------- src/epics/trackerCapture.epics.ts | 6 +- 14 files changed, 136 insertions(+), 134 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 4b49716d22..e1401fff16 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-28T07:31:16.181Z\n" -"PO-Revision-Date: 2026-05-28T07:31:16.181Z\n" +"POT-Creation-Date: 2026-05-28T13:43:14.066Z\n" +"PO-Revision-Date: 2026-05-28T13:43:14.066Z\n" msgid "The application could not be loaded." msgstr "The application could not be loaded." diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics.ts b/src/core_modules/capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics.ts index 6d37b8299b..2b0fc3a0e7 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics.ts +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics.ts @@ -67,7 +67,7 @@ export const addNoteForViewEventEpic = (action$: any, store: any, { fromClientDa }, storedBy: username, storedAt: fromClientDate(moment().toISOString()).getServerZonedISOString(), - clientId, + clientId: uuid(), }; return batchActions([ startSaveEventNote(eventId, serverData, state.currentSelections, clientNote.clientId), diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/editEvent.actions.ts b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/editEvent.actions.ts index 8e4ef15909..87177c8eaa 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/editEvent.actions.ts +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/editEvent.actions.ts @@ -6,6 +6,8 @@ export const actionTypes = { EVENT_FROM_URL_RETRIEVED: 'EventFromUrlRetrievedForEditEvent', EVENT_FROM_URL_COULD_NOT_BE_RETRIEVED: 'EventFromUrlCouldNotBeRetrievedForEditEvent', ORG_UNIT_RETRIEVAL_FAILED_ON_URL_UPDATE: 'OrgUnitRetrievalFailedForEditEventOnUrlUpdate', + ADD_EVENT_NOTE: 'AddEventNote', + REMOVE_EVENT_NOTE: 'RemoveEventNote', }; export const eventFromUrlCouldNotBeRetrieved = (message: string) => @@ -16,3 +18,9 @@ export const eventFromUrlRetrieved = (eventContainer: any, orgUnit: OrgUnit, pre export const orgUnitCouldNotBeRetrievedOnUrlUpdate = (eventContainer: any) => actionCreator(actionTypes.ORG_UNIT_RETRIEVAL_FAILED_ON_URL_UPDATE)({ eventContainer }); + +export const addEventNote = (eventId: string, note: any) => + actionCreator(actionTypes.ADD_EVENT_NOTE)({ eventId, note }); + +export const removeEventNote = (eventId: string, noteClientId: string) => + actionCreator(actionTypes.REMOVE_EVENT_NOTE)({ eventId, noteClientId }); diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions.ts b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions.ts index 88af3a7479..a24712b319 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions.ts +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions.ts @@ -8,6 +8,8 @@ export const actionTypes = { ORG_UNIT_RETRIEVED_ON_URL_UPDATE: 'OrgUnitRetrievedForViewEventOnUrlUpdate', ORG_UNIT_RETRIEVAL_FAILED_ON_URL_UPDATE: 'OrgUnitRetrievalFailedForViewEventOnUrlUpdate', START_OPEN_EVENT_FOR_VIEW: 'StartOpenEventForView', + ADD_EVENT_NOTE: 'AddEventNoteForViewEvent', + REMOVE_EVENT_NOTE: 'RemoveEventNoteForViewEvent', UPDATE_WORKING_LIST_ON_BACK_TO_MAIN_PAGE: 'UpdateWorkingListOnBackToMainPageForViewEvent', NO_WORKING_LIST_UPDATE_NEEDED_ON_BACK_TO_MAIN_PAGE: 'NoWorkingListUpdateNeededOnBackToMainPageForViewEvent', START_GO_BACK_TO_MAIN_PAGE: 'StartGoBackToMainPageForViewEvent', @@ -47,6 +49,12 @@ export const orgUnitCouldNotBeRetrievedOnUrlUpdate = (eventContainer: any) => export const startOpenEventForView = (eventContainer: any, orgUnit: any) => actionCreator(actionTypes.START_OPEN_EVENT_FOR_VIEW)({ eventContainer, orgUnit }); +export const addEventNote = (eventId: string, note: any) => + actionCreator(actionTypes.ADD_EVENT_NOTE)({ eventId, note }); + +export const removeEventNote = (eventId: string, noteClientId: string) => + actionCreator(actionTypes.REMOVE_EVENT_NOTE)({ eventId, noteClientId }); + export const startGoBackToMainPage = (orgUnitId: string | null) => actionCreator(actionTypes.START_GO_BACK_TO_MAIN_PAGE)({ orgUnitId }); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts index 7ade3abd34..619f3bffc9 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts @@ -7,12 +7,12 @@ export const actionTypes = { START_ADD_NOTE_FOR_ENROLLMENT: 'StartAddNoteForEnrollment', NOTE_ADDED_FOR_ENROLLMENT: 'NoteAddedForEnrollment', ADD_ENROLLMENT_NOTE: 'AddEnrollmentNote', - REMOVE_ENROLLMENT_NOTE: 'RemoveEnrollmentNote', ADD_NOTE_FAILED_FOR_ENROLLMENT: 'AddNoteFailedForEnrollment', }; export const batchActionTypes = { ADD_NOTE_BATCH_FOR_ENROLLMENT: 'AddNoteBatchForEnrollment', + REMOVE_NOTE_BATCH_FOR_ENROLLMENT: 'RemoveNoteBatchForEnrollment', }; export const requestAddNoteForEnrollment = (enrollmentId: string, note: string) => @@ -40,6 +40,3 @@ export const startAddNoteForEnrollment = ( export const addEnrollmentNote = (enrollmentUid: string, note: Record) => actionCreator(actionTypes.ADD_ENROLLMENT_NOTE)({ enrollmentUid, note }); - -export const removeEnrollmentNote = (enrollmentUid: string, noteClientId: string) => - actionCreator(actionTypes.REMOVE_ENROLLMENT_NOTE)({ enrollmentUid, noteClientId }); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts index 9b4a5b0272..609f3a200e 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts @@ -6,7 +6,7 @@ import uuid from 'd2-utilizr/lib/uuid'; import moment from 'moment'; import type { ReduxStore, ApiUtils, EpicAction } from 'capture-core-utils/types/global'; import { CurrentUser } from '../../utils/userInfo/CurrentUser'; -import { actionTypes, batchActionTypes, startAddNoteForEnrollment, addEnrollmentNote, removeEnrollmentNote } +import { actionTypes, batchActionTypes, startAddNoteForEnrollment, addEnrollmentNote } from './WidgetEnrollmentNote.actions'; import type { ClientNote, SaveContext } from './WidgetEnrollmentNote.types'; @@ -47,7 +47,6 @@ export const addNoteForEnrollmentEpic = ( }, storedBy: username, storedAt: fromClientDate(moment().toISOString()).getServerZonedISOString(), - clientId, }; const saveContext: SaveContext = { @@ -60,12 +59,3 @@ export const addNoteForEnrollmentEpic = ( addEnrollmentNote(enrollmentId, clientNote), ], batchActionTypes.ADD_NOTE_BATCH_FOR_ENROLLMENT); })); - -export const removeNoteForEnrollmentEpic = ( - action$: EpicAction, -) => - action$.pipe( - ofType(actionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT), - map((action: { meta: { context: SaveContext } }) => - removeEnrollmentNote(action.meta.context.enrollmentId, action.meta.context.noteClientId), - )); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.types.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.types.ts index 4cc1e94307..4f3470de6e 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.types.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.types.ts @@ -7,7 +7,6 @@ export type ClientNote = { }; storedBy: string; storedAt: string; - clientId: string; }; export type SaveContext = { diff --git a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.actions.ts b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.actions.ts index 7e62d9c502..3e91ecc142 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.actions.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.actions.ts @@ -11,6 +11,7 @@ export const actionTypes = { export const batchActionTypes = { ADD_NOTE_BATCH_FOR_EVENT: 'AddNoteBatchForEvent', + REMOVE_NOTE_BATCH_FOR_EVENT: 'RemoveNoteBatchForEvent', }; export const requestAddNoteForEvent = (itemId: string, dataEntryId: string, note: string) => diff --git a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.epics.ts b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.epics.ts index e37d3a81ae..9fca9c4e59 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.epics.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.epics.ts @@ -7,7 +7,12 @@ import moment from 'moment'; import type { ReduxStore, ApiUtils, EpicAction } from 'capture-core-utils/types'; import { CurrentUser } from '../../utils/userInfo/CurrentUser'; import { actionTypes, batchActionTypes, startAddNoteForEvent } from './WidgetEventNote.actions'; -import type { FormNote, SaveContext } from './WidgetEventNote.types'; +import type { ClientNote, FormNote, SaveContext } from './WidgetEventNote.types'; + +import { + addEventNote, + removeEventNote, +} from '../Pages/ViewEvent/ViewEventComponent/editEvent.actions'; import { addNote, @@ -48,16 +53,24 @@ export const addNoteForEventEpic = ( const serverData = createServerData(eventId, payload.note, useNewEndpoint); - const formNote: FormNote = { + const clientNote: ClientNote = { value: payload.note, - createdBy: { + lastUpdatedBy: { firstName, surname, uid: clientId, }, storedBy: username, storedAt: fromClientDate(moment().toISOString()).getServerZonedISOString(), - clientId, + }; + const formNote: FormNote = { + ...clientNote, + storedAt: clientNote.storedAt, + createdBy: { + firstName, + surname, + uid: clientId, + }, }; const saveContext: SaveContext = { dataEntryId: payload.dataEntryId, @@ -69,6 +82,7 @@ export const addNoteForEventEpic = ( return batchActions([ startAddNoteForEvent(eventId, serverData, state.currentSelections, saveContext), addNote(payload.dataEntryId, payload.itemId, formNote), + addEventNote(eventId, clientNote), ], batchActionTypes.ADD_NOTE_BATCH_FOR_EVENT); })); @@ -77,5 +91,8 @@ export const removeNoteForEventEpic = (action$: EpicAction { const context = action.meta.context; - return removeNote(context.dataEntryId, context.itemId, context.noteClientId); + return batchActions([ + removeNote(context.dataEntryId, context.itemId, context.noteClientId), + removeEventNote(context.eventId, context.noteClientId), + ], batchActionTypes.REMOVE_NOTE_BATCH_FOR_EVENT); })); diff --git a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.types.ts b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.types.ts index 9331e9347e..87957e6627 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.types.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.types.ts @@ -3,16 +3,23 @@ export type Props = { dataEntryId: string; }; -export type FormNote = { +export type ClientNote = { value: string; - createdBy: { + lastUpdatedBy: { firstName: string; surname: string; uid: string; }; storedBy: string; storedAt: string; - clientId: string; +}; + +export type FormNote = ClientNote & { + createdBy: { + firstName: string; + surname: string; + uid: string; + }; }; export type SaveContext = { diff --git a/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts b/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts index ea63dd09ef..42f057dbe8 100644 --- a/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts +++ b/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts @@ -1,6 +1,7 @@ import { createReducerDescription } from '../../trackerRedux'; import { enrollmentSiteActionTypes } from '../../components/Pages/common/EnrollmentOverviewDomain'; -import { enrollmentNoteActionTypes } from '../../components/WidgetEnrollmentNote'; +import { actionTypes as enrollmentNoteActionTypes } + from '../../components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions'; import { actionTypes as editEventActionTypes } from '../../components/WidgetEventEdit/EditEventDataEntry/editEventDataEntry.actions'; import { newEventWidgetActionTypes } from '../../components/WidgetEnrollmentEventNew/Validated/validated.actions'; @@ -259,14 +260,6 @@ export const enrollmentDomainDesc = createReducerDescription( notes: [...state.enrollment.notes, note], }, }), - [enrollmentNoteActionTypes.REMOVE_ENROLLMENT_NOTE]: - (state, { payload: { noteClientId } }) => ({ - ...state, - enrollment: { - ...state.enrollment, - notes: state.enrollment.notes.filter((n: any) => n?.clientId !== noteClientId), - }, - }), [editEventActionTypes.REQUEST_DELETE_EVENT_DATA_ENTRY]: (state, { payload: { eventId } }) => { const events = state.enrollment.events?.map((event) => { if (event.event === eventId) { diff --git a/src/core_modules/capture-core/reducers/descriptions/events.reducerDescription.ts b/src/core_modules/capture-core/reducers/descriptions/events.reducerDescription.ts index 88cf5bea3f..24cc4d1cdb 100644 --- a/src/core_modules/capture-core/reducers/descriptions/events.reducerDescription.ts +++ b/src/core_modules/capture-core/reducers/descriptions/events.reducerDescription.ts @@ -48,6 +48,22 @@ export const eventsDesc = createReducerDescription({ }; return newState; }, + [viewEventActionTypes.ADD_EVENT_NOTE]: (state, action) => { + const newState = { ...state }; + const payload = action.payload; + if (newState[payload.eventId]) { + newState[payload.eventId].notes = [...state[payload.eventId].notes, payload.note]; + } + return newState; + }, + [viewEventActionTypes.REMOVE_EVENT_NOTE]: (state, action) => { + const newState = { ...state }; + const payload = action.payload; + if (newState[payload.eventId]) { + newState[payload.eventId].notes = state[payload.eventId].notes.filter(n => n.clientId !== payload.noteClientId); + } + return newState; + }, }, 'events', {}); export const eventsValuesDesc = createReducerDescription({ diff --git a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts index 05e1db06d8..e5e4cd7d09 100644 --- a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts +++ b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts @@ -3,6 +3,7 @@ import log from 'loglevel'; import i18n from '@dhis2/d2-i18n'; import isString from 'd2-utilizr/lib/isString'; import isObject from 'd2-utilizr/lib/isObject'; +import uuid from 'd2-utilizr/lib/uuid'; import { errorCreator } from 'capture-core-utils'; import { createReducerDescription } from '../../trackerRedux/trackerReducer'; import { actionTypes as feedbackActionTypes } from '../../components/FeedbackBar/actions/feedback.actions'; @@ -44,31 +45,19 @@ type ErrorFeedbackInput = { action?: ReactNode, }; -function addErrorFeedback( - state: any, - { message, variant = alertVariants.critical as keyof typeof alertVariants, action }: ErrorFeedbackInput, -) { - return [ - ...state, - { - message, - action, - feedbackType: 'ERROR', - variant, - }, - ]; -} +const getErrorFeedback = ({ + message, + variant = 'critical', + action, +}: ErrorFeedbackInput) => ({ + id: uuid(), + message, + action, + feedbackType: 'ERROR' as const, + variant, +}); -function getErrorFeedback( - { message, variant = alertVariants.critical as keyof typeof alertVariants, action }: ErrorFeedbackInput, -) { - return { - message, - action, - feedbackType: 'ERROR', - variant, - }; -} +const addErrorFeedback = (input: ErrorFeedbackInput) => [getErrorFeedback(input)]; export const getFeedbackDesc = (appUpdaters: Updaters) => createReducerDescription({ ...appUpdaters, @@ -77,86 +66,67 @@ export const getFeedbackDesc = (appUpdaters: Updaters) => createReducerDescripti newState.shift(); return newState; }, - [dataEntryActionTypes.COMPLETE_EVENT_ERROR]: (state, action) => - addErrorFeedback(state, { + [dataEntryActionTypes.COMPLETE_EVENT_ERROR]: (_state, action) => + addErrorFeedback({ message: action.payload.error, action: action.payload.action, }), - [enrollmentActionTypes.ENROLLMENT_LOAD_FAILED]: (state, action) => - addErrorFeedback(state, action.payload), - [workingListsCommonActionTypes.LIST_VIEW_INIT_ERROR]: (state, action) => - addErrorFeedback(state, action.payload.errorMessage), - [newEventDataEntryActionTypes.SAVE_FAILED_FOR_NEW_EVENT_AFTER_RETURNED_TO_MAIN_PAGE]: (state, action) => { + [enrollmentActionTypes.ENROLLMENT_LOAD_FAILED]: (_state, action) => + addErrorFeedback(action.payload), + [workingListsCommonActionTypes.LIST_VIEW_INIT_ERROR]: (_state, action) => + addErrorFeedback(action.payload.errorMessage), + [newEventDataEntryActionTypes.SAVE_FAILED_FOR_NEW_EVENT_AFTER_RETURNED_TO_MAIN_PAGE]: (_state, action) => { const error = action.payload; const errorMessage = isString(error) ? error : error.message; const errorObject = isObject(error) ? error : null; log.error(errorCreator(errorMessage || 'Error saving event')(errorObject)); - const newState = [ - ...state, - getErrorFeedback({ message: i18n.t('Could not save event') }), - ]; - return newState; + return addErrorFeedback({ message: i18n.t('Could not save event') }); }, - [workingListsCommonActionTypes.LIST_UPDATE_ERROR]: (state, action) => [ - ...state, - getErrorFeedback({ message: action.payload.errorMessage }), - ], - [eventWorkingListsActionTypes.EVENT_DELETE_ERROR]: state => [ - ...state, - getErrorFeedback({ message: i18n.t('Could not delete event') }), - ], - - [workingListsCommonActionTypes.TEMPLATE_UPDATE_ERROR]: state => [ - ...state, - getErrorFeedback({ message: i18n.t('Could not save working list') }), - ], - [workingListsCommonActionTypes.TEMPLATE_ADD_ERROR]: state => [ - ...state, - getErrorFeedback({ message: i18n.t('Could not add working list') }), - ], - [workingListsCommonActionTypes.TEMPLATE_DELETE_ERROR]: state => [ - ...state, - getErrorFeedback({ message: i18n.t('Could not delete working list') }), - ], - [asyncHandlerActionTypes.ASYNC_UPDATE_FIELD_FAILED]: (state, { payload }) => - addErrorFeedback(state, { message: payload.message }), - [newEventDataEntryActionTypes.SAVE_FAILED_FOR_NEW_EVENT_ADD_ANOTHER]: (state, action) => { + [workingListsCommonActionTypes.LIST_UPDATE_ERROR]: (_state, action) => + addErrorFeedback({ message: action.payload.errorMessage }), + [eventWorkingListsActionTypes.EVENT_DELETE_ERROR]: () => + addErrorFeedback({ message: i18n.t('Could not delete event') }), + [workingListsCommonActionTypes.TEMPLATE_UPDATE_ERROR]: () => + addErrorFeedback({ message: i18n.t('Could not save working list') }), + [workingListsCommonActionTypes.TEMPLATE_ADD_ERROR]: () => + addErrorFeedback({ message: i18n.t('Could not add working list') }), + [workingListsCommonActionTypes.TEMPLATE_DELETE_ERROR]: () => + addErrorFeedback({ message: i18n.t('Could not delete working list') }), + [asyncHandlerActionTypes.ASYNC_UPDATE_FIELD_FAILED]: (_state, { payload }) => + addErrorFeedback({ message: payload.message }), + [newEventDataEntryActionTypes.SAVE_FAILED_FOR_NEW_EVENT_ADD_ANOTHER]: (_state, action) => { const error = action.payload; const errorMessage = isString(error) ? error : error.message; const errorObject = isObject(error) ? error : null; log.error(errorCreator(errorMessage || 'Error saving event')(errorObject)); - const newState = [ - ...state, - getErrorFeedback({ message: i18n.t('Could not save event') }), - ]; - return newState; + return addErrorFeedback({ message: i18n.t('Could not save event') }); }, - [dataEntryActionTypes.DATA_ENTRY_RELATIONSHIP_ALREADY_EXISTS]: (state, action) => - addErrorFeedback(state, { message: action.payload.message }), - [viewEventNewRelationshipActionTypes.EVENT_RELATIONSHIP_ALREADY_EXISTS]: (state, action) => - addErrorFeedback(state, { message: action.payload.message }), - [registrationSectionActionTypes.ORG_UNIT_SEARCH_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Organisation unit search failed.') }), - [registrationFormActionTypes.NEW_TRACKED_ENTITY_INSTANCE_SAVE_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Error saving tracked entity instance') }), - [registrationFormActionTypes.NEW_TRACKED_ENTITY_INSTANCE_WITH_ENROLLMENT_SAVE_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Error saving enrollment') }), - [enrollmentSiteActionTypes.SAVE_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Error saving the enrollment event') }), - [editEventActionTypes.DELETE_EVENT_DATA_ENTRY_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Error deleting the enrollment event') }), - [editEventDataEntryAction.SAVE_EDIT_EVENT_DATA_ENTRY_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Error editing the event, the changes made were not saved') }), - [enrollmentSiteActionTypes.ERROR_ENROLLMENT]: (state, action) => - addErrorFeedback(state, { message: i18n.t(action.payload.message) }), - [viewEventActionTypes.ASSIGNEE_SAVE_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Error updating the Assignee') }), - [enrollmentEditEventActionTypes.ASSIGNEE_SAVE_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Error updating the Assignee') }), - [enrollmentNoteActionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT]: state => - addErrorFeedback(state, { message: i18n.t('Could not save enrollment note') }), - [eventNoteActionTypes.ADD_NOTE_FAILED_FOR_EVENT]: state => - addErrorFeedback(state, { message: i18n.t('Could not save event note') }), - [viewEventNotesActionTypes.SAVE_EVENT_NOTE_FAILED]: state => - addErrorFeedback(state, { message: i18n.t('Could not save event note') }), + [dataEntryActionTypes.DATA_ENTRY_RELATIONSHIP_ALREADY_EXISTS]: (_state, action) => + addErrorFeedback({ message: action.payload.message }), + [viewEventNewRelationshipActionTypes.EVENT_RELATIONSHIP_ALREADY_EXISTS]: (_state, action) => + addErrorFeedback({ message: action.payload.message }), + [registrationSectionActionTypes.ORG_UNIT_SEARCH_FAILED]: () => + addErrorFeedback({ message: i18n.t('Organisation unit search failed.') }), + [registrationFormActionTypes.NEW_TRACKED_ENTITY_INSTANCE_SAVE_FAILED]: () => + addErrorFeedback({ message: i18n.t('Error saving tracked entity instance') }), + [registrationFormActionTypes.NEW_TRACKED_ENTITY_INSTANCE_WITH_ENROLLMENT_SAVE_FAILED]: () => + addErrorFeedback({ message: i18n.t('Error saving enrollment') }), + [enrollmentSiteActionTypes.SAVE_FAILED]: () => + addErrorFeedback({ message: i18n.t('Error saving the enrollment event') }), + [editEventActionTypes.DELETE_EVENT_DATA_ENTRY_FAILED]: () => + addErrorFeedback({ message: i18n.t('Error deleting the enrollment event') }), + [editEventDataEntryAction.SAVE_EDIT_EVENT_DATA_ENTRY_FAILED]: () => + addErrorFeedback({ message: i18n.t('Error editing the event, the changes made were not saved') }), + [enrollmentSiteActionTypes.ERROR_ENROLLMENT]: (_state, action) => + addErrorFeedback({ message: i18n.t(action.payload.message) }), + [viewEventActionTypes.ASSIGNEE_SAVE_FAILED]: () => + addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), + [enrollmentEditEventActionTypes.ASSIGNEE_SAVE_FAILED]: () => + addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), + [enrollmentNoteActionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT]: () => + addErrorFeedback({ message: i18n.t('Could not save enrollment note') }), + [eventNoteActionTypes.ADD_NOTE_FAILED_FOR_EVENT]: () => + addErrorFeedback({ message: i18n.t('Could not save event note') }), + [viewEventNotesActionTypes.SAVE_EVENT_NOTE_FAILED]: () => + addErrorFeedback({ message: i18n.t('Could not save event note') }), }, 'feedbacks', []); diff --git a/src/epics/trackerCapture.epics.ts b/src/epics/trackerCapture.epics.ts index e3786155d4..0b03a2f174 100644 --- a/src/epics/trackerCapture.epics.ts +++ b/src/epics/trackerCapture.epics.ts @@ -128,10 +128,7 @@ import { saveNoteForViewEventFailedEpic, } from 'capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics'; -import { - addNoteForEnrollmentEpic, - removeNoteForEnrollmentEpic, -} from 'capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics'; +import { addNoteForEnrollmentEpic } from 'capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics'; import { openNewRelationshipRegisterTeiEpic, loadSearchGroupDuplicatesForReviewEpic, @@ -376,7 +373,6 @@ export const epics = (combineEpics as any)( updateEventFailedEpic, addNoteForNewEnrollmentEventEpic, addNoteForEnrollmentEpic, - removeNoteForEnrollmentEpic, navigateToEnrollmentOverviewEpic, scheduleEnrollmentEventEpic, orgUnitFetcherEpic, From 9fe9fdd533aaccf0134af70f7b0dec4b4f318d09 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Thu, 28 May 2026 16:16:04 +0200 Subject: [PATCH 06/11] fix: revert code --- .../components/FeedbackBar/FeedbackBar.component.tsx | 4 ++-- .../capture-core/components/FeedbackBar/FeedbackBar.types.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.tsx b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.tsx index d478dccaa7..bbf92a312c 100644 --- a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.tsx +++ b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.tsx @@ -24,7 +24,7 @@ const FeedbackBarComponentPlain = ({ feedback, onClose }: Props) => { return null; } - const { message, displayType, variant } = feedback; + const { id, message, displayType, variant } = feedback; const isAlertBarOpen = typeof message === 'string' && !displayType; const isDialogOpen = typeof message === 'object' && displayType === 'dialog'; const alertVariant = getAlertVariant(variant); @@ -33,7 +33,7 @@ const FeedbackBarComponentPlain = ({ feedback, onClose }: Props) => { <> {isAlertBarOpen && ( - + {message} )} diff --git a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.types.ts b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.types.ts index f7acaada51..55a54cb07d 100644 --- a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.types.ts +++ b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.types.ts @@ -1,6 +1,7 @@ import { ReactNode } from 'react'; export type Feedback = { + id: string; message: string | { title: string; content: string }; action?: ReactNode; displayType?: 'alert' | 'dialog'; From a224519e16de0d490fc792039f906dd061642885 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Thu, 28 May 2026 16:57:55 +0200 Subject: [PATCH 07/11] feat: add action types for enrollment and event notes --- i18n/en.pot | 10 ++++++++-- .../components/WidgetEnrollmentNote/index.ts | 1 + .../capture-core/components/WidgetEventNote/index.ts | 1 + .../descriptions/feedback.reducerDescriptionGetter.ts | 9 +++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index f6f4f6195b..fcaf2e5c92 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-28T14:47:51.268Z\n" -"PO-Revision-Date: 2026-05-28T14:47:51.268Z\n" +"POT-Creation-Date: 2026-05-28T14:57:56.778Z\n" +"PO-Revision-Date: 2026-05-28T14:57:56.778Z\n" msgid "The application could not be loaded." msgstr "The application could not be loaded." @@ -2234,6 +2234,12 @@ msgstr "Error editing the event, the changes made were not saved" msgid "Error updating the Assignee" msgstr "Error updating the Assignee" +msgid "Could not save enrollment note" +msgstr "Could not save enrollment note" + +msgid "Could not save event note" +msgstr "Could not save event note" + msgid "There was an error fetching metadata" msgstr "There was an error fetching metadata" diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts index 2076d9af43..f06eb07149 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts @@ -1 +1,2 @@ export { WidgetEnrollmentNote } from './WidgetEnrollmentNote.component'; +export { actionTypes as enrollmentNoteActionTypes } from './WidgetEnrollmentNote.actions'; diff --git a/src/core_modules/capture-core/components/WidgetEventNote/index.ts b/src/core_modules/capture-core/components/WidgetEventNote/index.ts index df498109aa..009fe50208 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/index.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/index.ts @@ -1,2 +1,3 @@ export { WidgetEventNote } from './WidgetEventNote.component'; export { addNoteForEventEpic, removeNoteForEventEpic } from './WidgetEventNote.epics'; +export { actionTypes as eventNoteActionTypes } from './WidgetEventNote.actions'; diff --git a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts index 781369f79d..e5e4cd7d09 100644 --- a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts +++ b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts @@ -28,6 +28,9 @@ import { registrationFormActionTypes } from '../../components/Pages/New/Registra import { enrollmentSiteActionTypes } from '../../components/Pages/common/EnrollmentOverviewDomain'; import { enrollmentEditEventActionTypes } from '../../components/Pages/EnrollmentEditEvent'; import { actionTypes as viewEventActionTypes } from '../../components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions'; +import { enrollmentNoteActionTypes } from '../../components/WidgetEnrollmentNote'; +import { eventNoteActionTypes } from '../../components/WidgetEventNote'; +import { actionTypes as viewEventNotesActionTypes } from '../../components/Pages/ViewEvent/Notes/viewEventNotes.actions'; const alertVariants = { info: 'info', @@ -120,4 +123,10 @@ export const getFeedbackDesc = (appUpdaters: Updaters) => createReducerDescripti addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), [enrollmentEditEventActionTypes.ASSIGNEE_SAVE_FAILED]: () => addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), + [enrollmentNoteActionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT]: () => + addErrorFeedback({ message: i18n.t('Could not save enrollment note') }), + [eventNoteActionTypes.ADD_NOTE_FAILED_FOR_EVENT]: () => + addErrorFeedback({ message: i18n.t('Could not save event note') }), + [viewEventNotesActionTypes.SAVE_EVENT_NOTE_FAILED]: () => + addErrorFeedback({ message: i18n.t('Could not save event note') }), }, 'feedbacks', []); From f933fca227b544e29b4e8672fdf02395f494dfa7 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Thu, 28 May 2026 17:13:56 +0200 Subject: [PATCH 08/11] feat: implement remove enrollment note action and epic --- .../WidgetEnrollmentNote.actions.ts | 4 ++++ .../WidgetEnrollmentNote.epics.ts | 16 +++++++++++++++- .../enrollmentDomain.reducerDescription.ts | 8 ++++++++ src/epics/trackerCapture.epics.ts | 7 ++++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts index 619f3bffc9..93e857a348 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts @@ -8,6 +8,7 @@ export const actionTypes = { NOTE_ADDED_FOR_ENROLLMENT: 'NoteAddedForEnrollment', ADD_ENROLLMENT_NOTE: 'AddEnrollmentNote', ADD_NOTE_FAILED_FOR_ENROLLMENT: 'AddNoteFailedForEnrollment', + REMOVE_ENROLLMENT_NOTE: 'RemoveEnrollmentNote', }; export const batchActionTypes = { @@ -40,3 +41,6 @@ export const startAddNoteForEnrollment = ( export const addEnrollmentNote = (enrollmentUid: string, note: Record) => actionCreator(actionTypes.ADD_ENROLLMENT_NOTE)({ enrollmentUid, note }); + +export const removeEnrollmentNote = (enrollmentUid: string, noteClientId: string) => + actionCreator(actionTypes.REMOVE_ENROLLMENT_NOTE)({ enrollmentUid, noteClientId }); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts index 609f3a200e..b0c8dc7541 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts @@ -6,7 +6,7 @@ import uuid from 'd2-utilizr/lib/uuid'; import moment from 'moment'; import type { ReduxStore, ApiUtils, EpicAction } from 'capture-core-utils/types/global'; import { CurrentUser } from '../../utils/userInfo/CurrentUser'; -import { actionTypes, batchActionTypes, startAddNoteForEnrollment, addEnrollmentNote } +import { actionTypes, batchActionTypes, startAddNoteForEnrollment, addEnrollmentNote, removeEnrollmentNote } from './WidgetEnrollmentNote.actions'; import type { ClientNote, SaveContext } from './WidgetEnrollmentNote.types'; @@ -15,6 +15,10 @@ type AddNoteActionPayload = { note: string; }; +type RemoveNoteActionMeta = { + context: SaveContext; +}; + const createServerData = (note: string, useNewEndpoint: boolean): Record => { if (useNewEndpoint) { return { value: note }; @@ -59,3 +63,13 @@ export const addNoteForEnrollmentEpic = ( addEnrollmentNote(enrollmentId, clientNote), ], batchActionTypes.ADD_NOTE_BATCH_FOR_ENROLLMENT); })); + +export const removeNoteForEnrollmentEpic = (action$: EpicAction) => + action$.pipe( + ofType(actionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT), + map((action: { meta: { context: SaveContext } }) => { + const { enrollmentId, noteClientId } = action.meta.context; + return batchActions([ + removeEnrollmentNote(enrollmentId, noteClientId), + ], batchActionTypes.REMOVE_NOTE_BATCH_FOR_ENROLLMENT); + })); diff --git a/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts b/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts index 42f057dbe8..52113e43cb 100644 --- a/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts +++ b/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts @@ -260,6 +260,14 @@ export const enrollmentDomainDesc = createReducerDescription( notes: [...state.enrollment.notes, note], }, }), + [enrollmentNoteActionTypes.REMOVE_ENROLLMENT_NOTE]: + (state, { payload: { noteClientId } }) => ({ + ...state, + enrollment: { + ...state.enrollment, + notes: state.enrollment.notes.filter(note => note.createdBy?.uid !== noteClientId), + }, + }), [editEventActionTypes.REQUEST_DELETE_EVENT_DATA_ENTRY]: (state, { payload: { eventId } }) => { const events = state.enrollment.events?.map((event) => { if (event.event === eventId) { diff --git a/src/epics/trackerCapture.epics.ts b/src/epics/trackerCapture.epics.ts index 0b03a2f174..eea8b06474 100644 --- a/src/epics/trackerCapture.epics.ts +++ b/src/epics/trackerCapture.epics.ts @@ -128,7 +128,11 @@ import { saveNoteForViewEventFailedEpic, } from 'capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics'; -import { addNoteForEnrollmentEpic } from 'capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics'; +import { + addNoteForEnrollmentEpic, + removeNoteForEnrollmentEpic, +} from 'capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics'; + import { openNewRelationshipRegisterTeiEpic, loadSearchGroupDuplicatesForReviewEpic, @@ -373,6 +377,7 @@ export const epics = (combineEpics as any)( updateEventFailedEpic, addNoteForNewEnrollmentEventEpic, addNoteForEnrollmentEpic, + removeNoteForEnrollmentEpic, navigateToEnrollmentOverviewEpic, scheduleEnrollmentEventEpic, orgUnitFetcherEpic, From 4180891e5a06748aa2670f958903ac82455abee3 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Fri, 29 May 2026 11:45:37 +0200 Subject: [PATCH 09/11] fix: revert conflict code --- i18n/en.pot | 10 ++-------- .../WidgetEnrollmentNote.actions.ts | 4 ---- .../WidgetEnrollmentNote.epics.ts | 16 +--------------- .../components/WidgetEnrollmentNote/index.ts | 1 - .../components/WidgetEventNote/index.ts | 1 - .../enrollmentDomain.reducerDescription.ts | 8 -------- .../feedback.reducerDescriptionGetter.ts | 9 --------- src/epics/trackerCapture.epics.ts | 7 +------ 8 files changed, 4 insertions(+), 52 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index fcaf2e5c92..58ea419d37 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-28T14:57:56.778Z\n" -"PO-Revision-Date: 2026-05-28T14:57:56.778Z\n" +"POT-Creation-Date: 2026-05-26T07:35:44.230Z\n" +"PO-Revision-Date: 2026-05-26T07:35:44.230Z\n" msgid "The application could not be loaded." msgstr "The application could not be loaded." @@ -2234,12 +2234,6 @@ msgstr "Error editing the event, the changes made were not saved" msgid "Error updating the Assignee" msgstr "Error updating the Assignee" -msgid "Could not save enrollment note" -msgstr "Could not save enrollment note" - -msgid "Could not save event note" -msgstr "Could not save event note" - msgid "There was an error fetching metadata" msgstr "There was an error fetching metadata" diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts index 93e857a348..619f3bffc9 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts @@ -8,7 +8,6 @@ export const actionTypes = { NOTE_ADDED_FOR_ENROLLMENT: 'NoteAddedForEnrollment', ADD_ENROLLMENT_NOTE: 'AddEnrollmentNote', ADD_NOTE_FAILED_FOR_ENROLLMENT: 'AddNoteFailedForEnrollment', - REMOVE_ENROLLMENT_NOTE: 'RemoveEnrollmentNote', }; export const batchActionTypes = { @@ -41,6 +40,3 @@ export const startAddNoteForEnrollment = ( export const addEnrollmentNote = (enrollmentUid: string, note: Record) => actionCreator(actionTypes.ADD_ENROLLMENT_NOTE)({ enrollmentUid, note }); - -export const removeEnrollmentNote = (enrollmentUid: string, noteClientId: string) => - actionCreator(actionTypes.REMOVE_ENROLLMENT_NOTE)({ enrollmentUid, noteClientId }); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts index b0c8dc7541..609f3a200e 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts @@ -6,7 +6,7 @@ import uuid from 'd2-utilizr/lib/uuid'; import moment from 'moment'; import type { ReduxStore, ApiUtils, EpicAction } from 'capture-core-utils/types/global'; import { CurrentUser } from '../../utils/userInfo/CurrentUser'; -import { actionTypes, batchActionTypes, startAddNoteForEnrollment, addEnrollmentNote, removeEnrollmentNote } +import { actionTypes, batchActionTypes, startAddNoteForEnrollment, addEnrollmentNote } from './WidgetEnrollmentNote.actions'; import type { ClientNote, SaveContext } from './WidgetEnrollmentNote.types'; @@ -15,10 +15,6 @@ type AddNoteActionPayload = { note: string; }; -type RemoveNoteActionMeta = { - context: SaveContext; -}; - const createServerData = (note: string, useNewEndpoint: boolean): Record => { if (useNewEndpoint) { return { value: note }; @@ -63,13 +59,3 @@ export const addNoteForEnrollmentEpic = ( addEnrollmentNote(enrollmentId, clientNote), ], batchActionTypes.ADD_NOTE_BATCH_FOR_ENROLLMENT); })); - -export const removeNoteForEnrollmentEpic = (action$: EpicAction) => - action$.pipe( - ofType(actionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT), - map((action: { meta: { context: SaveContext } }) => { - const { enrollmentId, noteClientId } = action.meta.context; - return batchActions([ - removeEnrollmentNote(enrollmentId, noteClientId), - ], batchActionTypes.REMOVE_NOTE_BATCH_FOR_ENROLLMENT); - })); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts index f06eb07149..2076d9af43 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts @@ -1,2 +1 @@ export { WidgetEnrollmentNote } from './WidgetEnrollmentNote.component'; -export { actionTypes as enrollmentNoteActionTypes } from './WidgetEnrollmentNote.actions'; diff --git a/src/core_modules/capture-core/components/WidgetEventNote/index.ts b/src/core_modules/capture-core/components/WidgetEventNote/index.ts index 009fe50208..df498109aa 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/index.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/index.ts @@ -1,3 +1,2 @@ export { WidgetEventNote } from './WidgetEventNote.component'; export { addNoteForEventEpic, removeNoteForEventEpic } from './WidgetEventNote.epics'; -export { actionTypes as eventNoteActionTypes } from './WidgetEventNote.actions'; diff --git a/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts b/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts index 52113e43cb..42f057dbe8 100644 --- a/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts +++ b/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts @@ -260,14 +260,6 @@ export const enrollmentDomainDesc = createReducerDescription( notes: [...state.enrollment.notes, note], }, }), - [enrollmentNoteActionTypes.REMOVE_ENROLLMENT_NOTE]: - (state, { payload: { noteClientId } }) => ({ - ...state, - enrollment: { - ...state.enrollment, - notes: state.enrollment.notes.filter(note => note.createdBy?.uid !== noteClientId), - }, - }), [editEventActionTypes.REQUEST_DELETE_EVENT_DATA_ENTRY]: (state, { payload: { eventId } }) => { const events = state.enrollment.events?.map((event) => { if (event.event === eventId) { diff --git a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts index e5e4cd7d09..781369f79d 100644 --- a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts +++ b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts @@ -28,9 +28,6 @@ import { registrationFormActionTypes } from '../../components/Pages/New/Registra import { enrollmentSiteActionTypes } from '../../components/Pages/common/EnrollmentOverviewDomain'; import { enrollmentEditEventActionTypes } from '../../components/Pages/EnrollmentEditEvent'; import { actionTypes as viewEventActionTypes } from '../../components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions'; -import { enrollmentNoteActionTypes } from '../../components/WidgetEnrollmentNote'; -import { eventNoteActionTypes } from '../../components/WidgetEventNote'; -import { actionTypes as viewEventNotesActionTypes } from '../../components/Pages/ViewEvent/Notes/viewEventNotes.actions'; const alertVariants = { info: 'info', @@ -123,10 +120,4 @@ export const getFeedbackDesc = (appUpdaters: Updaters) => createReducerDescripti addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), [enrollmentEditEventActionTypes.ASSIGNEE_SAVE_FAILED]: () => addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), - [enrollmentNoteActionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT]: () => - addErrorFeedback({ message: i18n.t('Could not save enrollment note') }), - [eventNoteActionTypes.ADD_NOTE_FAILED_FOR_EVENT]: () => - addErrorFeedback({ message: i18n.t('Could not save event note') }), - [viewEventNotesActionTypes.SAVE_EVENT_NOTE_FAILED]: () => - addErrorFeedback({ message: i18n.t('Could not save event note') }), }, 'feedbacks', []); diff --git a/src/epics/trackerCapture.epics.ts b/src/epics/trackerCapture.epics.ts index eea8b06474..0b03a2f174 100644 --- a/src/epics/trackerCapture.epics.ts +++ b/src/epics/trackerCapture.epics.ts @@ -128,11 +128,7 @@ import { saveNoteForViewEventFailedEpic, } from 'capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics'; -import { - addNoteForEnrollmentEpic, - removeNoteForEnrollmentEpic, -} from 'capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics'; - +import { addNoteForEnrollmentEpic } from 'capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics'; import { openNewRelationshipRegisterTeiEpic, loadSearchGroupDuplicatesForReviewEpic, @@ -377,7 +373,6 @@ export const epics = (combineEpics as any)( updateEventFailedEpic, addNoteForNewEnrollmentEventEpic, addNoteForEnrollmentEpic, - removeNoteForEnrollmentEpic, navigateToEnrollmentOverviewEpic, scheduleEnrollmentEventEpic, orgUnitFetcherEpic, From 07650047891bd0ba66a559ceb3b5a6faa1fc60a2 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Fri, 29 May 2026 11:53:54 +0200 Subject: [PATCH 10/11] feat: add note failure handling --- i18n/en.pot | 10 +++++-- .../ViewEvent/Notes/viewEventNotes.epics.ts | 2 +- .../ViewEventComponent/editEvent.actions.ts | 8 ------ .../ViewEventComponent/viewEvent.actions.ts | 8 ------ .../WidgetEnrollmentNote.actions.ts | 5 +++- .../WidgetEnrollmentNote.epics.ts | 12 ++++++++- .../WidgetEnrollmentNote.types.ts | 1 + .../components/WidgetEnrollmentNote/index.ts | 1 + .../WidgetEventNote.actions.ts | 1 - .../WidgetEventNote/WidgetEventNote.epics.ts | 27 ++++--------------- .../WidgetEventNote/WidgetEventNote.types.ts | 13 +++------ .../components/WidgetEventNote/index.ts | 1 + .../enrollmentDomain.reducerDescription.ts | 11 ++++++-- .../descriptions/events.reducerDescription.ts | 16 ----------- .../feedback.reducerDescriptionGetter.ts | 9 +++++++ src/epics/trackerCapture.epics.ts | 5 +++- 16 files changed, 57 insertions(+), 73 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 58ea419d37..33736f34cd 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-29T09:53:55.823Z\n" +"PO-Revision-Date: 2026-05-29T09:53:55.823Z\n" msgid "The application could not be loaded." msgstr "The application could not be loaded." @@ -2234,6 +2234,12 @@ msgstr "Error editing the event, the changes made were not saved" msgid "Error updating the Assignee" msgstr "Error updating the Assignee" +msgid "Could not save enrollment note" +msgstr "Could not save enrollment note" + +msgid "Could not save event note" +msgstr "Could not save event note" + msgid "There was an error fetching metadata" msgstr "There was an error fetching metadata" diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics.ts b/src/core_modules/capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics.ts index 2b0fc3a0e7..6d37b8299b 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics.ts +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics.ts @@ -67,7 +67,7 @@ export const addNoteForViewEventEpic = (action$: any, store: any, { fromClientDa }, storedBy: username, storedAt: fromClientDate(moment().toISOString()).getServerZonedISOString(), - clientId: uuid(), + clientId, }; return batchActions([ startSaveEventNote(eventId, serverData, state.currentSelections, clientNote.clientId), diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/editEvent.actions.ts b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/editEvent.actions.ts index 87177c8eaa..8e4ef15909 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/editEvent.actions.ts +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/editEvent.actions.ts @@ -6,8 +6,6 @@ export const actionTypes = { EVENT_FROM_URL_RETRIEVED: 'EventFromUrlRetrievedForEditEvent', EVENT_FROM_URL_COULD_NOT_BE_RETRIEVED: 'EventFromUrlCouldNotBeRetrievedForEditEvent', ORG_UNIT_RETRIEVAL_FAILED_ON_URL_UPDATE: 'OrgUnitRetrievalFailedForEditEventOnUrlUpdate', - ADD_EVENT_NOTE: 'AddEventNote', - REMOVE_EVENT_NOTE: 'RemoveEventNote', }; export const eventFromUrlCouldNotBeRetrieved = (message: string) => @@ -18,9 +16,3 @@ export const eventFromUrlRetrieved = (eventContainer: any, orgUnit: OrgUnit, pre export const orgUnitCouldNotBeRetrievedOnUrlUpdate = (eventContainer: any) => actionCreator(actionTypes.ORG_UNIT_RETRIEVAL_FAILED_ON_URL_UPDATE)({ eventContainer }); - -export const addEventNote = (eventId: string, note: any) => - actionCreator(actionTypes.ADD_EVENT_NOTE)({ eventId, note }); - -export const removeEventNote = (eventId: string, noteClientId: string) => - actionCreator(actionTypes.REMOVE_EVENT_NOTE)({ eventId, noteClientId }); diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions.ts b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions.ts index a24712b319..88af3a7479 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions.ts +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions.ts @@ -8,8 +8,6 @@ export const actionTypes = { ORG_UNIT_RETRIEVED_ON_URL_UPDATE: 'OrgUnitRetrievedForViewEventOnUrlUpdate', ORG_UNIT_RETRIEVAL_FAILED_ON_URL_UPDATE: 'OrgUnitRetrievalFailedForViewEventOnUrlUpdate', START_OPEN_EVENT_FOR_VIEW: 'StartOpenEventForView', - ADD_EVENT_NOTE: 'AddEventNoteForViewEvent', - REMOVE_EVENT_NOTE: 'RemoveEventNoteForViewEvent', UPDATE_WORKING_LIST_ON_BACK_TO_MAIN_PAGE: 'UpdateWorkingListOnBackToMainPageForViewEvent', NO_WORKING_LIST_UPDATE_NEEDED_ON_BACK_TO_MAIN_PAGE: 'NoWorkingListUpdateNeededOnBackToMainPageForViewEvent', START_GO_BACK_TO_MAIN_PAGE: 'StartGoBackToMainPageForViewEvent', @@ -49,12 +47,6 @@ export const orgUnitCouldNotBeRetrievedOnUrlUpdate = (eventContainer: any) => export const startOpenEventForView = (eventContainer: any, orgUnit: any) => actionCreator(actionTypes.START_OPEN_EVENT_FOR_VIEW)({ eventContainer, orgUnit }); -export const addEventNote = (eventId: string, note: any) => - actionCreator(actionTypes.ADD_EVENT_NOTE)({ eventId, note }); - -export const removeEventNote = (eventId: string, noteClientId: string) => - actionCreator(actionTypes.REMOVE_EVENT_NOTE)({ eventId, noteClientId }); - export const startGoBackToMainPage = (orgUnitId: string | null) => actionCreator(actionTypes.START_GO_BACK_TO_MAIN_PAGE)({ orgUnitId }); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts index 619f3bffc9..7ade3abd34 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions.ts @@ -7,12 +7,12 @@ export const actionTypes = { START_ADD_NOTE_FOR_ENROLLMENT: 'StartAddNoteForEnrollment', NOTE_ADDED_FOR_ENROLLMENT: 'NoteAddedForEnrollment', ADD_ENROLLMENT_NOTE: 'AddEnrollmentNote', + REMOVE_ENROLLMENT_NOTE: 'RemoveEnrollmentNote', ADD_NOTE_FAILED_FOR_ENROLLMENT: 'AddNoteFailedForEnrollment', }; export const batchActionTypes = { ADD_NOTE_BATCH_FOR_ENROLLMENT: 'AddNoteBatchForEnrollment', - REMOVE_NOTE_BATCH_FOR_ENROLLMENT: 'RemoveNoteBatchForEnrollment', }; export const requestAddNoteForEnrollment = (enrollmentId: string, note: string) => @@ -40,3 +40,6 @@ export const startAddNoteForEnrollment = ( export const addEnrollmentNote = (enrollmentUid: string, note: Record) => actionCreator(actionTypes.ADD_ENROLLMENT_NOTE)({ enrollmentUid, note }); + +export const removeEnrollmentNote = (enrollmentUid: string, noteClientId: string) => + actionCreator(actionTypes.REMOVE_ENROLLMENT_NOTE)({ enrollmentUid, noteClientId }); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts index 609f3a200e..9b4a5b0272 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics.ts @@ -6,7 +6,7 @@ import uuid from 'd2-utilizr/lib/uuid'; import moment from 'moment'; import type { ReduxStore, ApiUtils, EpicAction } from 'capture-core-utils/types/global'; import { CurrentUser } from '../../utils/userInfo/CurrentUser'; -import { actionTypes, batchActionTypes, startAddNoteForEnrollment, addEnrollmentNote } +import { actionTypes, batchActionTypes, startAddNoteForEnrollment, addEnrollmentNote, removeEnrollmentNote } from './WidgetEnrollmentNote.actions'; import type { ClientNote, SaveContext } from './WidgetEnrollmentNote.types'; @@ -47,6 +47,7 @@ export const addNoteForEnrollmentEpic = ( }, storedBy: username, storedAt: fromClientDate(moment().toISOString()).getServerZonedISOString(), + clientId, }; const saveContext: SaveContext = { @@ -59,3 +60,12 @@ export const addNoteForEnrollmentEpic = ( addEnrollmentNote(enrollmentId, clientNote), ], batchActionTypes.ADD_NOTE_BATCH_FOR_ENROLLMENT); })); + +export const removeNoteForEnrollmentEpic = ( + action$: EpicAction, +) => + action$.pipe( + ofType(actionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT), + map((action: { meta: { context: SaveContext } }) => + removeEnrollmentNote(action.meta.context.enrollmentId, action.meta.context.noteClientId), + )); diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.types.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.types.ts index 4f3470de6e..4cc1e94307 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.types.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.types.ts @@ -7,6 +7,7 @@ export type ClientNote = { }; storedBy: string; storedAt: string; + clientId: string; }; export type SaveContext = { diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts b/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts index 2076d9af43..f06eb07149 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts +++ b/src/core_modules/capture-core/components/WidgetEnrollmentNote/index.ts @@ -1 +1,2 @@ export { WidgetEnrollmentNote } from './WidgetEnrollmentNote.component'; +export { actionTypes as enrollmentNoteActionTypes } from './WidgetEnrollmentNote.actions'; diff --git a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.actions.ts b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.actions.ts index 3e91ecc142..7e62d9c502 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.actions.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.actions.ts @@ -11,7 +11,6 @@ export const actionTypes = { export const batchActionTypes = { ADD_NOTE_BATCH_FOR_EVENT: 'AddNoteBatchForEvent', - REMOVE_NOTE_BATCH_FOR_EVENT: 'RemoveNoteBatchForEvent', }; export const requestAddNoteForEvent = (itemId: string, dataEntryId: string, note: string) => diff --git a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.epics.ts b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.epics.ts index 9fca9c4e59..e37d3a81ae 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.epics.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.epics.ts @@ -7,12 +7,7 @@ import moment from 'moment'; import type { ReduxStore, ApiUtils, EpicAction } from 'capture-core-utils/types'; import { CurrentUser } from '../../utils/userInfo/CurrentUser'; import { actionTypes, batchActionTypes, startAddNoteForEvent } from './WidgetEventNote.actions'; -import type { ClientNote, FormNote, SaveContext } from './WidgetEventNote.types'; - -import { - addEventNote, - removeEventNote, -} from '../Pages/ViewEvent/ViewEventComponent/editEvent.actions'; +import type { FormNote, SaveContext } from './WidgetEventNote.types'; import { addNote, @@ -53,24 +48,16 @@ export const addNoteForEventEpic = ( const serverData = createServerData(eventId, payload.note, useNewEndpoint); - const clientNote: ClientNote = { + const formNote: FormNote = { value: payload.note, - lastUpdatedBy: { + createdBy: { firstName, surname, uid: clientId, }, storedBy: username, storedAt: fromClientDate(moment().toISOString()).getServerZonedISOString(), - }; - const formNote: FormNote = { - ...clientNote, - storedAt: clientNote.storedAt, - createdBy: { - firstName, - surname, - uid: clientId, - }, + clientId, }; const saveContext: SaveContext = { dataEntryId: payload.dataEntryId, @@ -82,7 +69,6 @@ export const addNoteForEventEpic = ( return batchActions([ startAddNoteForEvent(eventId, serverData, state.currentSelections, saveContext), addNote(payload.dataEntryId, payload.itemId, formNote), - addEventNote(eventId, clientNote), ], batchActionTypes.ADD_NOTE_BATCH_FOR_EVENT); })); @@ -91,8 +77,5 @@ export const removeNoteForEventEpic = (action$: EpicAction { const context = action.meta.context; - return batchActions([ - removeNote(context.dataEntryId, context.itemId, context.noteClientId), - removeEventNote(context.eventId, context.noteClientId), - ], batchActionTypes.REMOVE_NOTE_BATCH_FOR_EVENT); + return removeNote(context.dataEntryId, context.itemId, context.noteClientId); })); diff --git a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.types.ts b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.types.ts index 87957e6627..9331e9347e 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.types.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/WidgetEventNote.types.ts @@ -3,23 +3,16 @@ export type Props = { dataEntryId: string; }; -export type ClientNote = { +export type FormNote = { value: string; - lastUpdatedBy: { + createdBy: { firstName: string; surname: string; uid: string; }; storedBy: string; storedAt: string; -}; - -export type FormNote = ClientNote & { - createdBy: { - firstName: string; - surname: string; - uid: string; - }; + clientId: string; }; export type SaveContext = { diff --git a/src/core_modules/capture-core/components/WidgetEventNote/index.ts b/src/core_modules/capture-core/components/WidgetEventNote/index.ts index df498109aa..009fe50208 100644 --- a/src/core_modules/capture-core/components/WidgetEventNote/index.ts +++ b/src/core_modules/capture-core/components/WidgetEventNote/index.ts @@ -1,2 +1,3 @@ export { WidgetEventNote } from './WidgetEventNote.component'; export { addNoteForEventEpic, removeNoteForEventEpic } from './WidgetEventNote.epics'; +export { actionTypes as eventNoteActionTypes } from './WidgetEventNote.actions'; diff --git a/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts b/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts index 42f057dbe8..ea63dd09ef 100644 --- a/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts +++ b/src/core_modules/capture-core/reducers/descriptions/enrollmentDomain.reducerDescription.ts @@ -1,7 +1,6 @@ import { createReducerDescription } from '../../trackerRedux'; import { enrollmentSiteActionTypes } from '../../components/Pages/common/EnrollmentOverviewDomain'; -import { actionTypes as enrollmentNoteActionTypes } - from '../../components/WidgetEnrollmentNote/WidgetEnrollmentNote.actions'; +import { enrollmentNoteActionTypes } from '../../components/WidgetEnrollmentNote'; import { actionTypes as editEventActionTypes } from '../../components/WidgetEventEdit/EditEventDataEntry/editEventDataEntry.actions'; import { newEventWidgetActionTypes } from '../../components/WidgetEnrollmentEventNew/Validated/validated.actions'; @@ -260,6 +259,14 @@ export const enrollmentDomainDesc = createReducerDescription( notes: [...state.enrollment.notes, note], }, }), + [enrollmentNoteActionTypes.REMOVE_ENROLLMENT_NOTE]: + (state, { payload: { noteClientId } }) => ({ + ...state, + enrollment: { + ...state.enrollment, + notes: state.enrollment.notes.filter((n: any) => n?.clientId !== noteClientId), + }, + }), [editEventActionTypes.REQUEST_DELETE_EVENT_DATA_ENTRY]: (state, { payload: { eventId } }) => { const events = state.enrollment.events?.map((event) => { if (event.event === eventId) { diff --git a/src/core_modules/capture-core/reducers/descriptions/events.reducerDescription.ts b/src/core_modules/capture-core/reducers/descriptions/events.reducerDescription.ts index 24cc4d1cdb..88cf5bea3f 100644 --- a/src/core_modules/capture-core/reducers/descriptions/events.reducerDescription.ts +++ b/src/core_modules/capture-core/reducers/descriptions/events.reducerDescription.ts @@ -48,22 +48,6 @@ export const eventsDesc = createReducerDescription({ }; return newState; }, - [viewEventActionTypes.ADD_EVENT_NOTE]: (state, action) => { - const newState = { ...state }; - const payload = action.payload; - if (newState[payload.eventId]) { - newState[payload.eventId].notes = [...state[payload.eventId].notes, payload.note]; - } - return newState; - }, - [viewEventActionTypes.REMOVE_EVENT_NOTE]: (state, action) => { - const newState = { ...state }; - const payload = action.payload; - if (newState[payload.eventId]) { - newState[payload.eventId].notes = state[payload.eventId].notes.filter(n => n.clientId !== payload.noteClientId); - } - return newState; - }, }, 'events', {}); export const eventsValuesDesc = createReducerDescription({ diff --git a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts index 781369f79d..e5e4cd7d09 100644 --- a/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts +++ b/src/core_modules/capture-core/reducers/descriptions/feedback.reducerDescriptionGetter.ts @@ -28,6 +28,9 @@ import { registrationFormActionTypes } from '../../components/Pages/New/Registra import { enrollmentSiteActionTypes } from '../../components/Pages/common/EnrollmentOverviewDomain'; import { enrollmentEditEventActionTypes } from '../../components/Pages/EnrollmentEditEvent'; import { actionTypes as viewEventActionTypes } from '../../components/Pages/ViewEvent/ViewEventComponent/viewEvent.actions'; +import { enrollmentNoteActionTypes } from '../../components/WidgetEnrollmentNote'; +import { eventNoteActionTypes } from '../../components/WidgetEventNote'; +import { actionTypes as viewEventNotesActionTypes } from '../../components/Pages/ViewEvent/Notes/viewEventNotes.actions'; const alertVariants = { info: 'info', @@ -120,4 +123,10 @@ export const getFeedbackDesc = (appUpdaters: Updaters) => createReducerDescripti addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), [enrollmentEditEventActionTypes.ASSIGNEE_SAVE_FAILED]: () => addErrorFeedback({ message: i18n.t('Error updating the Assignee') }), + [enrollmentNoteActionTypes.ADD_NOTE_FAILED_FOR_ENROLLMENT]: () => + addErrorFeedback({ message: i18n.t('Could not save enrollment note') }), + [eventNoteActionTypes.ADD_NOTE_FAILED_FOR_EVENT]: () => + addErrorFeedback({ message: i18n.t('Could not save event note') }), + [viewEventNotesActionTypes.SAVE_EVENT_NOTE_FAILED]: () => + addErrorFeedback({ message: i18n.t('Could not save event note') }), }, 'feedbacks', []); diff --git a/src/epics/trackerCapture.epics.ts b/src/epics/trackerCapture.epics.ts index 0b03a2f174..d99b8fb5d1 100644 --- a/src/epics/trackerCapture.epics.ts +++ b/src/epics/trackerCapture.epics.ts @@ -128,7 +128,9 @@ import { saveNoteForViewEventFailedEpic, } from 'capture-core/components/Pages/ViewEvent/Notes/viewEventNotes.epics'; -import { addNoteForEnrollmentEpic } from 'capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics'; +import { addNoteForEnrollmentEpic, + removeNoteForEnrollmentEpic, +} from 'capture-core/components/WidgetEnrollmentNote/WidgetEnrollmentNote.epics'; import { openNewRelationshipRegisterTeiEpic, loadSearchGroupDuplicatesForReviewEpic, @@ -374,6 +376,7 @@ export const epics = (combineEpics as any)( addNoteForNewEnrollmentEventEpic, addNoteForEnrollmentEpic, navigateToEnrollmentOverviewEpic, + removeNoteForEnrollmentEpic, scheduleEnrollmentEventEpic, orgUnitFetcherEpic, getCoreOrgUnitEpic, From 01e55d8209537e779ff096553c5aa4f4e998cd29 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Fri, 29 May 2026 11:57:18 +0200 Subject: [PATCH 11/11] fix: revert package json changes --- package.json | 6 +++--- yarn.lock | 53 ++++++++++++++++++++++++---------------------------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 8031650743..a888c17cf9 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "regenerator-runtime": "^0.14.1", "reselect": "^4.1.7", "rxjs": "^7.8.2", - "typeface-roboto": "^1.1.13", + "typeface-roboto": "^0.0.75", "uuid": "^9.0.0", "zod": "^3.24.4" }, @@ -84,14 +84,14 @@ "devDependencies": { "@actions/core": "^3.0.0", "@babel/core": "^7.17.8", - "@babel/eslint-parser": "^7.28.6", + "@babel/eslint-parser": "^7.19.1", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.26.3", "@babel/preset-typescript": "^7.27.0", "@badeball/cypress-cucumber-preprocessor": "17.2.1", "@cypress/webpack-preprocessor": "^6.0.0", - "@dhis2/cli-app-scripts": "^12.11.1", + "@dhis2/cli-app-scripts": "^12.11.0", "@dhis2/cli-helpers-engine": "^3.2.1", "@dhis2/cli-style": "^10.7.10", "@dhis2/cli-utils-cypress": "^9.0.2", diff --git a/yarn.lock b/yarn.lock index d67b1b4135..016bbe9e34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -90,10 +90,10 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/eslint-parser@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.28.6.tgz#6a294a4add732ebe7ded8a8d2792dd03dd81dc3f" - integrity sha512-QGmsKi2PBO/MHSQk+AAgA9R6OHQr+VqnniFE0eMWZcVcfBZoA2dKn2hUsl3Csg/Plt9opRUWdY7//VXsrIlEiA== +"@babel/eslint-parser@^7.19.1": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.28.0.tgz#c1b3fbba070f5bac32e3d02f244201add4afdd6e" + integrity sha512-N4ntErOlKvcbTt01rr5wj3y55xnIdx1ymrfIr8C2WnM1Y9glFgWaGDEULJIazOX3XM9NRzhfJ6zZnQ1sBNWU+w== dependencies: "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" eslint-visitor-keys "^2.1.0" @@ -2313,12 +2313,12 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2/app-adapter@12.11.1": - version "12.11.1" - resolved "https://registry.yarnpkg.com/@dhis2/app-adapter/-/app-adapter-12.11.1.tgz#f12f3e2ed6eb4c572997ff04d6d8bfce61e24912" - integrity sha512-xPc/SfnQ4AsDknCoH6eEyzHW+cwLHA6fJmuvbBSjOs8rFUw0T/ZMOOSh9kcAb+/qmFpcFTRlnCQXwEnLkadgtg== +"@dhis2/app-adapter@12.11.0": + version "12.11.0" + resolved "https://registry.yarnpkg.com/@dhis2/app-adapter/-/app-adapter-12.11.0.tgz#bc76fd317c0b95b9a1498f4bc717622a8dd5be6a" + integrity sha512-XwAVGJtBMIq1tf3yIGYbsgUVn08W4021jo3E5mkIuTsds20q5hk3pt6KEQK21dlWIMPM0OYYvNdhFTTuXj9d2A== dependencies: - "@dhis2/pwa" "12.11.1" + "@dhis2/pwa" "12.11.0" moment "^2.24.0" "@dhis2/app-runtime@^3.14.3", "@dhis2/app-runtime@^3.17.0": @@ -2379,15 +2379,15 @@ dependencies: prop-types "^15.7.2" -"@dhis2/app-shell@12.11.1": - version "12.11.1" - resolved "https://registry.yarnpkg.com/@dhis2/app-shell/-/app-shell-12.11.1.tgz#9b6e3ed97e1a2c1b7617e42fd5bc82eeb9480510" - integrity sha512-8Vbms2pE1GFCgJOuAafSZuLrOPOmpiqt5lcFvDlhBzXOLx2VDzM9BwTtGi8bm+kX4jrTFkDCTkxkvelRNonjvQ== +"@dhis2/app-shell@12.11.0": + version "12.11.0" + resolved "https://registry.yarnpkg.com/@dhis2/app-shell/-/app-shell-12.11.0.tgz#7535240ee60d5ba179989d10aaf2d8fe16b36ed3" + integrity sha512-b1wm7nC5cMpoprRfrC8/OOrDTe1+1im50cxwQwNIL2Q/8v0fwd14NSJzWbyxGL0To8S9tbK5ruZL+QllrWtGfg== dependencies: - "@dhis2/app-adapter" "12.11.1" + "@dhis2/app-adapter" "12.11.0" "@dhis2/app-runtime" "^3.14.3" "@dhis2/d2-i18n" "^1.2.0" - "@dhis2/pwa" "12.11.1" + "@dhis2/pwa" "12.11.0" "@dhis2/ui" "^10.9.2" classnames "^2.2.6" moment "^2.29.1" @@ -2398,10 +2398,10 @@ styled-jsx "^4.0.1" typeface-roboto "^0.0.75" -"@dhis2/cli-app-scripts@^12.11.1": - version "12.11.1" - resolved "https://registry.yarnpkg.com/@dhis2/cli-app-scripts/-/cli-app-scripts-12.11.1.tgz#ca33d006a8743c35366864c8ac22e488680324e7" - integrity sha512-zgyiqR3UTo9bK2yDUFRDusNGPX1gKNShSIjou63RbWLKJ3tfPgxpXR9pX6D+wqeBwKYu/S+zuZziCjgyX6U0dA== +"@dhis2/cli-app-scripts@^12.11.0": + version "12.11.0" + resolved "https://registry.yarnpkg.com/@dhis2/cli-app-scripts/-/cli-app-scripts-12.11.0.tgz#cddecb6c6c3e2c40cdfbf6250ab3e0ecae7e3fb7" + integrity sha512-dBbnNS4tOzez1QIBoYfpS2wotWWTig29VSOT09zruqILyIpT6uQ8kWx2kF97Iq0tSfdIq5I5x8U4/yxdzO9Vfg== dependencies: "@babel/core" "^7.27.4" "@babel/plugin-syntax-dynamic-import" "^7.8.3" @@ -2414,7 +2414,7 @@ "@babel/preset-env" "^7.27.2" "@babel/preset-react" "^7.0.0" "@babel/preset-typescript" "^7.27.1" - "@dhis2/app-shell" "12.11.1" + "@dhis2/app-shell" "12.11.0" "@dhis2/cli-helpers-engine" "^3.2.2" "@jest/core" "^27.0.6" "@pmmmwh/react-refresh-webpack-plugin" "^0.5.4" @@ -2574,10 +2574,10 @@ resolved "https://registry.yarnpkg.com/@dhis2/prop-types/-/prop-types-3.1.2.tgz#65b8ad2da8cd2f72bc8b951049a6c9d1b97af3e9" integrity sha512-eM0jjLOWvtXWqSFp5YC4DHFpkP8Y1D2eUwGV7MBWjni+o27oesVan+oT7WHeOeLdlAd4acRJrnaaAyB4Ck1wGQ== -"@dhis2/pwa@12.11.1": - version "12.11.1" - resolved "https://registry.yarnpkg.com/@dhis2/pwa/-/pwa-12.11.1.tgz#76448bbcbf0b2a347a04fe5524ac627bca1aa550" - integrity sha512-q1bIYrvF2R/peQp/bu8AZ6LsEOAYNHliJEGSr/0lczrrke61oHAk4WcYFATYRaUDlvRA1vxstRSSVsUWtB0qRA== +"@dhis2/pwa@12.11.0": + version "12.11.0" + resolved "https://registry.yarnpkg.com/@dhis2/pwa/-/pwa-12.11.0.tgz#6600c91d2d9595fdf35243dce0ef714c6e414e15" + integrity sha512-ZcWHMBLzqW4TzvKQxsX+NALyKH9IEc/QvIIf5tR5pSdhIUPhy0WBtRdczgBfuUcBMtyNR+i9iORgnsUHA4Iefg== dependencies: idb "^6.0.0" workbox-precaching "^7.1.0" @@ -14140,11 +14140,6 @@ typeface-roboto@^0.0.75: resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-0.0.75.tgz#98d5ba35ec234bbc7172374c8297277099cc712b" integrity sha512-VrR/IiH00Z1tFP4vDGfwZ1esNqTiDMchBEXYY9kilT6wRGgFoCAlgkEUMHb1E3mB0FsfZhv756IF0+R+SFPfdg== -typeface-roboto@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-1.1.13.tgz#9c4517cb91e311706c74823e857b4bac9a764ae5" - integrity sha512-YXvbd3a1QTREoD+FJoEkl0VQNJoEjewR2H11IjVv4bp6ahuIcw0yyw/3udC4vJkHw3T3cUh85FTg8eWef3pSaw== - typescript@^5.6.3, typescript@^5.8.2: version "5.8.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"