handle nested forms

This commit is contained in:
cyril lopez 2017-08-01 11:26:38 +02:00
parent 0a4d5fd021
commit 2e83559b58
10 changed files with 124 additions and 55 deletions

View File

@ -23,7 +23,11 @@ class EditForm extends React.Component { // eslint-disable-line react/prefer-sta
} }
return ( return (
<div key={key}> <div key={key}>
<EditFormSection section={section} values={this.props.values} handleChange={this.props.handleChange} /> <EditFormSection
section={section}
values={this.props.values}
handleChange={this.props.handleChange}
/>
{line} {line}
</div> </div>
) )

View File

@ -9,12 +9,15 @@ import { map, isEmpty } from 'lodash';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
// HOC Form // HOC Form
import WithFormSection from 'components/WithFormSection'; import WithFormSection from 'components/WithFormSection';
// nested form
import EditFormSectionNested from 'components/EditFormSectionNested';
class EditFormSection extends React.Component { // eslint-disable-line react/prefer-stateless-function class EditFormSection extends React.Component { // eslint-disable-line react/prefer-stateless-function
render() { render() {
const sectionName = isEmpty(this.props.section.name) ? '' : <FormattedMessage {...{id: this.props.section.name}} />; const sectionName = isEmpty(this.props.section.name) ? '' : <FormattedMessage {...{id: this.props.section.name}} />;
// get the styles from the WithFormSection HOC // get the styles from the WithFormSection HOC
const styles = this.props.styles; const styles = this.props.styles;
return ( return (
<div className={styles.editFormSection}> <div className={styles.editFormSection}>
<div className="container-fluid"> <div className="container-fluid">
@ -25,10 +28,22 @@ class EditFormSection extends React.Component { // eslint-disable-line react/pre
</span> </span>
</div> </div>
<form> <form>
{map(this.props.section.items, (item, key) => ( {map(this.props.section.items, (item, key) => {
this.props.renderInput( item, key)
// this.props.renderInput(this.props.section.items, item, key) if (this.props.showNestedForm) {
))} return (
<div key={key}>
{this.props.renderInput(item, key)}
<EditFormSectionNested
section={item.items}
values={this.props.values}
handleChange={this.props.handleChange}
/>
</div>
)
}
return this.props.renderInput(item, key);
})}
</form> </form>
</div> </div>
</div> </div>
@ -38,9 +53,12 @@ class EditFormSection extends React.Component { // eslint-disable-line react/pre
} }
EditFormSection.propTypes = { EditFormSection.propTypes = {
handleChange: React.PropTypes.func,
renderInput: React.PropTypes.func, renderInput: React.PropTypes.func,
section: React.PropTypes.object, section: React.PropTypes.object,
showNestedForm: React.PropTypes.bool,
styles: React.PropTypes.object, styles: React.PropTypes.object,
values: React.PropTypes.object,
}; };
export default WithFormSection(EditFormSection); // eslint-disable-line new-cap export default WithFormSection(EditFormSection); // eslint-disable-line new-cap

View File

@ -0,0 +1,33 @@
/**
*
* EditFormSectionNested
*
*/
import React from 'react';
import { map } from 'lodash';
// HOC
import WithFormSection from 'components/WithFormSection';
class EditFormSectionNested extends React.Component { // eslint-disable-line react/prefer-stateless-function
render() {
return (
<div>
{map(this.props.section, (item, key) => (
this.props.renderInput(item, key)
))}
</div>
);
}
}
EditFormSectionNested.propTypes = {
renderInput: React.PropTypes.func,
section: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.object,
]),
};
export default WithFormSection(EditFormSectionNested); // eslint-disable-line new-cap

View File

@ -0,0 +1,11 @@
// import EditFormSectionNested from '../index';
import expect from 'expect';
// import { shallow } from 'enzyme';
// import React from 'react';
describe('<EditFormSectionNested />', () => {
it('Expect to have unit tests specified', () => {
expect(true).toEqual(false);
});
});

View File

@ -161,7 +161,7 @@ InputText.propTypes = {
styles: React.PropTypes.object, styles: React.PropTypes.object,
target: React.PropTypes.string.isRequired, target: React.PropTypes.string.isRequired,
validations: React.PropTypes.object.isRequired, validations: React.PropTypes.object.isRequired,
value: React.PropTypes.string.isRequired, value: React.PropTypes.string,
} }
export default WithInput(InputText); // eslint-disable-line new-cap export default WithInput(InputText); // eslint-disable-line new-cap

View File

@ -74,7 +74,7 @@ class InputToggle extends React.Component { // eslint-disable-line react/prefer-
InputToggle.propTypes = { InputToggle.propTypes = {
customBootstrapClass: React.PropTypes.string, customBootstrapClass: React.PropTypes.string,
handleChange: React.PropTypes.func.isRequired, handleChange: React.PropTypes.func.isRequired,
isChecked: React.PropTypes.bool.isRequired, isChecked: React.PropTypes.bool,
name: React.PropTypes.string, name: React.PropTypes.string,
target: React.PropTypes.string.isRequired, target: React.PropTypes.string.isRequired,
} }

View File

@ -5,7 +5,7 @@
*/ */
import React from 'react'; import React from 'react';
import { forEach, has } from 'lodash'; import { forEach, has, isObject } from 'lodash';
import InputNumber from 'components/InputNumber'; import InputNumber from 'components/InputNumber';
import InputText from 'components/InputText'; import InputText from 'components/InputText';
@ -18,9 +18,11 @@ import styles from './styles.scss';
const WithFormSection = (InnerComponent) => class extends React.Component { const WithFormSection = (InnerComponent) => class extends React.Component {
static propTypes = { static propTypes = {
checkForNestedForm: React.PropTypes.bool,
handleChange: React.PropTypes.func.isRequired, handleChange: React.PropTypes.func.isRequired,
section: React.PropTypes.object, section: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array,
]),
values: React.PropTypes.object, values: React.PropTypes.object,
} }
@ -33,40 +35,43 @@ const WithFormSection = (InnerComponent) => class extends React.Component {
}; };
} }
handleChange = ({ target }) => { componentDidMount() {
// check if there is inside a section an input that requires nested input to display it on the entire line
if (isObject(this.props.section)) {
this.checkForNestedForm(this.props);
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.section !== this.props.section) {
this.setState({ showNestedForm: false, hasNestedInput: false, inputWithNestedForm: '' });
if (isObject(nextProps.section)) {
this.checkForNestedForm(nextProps);
}
}
}
checkForNestedForm(props) {
forEach(props.section.items, (input) => {
if(has(input, 'items')) {
this.setState({ hasNestedInput: true, inputWithNestedForm: input.target })
if (props.values[input.target]) {
this.setState({ showNestedForm: true });
}
}
});
}
handleChange = ({ target }) => {
// display nestedForm if the selected input has a nested form // display nestedForm if the selected input has a nested form
if (target.id === this.state.inputWithNestedForm) { if (target.name === this.state.inputWithNestedForm) {
this.setState({ showNestedForm: true }); this.setState({ showNestedForm: target.value });
} else {
this.setState({ showNestedForm: false });
} }
this.props.handleChange({ target }); this.props.handleChange({ target });
} }
componentDidMount() {
// check if there is inside a section an input that requires nested input to display it on the entire line
if (this.props.checkForNestedForm) {
forEach(this.props.section.items, (items) => {
forEach(items, (item) => {
forEach(item, (input) => {
if (has(input, 'items')) {
// store the name of the input that has a nested form
this.setState({ hasNestedInput: true, inputWithNestedForm: input.name });
// showNestedForm if the selected input has a nested form
if (items.value === input.value) {
this.setState({ showNestedForm: true });
}
}
});
});
});
}
}
renderInput = (props, key) => { renderInput = (props, key) => {
const inputs = { const inputs = {
string: InputText, string: InputText,
@ -80,14 +85,14 @@ const WithFormSection = (InnerComponent) => class extends React.Component {
// retrieve options for the select input // retrieve options for the select input
const selectOptions = props.type === 'enum' || props.type === 'select' ? props.items : []; const selectOptions = props.type === 'enum' || props.type === 'select' ? props.items : [];
// check if the input has a nested form so it is display on the entire line // check if the input has a nested form so it is displayed on the entire line
const customBootstrapClass = this.state.hasNestedInput ? const customBootstrapClass = this.state.hasNestedInput ?
// bootstrap class to make the input display on the entire line // bootstrap class to make the input displayed on the entire line
'col-md-6 offset-md-6 pull-md-6' : 'col-md-6 offset-md-6 pull-md-6' :
// if the input hasn't a nested form but the config requires him to be displayed differently // if the input hasn't a nested form but the config requires him to be displayed differently
config[props.target] || ''; config[props.target] || '';
// custom handle change props for nested input form // custom handleChange props for nested input form
const handleChange = this.state.hasNestedInput ? this.handleChange : this.props.handleChange; const handleChange = this.state.hasNestedInput ? this.handleChange : this.props.handleChange;
return ( return (
<Input <Input
@ -108,6 +113,7 @@ const WithFormSection = (InnerComponent) => class extends React.Component {
return ( return (
<InnerComponent <InnerComponent
{...this.props} {...this.props}
showNestedForm={this.state.showNestedForm}
renderInput={this.renderInput} renderInput={this.renderInput}
styles={styles} styles={styles}
/> />
@ -116,5 +122,3 @@ const WithFormSection = (InnerComponent) => class extends React.Component {
} }
export default WithFormSection; export default WithFormSection;
// Object {name: "form.security.item.xframe.allow-from", value: "ALLOW-FROM", items: Array(1)}

View File

@ -295,9 +295,6 @@ export class Home extends React.Component { // eslint-disable-line react/prefer-
// custom rendering for PopUpForm // custom rendering for PopUpForm
const renderPopUpForm = this.props.params.slug === 'languages' ? this.renderPopUpFormLanguage : false; const renderPopUpForm = this.props.params.slug === 'languages' ? this.renderPopUpFormLanguage : false;
// TODO remove temporary condition to handle nestedForm rendering
const checkForNestedForm = this.props.params.slug !== 'languages'
let renderRow = false; let renderRow = false;
if (this.props.params.slug === 'languages') { if (this.props.params.slug === 'languages') {
@ -324,7 +321,6 @@ export class Home extends React.Component { // eslint-disable-line react/prefer-
handleListPopUpSubmit={this.addLanguage} handleListPopUpSubmit={this.addLanguage}
selectOptions={selectOptions} selectOptions={selectOptions}
renderPopUpForm={renderPopUpForm} renderPopUpForm={renderPopUpForm}
checkForNestedForm={checkForNestedForm}
/> />
); );
} }

View File

@ -42,6 +42,7 @@ export function* deleteLanguage(action) {
yield put(languageActiontSucceded()); yield put(languageActiontSucceded());
} catch(error) { } catch(error) {
console.log(error);
window.Strapi.notification.error('An Error occured'); window.Strapi.notification.error('An Error occured');
} }
} }
@ -58,6 +59,7 @@ export function* fetchConfig(action) {
yield put(configFetchSucceded(data)); yield put(configFetchSucceded(data));
} catch(error) { } catch(error) {
console.log(error);
window.Strapi.notification.error('An error occurred '); window.Strapi.notification.error('An error occurred ');
} }
} }
@ -109,6 +111,7 @@ export function* postLanguage() {
yield put(languageActiontSucceded()); yield put(languageActiontSucceded());
} catch(error) { } catch(error) {
console.log(error);
// TODO handle error i18n // TODO handle error i18n
window.Strapi.notification.error(error); window.Strapi.notification.error(error);
} }

View File

@ -128,7 +128,7 @@ module.exports = {
description: 'form.security.description', description: 'form.security.description',
sections: [ sections: [
{ {
name: 'form.security.item.csrf', name: 'form.security.item.session',
items: [ items: [
{ {
name: 'form.security.item.session.enabled', name: 'form.security.item.session.enabled',
@ -235,13 +235,13 @@ module.exports = {
items: [ items: [
{ {
name: 'form.security.item.hsts.enabled', name: 'form.security.item.hsts.enabled',
target: 'security.p3p.enabled', target: 'security.hsts.enabled',
type: 'boolean', type: 'boolean',
value: _.get(strapi.config, `environments.${env}.security.hsts.enabled`, null), value: _.get(strapi.config, `environments.${env}.security.hsts.enabled`, null),
items: [ items: [
{ {
name: 'form.security.item.p3p.maxAge', name: 'form.security.item.hsts.maxAge',
target: 'security.p3p.maxAge', target: 'security.hsts.maxAge',
type: 'number', type: 'number',
value: _.get(strapi.config, `environments.${env}.security.hsts.maxAge`, null), value: _.get(strapi.config, `environments.${env}.security.hsts.maxAge`, null),
validations: { validations: {
@ -249,15 +249,15 @@ module.exports = {
} }
}, },
{ {
name: 'form.security.item.p3p.includeSubDomains', name: 'form.security.item.hsts.includeSubDomains',
target: 'security.p3p.includeSubDomains', target: 'security.hsts.includeSubDomains',
type: 'boolean', type: 'boolean',
value: _.get(strapi.config, `environments.${env}.security.hsts.includeSubDomains`, null), value: _.get(strapi.config, `environments.${env}.security.hsts.includeSubDomains`, null),
validations: {} validations: {}
}, },
{ {
name: 'form.security.item.p3p.preload', name: 'form.security.item.hsts.preload',
target: 'security.p3p.preload', target: 'security.hsts.preload',
type: 'boolean', type: 'boolean',
value: _.get(strapi.config, `environments.${env}.security.hsts.preload`, null), value: _.get(strapi.config, `environments.${env}.security.hsts.preload`, null),
validations: {} validations: {}