From 459ab9a7fc0b0f3c3ce98e19a7acf213b35eb6e8 Mon Sep 17 00:00:00 2001 From: Simona Domnisoru Date: Tue, 9 Jul 2024 14:04:17 +0200 Subject: [PATCH] fix: [BETA-116][DHIS2-15896] validate values assigned from the rules engine (#3612) --- .../FormBuilder/FormBuilder.component.js | 37 ++++++++++++++++--- .../descriptions/form.reducerDescription.js | 6 +-- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/core_modules/capture-core/components/D2Form/FormBuilder/FormBuilder.component.js b/src/core_modules/capture-core/components/D2Form/FormBuilder/FormBuilder.component.js index df14dbb598..6707d84ca7 100644 --- a/src/core_modules/capture-core/components/D2Form/FormBuilder/FormBuilder.component.js +++ b/src/core_modules/capture-core/components/D2Form/FormBuilder/FormBuilder.component.js @@ -1,6 +1,7 @@ // @flow /* eslint-disable complexity */ import i18n from '@dhis2/d2-i18n'; +import { isEqual } from 'lodash'; import log from 'loglevel'; import { v4 as uuid } from 'uuid'; import * as React from 'react'; @@ -40,6 +41,7 @@ type FieldUI = { errorType?: ?string, errorData?: ErrorData, validatingMessage?: ?string, + pendingValidation?: ?boolean, }; type RenderDividerFn = (index: number, fieldsCount: number, field: FieldConfig) => React.Node; @@ -108,6 +110,7 @@ export class FormBuilder extends React.Component { if (!validators || validators.length === 0) { return { valid: true, + pendingValidation: false, }; } @@ -139,11 +142,16 @@ export class FormBuilder extends React.Component { errorMessage: validatorResult.message, errorType: validatorResult.type, errorData: validatorResult.data, + pendingValidation: false, }; } return { valid: true, + errorMessage: null, + errorType: null, + errorData: null, + pendingValidation: false, }; } @@ -180,17 +188,19 @@ export class FormBuilder extends React.Component { }, asyncUIState); } - static executeValidateAllFields( + static executeValidateFields( props: Props, fieldsValidatingPromiseContainer: FieldsValidatingPromiseContainer, + customFields?: Array, ) { const { id, - fields, + fields: allFields, values, onGetValidationContext, onIsValidating, } = props; + const fields = customFields || allFields || []; const validationContext = onGetValidationContext && onGetValidationContext(); const validationPromises = fields .map(async (field) => { @@ -233,6 +243,7 @@ export class FormBuilder extends React.Component { valid: false, errorMessage: [i18n.t('error encountered during field validation')], errorType: i18n.t('error'), + pendingValidation: false, }; log.error({ reason, field }); } @@ -268,7 +279,7 @@ export class FormBuilder extends React.Component { this.commitUpdateTriggeredForFields = {}; if (this.props.validateIfNoUIData) { - this.validateAllFields(this.props); + this.validateFields(this.props); } } @@ -277,7 +288,7 @@ export class FormBuilder extends React.Component { this.asyncUIState = FormBuilder.getAsyncUIState(this.props.fieldsUI); this.commitUpdateTriggeredForFields = {}; if (this.props.validateIfNoUIData) { - this.validateAllFields(newProps); + this.validateFields(newProps); } } else { this.asyncUIState = @@ -285,6 +296,19 @@ export class FormBuilder extends React.Component { } } + componentDidUpdate(prevProps: Props) { + const { fieldsUI, fields } = this.props; + + if (!isEqual(prevProps.fieldsUI, fieldsUI)) { + const pendingValidationFields = Object.keys(fieldsUI).filter(key => fieldsUI[key].pendingValidation); + + if (pendingValidationFields.length !== 0 && !this.validateAllCancelablePromise) { + const fieldsToValidate = fields.filter(field => pendingValidationFields.includes(field.id)); + this.validateFields(this.props, fieldsToValidate); + } + } + } + getCleanUpData() { const remainingCompleteUids: Array = Object .keys(this.fieldsValidatingPromiseContainer) @@ -300,12 +324,13 @@ export class FormBuilder extends React.Component { return remainingCompleteUids; } - validateAllFields( + validateFields( props: Props, + customFields?: Array, ) { this.validateAllCancelablePromise && this.validateAllCancelablePromise.cancel(); this.validateAllCancelablePromise = makeCancelablePromise( - FormBuilder.executeValidateAllFields(props, this.fieldsValidatingPromiseContainer), + FormBuilder.executeValidateFields(props, this.fieldsValidatingPromiseContainer, customFields), ); this.validateAllCancelablePromise diff --git a/src/core_modules/capture-core/reducers/descriptions/form.reducerDescription.js b/src/core_modules/capture-core/reducers/descriptions/form.reducerDescription.js index 30dd29a15f..b0d3bd5231 100644 --- a/src/core_modules/capture-core/reducers/descriptions/form.reducerDescription.js +++ b/src/core_modules/capture-core/reducers/descriptions/form.reducerDescription.js @@ -216,13 +216,11 @@ export const formsSectionsFieldsUIDesc = createReducerDescription({ const updatedFields = Object.keys(assignEffects).reduce((acc, id) => { if (formSectionFields[id]) { acc[id] = { - valid: true, - errorData: undefined, - errorMessage: undefined, - errorType: undefined, + ...state[formId][id], modified: true, touched: true, validatingMessage: null, + pendingValidation: true, }; } return acc;