Design EditPage top block, started design inputSearch and add change dynamic

This commit is contained in:
cyril lopez 2017-11-07 16:33:15 +01:00
parent 9c65e2824e
commit c720955269
13 changed files with 357 additions and 36 deletions

View File

@ -0,0 +1,60 @@
/**
*
* InputSearch
*
*/
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { isEmpty } from 'lodash';
import cn from 'classnames';
import PropTypes from 'prop-types';
import styles from './styles.scss';
class InputSearch extends React.Component { // eslint-disable-line react/prefer-stateless-function
state = { errors: [] };
render() {
return (
<div className={cn(styles.inputSearch, 'col-md-6')}>
<label htmlFor={this.props.name}>
<FormattedMessage id={this.props.label} values={this.props.labelValues} />
</label>
<div className={cn('input-group')}>
<span className={cn('input-group-addon', styles.addon)} />
<FormattedMessage id="users-permissions.InputSearch.placeholder">
{(message) => (
<input
className={cn('form-control', !isEmpty(this.state.errors) ? 'is-invalid': '')}
id={this.props.name}
name={this.props.name}
onChange={this.props.onChange}
value={this.props.value}
placeholder={message}
type="text"
/>
)}
</FormattedMessage>
</div>
</div>
);
}
}
InputSearch.defaultProps = {
labelValues: {
number: 0,
},
value: '',
}
InputSearch.proptypes = {
label: PropTypes.string.isRequired,
labelValues: PropTypes.object,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
value: PropTypes.string,
};
export default InputSearch;

View File

@ -0,0 +1,45 @@
.addon {
width: 3.2rem;
height: 3.4rem;
margin-top: .9rem;
background-color: rgba(16, 22, 34, 0.02);
border: 1px solid #E3E9F3;
border-radius: 0.25rem;
color: rgba(16, 22, 34, 0.5);
line-height: 3.2rem;
font-size: 1.3rem;
font-family: 'Lato';
font-weight: 600!important;
text-transform: capitalize;
-moz-appearance: none;
-webkit-appearance: none;
&:before {
content: '\f002';
display: inline-table;
font-family: 'FontAwesome';
}
}
.inputSearch {
min-width: 200px;
margin-bottom: 1.5rem;
font-size: 1.3rem;
label {
margin-bottom: 0;
font-weight: 500;
text-transform: capitalize;
}
input {
height: 3.4rem;
margin-top: .9rem;
padding-left: 1rem;
background-size: 0 !important;
border: 1px solid #E3E9F3;
border-radius: 0.25rem;
line-height: 3.4rem;
font-size: 1.3rem;
font-family: 'Lato' !important;
}
}

View File

@ -7,6 +7,7 @@
import React from 'react'; import React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { router } from 'app';
// Design // Design
import IcoContainer from 'components/IcoContainer'; import IcoContainer from 'components/IcoContainer';
@ -23,13 +24,11 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
} }
} }
handleDelete = () => this.props.deleteData(this.props.item, this.props.settingType);
generateContent = () => { generateContent = () => {
let icons = [ let icons = [
{ {
icoType: 'pencil', icoType: 'pencil',
onClick: () => { console.log('edit') }, onClick: this.handleClick,
}, },
{ {
icoType: 'trash', icoType: 'trash',
@ -90,7 +89,7 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
icons = [ icons = [
{ {
icoType: 'pencil', icoType: 'pencil',
onClick: () => { console.log('edit') }, onClick: this.handleClick,
}, },
]; ];
@ -117,9 +116,23 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
} }
} }
handleClick = () => {
switch (this.props.settingType) {
case 'roles':
return router.push(`${router.location.pathname}/${this.props.item.id}`);
case 'providers':
case 'email-templates':
return console.log('click');
default:
return;
}
}
handleDelete = () => this.props.deleteData(this.props.item, this.props.settingType);
render() { render() {
return ( return (
<li className={styles.li}> <li className={styles.li} onClick={this.handleClick}>
<div className={styles.container}> <div className={styles.container}>
{this.generateContent()} {this.generateContent()}
</div> </div>

View File

@ -27,6 +27,12 @@ class App extends React.Component {
} }
} }
componentDidUpdate() {
if (!this.props.location.pathname.split('/')[3]) {
this.props.history.push('/plugins/users-permissions/roles');
}
}
render() { render() {
return ( return (
<div className={pluginId}> <div className={pluginId}>

View File

@ -5,11 +5,20 @@
*/ */
import { import {
DEFAULT_ACTION, ON_CANCEL,
ON_CHANGE_INPUT,
} from './constants'; } from './constants';
export function defaultAction() { export function onCancel() {
return { return {
type: DEFAULT_ACTION, type: ON_CANCEL,
};
}
export function onChangeInput({ target }) {
return {
type: ON_CHANGE_INPUT,
key: target.name,
value: target.value,
}; };
} }

View File

@ -4,4 +4,5 @@
* *
*/ */
export const DEFAULT_ACTION = 'UsersPermissions/EditPage/DEFAULT_ACTION'; export const ON_CANCEL = 'UsersPermissions/EditPage/ON_CANCEL';
export const ON_CHANGE_INPUT = 'UsersPermissions/EditPage/ON_CHANGE_INPUT';

View File

@ -5,42 +5,150 @@
*/ */
import React from 'react'; import React from 'react';
// import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Helmet } from 'react-helmet';
import { createStructuredSelector } from 'reselect'; import { createStructuredSelector } from 'reselect';
import { bindActionCreators, compose } from 'redux'; import { bindActionCreators, compose } from 'redux';
import { FormattedMessage } from 'react-intl';
import { get } from 'lodash';
import cn from 'classnames';
// Design
import BackHeader from 'components/BackHeader';
import Input from 'components/Input';
import InputSearch from 'components/InputSearch';
import PluginHeader from 'components/PluginHeader';
import injectSaga from 'utils/injectSaga'; import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer'; import injectReducer from 'utils/injectReducer';
// Actions
import {
onCancel,
onChangeInput,
} from './actions';
// Selectors
import makeSelectEditPage from './selectors'; import makeSelectEditPage from './selectors';
import reducer from './reducer'; import reducer from './reducer';
import saga from './saga'; import saga from './saga';
import styles from './styles.scss';
export class EditPage extends React.Component { // eslint-disable-line react/prefer-stateless-function export class EditPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
pluginHeaderActions = [
{
label: 'users-permissions.EditPage.cancel',
kind: 'secondary',
onClick: this.props.onCancel,
type: 'button',
},
{
kind: 'primary',
label: 'users-permissions.EditPage.submit',
onClick: () => console.log('submit'),
type: 'submit',
},
];
render() { render() {
const pluginHeaderTitle = this.props.match.params.id === 'create' ?
'users-permissions.EditPage.header.title.create'
: 'users-permissions.EditPage.header.title';
const pluginHeaderDescription = this.props.match.params.id === 'create' ?
'users-permissions.EditPage.header.description.create'
: 'users-permissions.EditPage.header.description';
const pluginHeaderActions = this.props.editPage.showButtons ? this.pluginHeaderActions : [];
return ( return (
<div> <div>
<Helmet> <BackHeader onClick={() => this.props.history.goBack()} />
<title>EditPage</title> <div className={cn('container-fluid', styles.containerFluid)}>
<meta name="description" content="Description of EditPage" /> <PluginHeader
</Helmet> title={{
id: pluginHeaderTitle,
values: {
name: '',
},
}}
description={{
id: pluginHeaderDescription,
values: {
description: '',
},
}}
actions={pluginHeaderActions}
/>
<div className="row">
<div className="col-md-12">
<div className={styles.main_wrapper}>
<div className={styles.titleContainer}>
<FormattedMessage id="users-permissions.EditPage.form.roles" />
</div>
<form className={styles.form}>
<div className="row">
<div className="col-md-6">
<div className="row">
<Input
customBootstrapClass="col-md-12"
label="users-permissions.EditPage.form.roles.label.name"
name="name"
onChange={this.props.onChangeInput}
type="text"
validations={{ required: true }}
value={get(this.props.editPage, ['modifiedData', 'name'])}
/>
</div>
<div className="row">
<Input
customBootstrapClass="col-md-12"
label="users-permissions.EditPage.form.roles.label.description"
name="description"
onChange={this.props.onChangeInput}
type="textarea"
validations={{ required: true }}
value={get(this.props.editPage, ['modifiedData', 'description'])}
/>
</div>
</div>
<InputSearch
label="users-permissions.EditPage.form.roles.label.users"
labelValues={{ number: 0 }}
onChange={() => console.log('change')}
type="text"
validations={{ required: true }}
value=""
name="users"
/>
</div>
</form>
</div>
</div>
</div>
</div>
</div> </div>
); );
} }
} }
EditPage.propTypes = { EditPage.propTypes = {
history: PropTypes.object.isRequired,
onCancel: PropTypes.func.isRequired,
onChangeInput: PropTypes.func.isRequired,
}; };
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
editpage: makeSelectEditPage(), editPage: makeSelectEditPage(),
}); });
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {
return bindActionCreators( return bindActionCreators(
{}, {
dispatch onCancel,
onChangeInput,
},
dispatch,
); );
} }

View File

@ -4,17 +4,36 @@
* *
*/ */
import { fromJS } from 'immutable'; import { fromJS, List, Map } from 'immutable';
import { import {
DEFAULT_ACTION, ON_CANCEL,
ON_CHANGE_INPUT,
} from './constants'; } from './constants';
const initialState = fromJS({}); const initialState = fromJS({
initialData: Map({
name: '',
description: '',
users: List([]),
}),
modifiedData: Map({
name: '',
description: '',
users: List([]),
}),
showButtons: false,
});
function editPageReducer(state = initialState, action) { function editPageReducer(state = initialState, action) {
switch (action.type) { switch (action.type) {
case DEFAULT_ACTION: case ON_CANCEL:
return state; return state
.set('showButtons', false)
.set('modifiedData', state.get('initialData'));
case ON_CHANGE_INPUT:
return state
.set('showButtons', true)
.setIn(['modifiedData', action.key], action.value);
default: default:
return state; return state;
} }

View File

@ -0,0 +1,20 @@
.containerFluid {
padding: 18px 30px;
}
.form {
padding-top: 2rem;
}
.main_wrapper{
background: #ffffff;
padding: 22px 10px;
border-radius: 2px;
box-shadow: 0 2px 4px #E3E9F3;
}
.titleContainer {
font-size: 18px;
font-weight: bold;
line-height: 18px;
}

View File

@ -3,58 +3,69 @@
{ {
"name": "Owner", "name": "Owner",
"description": "Rule them all. This role can't be deleted", "description": "Rule them all. This role can't be deleted",
"nb_users": 1 "nb_users": 1,
"id": 1
}, },
{ {
"name": "Administrator", "name": "Administrator",
"description": "Full access to everything", "description": "Full access to everything",
"nb_users": 3 "nb_users": 3,
"id": 2
}, },
{ {
"name": "Moderator", "name": "Moderator",
"description": "Allow editing and deleting (except users)", "description": "Allow editing and deleting (except users)",
"nb_users": 12 "nb_users": 12,
"id": 3
}, },
{ {
"name": "Editor", "name": "Editor",
"description": "Allow creating and editing your entries", "description": "Allow creating and editing your entries",
"nb_users": 429 "nb_users": 429,
"id": 4
} }
], ],
"providers": [ "providers": [
{ {
"name": "email", "name": "email",
"enabled": true, "enabled": true,
"ico": "envelope" "ico": "envelope",
"id": 1
}, },
{ {
"name": "facebook", "name": "facebook",
"enabled": false, "enabled": false,
"ico": "facebook" "ico": "facebook",
"id": 2
}, },
{ {
"name": "twitter", "name": "twitter",
"enabled": true, "enabled": true,
"ico": "twitter" "ico": "twitter",
"id": 3
}, },
{ {
"name": "google", "name": "google",
"enabled": false, "enabled": false,
"ico": "google" "ico": "google",
"id": 4
} }
], ],
"email-templates": [ "email-templates": [
{ {
"name": "Email address validation", "name": "Email address validation",
"ico": "envelope" "ico": "envelope",
"id": 1
}, },
{ {
"name": "Reset password", "name": "Reset password",
"ico": "refresh" "ico": "refresh",
"id": 2
}, },
{ {
"name": "Successfull sign-in", "name": "Successfull sign-in",
"ico": "check" "ico": "check",
"id": 3
} }
] ]
} }

View File

@ -47,16 +47,19 @@ export class HomePage extends React.Component {
} }
} }
onButtonClick = () => this.props.history.push(`${this.props.location.pathname}/create`);
render() { render() {
const noButtonList = this.props.match.params.settingType === 'email-templates'; const noButtonList = this.props.match.params.settingType === 'email-templates';
const component = this.props.match.params.settingType === 'advanced-settings' ? const component = this.props.match.params.settingType === 'advanced-settings' ?
<div>coucou</div> : <div>coucou</div> :
<List <List
data={this.props.data} data={this.props.data}
settingType={this.props.match.params.settingType}
noButton={noButtonList}
deleteActionSucceeded={this.props.deleteActionSucceeded} deleteActionSucceeded={this.props.deleteActionSucceeded}
deleteData={this.props.deleteData} deleteData={this.props.deleteData}
noButton={noButtonList}
onButtonClick={this.onButtonClick}
settingType={this.props.match.params.settingType}
/>; />;
return ( return (
<div> <div>

View File

@ -1,4 +1,15 @@
{ {
"EditPage.cancel": "Cancel",
"EditPage.submit": "Save",
"EditPage.form.roles": "Roles details",
"EditPage.form.roles.label.description": "Description",
"EditPage.form.roles.label.name": "Name",
"EditPage.form.roles.label.users": "Users associated with this role ({number})",
"EditPage.header.title": "{name}",
"EditPage.header.title.create": "Create a new role",
"EditPage.header.description": "{description}",
"EditPage.header.description.create": " ",
"HeaderNav.link.advancedSettings": "Advanced settings", "HeaderNav.link.advancedSettings": "Advanced settings",
"HeaderNav.link.emailTemplates": "Email templates", "HeaderNav.link.emailTemplates": "Email templates",
"HeaderNav.link.providers": "Providers", "HeaderNav.link.providers": "Providers",
@ -7,6 +18,8 @@
"HomePage.header.title": "Auth & Permissions", "HomePage.header.title": "Auth & Permissions",
"HomePage.header.description": "Define the roles and permissions for every one of them", "HomePage.header.description": "Define the roles and permissions for every one of them",
"InputSearch.placeholder": "Search for a user",
"List.button.roles": "Add a New Role", "List.button.roles": "Add a New Role",
"List.button.providers": "Add a New Provider", "List.button.providers": "Add a New Provider",

View File

@ -1,4 +1,15 @@
{ {
"EditPage.cancel": "Cancel",
"EditPage.submit": "Sauvegarder",
"EditPage.form.roles": "Rôles détails",
"EditPage.form.roles.label.description": "Description",
"EditPage.form.roles.label.name": "Nom",
"EditPage.form.roles.label.users": "Utilisateurs associés avec ce rôle ({number})",
"EditPage.header.title": "{name}",
"EditPage.header.title.create": "Créez un nouveau rôle",
"EditPage.header.description": "{description}",
"EditPage.header.description.create": " ",
"HeaderNav.link.advancedSettings": "Paramètres avancés", "HeaderNav.link.advancedSettings": "Paramètres avancés",
"HeaderNav.link.emailTemplates": "Templates d'email", "HeaderNav.link.emailTemplates": "Templates d'email",
"HeaderNav.link.providers": "Fournisseurs", "HeaderNav.link.providers": "Fournisseurs",
@ -7,6 +18,8 @@
"HomePage.header.title": "Auth & Permissions", "HomePage.header.title": "Auth & Permissions",
"HomePage.header.description": "Définissez les rôles et permissions pour chacun d'eux", "HomePage.header.description": "Définissez les rôles et permissions pour chacun d'eux",
"InputSearch.placeholder": "Recherez un utilisateur",
"List.button.roles": "Ajouter un Nouveau Rôle", "List.button.roles": "Ajouter un Nouveau Rôle",
"List.button.providers": "Ajouter Un Nouveau Provider", "List.button.providers": "Ajouter Un Nouveau Provider",