From 982dfb4d9dc81912646640ff8d3307d2158037cc Mon Sep 17 00:00:00 2001 From: Prasanna Vijayan Date: Thu, 16 Nov 2023 13:24:59 +0530 Subject: [PATCH] refactor: optimized code to render dependent dropdown better --- .../components/fb-field-dropdown.scss | 8 +- .../form-builder/components/field-editor.scss | 20 +- .../form-builder/components/field-editor.tsx | 413 +++++++++++------- packages/crayons-i18n/i18n/en-US.json | 2 + 4 files changed, 277 insertions(+), 166 deletions(-) diff --git a/packages/crayons-extended/custom-objects/src/components/form-builder/components/fb-field-dropdown.scss b/packages/crayons-extended/custom-objects/src/components/form-builder/components/fb-field-dropdown.scss index 16d3fd14b..3c852f22b 100644 --- a/packages/crayons-extended/custom-objects/src/components/form-builder/components/fb-field-dropdown.scss +++ b/packages/crayons-extended/custom-objects/src/components/form-builder/components/fb-field-dropdown.scss @@ -59,6 +59,8 @@ $warning-color: $color-casablanca-300; } .fb-field-dependent { + width: calc(100% - 50px); + .fb-field-dropdown-label-dependent-field { font-size: 14px; line-height: 21px; @@ -71,14 +73,14 @@ $warning-color: $color-casablanca-300; } .spacing-bottom-1 { - margin-block-start: 20px; + margin-block-start: 0px; } .spacing-bottom-2 { - margin-block-start: 40px; + margin-block-start: 20px; } .spacing-bottom-3 { - margin-block-start: 60px; + margin-block-start: 40px; } } diff --git a/packages/crayons-extended/custom-objects/src/components/form-builder/components/field-editor.scss b/packages/crayons-extended/custom-objects/src/components/form-builder/components/field-editor.scss index ce91850d5..892080aac 100644 --- a/packages/crayons-extended/custom-objects/src/components/form-builder/components/field-editor.scss +++ b/packages/crayons-extended/custom-objects/src/components/form-builder/components/field-editor.scss @@ -26,10 +26,6 @@ div { width: 100%; } - - fw-fb-field-dropdown { - width: 270px; - } } } @@ -434,6 +430,22 @@ flex-direction: column; } } + + &-content-label-interalName { + display: flex; + flex-direction: column; + gap: 16px; + } + + &-content-label { + text-transform: uppercase; + color: $color-elephant-900; + font-size: 12px; + font-weight: 600; + line-height: 20px; + margin-block-end: 8px; + display: block; + } } .fw-field-editor-delete-modal-content { diff --git a/packages/crayons-extended/custom-objects/src/components/form-builder/components/field-editor.tsx b/packages/crayons-extended/custom-objects/src/components/form-builder/components/field-editor.tsx index bb52b034a..032445e4e 100644 --- a/packages/crayons-extended/custom-objects/src/components/form-builder/components/field-editor.tsx +++ b/packages/crayons-extended/custom-objects/src/components/form-builder/components/field-editor.tsx @@ -1086,19 +1086,20 @@ export class FieldEditor { private renderDropdown( boolDisableDropdowns, - fieldBuilderOptions, - choices, - parentId + fieldBuilderOptions = null, + choices = null, + parentId = null ) { const level = fieldBuilderOptions?.field_options?.level; const dictElName = this.isDependentField ? `choices_level_${level}` : 'choices'; + const dropdownChoices = choices || this.fieldBuilderOptions.choices; return ( (this.dictInteractiveElements[dictElName] = el)} - dataProvider={choices} + dataProvider={dropdownChoices} productName={this.productName} showErrors={this.showErrors[dictElName]} disabled={boolDisableDropdowns} @@ -1254,83 +1255,224 @@ export class FieldEditor { ); } + private renderLabel( + objMaxLimits, + isDefaultNonCustomField, + boolEditAllowed, + fieldBuilderOptions + ) { + const objFieldBuilder = fieldBuilderOptions; + const strBaseClassName = 'fw-field-editor'; + const strInputLabel = hasCustomProperty(objFieldBuilder, 'label') + ? objFieldBuilder.label + : ''; + const boolDIsableInputLabel = isDefaultNonCustomField || !boolEditAllowed; + + const strInputHint = this.isPrimaryField + ? i18nText('primaryFieldNameHint') + : ''; + // Dependent Level checks + const level = fieldBuilderOptions?.field_options?.level; + const dictElName = this.isDependentField ? `name_level_${level}` : 'name'; + + const boolShowLabelError = + this.showErrors[dictElName] && + this.labelErrorMessage && + this.labelErrorMessage !== '' + ? true + : false; + + const boolShowLabelWarning = + !boolShowLabelError && + this.labelWarningMessage && + this.labelWarningMessage !== '' + ? true + : false; + const strInputWarning = boolShowLabelWarning + ? this.labelWarningMessage + : ''; + const strInputError = boolShowLabelError ? this.labelErrorMessage : ''; + const numLabelMaxChars = objMaxLimits?.['maxLabelChars']?.count || 255; + + return ( + (this.dictInteractiveElements[dictElName] = el)} + class={`${strBaseClassName}-content-required-input`} + placeholder={i18nText('fieldLabelPlaceholder')} + label={i18nText('fieldLabel')} + required={true} + maxlength={numLabelMaxChars} + value={strInputLabel} + hintText={strInputHint} + errorText={strInputError} + warningText={strInputWarning} + state={ + boolShowLabelError + ? 'error' + : boolShowLabelWarning + ? 'warning' + : 'normal' + } + disabled={boolDIsableInputLabel} + onFwBlur={(el) => this.labelBlurHandler(el, level)} + onFwInput={(el) => this.labelInputHandler(el, level)} + > + ); + } + private renderFieldContent( objProductConfig, isDefaultNonCustomField, boolEditAllowed ) { + const strBaseClassName = 'fw-field-editor'; + const renderLabelAndName = []; const renderFields = []; - renderFields.push( - this.renderContent( + const objFieldBuilder = this.fieldBuilderOptions; + const boolDisableDropdowns = isDefaultNonCustomField || !boolEditAllowed; + + const arrCheckboxes = hasCustomProperty(objFieldBuilder, 'checkboxes') + ? objFieldBuilder.checkboxes + : null; + + const checkboxItems = + arrCheckboxes && arrCheckboxes.length > 0 + ? arrCheckboxes.map((dataItem) => this.renderCheckboxField(dataItem)) + : null; + + // Initial Render of Name and Label + renderLabelAndName.push( + this.renderLabelAndInternalName( objProductConfig, isDefaultNonCustomField, boolEditAllowed, + this.fieldBuilderOptions + ) + ); + + // Initial Level Render of Dropdown + renderFields.push( + this.renderDropdown( + boolDisableDropdowns, this.fieldBuilderOptions, this.fieldBuilderOptions.choices, null ) ); - if ( - this.isDependentField && - this.fieldBuilderOptions.fields && - this.fieldBuilderOptions.fields.length > 0 - ) { - const recurseFieldContent = ( + const recurseFieldContent = (builderOption, parentChoices, parentLevel) => { + const choices = getChildChoices( + parentChoices, builderOption, + parentLevel, + this.dependentLevels + ); + + const parentId = getParentId( parentChoices, - parentLevel - ) => { - const choices = getChildChoices( - parentChoices, + parentLevel, + this.dependentLevels + ); + + renderLabelAndName.push( + this.renderLabelAndInternalName( + objProductConfig, + isDefaultNonCustomField, + boolEditAllowed, + builderOption + ) + ); + + renderFields.push( + this.renderDropdown( + boolDisableDropdowns, builderOption, - parentLevel, - this.dependentLevels - ); + choices, + parentId + ) + ); - const parentId = getParentId( - parentChoices, - parentLevel, - this.dependentLevels + if (builderOption?.fields?.length > 0) { + recurseFieldContent( + builderOption.fields[0], + choices, + builderOption.field_options.level ); + } + }; - renderFields.push( - this.renderContent( - objProductConfig, - isDefaultNonCustomField, - boolEditAllowed, - builderOption, - choices, - parentId - ) - ); + recurseFieldContent( + this.fieldBuilderOptions.fields[0], + this.fieldBuilderOptions.choices, + this.fieldBuilderOptions.field_options.level + ); - if (builderOption?.fields?.length > 0) { - recurseFieldContent( - builderOption.fields[0], - choices, - builderOption.field_options.level - ); - } - }; + return ( +
+
+
+ + {checkboxItems} +
+
+ +
+ {renderLabelAndName.map((field) => field)} +
+
+
+ +
+ {renderFields.map((field) => field)} +
+
+
+
+ ); + } - recurseFieldContent( - this.fieldBuilderOptions.fields[0], - this.fieldBuilderOptions.choices, - this.fieldBuilderOptions.field_options.level - ); - } + private renderLabelAndInternalName( + objProductConfig, + isDefaultNonCustomField, + boolEditAllowed, + fieldBuilderOptions + ) { + const objMaxLimits = getMaximumLimitsConfig(this.productName); + const boolSupportInternalName = objProductConfig.editInternalName; + const strBaseClassName = 'fw-field-editor'; - return renderFields.map((field) => field); + return ( + + ); } private renderContent( objProductConfig, isDefaultNonCustomField, - boolEditAllowed, - fieldBuilderOptions, - choices, - parentId + boolEditAllowed ) { if (!this.expanded) { return null; @@ -1339,17 +1481,14 @@ export class FieldEditor { const objMaxLimits = getMaximumLimitsConfig(this.productName); const boolSupportInternalName = objProductConfig.editInternalName; const strBaseClassName = 'fw-field-editor'; - const objFieldBuilder = fieldBuilderOptions; + const objFieldBuilder = this.fieldBuilderOptions; /** Adding extra check for status type */ const isStatusType = checkIfCustomToggleField( this.productName, objFormValue.name ); - const strInputLabel = hasCustomProperty(objFieldBuilder, 'label') - ? objFieldBuilder.label - : ''; - const boolDIsableInputLabel = isDefaultNonCustomField || !boolEditAllowed; + const boolDisableDropdowns = isDefaultNonCustomField || !boolEditAllowed; const strFieldType = hasCustomProperty(objFieldBuilder, 'type') @@ -1375,9 +1514,19 @@ export class FieldEditor { } } - // Dependent Level checks - const level = fieldBuilderOptions?.field_options?.level; - const dictElName = this.isDependentField ? `name_level_${level}` : 'name'; + const arrCheckboxes = hasCustomProperty(objFieldBuilder, 'checkboxes') + ? objFieldBuilder.checkboxes + : null; + + const checkboxItems = + arrCheckboxes && arrCheckboxes.length > 0 + ? arrCheckboxes.map((dataItem) => this.renderCheckboxField(dataItem)) + : null; + + const isLookupType = strFieldType === 'RELATIONSHIP'; + const elementRelationship = isLookupType + ? this.renderLookup(boolDisableDropdowns) + : null; const elementStatusToggle = isStatusType ? this.renderStatusToggle(objFormValue) @@ -1385,74 +1534,46 @@ export class FieldEditor { const elementDropdown = isDropdownType && !boolIgnoreDropdownChoices - ? this.renderDropdown( - boolDisableDropdowns, - fieldBuilderOptions, - choices, - parentId - ) + ? this.renderDropdown(boolDisableDropdowns) : null; - const boolShowLabelError = - this.showErrors[dictElName] && - this.labelErrorMessage && - this.labelErrorMessage !== '' - ? true - : false; - const strInputHint = this.isPrimaryField - ? i18nText('primaryFieldNameHint') - : ''; - const strInputError = boolShowLabelError ? this.labelErrorMessage : ''; - const boolShowLabelWarning = - !boolShowLabelError && - this.labelWarningMessage && - this.labelWarningMessage !== '' - ? true - : false; - const strInputWarning = boolShowLabelWarning - ? this.labelWarningMessage - : ''; - const numLabelMaxChars = objMaxLimits?.['maxLabelChars']?.count || 255; - return ( -
- (this.dictInteractiveElements[dictElName] = el)} - class={`${strBaseClassName}-content-required-input`} - placeholder={i18nText('fieldLabelPlaceholder')} - label={i18nText('fieldLabel')} - required={true} - maxlength={numLabelMaxChars} - value={strInputLabel} - hintText={strInputHint} - errorText={strInputError} - warningText={strInputWarning} - state={ - boolShowLabelError - ? 'error' - : boolShowLabelWarning - ? 'warning' - : 'normal' - } - disabled={boolDIsableInputLabel} - onFwBlur={(el) => this.labelBlurHandler(el, level)} - onFwInput={(el) => this.labelInputHandler(el, level)} - > - {boolSupportInternalName && - this.renderInternalName( - objProductConfig, +
+
+
+ + {checkboxItems} +
+ {isLookupType && ( +
+ {elementRelationship} +
+ )} + {this.renderLabel( objMaxLimits, isDefaultNonCustomField, boolEditAllowed, - fieldBuilderOptions + this.fieldBuilderOptions )} - {/* NEED TO CLEAN THIS UP ASAP */} - {elementStatusToggle} - {isDropdownType && ( -
- {elementDropdown} -
- )} + {boolSupportInternalName && + this.renderInternalName( + objProductConfig, + objMaxLimits, + isDefaultNonCustomField, + boolEditAllowed, + this.fieldBuilderOptions + )} + {elementStatusToggle} + {isDropdownType && ( +
+ {elementDropdown} +
+ )} +
); } @@ -1612,24 +1733,21 @@ export class FieldEditor { strFooterClassName += ` ${strBaseClassName}-footer-with-error`; } - const boolDisableDropdowns = isDefaultNonCustomField || !boolEditAllowed; - const checkboxItems = - arrCheckboxes && arrCheckboxes.length > 0 - ? arrCheckboxes.map((dataItem) => this.renderCheckboxField(dataItem)) - : null; - - const isLookupType = strFieldType === 'RELATIONSHIP'; - const elementRelationship = isLookupType - ? this.renderLookup(boolDisableDropdowns) - : null; - const fieldIcon = this.isDependentField ? presetSchema.fieldTypes.DEPENDENT_FIELD.icon : objFieldBuilder.icon; - const dependentFieldClass = this.isDependentField - ? 'flex flex-space-between' - : ''; + const contentElements = this.isDependentField + ? this.renderFieldContent( + objProductConfig, + isDefaultNonCustomField, + boolEditAllowed + ) + : this.renderContent( + objProductConfig, + isDefaultNonCustomField, + boolEditAllowed + ); return ( @@ -1696,30 +1814,7 @@ export class FieldEditor {
{this.expanded && (
-
-
-
- - {checkboxItems} -
- {isLookupType && ( -
- {elementRelationship} -
- )} -
- {this.renderFieldContent( - objProductConfig, - isDefaultNonCustomField, - boolEditAllowed - )} -
-
-
+ {contentElements}
{boolShowFieldValidationError && (