Handle form in HomePageContainer

This commit is contained in:
cyril lopez 2017-11-08 16:06:21 +01:00
parent 4352cece3d
commit 854360d811
16 changed files with 242 additions and 122 deletions

View File

@ -34,7 +34,7 @@ class {{ properCase name }} extends React.Component { // eslint-disable-line rea
}
// Uncomment to use PropTypes
// {{ properCase name }}.proptypes = {
// {{ properCase name }}.propTypes = {
// foo: PropTypes.string,
// };

View File

@ -29,7 +29,7 @@ function {{ properCase name}}() {
);
}
{{ properCase name }}.proptypes = {
{{ properCase name }}.propTypes = {
};

View File

@ -5,20 +5,14 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { get } from 'lodash';
// Uncomment to use PropTypes
import Input from 'components/Input';
// import PropTypes from 'prop-types';
import styles from './styles.scss';
class EditForm extends React.Component { // eslint-disable-line react/prefer-stateless-function
state = { value: false }
handleChange = ({target}) => {
this.setState({ value: target.value });
}
render() {
return (
<div className={styles.editForm}>
@ -27,9 +21,9 @@ class EditForm extends React.Component { // eslint-disable-line react/prefer-sta
label="users-permissions.EditForm.inputToggle.label"
inputDescription="users-permissions.EditForm.inputToggle.description"
name="uniqueAccount"
onChange={this.handleChange}
onChange={this.props.onChange}
type="toggle"
value={this.state.value}
value={get(this.props.values, 'uniqueAccount')}
validations={{}}
/>
</div>
@ -40,25 +34,24 @@ class EditForm extends React.Component { // eslint-disable-line react/prefer-sta
label="users-permissions.EditForm.inputSelect.subscriptions.label"
inputDescription="users-permissions.EditForm.inputSelect.subscriptions.description"
name="subscriptions"
onChange={() => console.log('change')}
onChange={this.props.onChange}
type="select"
value={'100'}
selectOptions={[ { value: '100' }, { value: '200' }]}
validations={{}}
value={get(this.props.values, 'subscriptions')}
/>
<div className="col-md-3" />
<div className="col-md-3" />
<Input
customBootstrapClass="col-md-3"
label="users-permissions.EditForm.inputSelect.durations.label"
inputDescription="users-permissions.EditForm.inputSelect.durations.description"
name="durations"
onChange={() => console.log('change')}
onChange={this.props.onChange}
type="select"
value={'24'}
selectOptions={[ { value: '24' }, { value: '48' }]}
validations={{}}
value={get(this.props.values, 'durations')}
/>
</div>
</div>
@ -66,9 +59,9 @@ class EditForm extends React.Component { // eslint-disable-line react/prefer-sta
}
}
// Uncomment to use PropTypes
// EditForm.proptypes = {
// foo: PropTypes.string,
// };
EditForm.propTypes = {
onChange: PropTypes.func.isRequired,
values: PropTypes.object.isRequired,
};
export default EditForm;

View File

@ -8,7 +8,7 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import { NavLink } from 'react-router-dom';
import { map } from 'lodash';
import cn from 'classnames';
// Utils
import { darken } from 'utils/colors';
@ -54,8 +54,6 @@ function HeaderNav() {
);
}
HeaderNav.proptypes = {
};
HeaderNav.propTypes = {};
export default HeaderNav;

View File

@ -25,8 +25,8 @@ class InputSearch extends React.Component { // eslint-disable-line react/prefer-
handleChange = ({ target }) => {
const filteredUsers = isEmpty(target.value) ?
this.state.users
: this.state.users.filter((user) => {
this.state.users
: this.state.users.filter((user) => {
if (includes(toLower(user.name), toLower(target.value))) {
return user;
}
@ -72,16 +72,16 @@ InputSearch.defaultProps = {
labelValues: {
number: 0,
},
value: '',
}
values: [],
};
InputSearch.proptypes = {
InputSearch.propTypes = {
didDeleteUser: PropTypes.bool.isRequired,
label: PropTypes.string.isRequired,
labelValues: PropTypes.object,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
onClickDelete: PropTypes.func.isRequired,
value: PropTypes.string,
values: PropTypes.array,
};
export default InputSearch;

View File

@ -26,10 +26,10 @@ function InputSearchLi({ item, onClickDelete }) {
InputSearchLi.defaultProps = {
item: {
name: '',
}
}
},
};
InputSearchLi.proptypes = {
InputSearchLi.propTypes = {
item: PropTypes.object,
onClickDelete: PropTypes.func.isRequired,
};

View File

@ -7,7 +7,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import cn from 'classnames';
import { map, size } from 'lodash';
// Design
@ -18,12 +17,14 @@ import styles from './styles.scss';
const generateListTitle = (data, settingType) => {
switch (settingType) {
case 'roles':
case 'roles': {
const title = size(data) < 2 ?
<FormattedMessage id="users-permissions.List.title.roles.singular" values={{ number: size(data) }} />
: <FormattedMessage id="users-permissions.List.title.roles.plural" values={{ number: size(data) }} />;
return title;
case 'providers':
}
case 'providers': {
const enabledProvidersSize = data.filter(o => o.enabled).length;
const enabledProviders = enabledProvidersSize > 1 ?
@ -36,15 +37,16 @@ const generateListTitle = (data, settingType) => {
return <div>{enabledProviders}&nbsp;{disabledProviders}</div>;
case 'email-templates':
}
case 'email-templates': {
return size(data) > 1 ?
<FormattedMessage id="users-permissions.List.title.emailTemplates.plural" values={{ number: size(data) }} />
: <FormattedMessage id="users-permissions.List.title.emailTemplates.singular" values={{ number: size(data) }} />;
}
default:
return '';
}
}
};
function List({ data, deleteActionSucceeded, deleteData, noButton, onButtonClick, settingType }) {
return (
@ -85,11 +87,13 @@ List.defaultProps = {
onButtonClick: () => {},
};
List.proptypes = {
List.propTypes = {
data: PropTypes.array.isRequired,
deleteActionSucceeded: PropTypes.bool.isRequired,
deleteData: PropTypes.func.isRequired,
noButton: PropTypes.bool,
onButtonClick: PropTypes.func,
settingType: PropTypes.string.isRequired,
};
export default List;

View File

@ -32,7 +32,7 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
},
{
icoType: 'trash',
onClick: () => { this.setState({ showModalDelete: true }) },
onClick: () => { this.setState({ showModalDelete: true }); },
},
];
@ -153,9 +153,9 @@ ListRow.defaultProps = {
nb_users: 1,
},
settingType: 'roles',
}
};
ListRow.proptypes = {
ListRow.propTypes = {
deleteActionSucceeded: PropTypes.bool.isRequired,
deleteData: PropTypes.func.isRequired,
item: PropTypes.object,

View File

@ -6,9 +6,10 @@
import React from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { router } from 'app';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import { get } from 'lodash';
import { router } from 'app';
import Input from 'components/Input';
@ -16,7 +17,6 @@ import styles from './styles.scss';
class PopUpForm extends React.Component { // eslint-disable-line react/prefer-stateless-function
toggleModal = () => router.push(router.location.pathname);
state = { value: '' }
renderButton = () => {
if (this.props.showLoader) {
@ -41,23 +41,24 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
return (
<div className="row">
<Input
autoFocus
label="users-permissions.popUpForm.inputSelect.providers.label"
name="provider"
onChange={() => console.log('change')}
onChange={this.props.onChange}
selectOptions={[{ value: 'Email'}, { value: 'Facebook' }, { value: 'Google' }]}
type="select"
validations={{ required: true }}
value="email"
value={get(this.props.values, 'provider')}
/>
<div className="col-md-6" />
<Input
inputDescription="users-permissions.popUpForm.inputToggle.providers.description"
label="users-permissions.popUpForm.inputToggle.providers.label"
name="enabled"
onChange={() => console.log('change')}
value={true}
onChange={this.props.onChange}
type="toggle"
validations={{}}
value={get(this.props.values, 'enabled')}
/>
</div>
);
@ -66,54 +67,54 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
return (
<div className="row">
<Input
autoFocus
label="users-permissions.popUpForm.inputText.shipperName.label"
name="shipperName"
onChange={() => console.log('change')}
value=""
onChange={this.props.onChange}
value={get(this.props.values, 'shipperName')}
placeholder="users-permissions.popUpForm.inputText.shipperName.placeholder"
type="text"
validations={{}}
autoFocus
/>
<Input
label="users-permissions.popUpForm.inputEmail.shipperEmail.label"
name="shipperEmail"
onChange={({ target }) => this.setState({ value: target.value })}
value={this.state.value}
onChange={this.props.onChange}
placeholder="users-permissions.popUpForm.inputEmail.placeholder"
type="email"
validations={{ required: true }}
value={get(this.props.values, 'shipperEmail')}
/>
<Input
label="users-permissions.popUpForm.inputEmail.responseEmail.label"
name="responseEmail"
onChange={() => console.log('change')}
value=""
onChange={this.props.onChange}
placeholder="users-permissions.popUpForm.inputEmail.placeholder"
type="email"
validations={{}}
value={get(this.props.values, 'responseEmail')}
/>
<div className="col-md-6" />
<Input
customBootstrapClass="col-md-12"
label="users-permissions.popUpForm.inputText.emailObject.label"
name="emailObject"
onChange={() => console.log('change')}
value=""
placeholder="users-permissions.popUpForm.inputText.emailObject.placeholder"
type="text"
validations={{}}
/>
<Input
customBootstrapClass="col-md-12"
label="users-permissions.popUpForm.inputTextArea.message.label"
name="message"
onChange={() => console.log('change')}
value=""
placeholder="users-permissions.popUpForm.inputTextArea.message.placeholder"
type="textarea"
validations={{}}
/>
<Input
customBootstrapClass="col-md-12"
label="users-permissions.popUpForm.inputText.emailObject.label"
name="emailObject"
onChange={this.props.onChange}
placeholder="users-permissions.popUpForm.inputText.emailObject.placeholder"
type="text"
validations={{}}
value={get(this.props.values, 'emailObject')}
/>
<Input
customBootstrapClass="col-md-12"
label="users-permissions.popUpForm.inputTextArea.message.label"
name="message"
onChange={this.props.onChange}
placeholder="users-permissions.popUpForm.inputTextArea.message.placeholder"
type="textarea"
validations={{}}
value={get(this.props.values, 'message')}
/>
</div>
);
}
@ -130,27 +131,38 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
) : <div />}
</div>
</div>
<ModalBody className={styles.modalBody}>
<div className="container-fluid">
{this.renderForm()}
</div>
</ModalBody>
<ModalFooter className={styles.modalFooter}>
<Button onClick={this.toggleModal} className={styles.secondary}>
<FormattedMessage id="users-permissions.popUpForm.button.cancel" />
</Button>
{this.renderButton()}
</ModalFooter>
<form onSubmit={this.props.onSubmit}>
<ModalBody className={styles.modalBody}>
<div className="container-fluid">
{this.renderForm()}
</div>
</ModalBody>
<ModalFooter className={styles.modalFooter}>
<Button onClick={() => router.push(router.location.pathname)} className={styles.secondary}>
<FormattedMessage id="users-permissions.popUpForm.button.cancel" />
</Button>
{this.renderButton()}
</ModalFooter>
</form>
</Modal>
</div>
);
}
}
PopUpForm.proptypes = {
PopUpForm.defaultProps = {
settingType: 'providers',
showLoader: false,
};
PopUpForm.propTypes = {
actionType: PropTypes.string.isRequired,
isOpen: PropTypes.bool.isRequired,
settingType: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
settingType: PropTypes.string,
showLoader: PropTypes.bool,
values: PropTypes.object.isRequired,
};
export default PopUpForm;

View File

@ -139,7 +139,9 @@ export class EditPage extends React.Component { // eslint-disable-line react/pre
EditPage.propTypes = {
addUser: PropTypes.func.isRequired,
editPage: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
onCancel: PropTypes.func.isRequired,
onChangeInput: PropTypes.func.isRequired,
onClickDelete: PropTypes.func.isRequired,

View File

@ -40,12 +40,13 @@ const initialState = fromJS({
function editPageReducer(state = initialState, action) {
switch (action.type) {
case ADD_USER:
return state.updateIn(['modifiedData', 'users'], list => list.push(action.newUser));
return state
.updateIn(['modifiedData', 'users'], list => list.push(action.newUser));
case ON_CANCEL:
return state
.set('showButtons', false)
.set('didDeleteUser', !state.get('didDeleteUser'))
.set('modifiedData', state.get('initialData'));
.set('showButtons', false)
.set('didDeleteUser', !state.get('didDeleteUser'))
.set('modifiedData', state.get('initialData'));
case ON_CHANGE_INPUT:
return state
.set('showButtons', true)

View File

@ -3,12 +3,15 @@
* HomePage actions
*
*/
import { Map } from 'immutable';
import {
DELETE_DATA,
DELETE_DATA_SUCCEEDED,
FETCH_DATA,
FETCH_DATA_SUCCEEDED,
ON_CHANGE,
SET_FORM,
} from './constants';
export function deleteData(dataToDelete, deleteEndPoint) {
@ -39,3 +42,52 @@ export function fetchDataSucceeded(data) {
data,
};
}
export function onChange({ target }) {
return {
type: ON_CHANGE,
key: target.name,
value: target.value,
};
}
export function setForm(formType) {
const form = generateForm(formType);
return {
type: SET_FORM,
form,
};
}
// Utils
function generateForm(formType) {
let form = Map({});
switch (formType) {
case 'providers':
form = Map({
provider: 'Facebook',
enabled: false,
});
break;
case 'email-templates':
form = Map({
shipperName: '',
shipperEmail: '',
responseEmail: '',
emailObject: '',
message: '',
});
break;
case 'advanced-settings':
form = Map({
uniqueAccount: false,
subscriptions: '100',
durations: '24',
});
break;
default:
}
return form;
}

View File

@ -8,3 +8,5 @@ export const DELETE_DATA = 'UsersPermissions/HomePage/DELETE_DATA';
export const DELETE_DATA_SUCCEEDED = 'UsersPermissions/HomePage/DELETE_DATA_SUCCEEDED';
export const FETCH_DATA = 'UsersPermissions/HomePage/FETCH_DATA';
export const FETCH_DATA_SUCCEEDED = 'UsersPermissions/HomePage/FETCH_DATA_SUCCEEDED';
export const ON_CHANGE = 'UsersPermissions/HomePage/ON_CHANGE';
export const SET_FORM = 'UsersPermissions/HomePage/SET_FORM';

View File

@ -7,7 +7,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { injectIntl } from 'react-intl';
import { bindActionCreators, compose } from 'redux';
import cn from 'classnames';
@ -34,6 +33,7 @@ import styles from './styles.scss';
import {
deleteData,
fetchData,
onChange,
} from './actions';
import reducer from './reducer';
@ -50,7 +50,7 @@ export class HomePage extends React.Component {
}
}
onButtonClick = () => {
handleButtonClick = () => {
if (this.props.match.params.settingType === 'roles') {
this.props.history.push(`${this.props.location.pathname}/create`);
} else {
@ -58,37 +58,67 @@ export class HomePage extends React.Component {
}
}
pluginHeaderActions = [
{
label: 'users-permissions.EditPage.cancel',
kind: 'secondary',
onClick: () => console.log('cancel'),
type: 'button',
},
{
kind: 'primary',
label: 'users-permissions.EditPage.submit',
onClick: () => console.log('submit'),
type: 'submit',
},
];
render() {
const headerActions = this.props.match.params.settingType === 'advanced-settings' && this.props.showButtons ?
this.pluginHeaderActions : [];
const noButtonList = this.props.match.params.settingType === 'email-templates';
const component = this.props.match.params.settingType === 'advanced-settings' ?
<EditForm /> :
<EditForm onChange={this.props.onChange} values={this.props.modifiedData} /> : (
<List
data={this.props.data}
deleteActionSucceeded={this.props.deleteActionSucceeded}
deleteData={this.props.deleteData}
noButton={noButtonList}
onButtonClick={this.onButtonClick}
onButtonClick={this.handleButtonClick}
settingType={this.props.match.params.settingType}
/>;
const hashArray = replace(this.props.location.hash, '#', '').split('::');
/>
);
const hashArray = replace(this.props.location.hash, '#', '').split('::');
return (
<div>
<div className={cn('container-fluid', styles.containerFluid)}>
<PluginHeader
title={{ id: 'users-permissions.HomePage.header.title' }}
description={{ id: 'users-permissions.HomePage.header.description' }}
actions={[]}
<form
onSubmit={(e) => {
e.preventDefault();
console.log('submit');
}}
>
<div className={cn('container-fluid', styles.containerFluid)}>
<PluginHeader
title={{ id: 'users-permissions.HomePage.header.title' }}
description={{ id: 'users-permissions.HomePage.header.description' }}
actions={headerActions}
/>
<HeaderNav />
{component}
</div>
<PopUpForm
actionType={hashArray[0]}
isOpen={!isEmpty(this.props.location.hash)}
onChange={this.props.onChange}
onSubmit={(e) => {
e.preventDefault();
console.log('submit popUp');
}}
settingType={hashArray[1]}
values={this.props.modifiedData}
/>
<HeaderNav />
{component}
</div>
<PopUpForm
actionType={hashArray[0]}
settingType={hashArray[1]}
isOpen={!isEmpty(this.props.location.hash)}
/>
</form>
</div>
);
}
@ -101,6 +131,12 @@ HomePage.propTypes = {
deleteActionSucceeded: PropTypes.bool.isRequired,
deleteData: PropTypes.func.isRequired,
fetchData: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
modifiedData: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
showButtons: PropTypes.bool.isRequired,
};
@ -109,6 +145,7 @@ function mapDispatchToProps(dispatch) {
{
deleteData,
fetchData,
onChange,
},
dispatch,
);

View File

@ -10,6 +10,8 @@ import {
DELETE_DATA,
DELETE_DATA_SUCCEEDED,
FETCH_DATA_SUCCEEDED,
ON_CHANGE,
SET_FORM,
} from './constants';
const initialState = fromJS({
@ -17,6 +19,9 @@ const initialState = fromJS({
dataToDelete: Map({}),
deleteActionSucceeded: false,
deleteEndPoint: '',
initialData: Map({}),
modifiedData: Map({}),
showButtons: false,
});
function homePageReducer(state = initialState, action) {
@ -33,6 +38,14 @@ function homePageReducer(state = initialState, action) {
.set('deleteActionSucceeded', !state.get('deleteActionSucceeded'));
case FETCH_DATA_SUCCEEDED:
return state.set('data', List(action.data));
case ON_CHANGE:
return state
.updateIn(['modifiedData', action.key], () => action.value)
.set('showButtons', true);
case SET_FORM:
return state
.set('initialData', action.form)
.set('modifiedData', action.form);
default:
return state;
}

View File

@ -1,9 +1,16 @@
import { LOCATION_CHANGE } from 'react-router-redux';
import { takeLatest, put, fork, take, cancel, select } from 'redux-saga/effects';
import { findIndex } from 'lodash';
import { takeLatest, put, fork, take, cancel, select } from 'redux-saga/effects';
import { deleteDataSucceeded, fetchDataSucceeded } from './actions';
import { DELETE_DATA, FETCH_DATA } from './constants';
import {
deleteDataSucceeded,
fetchDataSucceeded,
setForm,
} from './actions';
import {
DELETE_DATA,
FETCH_DATA,
} from './constants';
import data from './data.json';
import {
makeSelectAllData,
@ -20,10 +27,8 @@ export function* dataDelete() {
if (indexDataToDelete !== -1) {
yield put(deleteDataSucceeded(indexDataToDelete));
window.Strapi.notification.success('users-permissions.notification.success.delete')
window.Strapi.notification.success('users-permissions.notification.success.delete');
}
} catch(err) {
window.Strapi.notification.error('users-permissions.notification.error.delete');
}
@ -34,6 +39,7 @@ export function* dataFetch(action) {
const response = data[action.endPoint];
yield put(fetchDataSucceeded(response));
yield put(setForm(action.endPoint));
} catch(err) {
window.Strapi.notification.error('users-permissions.notification.error.fetch');