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 (
<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}
</div>
)

View File

@ -9,12 +9,15 @@ import { map, isEmpty } from 'lodash';
import { FormattedMessage } from 'react-intl';
// HOC Form
import WithFormSection from 'components/WithFormSection';
// nested form
import EditFormSectionNested from 'components/EditFormSectionNested';
class EditFormSection extends React.Component { // eslint-disable-line react/prefer-stateless-function
render() {
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;
return (
<div className={styles.editFormSection}>
<div className="container-fluid">
@ -25,10 +28,22 @@ class EditFormSection extends React.Component { // eslint-disable-line react/pre
</span>
</div>
<form>
{map(this.props.section.items, (item, key) => (
this.props.renderInput( item, key)
// this.props.renderInput(this.props.section.items, item, key)
))}
{map(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>
</div>
</div>
@ -38,9 +53,12 @@ class EditFormSection extends React.Component { // eslint-disable-line react/pre
}
EditFormSection.propTypes = {
handleChange: React.PropTypes.func,
renderInput: React.PropTypes.func,
section: React.PropTypes.object,
showNestedForm: React.PropTypes.bool,
styles: React.PropTypes.object,
values: React.PropTypes.object,
};
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,
target: React.PropTypes.string.isRequired,
validations: React.PropTypes.object.isRequired,
value: React.PropTypes.string.isRequired,
value: React.PropTypes.string,
}
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 = {
customBootstrapClass: React.PropTypes.string,
handleChange: React.PropTypes.func.isRequired,
isChecked: React.PropTypes.bool.isRequired,
isChecked: React.PropTypes.bool,
name: React.PropTypes.string,
target: React.PropTypes.string.isRequired,
}

View File

@ -5,7 +5,7 @@
*/
import React from 'react';
import { forEach, has } from 'lodash';
import { forEach, has, isObject } from 'lodash';
import InputNumber from 'components/InputNumber';
import InputText from 'components/InputText';
@ -18,9 +18,11 @@ import styles from './styles.scss';
const WithFormSection = (InnerComponent) => class extends React.Component {
static propTypes = {
checkForNestedForm: React.PropTypes.bool,
handleChange: React.PropTypes.func.isRequired,
section: React.PropTypes.object,
section: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array,
]),
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
if (target.id === this.state.inputWithNestedForm) {
this.setState({ showNestedForm: true });
} else {
this.setState({ showNestedForm: false });
if (target.name === this.state.inputWithNestedForm) {
this.setState({ showNestedForm: target.value });
}
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) => {
const inputs = {
string: InputText,
@ -80,14 +85,14 @@ const WithFormSection = (InnerComponent) => class extends React.Component {
// retrieve options for the select input
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 ?
// 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' :
// if the input hasn't a nested form but the config requires him to be displayed differently
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;
return (
<Input
@ -108,6 +113,7 @@ const WithFormSection = (InnerComponent) => class extends React.Component {
return (
<InnerComponent
{...this.props}
showNestedForm={this.state.showNestedForm}
renderInput={this.renderInput}
styles={styles}
/>
@ -116,5 +122,3 @@ const WithFormSection = (InnerComponent) => class extends React.Component {
}
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
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;
if (this.props.params.slug === 'languages') {
@ -324,7 +321,6 @@ export class Home extends React.Component { // eslint-disable-line react/prefer-
handleListPopUpSubmit={this.addLanguage}
selectOptions={selectOptions}
renderPopUpForm={renderPopUpForm}
checkForNestedForm={checkForNestedForm}
/>
);
}

View File

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

View File

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