From e34107075678b78773d941bc1bca5dbf93f5088e Mon Sep 17 00:00:00 2001 From: Alaa Yahia <6881345+alaa-yahia@users.noreply.github.com> Date: Tue, 28 Jan 2025 10:23:28 +0200 Subject: [PATCH 1/8] fix: [DHIS2-18673] prevent saving in profile widget when validation errors are present (#3943) fix: prevent saving in profile widget when validation errors are present --- .../components/WidgetProfile/DataEntry/dataEntry.actions.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/dataEntry.actions.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/dataEntry.actions.js index f326ab200c..dccc04badc 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/dataEntry.actions.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/dataEntry.actions.js @@ -19,6 +19,7 @@ import { loadNewDataEntry } from '../../DataEntry/actions/dataEntryLoadNew.actio import { rulesExecutedPostUpdateField } from '../../DataEntry/actions/dataEntry.actions'; import { getRulesActionsForTEIAsync } from './ProgramRules'; import { addFormData } from '../../D2Form/actions/form.actions'; +import { updateFieldUIOnly } from '../../D2Form/FormBuilder/formBuilder.actions'; import type { Geometry } from './helpers/types'; import type { QuerySingleResource } from '../../../utils/api'; @@ -112,12 +113,14 @@ export const getUpdateFieldActions = async ({ querySingleResource, onGetValidationContext, }); + const updateFieldUIAction = updateFieldUIOnly(uiState, elementId, formId); return batchActions( [ innerAction, rulesActions, rulesExecutedPostUpdateField(dataEntryId, itemId, uid), + updateFieldUIAction, ], dataEntryActionTypes.UPDATE_FIELD_PROFILE_ACTION_BATCH, ); From e77cb3140b93eb7bf7024808a139f6124897379d Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Tue, 28 Jan 2025 08:29:19 +0000 Subject: [PATCH 2/8] chore(release): cut 101.23.1 [skip release] ## [101.23.1](https://github.com/dhis2/capture-app/compare/v101.23.0...v101.23.1) (2025-01-28) ### Bug Fixes * [DHIS2-18673] prevent saving in profile widget when validation errors are present ([#3943](https://github.com/dhis2/capture-app/issues/3943)) ([e341070](https://github.com/dhis2/capture-app/commit/e34107075678b78773d941bc1bca5dbf93f5088e)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4315d38cf1..7f97b8c059 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [101.23.1](https://github.com/dhis2/capture-app/compare/v101.23.0...v101.23.1) (2025-01-28) + + +### Bug Fixes + +* [DHIS2-18673] prevent saving in profile widget when validation errors are present ([#3943](https://github.com/dhis2/capture-app/issues/3943)) ([e341070](https://github.com/dhis2/capture-app/commit/e34107075678b78773d941bc1bca5dbf93f5088e)) + # [101.23.0](https://github.com/dhis2/capture-app/compare/v101.22.0...v101.23.0) (2025-01-24) diff --git a/package.json b/package.json index ac11f9289d..4a7f69fce5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "101.23.0", + "version": "101.23.1", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "101.23.0", + "@dhis2/rules-engine-javascript": "101.23.1", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index 01683af635..f8ed08829d 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "101.23.0", + "version": "101.23.1", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 6326f7a134851a80352d6cf34ea2f8dbdb5b210d Mon Sep 17 00:00:00 2001 From: Tony Valle <79843014+superskip@users.noreply.github.com> Date: Tue, 28 Jan 2025 12:22:52 +0100 Subject: [PATCH 3/8] fix: [DHIS2-18902] keep program selection on unique id fallback search (#3950) --- .../capture-core/components/SearchBox/SearchBox.actions.js | 4 ++-- .../components/SearchBox/SearchForm/SearchForm.epics.js | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core_modules/capture-core/components/SearchBox/SearchBox.actions.js b/src/core_modules/capture-core/components/SearchBox/SearchBox.actions.js index 4c344d4480..ada39e35e1 100644 --- a/src/core_modules/capture-core/components/SearchBox/SearchBox.actions.js +++ b/src/core_modules/capture-core/components/SearchBox/SearchBox.actions.js @@ -32,8 +32,8 @@ export const saveCurrentSearchInfo = ({ }) => actionCreator(searchBoxActionTypes.CURRENT_SEARCH_INFO_SAVE)( { searchScopeType, searchScopeId, formId, currentSearchTerms }); -export const searchViaUniqueIdOnScopeTrackedEntityType = ({ trackedEntityTypeId, formId }) => - actionCreator(searchBoxActionTypes.VIA_UNIQUE_ID_ON_SCOPE_TRACKED_ENTITY_TYPE_SEARCH)({ trackedEntityTypeId, formId }); +export const searchViaUniqueIdOnScopeTrackedEntityType = ({ trackedEntityTypeId, formId, programId }) => + actionCreator(searchBoxActionTypes.VIA_UNIQUE_ID_ON_SCOPE_TRACKED_ENTITY_TYPE_SEARCH)({ trackedEntityTypeId, formId, programId }); export const searchViaUniqueIdOnScopeProgram = ({ programId, formId }) => actionCreator(searchBoxActionTypes.VIA_UNIQUE_ID_ON_SCOPE_PROGRAM_SEARCH)({ programId, formId }); diff --git a/src/core_modules/capture-core/components/SearchBox/SearchForm/SearchForm.epics.js b/src/core_modules/capture-core/components/SearchBox/SearchForm/SearchForm.epics.js index 3b72d98f5b..49f79bf410 100644 --- a/src/core_modules/capture-core/components/SearchBox/SearchForm/SearchForm.epics.js +++ b/src/core_modules/capture-core/components/SearchBox/SearchForm/SearchForm.epics.js @@ -58,7 +58,7 @@ const searchViaUniqueIdStream = ({ flatMap(({ trackedEntityInstanceContainers }) => { const searchResults = trackedEntityInstanceContainers; if (searchResults.length === 0 && queryArgs.program) { - return of(searchViaUniqueIdOnScopeTrackedEntityType({ trackedEntityTypeId: programTETId, formId })); + return of(searchViaUniqueIdOnScopeTrackedEntityType({ trackedEntityTypeId: programTETId, formId, programId })); } if (searchResults.length > 0) { const { id, tei: { orgUnit: orgUnitId, enrollments } } = searchResults[0]; @@ -183,7 +183,7 @@ export const searchViaUniqueIdOnScopeTrackedEntityTypeEpic = ( ) => action$.pipe( ofType(searchBoxActionTypes.VIA_UNIQUE_ID_ON_SCOPE_TRACKED_ENTITY_TYPE_SEARCH), - flatMap(({ payload: { formId, trackedEntityTypeId } }) => { + flatMap(({ payload: { formId, trackedEntityTypeId, programId } }) => { const { formsValues, } = store.value; @@ -200,6 +200,7 @@ export const searchViaUniqueIdOnScopeTrackedEntityTypeEpic = ( return searchViaUniqueIdStream({ queryArgs, attributes, + programId, absoluteApiPath, querySingleResource, }); From 164f1efde0eb6bab65e24fcf14719a065862cfae Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Tue, 28 Jan 2025 11:27:04 +0000 Subject: [PATCH 4/8] chore(release): cut 101.23.2 [skip release] ## [101.23.2](https://github.com/dhis2/capture-app/compare/v101.23.1...v101.23.2) (2025-01-28) ### Bug Fixes * [DHIS2-18902] keep program selection on unique id fallback search ([#3950](https://github.com/dhis2/capture-app/issues/3950)) ([6326f7a](https://github.com/dhis2/capture-app/commit/6326f7a134851a80352d6cf34ea2f8dbdb5b210d)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f97b8c059..e1fab41b0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [101.23.2](https://github.com/dhis2/capture-app/compare/v101.23.1...v101.23.2) (2025-01-28) + + +### Bug Fixes + +* [DHIS2-18902] keep program selection on unique id fallback search ([#3950](https://github.com/dhis2/capture-app/issues/3950)) ([6326f7a](https://github.com/dhis2/capture-app/commit/6326f7a134851a80352d6cf34ea2f8dbdb5b210d)) + ## [101.23.1](https://github.com/dhis2/capture-app/compare/v101.23.0...v101.23.1) (2025-01-28) diff --git a/package.json b/package.json index 4a7f69fce5..7db79d335a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "101.23.1", + "version": "101.23.2", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "101.23.1", + "@dhis2/rules-engine-javascript": "101.23.2", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index f8ed08829d..8923911d99 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "101.23.1", + "version": "101.23.2", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 4013d9326d17f93ff3b0ca11b7844764f92c6850 Mon Sep 17 00:00:00 2001 From: henrikmv <110386561+henrikmv@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:31:10 +0100 Subject: [PATCH 5/8] feat: [DHIS2-18329] Add org unit selector in schedule event form (#3925) * feat: add org unit selector in schedule event form * fix: review comments * fix: missing org unit name in info box * fix: missing org unit name * fix: review comment * Revert "fix: review comment" This reverts commit d4e588504a3c8eecf0249e3680e219046a4249ea. * fix: info box missing org unit optimisation --- i18n/en.pot | 34 ++-- .../Widget/widgetCollapsible.types.js | 2 +- .../Widget/widgetNonCollapsible.types.js | 2 +- .../DataEntry/dataEntryFieldLabels.module.css | 2 +- .../InfoBox/InfoBox.component.js | 76 +++++--- .../ScheduleDate/ScheduleDate.component.js | 112 +++++++---- .../dataEntryFieldLabels.module.css | 3 + .../ScheduleDate/scheduleDate.types.js | 1 + .../ScheduleOrgUnit.component.js | 74 ++++++++ .../ScheduleOrgUnit/commonProps.js | 6 + .../dataEntryFieldLabels.module.css | 3 + .../WidgetEventSchedule.component.js | 177 +++++++++--------- .../WidgetEventSchedule.container.js | 43 +++-- .../widgetEventSchedule.types.js | 8 +- 14 files changed, 349 insertions(+), 194 deletions(-) create mode 100644 src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/dataEntryFieldLabels.module.css create mode 100644 src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/ScheduleOrgUnit.component.js create mode 100644 src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/commonProps.js create mode 100644 src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/dataEntryFieldLabels.module.css diff --git a/i18n/en.pot b/i18n/en.pot index b0d18cfda4..fcb7085885 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: 2025-01-02T13:08:32.303Z\n" -"PO-Revision-Date: 2025-01-02T13:08:32.303Z\n" +"POT-Creation-Date: 2025-01-24T15:26:19.128Z\n" +"PO-Revision-Date: 2025-01-24T15:26:19.128Z\n" msgid "Choose one or more dates..." msgstr "Choose one or more dates..." @@ -1231,9 +1231,6 @@ msgstr "Add coordinates" msgid "Add area" msgstr "Add area" -msgid "Please add or cancel the note before saving the event" -msgstr "Please add or cancel the note before saving the event" - msgid "Please provide an valid organisation unit" msgstr "Please provide an valid organisation unit" @@ -1294,6 +1291,12 @@ msgstr "Write a note about this event" msgid "This event doesn't have any notes" msgstr "This event doesn't have any notes" +msgid "after" +msgstr "after" + +msgid "before" +msgstr "before" + msgid "Schedule date info" msgstr "Schedule date info" @@ -1308,29 +1311,29 @@ msgid_plural "The scheduled date is {{count}} days {{position}} the suggested da msgstr[0] "The scheduled date is {{count}} day {{position}} the suggested date." msgstr[1] "The scheduled date is {{count}} days {{position}} the suggested date." -msgid "after" -msgstr "after" - -msgid "before" -msgstr "before" - msgid "There are {{count}} scheduled event in {{orgUnitName}} on this day." msgid_plural "There are {{count}} scheduled event in {{orgUnitName}} on this day." msgstr[0] "There are {{count}} scheduled event in {{orgUnitName}} on this day." msgstr[1] "There are {{count}} scheduled events in {{orgUnitName}} on this day." -msgid "Schedule info" -msgstr "Schedule info" - msgid "Schedule date / Due date" msgstr "Schedule date / Due date" +msgid "Please provide a valid organisation unit" +msgstr "Please provide a valid organisation unit" + +msgid "Schedule info" +msgstr "Schedule info" + msgid "Event notes" msgstr "Event notes" msgid "Write a note about this scheduled event" msgstr "Write a note about this scheduled event" +msgid "Program or stage is invalid" +msgstr "Program or stage is invalid" + msgid "Save note" msgstr "Save note" @@ -1430,9 +1433,6 @@ msgstr "Report date" msgid "Please enter a date" msgstr "Please enter a date" -msgid "Please provide a valid organisation unit" -msgstr "Please provide a valid organisation unit" - msgid "Please select a valid event" msgstr "Please select a valid event" diff --git a/src/core_modules/capture-core/components/Widget/widgetCollapsible.types.js b/src/core_modules/capture-core/components/Widget/widgetCollapsible.types.js index 3f182d8f8e..6392f0fc94 100644 --- a/src/core_modules/capture-core/components/Widget/widgetCollapsible.types.js +++ b/src/core_modules/capture-core/components/Widget/widgetCollapsible.types.js @@ -2,7 +2,7 @@ import type { Node } from 'react'; export type WidgetCollapsibleProps = {| - header: Node, + header?: Node, children: Node, open: boolean, onOpen: () => void, diff --git a/src/core_modules/capture-core/components/Widget/widgetNonCollapsible.types.js b/src/core_modules/capture-core/components/Widget/widgetNonCollapsible.types.js index 3af55c409b..4e1e8e4f3d 100644 --- a/src/core_modules/capture-core/components/Widget/widgetNonCollapsible.types.js +++ b/src/core_modules/capture-core/components/Widget/widgetNonCollapsible.types.js @@ -2,7 +2,7 @@ import type { Node } from 'react'; export type WidgetNonCollapsibleProps = {| - header: Node, + header?: Node, children: Node, color?: string, borderless?: boolean, diff --git a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/dataEntryFieldLabels.module.css b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/dataEntryFieldLabels.module.css index 19bf2d5799..27d4299344 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/dataEntryFieldLabels.module.css +++ b/src/core_modules/capture-core/components/WidgetEnrollmentEventNew/DataEntry/dataEntryFieldLabels.module.css @@ -41,7 +41,7 @@ } .orgUnitLabel { - padding-top: 3px; + padding-top: 13px; } .selectLabel { diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/InfoBox/InfoBox.component.js b/src/core_modules/capture-core/components/WidgetEventSchedule/InfoBox/InfoBox.component.js index d62a901d0d..e124738453 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/InfoBox/InfoBox.component.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/InfoBox/InfoBox.component.js @@ -10,9 +10,13 @@ const styles = { infoBox: { marginTop: spacersNum.dp16, padding: spacersNum.dp16, + width: 'fit-content', }, }; +const getDayDifference = (startDate: string, endDate: string): number => + moment(startDate).diff(moment(endDate), 'days'); + const InfoBoxPlain = ({ scheduleDate, suggestedScheduleDate, @@ -21,38 +25,54 @@ const InfoBoxPlain = ({ orgUnitName, classes, }: Props) => { - if (!scheduleDate || !suggestedScheduleDate) { return null; } - const differenceScheduleDateAndSuggestedDate = moment(scheduleDate).diff(moment(suggestedScheduleDate), 'days'); + if (!scheduleDate || !suggestedScheduleDate) { + return null; + } + + const dayDifference = getDayDifference(scheduleDate, suggestedScheduleDate); + const absoluteDifference = Math.abs(dayDifference); + const position = dayDifference > 0 ? i18n.t('after') : i18n.t('before'); + const scheduledDateMatchesSuggested = scheduleDate === suggestedScheduleDate; return ( - {hideDueDate ? <> - {i18n.t('Scheduled automatically for {{suggestedScheduleDate}}', { suggestedScheduleDate })} - : <> - {scheduleDate === suggestedScheduleDate ? - i18n.t('The scheduled date matches the suggested date, but can be changed if needed.') - : - i18n.t( - 'The scheduled date is {{count}} days {{position}} the suggested date.', - { - position: differenceScheduleDateAndSuggestedDate > 0 ? i18n.t('after') : i18n.t('before'), - count: Math.abs(differenceScheduleDateAndSuggestedDate), - defaultValue: 'The scheduled date is {{count}} day {{position}} the suggested date.', - defaultValue_plural: 'The scheduled date is {{count}} days {{position}} the suggested date.', - }) - } - {' '} - {i18n.t('There are {{count}} scheduled event in {{orgUnitName}} on this day.', { - count: eventCountInOrgUnit, - orgUnitName, - defaultValue: 'There are {{count}} scheduled event in {{orgUnitName}} on this day.', - defaultValue_plural: 'There are {{count}} scheduled events in {{orgUnitName}} on this day.', - interpolation: { - escapeValue: false, - }, - })}} + {hideDueDate ? ( + <> + {i18n.t('Scheduled automatically for {{suggestedScheduleDate}}', { suggestedScheduleDate })} + + ) : ( + <> + {scheduledDateMatchesSuggested + ? i18n.t('The scheduled date matches the suggested date, but can be changed if needed.') + : i18n.t( + 'The scheduled date is {{count}} days {{position}} the suggested date.', + { + position, + count: absoluteDifference, + defaultValue: 'The scheduled date is {{count}} day {{position}} the suggested date.', + defaultValue_plural: 'The scheduled date is {{count}} days {{position}} the suggested date.', + }, + ) + } + {!!orgUnitName && ( + <> + {' '} + {i18n.t('There are {{count}} scheduled event in {{orgUnitName}} on this day.', { + count: eventCountInOrgUnit, + orgUnitName, + defaultValue: 'There are {{count}} scheduled event in {{orgUnitName}} on this day.', + defaultValue_plural: 'There are {{count}} scheduled events in {{orgUnitName}} on this day.', + interpolation: { + escapeValue: false, + }, + })} + + )} + + + )} ); }; -export const InfoBox: ComponentType<$Diff> = (withStyles(styles)(InfoBoxPlain)); +export const InfoBox: ComponentType<$Diff> = withStyles(styles)(InfoBoxPlain); diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/ScheduleDate.component.js b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/ScheduleDate.component.js index ca3f806f2d..9f8c790587 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/ScheduleDate.component.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/ScheduleDate.component.js @@ -1,18 +1,46 @@ // @flow import React, { type ComponentType } from 'react'; -import { spacersNum } from '@dhis2/ui'; +import i18n from '@dhis2/d2-i18n'; import withStyles from '@material-ui/core/styles/withStyles'; -import { DateField } from 'capture-core/components/FormFields/New'; -import { InfoBox } from '../InfoBox'; +import { spacers, colors } from '@dhis2/ui'; +import { + DateField, + withDefaultFieldContainer, + withLabel, + withDisplayMessages, + withInternalChangeHandler, +} from 'capture-core/components/FormFields/New'; + import type { Props } from './scheduleDate.types'; +import labelTypeClasses from './dataEntryFieldLabels.module.css'; +import { InfoBox } from '../InfoBox'; +import { baseInputStyles } from '../ScheduleOrgUnit/commonProps'; + + +const ScheduleDateField = withDefaultFieldContainer()( + withLabel({ + onGetCustomFieldLabeClass: () => labelTypeClasses.dateLabel, + })( + withDisplayMessages()( + withInternalChangeHandler()( + DateField, + ), + ), + ), +); const styles = { - container: { + infoBox: { + padding: `0 ${spacers.dp16} ${spacers.dp16} ${spacers.dp16}`, + }, + fieldWrapper: { display: 'flex', - marginTop: spacersNum.dp4, + flexWrap: 'wrap', }, - button: { - paddingRight: spacersNum.dp16, + fieldLabel: { + color: colors.grey900, + padding: `${spacers.dp16} ${spacers.dp24} 0 ${spacers.dp16}`, + fontSize: '14px', }, }; @@ -22,35 +50,51 @@ const ScheduleDatePlain = ({ setScheduleDate, orgUnit, serverSuggestedScheduleDate, + displayDueDateLabel, eventCountInOrgUnit, classes, hideDueDate, -}: Props) => (<> - {!hideDueDate &&
- {}} - onFocus={() => { }} - onRemoveFocus={() => { }} - onBlur={(e, internalComponentError) => { - const { error } = internalComponentError; - if (error) { - setScheduleDate(''); - return; - } - setScheduleDate(e); - }} - /> -
} - -); +}: Props) => ( +
+ {!hideDueDate ? + { }} + onFocus={() => { }} + onRemoveFocus={() => { }} + onBlur={(e, internalComponentError) => { + const { error } = internalComponentError; + if (error) { + setScheduleDate(''); + return; + } + setScheduleDate(e); + }} + /> + : +
+ {displayDueDateLabel ?? i18n.t('Schedule date / Due date', { + interpolation: { escapeValue: false }, + }, + )} +
+ } +
+ +
+
+); + export const ScheduleDate: ComponentType<$Diff> = (withStyles(styles)(ScheduleDatePlain)); diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/dataEntryFieldLabels.module.css b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/dataEntryFieldLabels.module.css new file mode 100644 index 0000000000..c795dd8efc --- /dev/null +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/dataEntryFieldLabels.module.css @@ -0,0 +1,3 @@ +.dateLabel { + padding-top: 13px; +} diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/scheduleDate.types.js b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/scheduleDate.types.js index ede74d4e37..6776f07c43 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/scheduleDate.types.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleDate/scheduleDate.types.js @@ -5,6 +5,7 @@ export type Props = {| stageId: string, programId: string, enrolledAt: string, + displayDueDateLabel: string, scheduleDate?: ?string, serverScheduleDate?: ?string, setScheduleDate: (date: string) => void, diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/ScheduleOrgUnit.component.js b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/ScheduleOrgUnit.component.js new file mode 100644 index 0000000000..9718127671 --- /dev/null +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/ScheduleOrgUnit.component.js @@ -0,0 +1,74 @@ +// @flow +import React, { useState } from 'react'; +import i18n from '@dhis2/d2-i18n'; +import { isValidOrgUnit } from 'capture-core-utils/validators/form'; +import labelTypeClasses from './dataEntryFieldLabels.module.css'; +import { baseInputStyles } from './commonProps'; +import { + SingleOrgUnitSelectField, + withDefaultFieldContainer, + withDisplayMessages, + withInternalChangeHandler, + withLabel, +} from '../../FormFields/New'; + +type OrgUnitValue = {| + checked: boolean, + id: string, + children: number, + name: string, + displayName: string, + path: string, + selected: string[], +|} + +type Props = { + onSelectOrgUnit: (orgUnit: OrgUnitValue) => void, + onDeselectOrgUnit: () => void, + orgUnit: OrgUnitValue, +}; + +const OrgUnitFieldForForm = withDefaultFieldContainer()( + withLabel({ + onGetCustomFieldLabeClass: () => labelTypeClasses.dateLabel, + })( + withDisplayMessages()( + withInternalChangeHandler()( + SingleOrgUnitSelectField, + ), + ), + ), +); + +export const ScheduleOrgUnit = ({ + onSelectOrgUnit, + onDeselectOrgUnit, + orgUnit, +}: Props) => { + const [touched, setTouched] = useState(false); + + const handleSelect = (event) => { + setTouched(true); + onSelectOrgUnit(event); + }; + + const handleDeselect = () => { + setTouched(true); + onDeselectOrgUnit(); + }; + + const shouldShowError = (!isValidOrgUnit(orgUnit) && touched); + const errorMessages = i18n.t('Please provide a valid organisation unit'); + + return ( + + ); +}; diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/commonProps.js b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/commonProps.js new file mode 100644 index 0000000000..909d053c6d --- /dev/null +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/commonProps.js @@ -0,0 +1,6 @@ +// @flow + +export const baseInputStyles = { + inputContainerStyle: { flexBasis: 150 }, + labelContainerStyle: { flexBasis: 200 }, +}; diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/dataEntryFieldLabels.module.css b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/dataEntryFieldLabels.module.css new file mode 100644 index 0000000000..c795dd8efc --- /dev/null +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/ScheduleOrgUnit/dataEntryFieldLabels.module.css @@ -0,0 +1,3 @@ +.dateLabel { + padding-top: 13px; +} diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js index d29cbd8a3a..a86780b8c4 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js @@ -1,9 +1,11 @@ // @flow -import React, { type ComponentType } from 'react'; -import { spacersNum, spacers, colors } from '@dhis2/ui'; +import React, { type ComponentType, useEffect } from 'react'; +import { spacersNum } from '@dhis2/ui'; import withStyles from '@material-ui/core/styles/withStyles'; import i18n from '@dhis2/d2-i18n'; +import { isValidOrgUnit } from 'capture-core-utils/validators/form'; import { DataSection } from '../DataSection'; +import { Widget } from '../Widget'; import { ScheduleButtons } from './ScheduleButtons'; import { ScheduleDate } from './ScheduleDate'; import { ScheduleText } from './ScheduleText'; @@ -11,43 +13,12 @@ import { NoteSection } from '../WidgetNote'; import type { Props } from './widgetEventSchedule.types'; import { CategoryOptions } from './CategoryOptions/CategoryOptions.component'; import { Assignee } from './Assignee'; +import { ScheduleOrgUnit } from './ScheduleOrgUnit/ScheduleOrgUnit.component'; const styles = () => ({ wrapper: { - padding: `${spacers.dp16} 0`, - maxWidth: '55.75rem', - }, - fieldWrapper: { - display: 'flex', - flexWrap: 'wrap', - justifyContent: 'space-between', - padding: `${spacers.dp8} ${spacers.dp16}`, - }, - fieldLabel: { - color: colors.grey900, - paddingTop: spacersNum.dp16, - paddingRight: spacersNum.dp16, - }, - fieldContent: { - flexBasis: '200px', - flexGrow: 1, - }, - containerWrapper: { - padding: `${spacers.dp8} ${spacers.dp16}`, - }, - container: { - display: 'flex', - alignItems: 'center', - paddingTop: 8, - paddingBottom: 8, - }, - label: { - flexBasis: 200, - paddingLeft: 5, - }, - field: { - flexBasis: 150, - flexGrow: 1, + paddingLeft: spacersNum.dp16, + minWidth: '300px', }, }); @@ -64,7 +35,9 @@ const WidgetEventSchedulePlain = ({ classes, scheduleDate, suggestedScheduleDate, + setScheduledOrgUnit, serverSuggestedScheduleDate, + setIsFormValid, notes, programCategory, enableUserAssignment, @@ -75,70 +48,92 @@ const WidgetEventSchedulePlain = ({ assignee, categoryOptionsError, ...passOnProps -}: Props) => ( -
- { + const onSelectOrgUnit = (e: { id: string, displayName: string, path: string }) => { + setScheduledOrgUnit({ + id: e.id, + name: e.displayName, + path: e.path, + }); + }; + + const onDeselectOrgUnit = () => { + setScheduledOrgUnit(undefined); + }; + + useEffect(() => { + const formIsValid = () => Boolean(isValidOrgUnit(orgUnit) && scheduleDate); + setIsFormValid(formIsValid()); + }, [orgUnit, scheduleDate, setIsFormValid]); + + return ( + -
-
- {displayDueDateLabel ?? i18n.t('Schedule date / Due date', { - interpolation: { escapeValue: false } }, - )} -
-
+
+ + -
+ + {programCategory && + + } + + + + {enableUserAssignment && ( + + + + )} + +
- - {programCategory && - - } - - - - {enableUserAssignment && ( - - - - )} - - -
-); +
+ ); +}; export const WidgetEventScheduleComponent: ComponentType<$Diff> = withStyles(styles)(WidgetEventSchedulePlain); diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.container.js b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.container.js index 1ea77bc470..aefbecd9ed 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.container.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.container.js @@ -4,7 +4,7 @@ import i18n from '@dhis2/d2-i18n'; import { useDispatch } from 'react-redux'; import moment from 'moment'; import { getProgramAndStageForProgram, TrackerProgram, getProgramEventAccess, dataElementTypes } from '../../metaData'; -import { useOrgUnitNameWithAncestors } from '../../metadataRetrieval/orgUnitName'; +import { getCachedOrgUnitName } from '../../metadataRetrieval/orgUnitName'; import { useLocationQuery } from '../../utils/routing'; import type { ContainerProps } from './widgetEventSchedule.types'; import { WidgetEventScheduleComponent } from './WidgetEventSchedule.component'; @@ -21,13 +21,12 @@ import { useCategoryCombinations } from '../DataEntryDhis2Helpers/AOC/useCategor import { convertFormToClient, convertClientToServer } from '../../converters'; import { pipe } from '../../../capture-core-utils'; - export const WidgetEventSchedule = ({ enrollmentId, teiId, stageId, programId, - orgUnitId, + orgUnitId: initialOrgUnitId, onSave, onSaveSuccessActionType, onSaveErrorActionType, @@ -39,26 +38,36 @@ export const WidgetEventSchedule = ({ }: ContainerProps) => { const { program, stage } = useMemo(() => getProgramAndStageForProgram(programId, stageId), [programId, stageId]); const dispatch = useDispatch(); - const orgUnit = { id: orgUnitId, name: useOrgUnitNameWithAncestors(orgUnitId).displayName }; const { programStageScheduleConfig } = useScheduleConfigFromProgramStage(stageId); const { programConfig } = useScheduleConfigFromProgram(programId); const suggestedScheduleDate = useDetermineSuggestedScheduleDate({ programStageScheduleConfig, programConfig, initialScheduleDate, ...passOnProps, }); + const orgUnitName = getCachedOrgUnitName(initialOrgUnitId); const { currentUser, noteId } = useNoteDetails(); const [scheduleDate, setScheduleDate] = useState(''); + const [scheduledOrgUnit, setScheduledOrgUnit] = useState(); + useEffect(() => { + if (initialOrgUnitId && orgUnitName) { + const orgUnit = { id: initialOrgUnitId, name: orgUnitName }; + setScheduledOrgUnit(orgUnit); + } + }, [orgUnitName, initialOrgUnitId]); + const [isFormValid, setIsFormValid] = useState(false); const convertFn = pipe(convertFormToClient, convertClientToServer); const serverScheduleDate = convertFn(scheduleDate, dataElementTypes.DATE); const serverSuggestedScheduleDate = convertFn(suggestedScheduleDate, dataElementTypes.DATE); const [notes, setNotes] = useState([]); const [assignee, setAssignee] = useState(storedAssignee); - const { events } = useEventsInOrgUnit(orgUnitId, serverScheduleDate); const { eventId } = useLocationQuery(); + const selectedOrgUnitId = scheduledOrgUnit?.id || initialOrgUnitId; + const { events = [] } = useEventsInOrgUnit(selectedOrgUnitId, serverScheduleDate); const eventCountInOrgUnit = events .filter(event => moment(event.scheduledAt).format('YYYY-MM-DD') === serverScheduleDate).length; const [selectedCategories, setSelectedCategories] = useState({}); const [categoryOptionsError, setCategoryOptionsError] = useState(); const { programCategory } = useCategoryCombinations(programId); + useEffect(() => { if (!scheduleDate && suggestedScheduleDate) { setScheduleDate(suggestedScheduleDate); } }, [suggestedScheduleDate, scheduleDate]); @@ -68,6 +77,7 @@ export const WidgetEventSchedule = ({ }, [storedAssignee]); const onHandleSchedule = useCallback(() => { + if (!isFormValid) { return; } if (programCategory?.categories && Object.keys(selectedCategories).length !== programCategory?.categories?.length) { const errors = programCategory.categories @@ -81,9 +91,9 @@ export const WidgetEventSchedule = ({ } dispatch(requestScheduleEvent({ scheduleDate: serverScheduleDate, + orgUnitId: selectedOrgUnitId, notes, programId, - orgUnitId, stageId, teiId, enrollmentId, @@ -100,7 +110,7 @@ export const WidgetEventSchedule = ({ serverScheduleDate, notes, programId, - orgUnitId, + selectedOrgUnitId, stageId, teiId, enrollmentId, @@ -111,15 +121,9 @@ export const WidgetEventSchedule = ({ onSaveErrorActionType, programCategory, assignee, + isFormValid, ]); - React.useEffect(() => { - if (suggestedScheduleDate && !scheduleDate) { - setScheduleDate(suggestedScheduleDate); - } - }, [scheduleDate, suggestedScheduleDate]); - - const onAddNote = (note) => { const newNote = { storedBy: currentUser.userName, @@ -159,7 +163,7 @@ export const WidgetEventSchedule = ({ if (!program || !stage || !(program instanceof TrackerProgram)) { return (
- {i18n.t('program or stage is invalid')}; + {i18n.t('Program or stage is invalid')};
); } @@ -167,9 +171,7 @@ export const WidgetEventSchedule = ({ const eventAccess = getProgramEventAccess(programId, stageId); if (!eventAccess?.write) { return ( - + ); } @@ -189,10 +191,12 @@ export const WidgetEventSchedule = ({ serverSuggestedScheduleDate={serverSuggestedScheduleDate} onCancel={onCancel} setScheduleDate={setScheduleDate} + setScheduledOrgUnit={setScheduledOrgUnit} + setIsFormValid={setIsFormValid} onSchedule={onHandleSchedule} onAddNote={onAddNote} eventCountInOrgUnit={eventCountInOrgUnit} - orgUnit={orgUnit} + orgUnit={scheduledOrgUnit} notes={notes} selectedCategories={selectedCategories} categoryOptionsError={categoryOptionsError} @@ -203,4 +207,3 @@ export const WidgetEventSchedule = ({ /> ); }; - diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/widgetEventSchedule.types.js b/src/core_modules/capture-core/components/WidgetEventSchedule/widgetEventSchedule.types.js index 7b89143d02..3ba2bc967a 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/widgetEventSchedule.types.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/widgetEventSchedule.types.js @@ -36,6 +36,12 @@ export type Props = {| scheduleDate?: ?string, serverScheduleDate?: ?string, suggestedScheduleDate?: ?string, + setScheduledOrgUnit: (orgUnit: ?{ + id: string, + name: string, + path: string, + }) => void, + setIsFormValid: (valid: boolean) => void, serverSuggestedScheduleDate?: ?string, eventCountInOrgUnit: number, notes: Array<{value: string}>, @@ -48,7 +54,7 @@ export type Props = {| onSetAssignee: () => void, assignee?: UserFormField | null, onCancel: () => void, - setScheduleDate: (date: string) => void, + setScheduleDate: (date: ?string) => void, onAddNote: (note: string) => void, onResetCategoryOption: (categoryId: string) => void, onClickCategoryOption: (optionId: string, categoryId: string) => void, From 402f2adb1c5b74b0f83f4b0340ec5291e4ff339c Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Fri, 31 Jan 2025 09:35:41 +0000 Subject: [PATCH 6/8] chore(release): cut 101.24.0 [skip release] # [101.24.0](https://github.com/dhis2/capture-app/compare/v101.23.2...v101.24.0) (2025-01-31) ### Features * [DHIS2-18329] Add org unit selector in schedule event form ([#3925](https://github.com/dhis2/capture-app/issues/3925)) ([4013d93](https://github.com/dhis2/capture-app/commit/4013d9326d17f93ff3b0ca11b7844764f92c6850)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fab41b0f..ce21c1a9b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [101.24.0](https://github.com/dhis2/capture-app/compare/v101.23.2...v101.24.0) (2025-01-31) + + +### Features + +* [DHIS2-18329] Add org unit selector in schedule event form ([#3925](https://github.com/dhis2/capture-app/issues/3925)) ([4013d93](https://github.com/dhis2/capture-app/commit/4013d9326d17f93ff3b0ca11b7844764f92c6850)) + ## [101.23.2](https://github.com/dhis2/capture-app/compare/v101.23.1...v101.23.2) (2025-01-28) diff --git a/package.json b/package.json index 7db79d335a..bc614c0b3e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "101.23.2", + "version": "101.24.0", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "101.23.2", + "@dhis2/rules-engine-javascript": "101.24.0", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index 8923911d99..0044677af5 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "101.23.2", + "version": "101.24.0", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From e79324029194f23c945b26cdd1f09f06bd27c213 Mon Sep 17 00:00:00 2001 From: henrikmv <110386561+henrikmv@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:48:51 +0100 Subject: [PATCH 7/8] fix: [DHIS2-18582] Data element with number option set are not displayed in Stages and Events widget (#3928) * fix: remove type check when comparing values * fix: convert options to client values * fix: type * fix: code cleanup --- .../StageDetail/StageDetail.component.js | 6 ++-- .../Stages/Stage/StageDetail/hooks/helpers.js | 4 +-- .../hooks/useClientDataElements.js | 32 +++++++++++++++++++ .../Stage/StageDetail/hooks/useEventList.js | 26 +++++++-------- .../types/common.types.js | 10 ++++++ 5 files changed, 59 insertions(+), 19 deletions(-) create mode 100644 src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useClientDataElements.js diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js index 4a02ddcd75..4ab54db15f 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js @@ -27,6 +27,7 @@ import { getProgramAndStageForProgram } from '../../../../../metaData/helpers'; import type { Props } from './stageDetail.types'; import { EventRow } from './EventRow'; import { errorCreator } from '../../../../../../capture-core-utils'; +import { useClientDataElements } from './hooks/useClientDataElements'; const styles = { @@ -113,7 +114,8 @@ const StageDetailPlain = (props: Props) => { }; const { stage } = getProgramAndStageForProgram(programId, stageId); const headerColumns = useComputeHeaderColumn(dataElements, hideDueDate, enableUserAssignment, stage?.stageForm); - const { loading, value: dataSource, error } = useComputeDataFromEvent(dataElements, events); + const dataElementsClient = useClientDataElements(dataElements); + const { loading, value: dataSource, error } = useComputeDataFromEvent(dataElementsClient, events); const [{ columnName, sortDirection }, setSortInstructions] = useState(defaultSortState); const [displayedRowNumber, setDisplayedRowNumber] = useState(DEFAULT_NUMBER_OF_ROW); @@ -177,7 +179,7 @@ const StageDetailPlain = (props: Props) => { return sortDataFromEvent({ dataA, dataB, type, columnName, direction: sortDirection }); }) .slice(0, displayedRowNumber) - .map(row => formatRowForView(row, dataElements)) + .map(row => formatRowForView(row, dataElementsClient)) .map((row: Object) => { const cells = headerColumns.map(({ id }) => ( , - dataElements: Array, + dataElements: Array, querySingleResource: QuerySingleResource, absoluteApiPath: string, ) => { diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useClientDataElements.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useClientDataElements.js new file mode 100644 index 0000000000..a375bdd296 --- /dev/null +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useClientDataElements.js @@ -0,0 +1,32 @@ +// @flow +import { useMemo } from 'react'; +import { convertValue } from 'capture-core/converters/serverToClient'; +import type { StageDataElement, StageDataElementClient } from '../../../../types/common.types'; + +export const useClientDataElements = (dataElements: Array) => + useMemo(() => { + if (!dataElements || !Array.isArray(dataElements)) { + return []; + } + + return dataElements.map ( + (dataElement: StageDataElement) => { + const { + options, + type, + ...rest + } = dataElement; + + const convertedOptions = options + ? Object.entries(options).map(([key, value]) => ({ + value: convertValue(key, type), + text: value, + })) : undefined; + + return { + ...rest, + type, + options: convertedOptions, + }; + }); + }, [dataElements]); diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useEventList.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useEventList.js index d6fcf10be0..3a545be6ec 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useEventList.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useEventList.js @@ -6,7 +6,7 @@ import { useDataEngine, useConfig } from '@dhis2/app-runtime'; import { makeQuerySingleResource } from 'capture-core/utils/api'; import { errorCreator, buildUrl } from 'capture-core-utils'; import { dataElementTypes, DataElement, OptionSet, Option } from '../../../../../../metaData'; -import type { StageDataElement } from '../../../../types/common.types'; +import type { StageDataElement, StageDataElementClient } from '../../../../types/common.types'; import { convertValue as convertClientToList } from '../../../../../../converters/clientToList'; import { convertValue as convertServerToClient } from '../../../../../../converters/serverToClient'; import { @@ -45,7 +45,7 @@ const getBaseColumns = props => baseFields.map((key, index) => ({ ...key, ...get const getAllFieldsWithValue = ( eventId: string, - dataElements: Array, + dataElements: Array, dataElementsByType: Array<{type: string, eventId: string, ids: Object}>, ) => dataElements .reduce((acc, { id, type }) => { @@ -59,7 +59,7 @@ const getAllFieldsWithValue = ( return acc; }, {}); -const useComputeDataFromEvent = (dataElements: Array, events: Array) => { +const useComputeDataFromEvent = (dataElements: Array, events: Array) => { const [value, setValue] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); @@ -132,32 +132,28 @@ const useComputeHeaderColumn = (dataElements: Array, hideDueDa return headerColumns; }; -const getDataElement = (stageDataElement, type) => { +function getDataElement(stageDataElement, type) { if (!stageDataElement) { return null; } - const dataElement = new DataElement((o) => { o.id = stageDataElement.id; o.type = type; }); if (stageDataElement.options) { - const options = Object.keys(stageDataElement.options).map( - (code: string) => - new Option((o) => { - // $FlowFixMe - o.text = stageDataElement.options[code]; - o.value = code; - }), - ); + const options = stageDataElement.options.map(({ value, text }) => + new Option((o) => { + o.text = text; + o.value = value; + })); const optionSet = new OptionSet(stageDataElement.id, options); dataElement.optionSet = optionSet; } return dataElement; -}; +} -const formatRowForView = (row: Object, dataElements: Array) => Object.keys(row).reduce((acc, id) => { +const formatRowForView = (row: Object, dataElements: Array) => Object.keys(row).reduce((acc, id) => { const { type: predefinedType } = baseFields.find(f => f.id === id) || {}; const stageDataElement = dataElements.find(el => el.id === id); const { type } = stageDataElement || {}; diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/types/common.types.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/types/common.types.js index cff6ac9938..24873d1721 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/types/common.types.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/types/common.types.js @@ -6,6 +6,7 @@ import { dataElementTypes, Option } from '../../../metaData'; type StageOptions = { [code: string]: string; } + export type StageDataElement = { id: string, name: string, @@ -15,6 +16,15 @@ export type StageDataElement = { optionSet?: { options: Array