Skip to content

Commit

Permalink
fix: dispach from componentDidUpdate
Browse files Browse the repository at this point in the history
  • Loading branch information
simonadomnisoru committed Apr 25, 2024
1 parent 108a237 commit e47e7ae
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 166 deletions.
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -76,17 +77,6 @@ type Props = {
onUpdateField: (value: any, uiState: FieldUI, fieldId: string, formBuilderId: string, promiseForIsValidating: string) => void,
onUpdateFieldUIOnly: (uiState: FieldUI, fieldId: string, formBuilderId: string) => void,
onFieldsValidated: ?(fieldsUI: { [id: string]: FieldUI }, formBuilderId: string, uidsForIsValidating: Array<string>) => void,
onFieldValidated: ?(
fieldUI: {
fieldId: string,
valid?: ?boolean,
errorMessage?: ?string | Array<string>,
errorType?: ?string,
errorData?: ErrorData,
},
formBuilderId: string,
uidForIsValidating: string,
) => void,
querySingleResource: QuerySingleResource,
validationAttempted?: ?boolean,
validateIfNoUIData?: ?boolean,
Expand Down Expand Up @@ -120,6 +110,7 @@ export class FormBuilder extends React.Component<Props> {
if (!validators || validators.length === 0) {
return {
valid: true,
pendingValidation: false,
};
}

Expand Down Expand Up @@ -151,6 +142,7 @@ export class FormBuilder extends React.Component<Props> {
errorMessage: validatorResult.message,
errorType: validatorResult.type,
errorData: validatorResult.data,
pendingValidation: false,
};
}

Expand All @@ -159,6 +151,7 @@ export class FormBuilder extends React.Component<Props> {
errorMessage: null,
errorType: null,
errorData: null,
pendingValidation: false,
};
}

Expand Down Expand Up @@ -195,17 +188,19 @@ export class FormBuilder extends React.Component<Props> {
}, asyncUIState);
}

static executeValidateAllFields(
static executeValidateFields(
props: Props,
fieldsValidatingPromiseContainer: FieldsValidatingPromiseContainer,
customFields?: Array<FieldConfig>,
) {
const {
id,
fields,
fields: allFields,
values,
onGetValidationContext,
onIsValidating,
} = props;
const fields = customFields || allFields || [];
const validationContext = onGetValidationContext && onGetValidationContext();
const validationPromises = fields
.map(async (field) => {
Expand Down Expand Up @@ -248,6 +243,7 @@ export class FormBuilder extends React.Component<Props> {
valid: false,
errorMessage: [i18n.t('error encountered during field validation')],
errorType: i18n.t('error'),
pendingValidation: false,
};
log.error({ reason, field });
}
Expand All @@ -269,68 +265,6 @@ export class FormBuilder extends React.Component<Props> {
);
}

static executeValidateField(
props: Props,
fieldsValidatingPromiseContainer: FieldsValidatingPromiseContainer,
field: FieldConfig,
) {
const {
id,
values,
onGetValidationContext,
onIsValidating,
} = props;
const validationContext = onGetValidationContext && onGetValidationContext();
const validationPromise = (async () => {
const fieldId = field.id;
const fieldValidatingPromiseContainer = fieldsValidatingPromiseContainer[fieldId] || {};
fieldsValidatingPromiseContainer[fieldId] = fieldValidatingPromiseContainer;

if (!fieldValidatingPromiseContainer.validatingCompleteUid) {
fieldValidatingPromiseContainer.validatingCompleteUid = uuid();
}
fieldValidatingPromiseContainer.cancelableValidatingPromise &&
fieldValidatingPromiseContainer.cancelableValidatingPromise.cancel();

const handleIsValidatingInternal = (message: ?string, promise: Promise<any>) => {
fieldValidatingPromiseContainer.cancelableValidatingPromise = makeCancelablePromise(promise);
onIsValidating && onIsValidating(
field.id,
id,
fieldValidatingPromiseContainer.validatingCompleteUid,
message,
null,
);

return fieldValidatingPromiseContainer.cancelableValidatingPromise.promise;
};

let validationData;
try {
validationData = await FormBuilder.validateField(
field,
values[field.id],
validationContext,
handleIsValidatingInternal,
);
} catch (reason) {
if (reason && isObject(reason) && reason.isCanceled) {
validationData = null;
} else {
validationData = {
valid: false,
errorMessage: [i18n.t('error encountered during field validation')],
errorType: i18n.t('error'),
};
log.error({ reason, field });
}
}

return { fieldId: field.id, ...validationData };
});

return validationPromise;
}

fieldInstances: Map<string, any>;
asyncUIState: { [id: string]: FieldUI };
Expand All @@ -346,7 +280,7 @@ export class FormBuilder extends React.Component<Props> {
this.commitUpdateTriggeredForFields = {};

if (this.props.validateIfNoUIData) {
this.validateAllFields(this.props);
this.validateFields(this.props);
}
}

Expand All @@ -355,14 +289,26 @@ export class FormBuilder extends React.Component<Props> {
this.asyncUIState = FormBuilder.getAsyncUIState(this.props.fieldsUI);
this.commitUpdateTriggeredForFields = {};
if (this.props.validateIfNoUIData) {
this.validateAllFields(newProps);
this.validateFields(newProps);
}
} else {
this.asyncUIState =
FormBuilder.updateAsyncUIState(this.props.fieldsUI, newProps.fieldsUI, this.asyncUIState);
}
}

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 customFields = fields.filter(field => pendingValidationFields.includes(field.id));
this.validateFields(this.props, customFields);
}
}
}

getCleanUpData() {
const remainingCompleteUids: Array<string> = Object
.keys(this.fieldsValidatingPromiseContainer)
Expand All @@ -378,49 +324,13 @@ export class FormBuilder extends React.Component<Props> {
return remainingCompleteUids;
}

validateField(
props: Props,
field: FieldConfig,
) {
const { cancelableValidatingPromise } = this.fieldsValidatingPromiseContainer[field.id] || {};
cancelableValidatingPromise && cancelableValidatingPromise.cancel();

const promiseValidateField = FormBuilder.executeValidateField(
props,
this.fieldsValidatingPromiseContainer,
field,
);

promiseValidateField()
.then((validationContainer) => {
props.onFieldValidated &&
this.fieldsValidatingPromiseContainer[field.id]?.validatingCompleteUid &&
props.onFieldValidated(
validationContainer,
props.id,
this.fieldsValidatingPromiseContainer[field.id].validatingCompleteUid,
);

if (!this.commitUpdateTriggeredForFields[field.id]) {
this.fieldsValidatingPromiseContainer[field.id] = null;
}
})
.catch((reason) => {
if (!reason || !isObject(reason) || !reason.isCanceled) {
log.error({
reason,
message: 'formBuilder validate field failed',
});
}
});
}

validateAllFields(
validateFields(
props: Props,
customFields?: Array<FieldConfig>,
) {
this.validateAllCancelablePromise && this.validateAllCancelablePromise.cancel();
this.validateAllCancelablePromise = makeCancelablePromise(
FormBuilder.executeValidateAllFields(props, this.fieldsValidatingPromiseContainer),
FormBuilder.executeValidateFields(props, this.fieldsValidatingPromiseContainer, customFields),
);

this.validateAllCancelablePromise
Expand Down Expand Up @@ -686,7 +596,6 @@ export class FormBuilder extends React.Component<Props> {
fieldsUI,
validationAttempted,
id,
onFieldValidated,
onFieldsValidated,
onUpdateField,
onUpdateFieldAsync,
Expand Down Expand Up @@ -717,11 +626,6 @@ export class FormBuilder extends React.Component<Props> {
asyncProps.onCommitAsync = (callback: Function) => this.handleCommitAsync(field.id, props.label, callback);
asyncProps.asyncUIState = this.asyncUIState[field.id];
}
if (fieldUI.pendingValidation) {
const asyncStateToAdd = { ...fieldUI, pendingValidation: false };
this.handleUpdateAsyncState(field.id, asyncStateToAdd);
this.validateField(this.props, field);
}

const errorMessage = onPostProcessErrorMessage && fieldUI.errorMessage ?
onPostProcessErrorMessage({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import i18n from '@dhis2/d2-i18n';
import { actionCreator } from '../../../actions/actions.utils';

export const actionTypes = {
FIELD_VALIDATED: 'FieldValidated',
FIELDS_VALIDATED: 'FieldsValidated',
FIELD_IS_VALIDATING: 'FieldIsValidating',
START_UPDATE_FIELD_ASYNC: 'StartUpdateFieldAsync',
Expand Down Expand Up @@ -39,13 +38,6 @@ export const fieldsValidated = (
actionCreator(actionTypes.FIELDS_VALIDATED)(
{ fieldsUI, formBuilderId, formId, validatingUids });

export const fieldValidated = (
fieldUI: Object,
formBuilderId: string,
formId: string,
validatingUid: string,
) => actionCreator(actionTypes.FIELD_VALIDATED)({ fieldUI, formBuilderId, formId, validatingUid });

export const startUpdateFieldAsync = (
elementId: string,
fieldLabel: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
import * as React from 'react';
import { connect } from 'react-redux';
import { v4 as uuid } from 'uuid';
import { fieldIsValidating, fieldsValidated, fieldValidated, startUpdateFieldAsync } from './actions';
import { fieldIsValidating, fieldsValidated, startUpdateFieldAsync } from './actions';

type Props = {
id: string,
onIsValidating: Function,
onFieldsValidated: Function,
onFieldValidated: Function,
onUpdateFieldAsyncInner: Function,
onUpdateFieldAsync: ?Function,
};
Expand All @@ -28,12 +27,6 @@ const getAsyncHandler = (InnerComponent: React.ComponentType<any>) =>
this.props.onFieldsValidated(...args, id);
}

// $FlowFixMe[missing-annot] automated comment
handleFieldValidated = (...args) => {
const { id } = this.props;
this.props.onFieldValidated(...args, id);
}

// $FlowFixMe[missing-annot] automated comment
handleUpdateFieldAsyncInner = (...args) => {
const { onUpdateFieldAsyncInner, onUpdateFieldAsync } = this.props;
Expand All @@ -44,7 +37,6 @@ const getAsyncHandler = (InnerComponent: React.ComponentType<any>) =>
const {
onIsValidating,
onFieldsValidated,
onFieldValidated,
onUpdateFieldAsyncInner,
onUpdateFieldAsync,
...passOnProps } = this.props;
Expand All @@ -53,7 +45,6 @@ const getAsyncHandler = (InnerComponent: React.ComponentType<any>) =>
<InnerComponent
onIsValidating={this.handleIsValidating}
onFieldsValidated={this.handleFieldsValidated}
onFieldValidated={this.handleFieldValidated}
onUpdateFieldAsync={this.handleUpdateFieldAsyncInner}
{...passOnProps}
/>
Expand Down Expand Up @@ -84,15 +75,6 @@ const mapDispatchToProps = (dispatch: ReduxDispatch) => ({
const action = fieldsValidated(fieldsUI, formBuilderId, formId, validatingUids);
dispatch(action);
},
onFieldValidated: (
fieldUI: Object,
formBuilderId: string,
validatingUid: string,
formId: string,
) => {
const action = fieldValidated(fieldUI, formBuilderId, formId, validatingUid);
dispatch(action);
},
onUpdateFieldAsyncInner: (
fieldId: string,
fieldLabel: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,14 +291,6 @@ export const dataEntriesInProgressListDesc = createReducerDescription({
[formId]: updatedList,
};
},
[formAsyncActionTypes.FIELD_VALIDATED]: (state, action) => {
const { formId, validatingUid } = action.payload;
const updatedList = (state[formId] || []).filter(item => item !== validatingUid);
return {
...state,
[formId]: updatedList,
};
},
[actionTypes.UPDATE_FORM_FIELD]: (state, action) => {
const { formId, updateCompleteUid } = action.payload;
const updatedList = (state[formId] || []).filter(item => item !== updateCompleteUid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,6 @@ export const formsSectionsFieldsUIDesc = createReducerDescription({

return newState;
},
[formAsyncActionTypes.FIELD_VALIDATED]: (state, action) => {
const newState = { ...state };
const { formId, fieldUI } = action.payload;
const { fieldId, ...restPayload } = fieldUI;
const newValues = { ...newState[formId][fieldId], ...restPayload, validatingMessage: null };

newState[formId] = { ...newState[formId], [fieldId]: newValues };
return newState;
},
[formAsyncActionTypes.FIELDS_VALIDATED]: (state, action) => {
const newState = { ...state };
const payload = action.payload;
Expand Down

0 comments on commit e47e7ae

Please sign in to comment.