Skip to content

Commit

Permalink
composeFields: improve user experience
Browse files Browse the repository at this point in the history
* chore: code cleanup
  • Loading branch information
kpsherva committed Jan 30, 2024
1 parent e27a4d1 commit bec4c29
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 75 deletions.
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 48 additions & 30 deletions src/lib/forms/widgets/custom_fields/ComposeFields.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import _isEmpty from "lodash/isEmpty";
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Divider } from "semantic-ui-react";
Expand All @@ -8,9 +9,11 @@ import { Extensions } from "./Extensions";
export class ComposeFields extends Component {
constructor(props) {
super(props);
const { composeSections } = this.props;

this.state = { sections: composeSections, tempFields: [] };
const { composeSections, record } = props;
const filled = Object.keys(record.custom_fields).map(
(key) => `custom_fields.${key}`
);
this.state = { sections: composeSections, tempFields: [], recordFields: filled };
this.fieldsCfg = this.getFieldsConfig(composeSections);
this.sectionsList = composeSections.map((section) => section.section);
}
Expand All @@ -29,15 +32,13 @@ export class ComposeFields extends Component {

getFieldsWithValues = (sectionFields) => {
const { record } = this.props;
const { tempFields } = this.state;
const { tempFields, recordFields } = this.state;
const filledFields = [];
if (!record.custom_fields) {
return [];
}
for (const field of sectionFields) {
if (
Object.keys(record.custom_fields).includes(
field.key.replace("custom_fields.", "")
) ||
tempFields.includes(field)
) {
if (recordFields.includes(field.key) || tempFields.includes(field)) {
filledFields.push(field);
}
}
Expand All @@ -53,44 +54,61 @@ export class ComposeFields extends Component {
}
};

addFieldCallback = (field) => {
addFieldCallback = (fields) => {
const { sections: prevSections, tempFields: prevTempFields } = this.state;

const sections = [...prevSections];
const sectionToUpdate = this.getSectionOfField(field);
for (const section of sections) {
if (section.section === sectionToUpdate) {
section["fields"] = [...section.fields, field].sort((a, b) =>
a.key.localeCompare(b.key)
);
for (const field of fields) {
const sectionToUpdate = this.getSectionOfField(field);
for (const section of sections) {
if (section.section === sectionToUpdate) {
section["fields"] = [...section.fields, field].sort((a, b) =>
a.key.localeCompare(b.key)
);
}
}
}
this.setState({ sections: [...sections], tempFields: [...prevTempFields, field] });
this.setState({
sections: [...sections],
tempFields: [...prevTempFields, ...fields],
});
};

render() {
const { templateLoaders, record } = this.props;
const { sections } = this.state;
const { sections, tempFields, recordFields } = this.state;
const existingFields = [
...Object.entries(tempFields).map(([key, value]) => value.key),
...recordFields,
];

return (
<AccordionField key="compose fields" label="Domain specific fields" active>
{sections.map(({ fields, paths, ...sectionConfig }) => (
<div key={sectionConfig.section} className="rel-mb-2">
<FieldLabel
htmlFor={sectionConfig.section}
icon={sectionConfig.icon}
label={sectionConfig.section}
/>
<Divider fitted className="rel-mb-1" />
<div className="rel-ml-1">{this.getFieldsWithValues(fields)}</div>
</div>
))}
{sections.map(({ fields, paths, ...sectionConfig }) => {
const recordCustomFields = this.getFieldsWithValues(fields);
if (_isEmpty(recordCustomFields)) {
return undefined;
}
return (
<div key={sectionConfig.section} className="rel-mb-2">
<FieldLabel
htmlFor={sectionConfig.section}
icon={sectionConfig.icon}
label={sectionConfig.section}
/>
<Divider fitted className="rel-mb-1" />
<div className="rel-ml-1">{recordCustomFields}</div>
</div>
);
})}
<Extensions
fieldPath="custom_fields"
{...this.fieldsCfg}
templateLoaders={templateLoaders}
addFieldCallback={this.addFieldCallback}
sections={this.sectionsList}
record={record}
existingFields={existingFields}
/>
</AccordionField>
);
Expand Down
77 changes: 61 additions & 16 deletions src/lib/forms/widgets/custom_fields/Extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ import PropTypes from "prop-types";
export class Extensions extends Component {
constructor(props) {
super(props);
const { existingFields } = props;
this.state = {
modalOpen: false,
selectedField: undefined,
selectedFieldTarget: undefined,
fields: [],
addFields: [],
existingFields: [...existingFields],
loading: false,
};
}

handleModalOpen = () => {
this.setState({ modalOpen: true });
};
Expand All @@ -36,6 +40,7 @@ export class Extensions extends Component {
if (previousSelected) {
previousSelected.classList.toggle("selected-background");
}
e.currentTarget.classList.toggle("selected-background");
const newField = {
field: fieldName,
props: { ...field },
Expand All @@ -45,23 +50,50 @@ export class Extensions extends Component {
selectedField: { ...newField },
selectedFieldTarget: e.currentTarget,
});
e.currentTarget.classList.toggle("selected-background");
};

handleAddField = async (withClose = false) => {
const { selectedField } = this.state;
const {
selectedField,
addFields: prevFields,
selectedFieldTarget,
existingFields: prevExisting,
} = this.state;
const { fieldPath, templateLoaders, addFieldCallback } = this.props;
this.setState({ loading: true });
const field = await importWidget(templateLoaders, {
...selectedField,
fieldPath: `${fieldPath}.${selectedField.field}`,
});
const { fields: prevFields } = this.state;
this.setState({ fields: [...prevFields, field] });
if (withClose) {
this.handleModalClosed();
}
this.setState({ selectedField: undefined, selectedFieldTarget: undefined });
addFieldCallback(field);

const performCallback = (selectedFieldTarget) => {
const { addFields } = this.state;

if (withClose) {
addFieldCallback(addFields);
this.setState({ addFields: [], existingFields: [] });
this.handleModalClosed();
}
};
selectedFieldTarget.classList.toggle("selected-background");
this.setState(
{
addFields: [...prevFields, field],
existingFields: [...prevExisting, field.key],
selectedField: undefined,
selectedFieldTarget: undefined,
loading: false,
},
() => performCallback(selectedFieldTarget)
);
};

handleCancel = () => {
const { addFields } = this.state;
const { addFieldCallback } = this.props;
addFieldCallback(addFields);
this.setState({ addFields: [] });
this.handleModalClosed();
};

render() {
Expand All @@ -73,10 +105,10 @@ export class Extensions extends Component {
templateLoaders,
addFieldCallback,
sections,
existingFields: selected,
...fieldsList
} = this.props;
const { modalOpen, fields } = this.state;

const { modalOpen, existingFields, loading } = this.state;
return (
<>
<Divider />
Expand All @@ -89,23 +121,35 @@ export class Extensions extends Component {
<ListAndFilterCustomFields
fieldPath={fieldPath}
handleSelectField={this.handleSelectField}
alreadyAddedFields={fields}
alreadyAddedFields={existingFields}
fieldsList={fieldsList}
sections={sections}
/>
<Modal.Actions>
<Button
onClick={this.handleModalClosed}
onClick={this.handleCancel}
floated="left"
icon="cancel"
labelPosition="left"
content="Cancel"
/>
<Button icon labelPosition="left" onClick={this.handleAddField}>
<Button
icon
labelPosition="left"
onClick={() => this.handleAddField(false)}
disabled={loading}
loading={loading}
>
<Icon name="plus" />
Add field and continue
</Button>
<Button icon labelPosition="left" onClick={() => this.handleAddField(true)}>
<Button
icon
labelPosition="left"
onClick={() => this.handleAddField(true)}
disabled={loading}
loading={loading}
>
<Icon name="plus" />
Add field and close
</Button>
Expand All @@ -124,6 +168,7 @@ Extensions.propTypes = {
templateLoaders: PropTypes.array.isRequired,
addFieldCallback: PropTypes.func.isRequired,
sections: PropTypes.array,
existingFields: PropTypes.array.isRequired,
};

Extensions.defaultProps = {
Expand Down
Loading

0 comments on commit bec4c29

Please sign in to comment.