diff --git a/src/ui/common/attributes/AttributeInfo.js b/src/ui/common/attributes/AttributeInfo.js index cd2ee2399..11e51ab1d 100644 --- a/src/ui/common/attributes/AttributeInfo.js +++ b/src/ui/common/attributes/AttributeInfo.js @@ -11,7 +11,7 @@ import { MODE_EDIT, MODE_ADD } from 'state/data-types/const'; import { convertReduxValidationsToFormikValidations } from 'helpers/formikUtils'; -const maxLength10 = maxLength(10); +const maxLength15 = maxLength(15); const maxLength50 = maxLength(50); const AttributeInfo = ({ isSearchable, isIndexable, mode }) => { @@ -68,7 +68,7 @@ const AttributeInfo = ({ isSearchable, isIndexable, mode }) => { } validate={value => - convertReduxValidationsToFormikValidations(value, [required, maxLength10])} + convertReduxValidationsToFormikValidations(value, [required, maxLength15])} disabled={mode === MODE_EDIT} /> ({ mode: 'add', attributesType: getProfileTypeAttributesIdList(state), - attributeCode: getAttributeTypeSelectFromProfileType(state), initialValues: { code: '', name: '', diff --git a/src/ui/profile-types/common/ProfileTypeForm.js b/src/ui/profile-types/common/ProfileTypeForm.js index 291b254e1..d9498ddd8 100644 --- a/src/ui/profile-types/common/ProfileTypeForm.js +++ b/src/ui/profile-types/common/ProfileTypeForm.js @@ -27,14 +27,14 @@ export class ProfileTypeFormBody extends Component { const { attributesType, mode, handleSubmit, onAddAttribute, isValid, isSubmitting, - profileTypeCode, intl, - dirty, onCancel, onDiscard, onSave, values, + profileTypeCode, values, intl, + isDirty, onCancel, onDiscard, onSave, } = this.props; const isEdit = mode === 'edit'; const handleCancelClick = () => { - if (dirty) { + if (isDirty) { onCancel(); } else { onDiscard(); @@ -183,15 +183,18 @@ ProfileTypeFormBody.propTypes = { onAddAttribute: PropTypes.func, attributesType: PropTypes.arrayOf(PropTypes.string).isRequired, isValid: PropTypes.bool, - isSubmitting: PropTypes.bool.isRequired, + isSubmitting: PropTypes.bool, mode: PropTypes.string, profileTypeCode: PropTypes.string, - dirty: PropTypes.bool, + attributeCode: PropTypes.string, + isDirty: PropTypes.bool, onSave: PropTypes.func.isRequired, onDiscard: PropTypes.func.isRequired, onCancel: PropTypes.func.isRequired, values: PropTypes.shape({ - type: PropTypes.string, + type: PropTypes.shape({ + code: PropTypes.string, + }), }).isRequired, }; @@ -199,10 +202,11 @@ ProfileTypeFormBody.defaultProps = { onWillMount: () => {}, onAddAttribute: () => {}, isValid: false, + isSubmitting: false, mode: 'add', profileTypeCode: '', - - dirty: false, + attributeCode: '', + isDirty: false, }; const ProfileTypeForm = injectIntl(withFormik({ diff --git a/src/ui/profile-types/edit/EditFormContainer.js b/src/ui/profile-types/edit/EditFormContainer.js index 0c6b24502..c4e5de156 100644 --- a/src/ui/profile-types/edit/EditFormContainer.js +++ b/src/ui/profile-types/edit/EditFormContainer.js @@ -12,7 +12,6 @@ import { import { getSelectedProfileTypeAttributes, getProfileTypeAttributesIdList, - getAttributeTypeSelectFromProfileType, getSelectedProfileType, } from 'state/profile-types/selectors'; import { setVisibleModal, setInfo } from 'state/modal/actions'; @@ -33,7 +32,6 @@ export const mapStateToProps = (state, { match: { params } }) => ( profileTypeCode: params.profiletypeCode, attributes: getSelectedProfileTypeAttributes(state), attributesType: getProfileTypeAttributesIdList(state), - attributeCode: getAttributeTypeSelectFromProfileType(state), routeToEdit: ROUTE_PROFILE_TYPE_ATTRIBUTE_EDIT, initialValues: getSelectedProfileType(state), } diff --git a/src/ui/user-profile/common/UserProfileField.js b/src/ui/user-profile/common/UserProfileField.js index eff3ae200..550a322a9 100644 --- a/src/ui/user-profile/common/UserProfileField.js +++ b/src/ui/user-profile/common/UserProfileField.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import PropTypes from 'prop-types'; import { get } from 'lodash'; import { Row, Col } from 'patternfly-react'; @@ -72,44 +72,48 @@ const getEnumeratorOptions = (component, items, separator, mandatory, intl) => { } }; -const userProfileValidators = {}; +export const generateValidatorFunc = ( + value, validatorFuncName, validatorFunc, + validatorArray, parseValueFunc, customErrorId, +) => { + const userProfileValidators = {}; + if (value === null || value === undefined) { + return; + } + const parsedValue = parseValueFunc ? parseValueFunc(value) : value; + if (!userProfileValidators[validatorFuncName]) { + userProfileValidators[validatorFuncName] = {}; + } + if (!userProfileValidators[validatorFuncName][value]) { + userProfileValidators[validatorFuncName] = { + ...userProfileValidators[validatorFuncName], + [value]: validatorFunc(parsedValue, customErrorId), + }; + } + validatorArray.push(userProfileValidators[validatorFuncName][value]); +}; -const UserProfileField = ({ attribute, intl, setFieldValue }) => { +export const UserProfileField = ({ + attribute, intl, setFieldValue, disabled, +}) => { const { validationRules } = attribute || {}; const { minLength: textMinLen, maxLength: textMaxLen, regex, rangeEndNumber, rangeStartNumber, } = validationRules || {}; - const generateValidatorFunc = ( - value, validatorFuncName, validatorFunc, - validatorArray, parseValueFunc, customErrorId, - ) => { - if (value === null || value === undefined) { - return; - } - const parsedValue = parseValueFunc ? parseValueFunc(value) : value; - if (!userProfileValidators[validatorFuncName]) { - userProfileValidators[validatorFuncName] = {}; - } - if (!userProfileValidators[validatorFuncName][value]) { - userProfileValidators[validatorFuncName] = { - ...userProfileValidators[validatorFuncName], - [value]: validatorFunc(parsedValue, customErrorId), - }; - } - validatorArray.push(userProfileValidators[validatorFuncName][value]); - }; - - const validateArray = [...(attribute.mandatory ? [required] : [])]; - generateValidatorFunc(textMinLen, 'minLength', minLength, validateArray); - generateValidatorFunc(textMaxLen, 'maxLength', maxLength, validateArray); - generateValidatorFunc( - regex, 'regex', matchRegex, validateArray, RegexParser, - attribute.type === 'Email' && 'validateForm.email', - ); - generateValidatorFunc(rangeEndNumber, 'rangeEndNumber', maxValue, validateArray); - generateValidatorFunc(rangeStartNumber, 'rangeStartNumber', minValue, validateArray); - + const vArray = useMemo(() => { + const validateArray = [...(attribute.mandatory ? [required] : [])]; + generateValidatorFunc(textMinLen, 'minLength', minLength, validateArray); + generateValidatorFunc(textMaxLen, 'maxLength', maxLength, validateArray); + generateValidatorFunc( + regex, 'regex', matchRegex, validateArray, RegexParser, + attribute.type === 'Email' && 'validateForm.email', + ); + generateValidatorFunc(rangeEndNumber, 'rangeEndNumber', maxValue, validateArray); + generateValidatorFunc(rangeStartNumber, 'rangeStartNumber', minValue, validateArray); + return validateArray; + }, [attribute.mandatory, attribute.type, rangeEndNumber, rangeStartNumber, + regex, textMaxLen, textMinLen]); const validationFunc = (value, validationFuncList) => { let validation = null; @@ -139,10 +143,11 @@ const UserProfileField = ({ attribute, intl, setFieldValue }) => { helpText={getHelpMessage(attribute.validationRules, intl)} required={attribute.mandatory} />} - validate={value => validationFunc(value, validateArray)} + validate={value => validationFunc(value, vArray)} readOnly={readOnlyFields.includes(attribute.code)} data-testid={`UserProfileForm__${attribute.code}Field`} onPickDate={value => setFieldValue(attribute.code, value)} + disabled={disabled} />); }; @@ -165,6 +170,11 @@ UserProfileField.propTypes = { attribute: basicAttributeShape.isRequired, intl: intlShape.isRequired, setFieldValue: PropTypes.func.isRequired, + disabled: PropTypes.bool, +}; + +UserProfileField.defaultProps = { + disabled: false, }; export const CompositeField = ({ @@ -232,5 +242,3 @@ CompositeField.defaultProps = { fieldName: '', noLabel: false, }; - -export default UserProfileField; diff --git a/src/ui/user-profile/common/UserProfileForm.js b/src/ui/user-profile/common/UserProfileForm.js index 62e4c7152..0bbd34e86 100644 --- a/src/ui/user-profile/common/UserProfileForm.js +++ b/src/ui/user-profile/common/UserProfileForm.js @@ -4,7 +4,7 @@ import get from 'lodash/get'; import { Button, Row, Col, FormGroup } from 'patternfly-react'; import { required } from '@entando/utils'; import { FormattedMessage, defineMessages, injectIntl, intlShape } from 'react-intl'; -import UserProfileField, { CompositeField } from 'ui/user-profile/common/UserProfileField'; +import { UserProfileField, CompositeField } from 'ui/user-profile/common/UserProfileField'; import FormLabel from 'ui/common/form/FormLabel'; import RenderListField from 'ui/common/formik-field/RenderListField'; import { BOOLEAN_OPTIONS, THREE_STATE_OPTIONS, getTranslatedOptions } from 'ui/users/common/const'; diff --git a/src/ui/users/my-profile/MyProfileEditForm.js b/src/ui/users/my-profile/MyProfileEditForm.js index 6d5e3f72e..130e1aa3d 100644 --- a/src/ui/users/my-profile/MyProfileEditForm.js +++ b/src/ui/users/my-profile/MyProfileEditForm.js @@ -1,7 +1,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import get from 'lodash/get'; -import { withFormik, Field, FieldArray } from 'formik'; +import { withFormik, FieldArray } from 'formik'; import { FormattedMessage, defineMessages, injectIntl, intlShape } from 'react-intl'; import { Panel } from 'react-bootstrap'; import { Form, Button, Row, Col } from 'patternfly-react'; @@ -15,9 +15,7 @@ import { TYPE_BOOLEAN, TYPE_THREESTATE, TYPE_ENUMERATOR, TYPE_ENUMERATOR_MAP, TYPE_MONOLIST, TYPE_LIST, TYPE_COMPOSITE, } from 'state/data-types/const'; -import { getComponentType } from 'helpers/formikEntities'; - -const defaultAttrCodes = ['fullname', 'email']; +import { UserProfileField } from 'ui/user-profile/common/UserProfileField'; const getComponentOptions = (component, intl) => { const booleanOptions = getTranslatedOptions(intl, BOOLEAN_OPTIONS); @@ -75,42 +73,6 @@ const getHelpMessage = (validationRules, intl) => { return null; }; -const field = (intl, attribute, disabled) => { - const labelProp = defaultAttrCodes.includes(attribute.code) ? ({ - labelId: `user.table.${attribute.code}`, - }) : ({ - labelText: attribute.name, - }); - - return ( - } - disabled={disabled} - /> - ); -}; - -const renderCompositeAttribute = (intl, compositeAttributes, disabled) => - compositeAttributes.map(attribute => field(intl, attribute, disabled)); - class MyProfileEditFormBody extends Component { constructor(props) { super(props); @@ -151,11 +113,23 @@ class MyProfileEditFormBody extends Component { render() { const { profileTypesAttributes, defaultLanguage, languages, intl, userEmail, onChangeProfilePicture, - handleSubmit, setFieldValue, isValid, resetForm, values, + handleSubmit, setFieldValue, isValid, resetForm, values, isSubmitting, } = this.props; const { editMode } = this.state; + const field = (attribute, disabled) => ( + + ); + + const renderCompositeAttribute = (compositeAttributes, disabled) => + compositeAttributes.map(attribute => field(attribute, disabled)); + const renderFieldArray = (attributeCode, attribute, component, language) => (
- {renderCompositeAttribute(intl, attribute.compositeAttributes, !editMode)} + {renderCompositeAttribute(attribute.compositeAttributes, !editMode)}
@@ -223,7 +197,7 @@ class MyProfileEditFormBody extends Component { ); } - return field(intl, attribute, !editMode); + return field(attribute, !editMode); }); const { profilepicture } = values; @@ -252,7 +226,7 @@ class MyProfileEditFormBody extends Component { className="pull-right" type="submit" bsStyle="primary" - disabled={!isValid} + disabled={!isValid || isSubmitting} data-testid="profile_saveBtn" onClick={() => { this.changeMode(); @@ -332,6 +306,7 @@ MyProfileEditFormBody.propTypes = { userEmail: PropTypes.string, onChangeProfilePicture: PropTypes.func.isRequired, isValid: PropTypes.bool.isRequired, + isSubmitting: PropTypes.bool.isRequired, }; MyProfileEditFormBody.defaultProps = {