Add errors and prepare for submit request

This commit is contained in:
cyril lopez 2018-02-21 18:45:18 +01:00
parent 10599cfab8
commit fbcce82f8e
7 changed files with 110 additions and 10 deletions

View File

@ -37,6 +37,12 @@ class InputSelectWithErrors extends React.Component {
}
}
handleBlur = ({ target }) => {
if (!isEmpty(target.value)) {
this.setState({ errors: [] });
}
}
render() {
const {
autoFocus,
@ -86,7 +92,7 @@ class InputSelectWithErrors extends React.Component {
disabled={disabled}
error={!isEmpty(this.state.errors)}
name={name}
onBlur={isFunction(onBlur) ? onBlur : () => {}}
onBlur={isFunction(onBlur) ? onBlur : this.handleBlur}
onChange={onChange}
onFocus={onFocus}
selectOptions={selectOptions}
@ -127,7 +133,7 @@ InputSelectWithErrors.defaultProps = {
label: '',
labelClassName: '',
labelStyle: {},
onBlur: () => {},
onBlur: false,
onFocus: () => {},
selectOptions: [],
style: {},

View File

@ -21,7 +21,7 @@ function PluginHeaderTitle({ description, title }) {
{contentTitle}
</h1>
<p className={styles.pluginHeaderTitleDescription}>
{contentDescription}
{contentDescription}&nbsp;
</p>
</div>
);

View File

@ -7,7 +7,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
// findIndex,
findIndex,
get,
isEmpty,
isFunction,
@ -69,6 +69,11 @@ class Edit extends React.PureComponent {
this.setState({ currentLayout, displayedFields });
}
getInputErrors = (attr) => {
const index = findIndex(this.props.formErrors, ['name', attr]);
return index !== -1 ? this.props.formErrors[index].errors : [];
}
/**
* Retrieve the Input layout
* @param {String} attr [description]
@ -83,6 +88,18 @@ class Edit extends React.PureComponent {
}, {})
)
/**
* Retrieve the input's validations
* @param {String} attr
* @return {Object}
*/
getInputValidations = (attr) => {
const { formValidations } = this.props;
const index = findIndex(formValidations, ['name', attr]);
return get(formValidations, [index, 'validations'], {});
}
render(){
return (
<div className={styles.form}>
@ -97,6 +114,7 @@ class Edit extends React.PureComponent {
autoFocus={key === 0}
customBootstrapClass={get(layout, 'className')}
didCheckErrors={this.props.didCheckErrors}
errors={this.getInputErrors(attr)}
key={attr}
label={get(layout, 'label') || details.label || ''}
name={attr}
@ -104,6 +122,7 @@ class Edit extends React.PureComponent {
selectOptions={get(this.props.attributes, [attr, 'enum'])}
placeholder={get(layout, 'placeholder') || details.placeholder}
type={get(layout, 'type', getInputType(details.type))}
validations={this.getInputValidations(attr)}
value={this.props.record[attr]}
/>
);
@ -116,6 +135,8 @@ class Edit extends React.PureComponent {
Edit.defaultProps = {
attributes: {},
formErrors: [],
formValidations: [],
layout: {},
onChange: () => {},
record: {},
@ -124,6 +145,8 @@ Edit.defaultProps = {
Edit.propTypes = {
attributes: PropTypes.object,
didCheckErrors: PropTypes.bool.isRequired,
formErrors: PropTypes.array,
formValidations: PropTypes.array,
layout: PropTypes.object,
onChange: PropTypes.func,
record: PropTypes.object,

View File

@ -4,12 +4,17 @@
*
*/
import { get } from 'lodash';
import { getValidationsFromForm } from 'utils/formValidations';
import {
CHANGE_DATA,
GET_DATA,
GET_DATA_SUCCEEDED,
INIT_MODEL_PROPS,
ON_CANCEL,
RESET_PROPS,
SET_FORM_ERRORS,
} from './constants';
export function changeData({ target }) {
@ -38,17 +43,36 @@ export function getDataSucceeded(id, data, pluginHeaderTitle) {
};
}
export function initModelProps(modelName, isCreating, source) {
export function initModelProps(modelName, isCreating, source, attributes) {
const formValidations = getValidationsFromForm(
Object.keys(attributes).map(attr => ({ name: attr, validations: get(attributes, attr, {}) })),
[],
);
return {
type: INIT_MODEL_PROPS,
modelName,
formValidations,
isCreating,
modelName,
source,
};
}
export function onCancel() {
return {
type: ON_CANCEL,
};
}
export function resetProps() {
return {
type: RESET_PROPS,
};
}
export function setFormErrors(formErrors) {
return {
type: SET_FORM_ERRORS,
formErrors,
};
}

View File

@ -8,4 +8,6 @@ export const CHANGE_DATA = 'ContentManager/EditPage/CHANGE_DATA';
export const GET_DATA = 'ContentManager/EditPage/GET_DATA';
export const GET_DATA_SUCCEEDED = 'ContentManager/EditPage/GET_DATA_SUCCEEDED';
export const INIT_MODEL_PROPS = 'ContentManager/EditPage/INIT_MODEL_PROPS';
export const ON_CANCEL = 'ContentManager/EditPage/ON_CANCEL';
export const RESET_PROPS = 'ContentManager/EditPage/RESET_PROPS';
export const SET_FORM_ERRORS = 'ContentManager/EditPage/SET_FORM_ERRORS';

View File

@ -10,7 +10,7 @@ import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { createStructuredSelector } from 'reselect';
import PropTypes from 'prop-types';
import { get, isObject, toNumber, toString, size } from 'lodash';
import { get, isEmpty, isObject, toNumber, toString, size } from 'lodash';
import cn from 'classnames';
// You can find these components in either
@ -30,6 +30,7 @@ import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import getQueryParameters from 'utils/getQueryParameters';
import { bindLayout } from 'utils/bindLayout';
import { checkFormValidity } from 'utils/formValidations';
// Layout
import layout from '../../../../config/layout';
@ -38,7 +39,9 @@ import {
changeData,
getData,
initModelProps,
onCancel,
resetProps,
setFormErrors,
} from './actions';
import reducer from './reducer';
@ -115,6 +118,17 @@ export class EditPage extends React.Component {
this.props.changeData({ target });
}
handleSubmit = (e) => {
e.preventDefault();
const formErrors = checkFormValidity(this.generateFormFromRecord(), this.props.editPage.formValidations);
if (isEmpty(formErrors)) {
// this.props.submit()
}
this.props.setFormErrors(formErrors);
}
layout = bindLayout.call(this, layout);
componentDidCatch(error, info) {
@ -126,11 +140,20 @@ export class EditPage extends React.Component {
isRelationComponentNull = () => size(get(this.getSchema(), 'relations')) === 0;
// NOTE: technical debt that needs to be redone
generateFormFromRecord = () => (
Object.keys(this.getModelAttributes()).reduce((acc, current) => {
acc[current] = get(this.props.editPage.record, current, '');
return acc;
}, {})
)
pluginHeaderActions = [
{
label: 'content-manager.containers.Edit.reset',
kind: 'secondary',
onClick: () => {},
onClick: this.props.onCancel,
type: 'button',
},
{
@ -146,7 +169,7 @@ export class EditPage extends React.Component {
return (
<div>
<form onSubmit={(e) => { e.preventDefault(); }}>
<form onSubmit={this.handleSubmit}>
<BackHeader onClick={() => this.props.history.goBack()} />
<div className={cn('container-fluid', styles.containerFluid)}>
<PluginHeader
@ -159,6 +182,8 @@ export class EditPage extends React.Component {
<Edit
attributes={this.getModelAttributes()}
didCheckErrors={editPage.didCheckErrors}
formValidations={editPage.formValidations}
formErrors={editPage.formErrors}
layout={this.layout}
modelName={this.getModelName()}
onChange={this.handleChange}
@ -197,8 +222,10 @@ EditPage.propTypes = {
location: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
models: PropTypes.object,
onCancel: PropTypes.func.isRequired,
resetProps: PropTypes.func.isRequired,
schema: PropTypes.object.isRequired,
setFormErrors: PropTypes.func.isRequired,
};
function mapDispatchToProps(dispatch) {
@ -207,7 +234,9 @@ function mapDispatchToProps(dispatch) {
changeData,
getData,
initModelProps,
onCancel,
resetProps,
setFormErrors,
},
dispatch,
);

View File

@ -4,18 +4,23 @@
*
*/
import { fromJS, Map } from 'immutable';
import { fromJS, Map, List } from 'immutable';
import {
CHANGE_DATA,
GET_DATA_SUCCEEDED,
INIT_MODEL_PROPS,
ON_CANCEL,
RESET_PROPS,
SET_FORM_ERRORS,
} from './constants';
const initialState = fromJS({
didCheckErrors: true,
formErrors: List([]),
formValidations: List([]),
isCreating: false,
id: '',
initialRecord: Map({}),
modelName: '',
pluginHeaderTitle: 'New Entry',
record: Map({}),
@ -29,15 +34,26 @@ function editPageReducer(state = initialState, action) {
case GET_DATA_SUCCEEDED:
return state
.update('id', () => action.id)
.update('initialRecord', () => Map(action.data))
.update('pluginHeaderTitle', () => action.pluginHeaderTitle)
.update('record', () => Map(action.data));
case INIT_MODEL_PROPS:
return state
.update('formValidations', () => List(action.formValidations))
.update('isCreating', () => action.isCreating)
.update('modelName', () => action.modelName)
.update('source', () => action.source);
case ON_CANCEL:
return state
.update('didCheckErrors', (v) => v = !v)
.update('formErrors', () => List([]))
.update('record', () => state.get('initialRecord'));
case RESET_PROPS:
return initialState;
case SET_FORM_ERRORS:
return state
.update('didCheckErrors', (v) => v = !v)
.update('formErrors', () => List(action.formErrors));
default:
return state;
}