Merge branch 'master' into add/input-checkbox

This commit is contained in:
cyril lopez 2018-02-06 17:06:37 +01:00 committed by GitHub
commit 7c2425c293
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1367 additions and 50 deletions

View File

@ -403,6 +403,12 @@ export default Foo;
*** ***
## InputEmail
Please refer to the [InputText documentation](#InputText);
***
## InputNumber ## InputNumber
InputNumber component. InputNumber component.
@ -424,6 +430,30 @@ InputNumber component.
*** ***
***
## InputSelect
InputSelect component.
| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| autoFocus | bool | no | Sets the input's autoFocus |
| className | string | no | custom className for the input |
| deactivateErrorHighlight | bool | no | Allow to deactivate the red border on the input when there is an error |
| disabled | bool | no | Disables the input |
| errors | array | no | Sets the red border on the input |
| onBlur | func | no | Function executed when the user leaves the input |
| onFocus | func | no | Function executed when the user enters the input |
| name | string | yes | The name of the input |
| placeholder | string | no | Input's placeholder, works with i18n |
| selectOptions | array of objects | yes | Options for the select. |
| style | object | no | Input's style property |
| tabIndex | string | no | Input's tabIndex |
| value | string or number | yes | Input's value |
***
## InputText ## InputText
InputText Component InputText Component
@ -487,12 +517,55 @@ Input type: 'toggle' component
*** ***
## InputEmailWithErrors
Please refer to the [InputTextWithErrors](#InputTextWithErrors) documentation.
***
## InputNumberWithErrors ## InputNumberWithErrors
Please refer to the [InputTextWithErrors](#InputTextWithErrors) documentation. Please refer to the [InputTextWithErrors](#InputTextWithErrors) documentation.
*** ***
## InputSelectWithErrors
Component integrates Label, InputSelect, InputDescription and InputErrors.
| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| autoFocus | bool | no | Sets the input's autoFocus |
| className | string | no | Overrides the container className |
| customBootstrapClass | string | no | Allows to override the input bootstrap col system |
| deactivateErrorHighlight | bool | no | Allow to deactivate the red border on the input when there is an error |
| didCheckErrors | bool | no | Use this props to display errors after submitting a form. |
| disabled | bool | no | Disables the input |
| errors | array | no | Array of errors |
| errorsClassName | string | no | Overrides the InputErrors' className |
| errorsStyle | object | no | Overrides the InputErrors' style |
| inputClassName | string | no | Overrides the InputText's className |
| inputDescriptionClassName | string | no | Overrides the InputDescription's className |
| inputDescriptionStyle | object | no | Overrides the InputDescription's style|
| inputStyle | object | no | Overrides the InputText's style |
| labelClassName | string | no | Overrides the Label's className |
| labelStyle | object | no | Overrides the Label's style |
| onBlur | func | no | Function executed when the user leaves the input |
| onChange | func | yes | Handler to modify the input's value |
| onFocus | func | no | Function executed when the user enters the input |
| name | string | yes | The name of the input |
| placeholder | string | no | Input's placeholder, works with i18n |
| style | object | no | Overrides the container style |
| selectOptions | array of objects | yes | Options for the select. |
| tabIndex | string | no | Input's tabIndex |
| value | string | yes | Input's value |
### Usage
Please refer to the [InputTextWithErrors](#InputTextWithErrors) documentation.
***
## InputTextWithErrors ## InputTextWithErrors
Component integrates Label, InputText, InputDescription and InputErrors. Component integrates Label, InputText, InputDescription and InputErrors.
@ -518,6 +591,7 @@ Component integrates Label, InputText, InputDescription and InputErrors.
| onChange | func | yes | Handler to modify the input's value | | onChange | func | yes | Handler to modify the input's value |
| onFocus | func | no | Function executed when the user enters the input | | onFocus | func | no | Function executed when the user enters the input |
| name | string | yes | The name of the input | | name | string | yes | The name of the input |
| noErrorsDescription | bool | no | Remove the input's errors description |
| placeholder | string | no | Input's placeholder, works with i18n | | placeholder | string | no | Input's placeholder, works with i18n |
| style | object | no | Overrides the container style | | style | object | no | Overrides the container style |
| tabIndex | string | no | Input's tabIndex | | tabIndex | string | no | Input's tabIndex |
@ -618,8 +692,9 @@ Component integrates Label, InputToggle, InputDescription and InputErrors.
| label | string or func or object | no sets the input's label | | label | string or func or object | no sets the input's label |
| labelClassName | string | no | Overrides the Label's className | | labelClassName | string | no | Overrides the Label's className |
| labelStyle | object | no | Overrides the Label's style | | labelStyle | object | no | Overrides the Label's style |
| onChange | func | yes | Handler to modify the input's value |
| name | string | yes | The name of the input | | name | string | yes | The name of the input |
| noErrorsDescription | bool | no | Remove the input's errors description |
| onChange | func | yes | Handler to modify the input's value |
| style | object | no | Overrides the container style | | style | object | no | Overrides the container style |
| tabIndex | string | no | Input's tabIndex | | tabIndex | string | no | Input's tabIndex |
| validations | object | no | Input's validations | | validations | object | no | Input's validations |
@ -656,6 +731,7 @@ Component integrates Label, InputTextArea, InputDescription and InputErrors.
| onChange | func | yes | Handler to modify the input's value | | onChange | func | yes | Handler to modify the input's value |
| onFocus | func | no | Function executed when the user enters the input | | onFocus | func | no | Function executed when the user enters the input |
| name | string | yes | The name of the input | | name | string | yes | The name of the input |
| noErrorsDescription | bool | no | Remove the input's errors description |
| placeholder | string | no | Input's placeholder, works with i18n | | placeholder | string | no | Input's placeholder, works with i18n |
| style | object | no | Overrides the container style | | style | object | no | Overrides the container style |
| tabIndex | string | no | Input's tabIndex | | tabIndex | string | no | Input's tabIndex |

View File

@ -1,6 +1,7 @@
# Don't check auto-generated stuff into git # Don't check auto-generated stuff into git
coverage coverage
node_modules node_modules
manifest.json
plugins.json plugins.json
stats.json stats.json
package-lock.json package-lock.json

View File

@ -55,7 +55,8 @@
"app.components.PluginCard.price.free": "Free", "app.components.PluginCard.price.free": "Free",
"app.components.PluginCard.more-details": "More details", "app.components.PluginCard.more-details": "More details",
"app.utils.placeholder.defaultMessage": " ", "app.utils.placeholder.defaultMessage": "\u0020",
"app.utils.SelectOption.defaultMessage": "\u0020",
"components.AutoReloadBlocker.header": "Reload feature is required for this plugin.", "components.AutoReloadBlocker.header": "Reload feature is required for this plugin.",
"components.AutoReloadBlocker.description": "Open the following file and enable the feature.", "components.AutoReloadBlocker.description": "Open the following file and enable the feature.",

View File

@ -55,7 +55,8 @@
"app.components.PluginCard.price.free": "Gratuit", "app.components.PluginCard.price.free": "Gratuit",
"app.components.PluginCard.more-details": "Plus de détails", "app.components.PluginCard.more-details": "Plus de détails",
"app.utils.placeholder.defaultMessage": " ", "app.utils.placeholder.defaultMessage": "\u0020",
"app.utils.SelectOption.defaultMessage": "\u0020",
"components.AutoReloadBlocker.header": "L'autoReload doit être activé pour ce plugin.", "components.AutoReloadBlocker.header": "L'autoReload doit être activé pour ce plugin.",
"components.AutoReloadBlocker.description": "Ouvrez le fichier suivant pour activer cette fonctionnalité.", "components.AutoReloadBlocker.description": "Ouvrez le fichier suivant pour activer cette fonctionnalité.",

View File

@ -1,5 +1,5 @@
{ {
"host": "localhost", "host": "127.0.0.1",
"port": 1337, "port": 1337,
"autoReload": { "autoReload": {
"enabled": true "enabled": true

View File

@ -5,7 +5,7 @@
"connector": "strapi-mongoose", "connector": "strapi-mongoose",
"settings": { "settings": {
"client": "mongo", "client": "mongo",
"host": "${process.env.DATABASE_HOST || 'localhost'}", "host": "${process.env.DATABASE_HOST || '127.0.0.1'}",
"port": "${process.env.DATABASE_PORT || 27017}", "port": "${process.env.DATABASE_PORT || 27017}",
"database": "${process.env.DATABASE_NAME || 'production'}", "database": "${process.env.DATABASE_NAME || 'production'}",
"username": "${process.env.DATABASE_USERNAME || ''}", "username": "${process.env.DATABASE_USERNAME || ''}",

View File

@ -1,5 +1,5 @@
{ {
"host": "localhost", "host": "127.0.0.1",
"port": 1337, "port": 1337,
"autoReload": { "autoReload": {
"enabled": false "enabled": false

View File

@ -5,7 +5,7 @@
"connector": "strapi-mongoose", "connector": "strapi-mongoose",
"settings": { "settings": {
"client": "mongo", "client": "mongo",
"host": "localhost", "host": "127.0.0.1",
"port": 27017, "port": 27017,
"database": "test", "database": "test",
"username": "", "username": "",

View File

@ -1,5 +1,5 @@
{ {
"host": "localhost", "host": "127.0.0.1",
"port": 1337, "port": 1337,
"autoReload": { "autoReload": {
"enabled": true "enabled": true

View File

@ -136,7 +136,7 @@ module.exports = (scope, cb) => {
prefix: '', prefix: '',
name: 'host', name: 'host',
message: 'Host:', message: 'Host:',
default: _.get(scope.database, 'host', 'localhost') default: _.get(scope.database, 'host', '127.0.0.1')
}, },
{ {
type: 'input', type: 'input',

View File

@ -0,0 +1,107 @@
/**
*
* InputEmail
*/
import React from 'react';
import PropTypes from 'prop-types';
import { isEmpty } from 'lodash';
import { FormattedMessage } from 'react-intl';
import cn from 'classnames';
import styles from './styles.scss';
class InputEmail extends React.Component {
state = { isFocused: false };
handleBlur = (e) => {
this.setState({ isFocused: !this.state.isFocused });
this.props.onBlur(e);
}
handleFocus = (e) => {
this.setState({ isFocused: !this.state.isFocused });
this.props.onFocus(e);
}
render() {
const {
autoFocus,
className,
deactivateErrorHighlight,
disabled,
error,
name,
onChange,
placeholder,
style,
tabIndex,
value,
} = this.props;
return (
<div className={cn(styles.inputEmail, 'input-group', !isEmpty(className) && className)} style={style}>
<span className={cn(
'input-group-addon',
styles.addonEmail,
this.state.isFocused && styles.addonFocus,
!deactivateErrorHighlight && error && styles.errorAddon,
)}
/>
<FormattedMessage id={placeholder} defaultMessage={placeholder}>
{(message) => (
<input
autoFocus={autoFocus}
className={cn(
'form-control',
!deactivateErrorHighlight && error && 'is-invalid',
!deactivateErrorHighlight && error && this.state.isFocused && styles.invalidEmail,
)}
disabled={disabled}
id={name}
name={name}
onBlur={this.handleBlur}
onChange={onChange}
onFocus={this.handleFocus}
placeholder={message}
tabIndex={tabIndex}
type="email"
value={value}
/>
)}
</FormattedMessage>
</div>
);
}
}
InputEmail.defaultProps = {
autoFocus: false,
className: '',
deactivateErrorHighlight: false,
disabled: false,
error: false,
onBlur: () => {},
onFocus: () => {},
placeholder: 'app.utils.placeholder.defaultMessage',
style: {},
tabIndex: '0',
};
InputEmail.propTypes = {
autoFocus: PropTypes.bool,
className: PropTypes.string,
deactivateErrorHighlight: PropTypes.bool,
disabled: PropTypes.bool,
error: PropTypes.bool,
onBlur: PropTypes.func,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
name: PropTypes.string.isRequired,
placeholder: PropTypes.string,
style: PropTypes.object,
tabIndex: PropTypes.string,
value: PropTypes.string.isRequired,
};
export default InputEmail;

View File

@ -0,0 +1,71 @@
.addonEmail {
width: 3.4rem;
height: 3.4rem;
margin-top: .9rem;
padding-left: 0.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;
-webkit-font-smoothing: antialiased;
&:after {
content: '@';
display: inline-table;
color: #B3B5B9;
font-size: 16px;
font-weight: 900;
font-family: Lato;
}
& + input {
border-left: 0px !important;
}
}
.inputEmail {
min-width: 200px;
margin-bottom: 1rem;
font-size: 1.3rem;
> 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;
box-shadow: 0px 1px 1px rgba(104, 118, 142, 0.05);
&:focus {
border-color: #78caff;
}
}
& + span {
border-color: #E3E9F3;
}
}
.errorAddon {
border: 1px solid #ff203c!important;
border-right: none!important;
}
.addonFocus {
border-color: #78caff;
border-right: 0;
}
.invalidEmail {
border-color: #ff203c !important;
border-left: 0;
}

View File

@ -0,0 +1,257 @@
/**
*
* InputEmailWithErrors
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { includes, isEmpty, isFunction, mapKeys, reject } from 'lodash';
import cn from 'classnames';
// Design
import Label from 'components/Label';
import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors';
import InputEmail from 'components/InputEmail';
import styles from './styles.scss';
class InputEmailWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
state = { errors: [], hasInitialValue: false };
componentDidMount() {
const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) {
this.setState({ hasInitialValue: true });
}
// Display input error if it already has some
if (!isEmpty(errors)) {
this.setState({ errors });
}
}
componentWillReceiveProps(nextProps) {
// Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set
const errors = isEmpty(nextProps.errors) ? [] : nextProps.errors;
this.setState({ errors });
}
}
/**
* Set the errors depending on the validations given to the input
* @param {Object} target
*/
handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value);
this.setState({ errors, hasInitialValue: true });
}
}
render() {
const {
autoFocus,
deactivateErrorHighlight,
disabled,
errorsClassName,
errorsStyle,
inputClassName,
inputDescription,
inputDescriptionClassName,
inputDescriptionStyle,
inputStyle,
label,
labelClassName,
labelStyle,
name,
noErrorsDescription,
onBlur,
onChange,
onFocus,
placeholder,
style,
tabIndex,
value,
} = this.props;
const handleBlur = isFunction(onBlur) ? onBlur : this.handleBlur;
let spacer = !isEmpty(inputDescription) ? <div className={styles.spacer} /> : <div />;
if (!noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = <div />;
}
return (
<div className={cn(
styles.container,
this.props.customBootstrapClass,
!isEmpty(this.props.className) && this.props.className,
)}
style={style}
>
<Label
className={labelClassName}
htmlFor={name}
message={label}
style={labelStyle}
/>
<InputEmail
autoFocus={autoFocus}
className={inputClassName}
disabled={disabled}
deactivateErrorHighlight={deactivateErrorHighlight}
error={!isEmpty(this.state.errors)}
name={name}
onBlur={handleBlur}
onChange={onChange}
onFocus={onFocus}
placeholder={placeholder}
style={inputStyle}
tabIndex={tabIndex}
value={value}
/>
<InputDescription
className={inputDescriptionClassName}
message={inputDescription}
style={inputDescriptionStyle}
/>
<InputErrors
className={errorsClassName}
errors={!noErrorsDescription && this.state.errors || []}
style={errorsStyle}
/>
{spacer}
</div>
);
}
validate = (value) => {
const emailRegex = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength': {
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
}
case 'minLength': {
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (!emailRegex.test(value)) {
errors.push({ id: 'components.Input.error.validation.email' });
}
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
}
InputEmailWithErrors.defaultProps = {
autoFocus: false,
className: '',
customBootstrapClass: 'col-md-6',
deactivateErrorHighlight: false,
didCheckErrors: false,
disabled: false,
onBlur: false,
onFocus: () => {},
errors: [],
errorsClassName: '',
errorsStyle: {},
inputClassName: '',
inputDescription: '',
inputDescriptionClassName: '',
inputDescriptionStyle: {},
inputStyle: {},
label: '',
labelClassName: '',
labelStyle: {},
noErrorsDescription: false,
placeholder: 'app.utils.placeholder.defaultMessage',
style: {},
tabIndex: '0',
validations: {},
};
InputEmailWithErrors.propTypes = {
autoFocus: PropTypes.bool,
className: PropTypes.string,
customBootstrapClass: PropTypes.string,
deactivateErrorHighlight: PropTypes.bool,
didCheckErrors: PropTypes.bool,
disabled: PropTypes.bool,
errors: PropTypes.array,
errorsClassName: PropTypes.string,
errorsStyle: PropTypes.object,
inputClassName: PropTypes.string,
inputDescription: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.shape({
id: PropTypes.string,
params: PropTypes.object,
}),
]),
inputDescriptionClassName: PropTypes.string,
inputDescriptionStyle: PropTypes.object,
inputStyle: PropTypes.object,
label: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.shape({
id: PropTypes.string,
params: PropTypes.object,
}),
]),
labelClassName: PropTypes.string,
labelStyle: PropTypes.object,
name: PropTypes.string.isRequired,
noErrorsDescription: PropTypes.bool,
onBlur: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.func,
]),
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
placeholder: PropTypes.string,
style: PropTypes.object,
tabIndex: PropTypes.string,
validations: PropTypes.object,
value: PropTypes.string.isRequired,
};
export default InputEmailWithErrors;

View File

@ -0,0 +1,9 @@
.container {
min-width: 200px;
margin-bottom: 1.5rem;
font-size: 1.3rem;
}
.spacer {
height: .5rem;
}

View File

@ -52,17 +52,23 @@ class InputNumberWithErrors extends React.Component { // eslint-disable-line rea
render() { render() {
const { const {
autoFocus, autoFocus,
className,
customBootstrapClass,
deactivateErrorHighlight, deactivateErrorHighlight,
disabled, disabled,
errorsClassName, errorsClassName,
errorsStyle, errorsStyle,
inputClassName, inputClassName,
inputDescription,
inputDescriptionClassName, inputDescriptionClassName,
inputDescriptionStyle, inputDescriptionStyle,
inputStyle, inputStyle,
label,
labelClassName, labelClassName,
labelStyle, labelStyle,
name, name,
noErrorsDescription,
onBlur,
onChange, onChange,
onFocus, onFocus,
placeholder, placeholder,
@ -70,20 +76,26 @@ class InputNumberWithErrors extends React.Component { // eslint-disable-line rea
tabIndex, tabIndex,
value, value,
} = this.props; } = this.props;
const handleBlur = isFunction(this.props.onBlur) ? this.props.onBlur : this.handleBlur; const handleBlur = isFunction(onBlur) ? onBlur : this.handleBlur;
let spacer = !isEmpty(inputDescription) ? <div className={styles.spacer} /> : <div />;
if (!noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = <div />;
}
return ( return (
<div className={cn( <div className={cn(
styles.container, styles.container,
this.props.customBootstrapClass, customBootstrapClass,
!isEmpty(this.props.className) && this.props.className, !isEmpty(className) && className,
)} )}
style={style} style={style}
> >
<Label <Label
className={labelClassName} className={labelClassName}
htmlFor={name} htmlFor={name}
message={this.props.label} message={label}
style={labelStyle} style={labelStyle}
/> />
<InputNumber <InputNumber
@ -103,14 +115,15 @@ class InputNumberWithErrors extends React.Component { // eslint-disable-line rea
/> />
<InputDescription <InputDescription
className={inputDescriptionClassName} className={inputDescriptionClassName}
message={this.props.inputDescription} message={inputDescription}
style={inputDescriptionStyle} style={inputDescriptionStyle}
/> />
<InputErrors <InputErrors
className={errorsClassName} className={errorsClassName}
errors={this.state.errors} errors={!noErrorsDescription && this.state.errors || []}
style={errorsStyle} style={errorsStyle}
/> />
{spacer}
</div> </div>
); );
} }
@ -178,6 +191,7 @@ InputNumberWithErrors.defaultProps = {
label: '', label: '',
labelClassName: '', labelClassName: '',
labelStyle: {}, labelStyle: {},
noErrorsDescription: false,
placeholder: 'app.utils.placeholder.defaultMessage', placeholder: 'app.utils.placeholder.defaultMessage',
style: {}, style: {},
tabIndex: '0', tabIndex: '0',
@ -217,6 +231,7 @@ InputNumberWithErrors.propTypes = {
labelClassName: PropTypes.string, labelClassName: PropTypes.string,
labelStyle: PropTypes.object, labelStyle: PropTypes.object,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
noErrorsDescription: PropTypes.bool,
onBlur: PropTypes.oneOfType([ onBlur: PropTypes.oneOfType([
PropTypes.bool, PropTypes.bool,
PropTypes.func, PropTypes.func,

View File

@ -3,3 +3,7 @@
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
font-size: 1.3rem; font-size: 1.3rem;
} }
.spacer {
height: .5rem;
}

View File

@ -0,0 +1,104 @@
/**
*
* InputPassword
*
*/
import React, { Fragment } from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import { isEmpty } from 'lodash';
import cn from 'classnames';
import styles from './styles.scss';
class InputPassword extends React.Component {
state = { showPassword: false };
handleClick = () => this.setState({ showPassword: !this.state.showPassword });
render() {
const {
autoFocus,
className,
deactivateErrorHighlight,
disabled,
error,
name,
onBlur,
onChange,
onFocus,
placeholder,
style,
tabIndex,
value,
} = this.props;
const eyeColor = this.state.showPassword ? { color: 'black' } : { color: '#9EA7B8' };
return (
<Fragment>
<FormattedMessage id={placeholder} defaultMessage={placeholder}>
{(message) => (
<input
autoFocus={autoFocus}
className={cn(
styles.inputPassword,
'form-control',
!deactivateErrorHighlight && error && 'is-invalid',
!isEmpty(className)&& className,
)}
disabled={disabled}
id={name}
name={name}
onBlur={onBlur}
onChange={onChange}
onFocus={onFocus}
placeholder={message}
style={style}
tabIndex={tabIndex}
type={!this.state.showPassword && 'password' || 'text'}
value={value}
/>
)}
</FormattedMessage>
<div className={styles.iconEyeWrapper}>
<div className={styles.iconEyeSubWrapper} onClick={this.handleClick} style={eyeColor}>
<i className="fa fa-eye" />
</div>
</div>
</Fragment>
);
}
}
InputPassword.defaultProps = {
autoFocus: false,
className: '',
deactivateErrorHighlight: false,
disabled: false,
error: false,
onBlur: () => {},
onFocus: () => {},
placeholder: 'app.utils.placeholder.defaultMessage',
style: {},
tabIndex: '0',
};
InputPassword.propTypes = {
autoFocus: PropTypes.bool,
className: PropTypes.string,
deactivateErrorHighlight: PropTypes.bool,
disabled: PropTypes.bool,
error: PropTypes.bool,
name: PropTypes.string.isRequired,
onBlur: PropTypes.func,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
placeholder: PropTypes.string,
style: PropTypes.object,
tabIndex: PropTypes.string,
value: PropTypes.string.isRequired,
};
export default InputPassword;

View File

@ -0,0 +1,26 @@
.inputPassword {
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;
box-shadow: 0px 1px 1px rgba(104, 118, 142, 0.05);
}
.iconEyeSubWrapper {
position: absolute;
top: -2.6rem;
right: 2.7rem;
color: #9EA7B8;
&:hover {
color: black!important;
}
}
.iconEyeWrapper {
position: relative;
}

View File

@ -0,0 +1,240 @@
/**
*
* InputPasswordWithErrors
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { includes, isEmpty, isFunction, mapKeys, reject } from 'lodash';
import cn from 'classnames';
// Design
import Label from 'components/Label';
import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors';
import InputPassword from 'components/InputPassword';
import styles from './styles.scss';
class InputPasswordWithErrors extends React.Component {
state = { errors: [], hasInitialValue: false };
componentDidMount() {
const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) {
this.setState({ hasInitialValue: true });
}
// Display input error if it already has some
if (!isEmpty(errors)) {
this.setState({ errors });
}
}
componentWillReceiveProps(nextProps) {
// Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set
const errors = isEmpty(nextProps.errors) ? [] : nextProps.errors;
this.setState({ errors });
}
}
/**
* Set the errors depending on the validations given to the input
* @param {Object} target
*/
handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value);
this.setState({ errors, hasInitialValue: true });
}
}
render() {
const {
autoFocus,
deactivateErrorHighlight,
disabled,
errorsClassName,
errorsStyle,
inputClassName,
inputDescriptionClassName,
inputDescriptionStyle,
inputStyle,
labelClassName,
labelStyle,
name,
onChange,
onFocus,
placeholder,
style,
tabIndex,
value,
} = this.props;
const handleBlur = isFunction(this.props.onBlur) ? this.props.onBlur : this.handleBlur;
return (
<div className={cn(
styles.container,
this.props.customBootstrapClass,
!isEmpty(this.props.className) && this.props.className,
)}
style={style}
>
<Label
className={labelClassName}
htmlFor={name}
message={this.props.label}
style={labelStyle}
/>
<InputPassword
autoFocus={autoFocus}
className={inputClassName}
disabled={disabled}
deactivateErrorHighlight={deactivateErrorHighlight}
error={!isEmpty(this.state.errors)}
name={name}
onBlur={handleBlur}
onChange={onChange}
onFocus={onFocus}
placeholder={placeholder}
style={inputStyle}
tabIndex={tabIndex}
value={value}
/>
<InputDescription
className={inputDescriptionClassName}
message={this.props.inputDescription}
style={inputDescriptionStyle}
/>
<InputErrors
className={errorsClassName}
errors={this.state.errors}
style={errorsStyle}
/>
</div>
);
}
validate = (value) => {
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength': {
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
}
case 'minLength': {
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
}
InputPasswordWithErrors.defaultProps = {
autoFocus: false,
className: '',
customBootstrapClass: 'col-md-6',
deactivateErrorHighlight: false,
didCheckErrors: false,
disabled: false,
onBlur: false,
onFocus: () => {},
errors: [],
errorsClassName: '',
errorsStyle: {},
inputClassName: '',
inputDescription: '',
inputDescriptionClassName: '',
inputDescriptionStyle: {},
inputStyle: {},
label: '',
labelClassName: '',
labelStyle: {},
placeholder: 'app.utils.placeholder.defaultMessage',
style: {},
tabIndex: '0',
validations: {},
};
InputPasswordWithErrors.propTypes = {
autoFocus: PropTypes.bool,
className: PropTypes.string,
customBootstrapClass: PropTypes.string,
deactivateErrorHighlight: PropTypes.bool,
didCheckErrors: PropTypes.bool,
disabled: PropTypes.bool,
errors: PropTypes.array,
errorsClassName: PropTypes.string,
errorsStyle: PropTypes.object,
inputClassName: PropTypes.string,
inputDescription: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.shape({
id: PropTypes.string,
params: PropTypes.object,
}),
]),
inputDescriptionClassName: PropTypes.string,
inputDescriptionStyle: PropTypes.object,
inputStyle: PropTypes.object,
label: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.shape({
id: PropTypes.string,
params: PropTypes.object,
}),
]),
labelClassName: PropTypes.string,
labelStyle: PropTypes.object,
name: PropTypes.string.isRequired,
onBlur: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.func,
]),
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
placeholder: PropTypes.string,
style: PropTypes.object,
tabIndex: PropTypes.string,
validations: PropTypes.object,
value: PropTypes.string.isRequired,
};
export default InputPasswordWithErrors;

View File

@ -0,0 +1,5 @@
.container {
min-width: 200px;
margin-bottom: 1.5rem;
font-size: 1.3rem;
}

View File

@ -0,0 +1,77 @@
/**
*
* InputSelect
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { isEmpty, map } from 'lodash';
import cn from 'classnames';
// Design
import SelectOption from 'components/SelectOption';
import styles from './styles.scss';
function InputSelect(props) {
return (
<select
autoFocus={props.autoFocus}
className={cn(
styles.inputSelect,
'form-control',
!props.deactivateErrorHighlight && props.error && 'is-invalid',
!isEmpty(props.className) && props.className,
)}
disabled={props.disabled}
id={props.name}
name={props.name}
onBlur={props.onBlur}
onChange={props.onChange}
onFocus={props.onFocus}
style={props.style}
tabIndex={props.tabIndex}
value={props.value}
>
{map(props.selectOptions, (option, key) => <SelectOption key={key} {...option} />)}
</select>
);
}
InputSelect.defaultProps = {
autoFocus: false,
className: '',
deactivateErrorHighlight: false,
disabled: false,
error: false,
onBlur: () => {},
onFocus: () => {},
style: {},
tabIndex: '0',
};
InputSelect.propTypes = {
autoFocus: PropTypes.bool,
className: PropTypes.string,
deactivateErrorHighlight: PropTypes.bool,
disabled: PropTypes.bool,
error: PropTypes.bool,
name: PropTypes.string.isRequired,
onBlur: PropTypes.func,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
selectOptions: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string,
params: PropTypes.object,
value: PropTypes.string.isRequired,
}).isRequired,
).isRequired,
style: PropTypes.object,
tabIndex: PropTypes.string,
value: PropTypes.string.isRequired,
};
export default InputSelect;

View File

@ -0,0 +1,17 @@
.inputSelect {
height: 3.4rem !important;
margin-top: .9rem;
padding-top: 0rem;
padding-left: 1rem;
background-position: right -1px center;
background-repeat: no-repeat;
background-image: url('../../assets/images/background_input.svg');
border: 1px solid #E3E9F3;
border-radius: 0.25rem;
line-height: 3.2rem;
font-size: 1.3rem;
font-family: 'Lato' !important;
-moz-appearance: none;
-webkit-appearance: none;
box-shadow: 0px 1px 1px rgba(104, 118, 142, 0.05);
}

View File

@ -0,0 +1,186 @@
/**
*
* InputSelectWithErrors;
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { includes, isEmpty, isFunction, mapKeys, reject } from 'lodash';
import cn from 'classnames';
// Design
import Label from 'components/Label';
import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors';
import InputSelect from 'components/InputSelect'
import styles from './styles.scss';
class InputSelectWithErrors extends React.Component {
state = { errors: [] };
componentDidMount() {
const { errors } = this.props;
// Display input error if it already has some
if (!isEmpty(errors)) {
this.setState({ errors });
}
}
componentWillReceiveProps(nextProps) {
// Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set
const errors = isEmpty(nextProps.errors) ? [] : nextProps.errors;
this.setState({ errors });
}
}
render() {
const {
autoFocus,
className,
customBootstrapClass,
deactivateErrorHighlight,
disabled,
errors,
errorsClassName,
errorsStyle,
inputClassName,
inputDescription,
inputDescriptionClassName,
inputDescriptionStyle,
inputStyle,
label,
labelClassName,
labelStyle,
name,
onBlur,
onChange,
onFocus,
selectOptions,
style,
tabIndex,
value,
} = this.props;
return (
<div className={cn(
styles.container,
customBootstrapClass,
!isEmpty(className) && className,
)}
style={style}
>
<Label
className={labelClassName}
htmlFor={name}
message={label}
style={labelStyle}
/>
<InputSelect
autoFocus={autoFocus}
className={inputClassName}
deactivateErrorHighlight={deactivateErrorHighlight}
disabled={disabled}
error={!isEmpty(this.state.errors)}
name={name}
onBlur={onBlur}
onChange={onChange}
onFocus={onFocus}
selectOptions={selectOptions}
style={inputStyle}
tabIndex={tabIndex}
value={value}
/>
<InputDescription
className={inputDescriptionClassName}
message={inputDescription}
style={inputDescriptionStyle}
/>
<InputErrors
className={errorsClassName}
errors={this.state.errors}
style={errorsStyle}
/>
</div>
);
}
}
InputSelectWithErrors.defaultProps = {
autoFocus: false,
className: '',
customBootstrapClass: 'col-md-6',
deactivateErrorHighlight: false,
didCheckErrors: false,
disabled: false,
errors: [],
errorsClassName: '',
errorsStyle: {},
inputClassName: '',
inputDescription: '',
inputDescriptionClassName: '',
inputDescriptionStyle: {},
inputStyle: {},
label: '',
labelClassName: '',
labelStyle: {},
onBlur: () => {},
onFocus: () => {},
selectOptions: [],
style: {},
tabIndex: '0',
};
InputSelectWithErrors.propTypes = {
autoFocus: PropTypes.bool,
className: PropTypes.string,
customBootstrapClass: PropTypes.string,
deactivateErrorHighlight: PropTypes.bool,
didCheckErrors: PropTypes.bool,
disabled: PropTypes.bool,
errors: PropTypes.array,
errorsClassName: PropTypes.string,
errorsStyle: PropTypes.object,
inputClassName: PropTypes.string,
inputDescription: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.shape({
id: PropTypes.string,
params: PropTypes.object,
}),
]),
inputDescriptionClassName: PropTypes.string,
inputDescriptionStyle: PropTypes.object,
inputStyle: PropTypes.object,
label: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.shape({
id: PropTypes.string,
params: PropTypes.object,
}),
]),
labelClassName: PropTypes.string,
labelStyle: PropTypes.object,
name: PropTypes.string.isRequired,
onBlur: PropTypes.func,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
selectOptions: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string,
params: PropTypes.object,
value: PropTypes.string.isRequired,
}).isRequired,
),
style: PropTypes.object,
tabIndex: PropTypes.string,
value: PropTypes.string.isRequired,
};
export default InputSelectWithErrors;

View File

@ -0,0 +1,5 @@
.container {
min-width: 200px;
margin-bottom: 1.5rem;
font-size: 1.3rem;
}

View File

@ -52,17 +52,23 @@ class InputTextAreaWithErrors extends React.Component { // eslint-disable-line r
render() { render() {
const { const {
autoFocus, autoFocus,
className,
customBootstrapClass,
deactivateErrorHighlight, deactivateErrorHighlight,
disabled, disabled,
errorsClassName, errorsClassName,
errorsStyle, errorsStyle,
inputClassName, inputClassName,
inputDescription,
inputDescriptionClassName, inputDescriptionClassName,
inputDescriptionStyle, inputDescriptionStyle,
inputStyle, inputStyle,
label,
labelClassName, labelClassName,
labelStyle, labelStyle,
name, name,
noErrorsDescription,
onBlur,
onChange, onChange,
onFocus, onFocus,
placeholder, placeholder,
@ -70,20 +76,26 @@ class InputTextAreaWithErrors extends React.Component { // eslint-disable-line r
tabIndex, tabIndex,
value, value,
} = this.props; } = this.props;
const handleBlur = isFunction(this.props.onBlur) ? this.props.onBlur : this.handleBlur; const handleBlur = isFunction(onBlur) ? onBlur : this.handleBlur;
let spacer = !isEmpty(inputDescription) ? <div className={styles.spacer} /> : <div />;
if (!noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = <div />;
}
return ( return (
<div className={cn( <div className={cn(
styles.container, styles.container,
this.props.customBootstrapClass, customBootstrapClass,
!isEmpty(this.props.className) && this.props.className, !isEmpty(className) && className,
)} )}
style={style} style={style}
> >
<Label <Label
className={labelClassName} className={labelClassName}
htmlFor={name} htmlFor={name}
message={this.props.label} message={label}
style={labelStyle} style={labelStyle}
/> />
<InputTextArea <InputTextArea
@ -103,14 +115,15 @@ class InputTextAreaWithErrors extends React.Component { // eslint-disable-line r
/> />
<InputDescription <InputDescription
className={inputDescriptionClassName} className={inputDescriptionClassName}
message={this.props.inputDescription} message={inputDescription}
style={inputDescriptionStyle} style={inputDescriptionStyle}
/> />
<InputErrors <InputErrors
className={errorsClassName} className={errorsClassName}
errors={this.state.errors} errors={!noErrorsDescription && this.state.errors || []}
style={errorsStyle} style={errorsStyle}
/> />
{spacer}
</div> </div>
); );
} }
@ -165,8 +178,6 @@ InputTextAreaWithErrors.defaultProps = {
deactivateErrorHighlight: false, deactivateErrorHighlight: false,
didCheckErrors: false, didCheckErrors: false,
disabled: false, disabled: false,
onBlur: false,
onFocus: () => {},
errors: [], errors: [],
errorsClassName: '', errorsClassName: '',
errorsStyle: {}, errorsStyle: {},
@ -178,6 +189,9 @@ InputTextAreaWithErrors.defaultProps = {
label: '', label: '',
labelClassName: '', labelClassName: '',
labelStyle: {}, labelStyle: {},
noErrorsDescription: false,
onBlur: false,
onFocus: () => {},
placeholder: 'app.utils.placeholder.defaultMessage', placeholder: 'app.utils.placeholder.defaultMessage',
style: {}, style: {},
tabIndex: '0', tabIndex: '0',
@ -217,6 +231,7 @@ InputTextAreaWithErrors.propTypes = {
labelClassName: PropTypes.string, labelClassName: PropTypes.string,
labelStyle: PropTypes.object, labelStyle: PropTypes.object,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
noErrorsDescription: PropTypes.bool,
onBlur: PropTypes.oneOfType([ onBlur: PropTypes.oneOfType([
PropTypes.bool, PropTypes.bool,
PropTypes.func, PropTypes.func,

View File

@ -52,17 +52,23 @@ class InputTextWithErrors extends React.Component { // eslint-disable-line react
render() { render() {
const { const {
autoFocus, autoFocus,
className,
customBootstrapClass,
deactivateErrorHighlight, deactivateErrorHighlight,
disabled, disabled,
errorsClassName, errorsClassName,
errorsStyle, errorsStyle,
inputClassName, inputClassName,
inputDescription,
inputDescriptionClassName, inputDescriptionClassName,
inputDescriptionStyle, inputDescriptionStyle,
inputStyle, inputStyle,
label,
labelClassName, labelClassName,
labelStyle, labelStyle,
name, name,
noErrorsDescription,
onBlur,
onChange, onChange,
onFocus, onFocus,
placeholder, placeholder,
@ -70,20 +76,26 @@ class InputTextWithErrors extends React.Component { // eslint-disable-line react
tabIndex, tabIndex,
value, value,
} = this.props; } = this.props;
const handleBlur = isFunction(this.props.onBlur) ? this.props.onBlur : this.handleBlur; const handleBlur = isFunction(onBlur) ? onBlur : this.handleBlur;
let spacer = !isEmpty(inputDescription) ? <div className={styles.spacer} /> : <div />;
if (!noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = <div />;
}
return ( return (
<div className={cn( <div className={cn(
styles.container, styles.container,
this.props.customBootstrapClass, customBootstrapClass,
!isEmpty(this.props.className) && this.props.className, !isEmpty(className) && className,
)} )}
style={style} style={style}
> >
<Label <Label
className={labelClassName} className={labelClassName}
htmlFor={name} htmlFor={name}
message={this.props.label} message={label}
style={labelStyle} style={labelStyle}
/> />
<InputText <InputText
@ -103,14 +115,15 @@ class InputTextWithErrors extends React.Component { // eslint-disable-line react
/> />
<InputDescription <InputDescription
className={inputDescriptionClassName} className={inputDescriptionClassName}
message={this.props.inputDescription} message={inputDescription}
style={inputDescriptionStyle} style={inputDescriptionStyle}
/> />
<InputErrors <InputErrors
className={errorsClassName} className={errorsClassName}
errors={this.state.errors} errors={!noErrorsDescription && this.state.errors || []}
style={errorsStyle} style={errorsStyle}
/> />
{spacer}
</div> </div>
); );
} }
@ -178,6 +191,7 @@ InputTextWithErrors.defaultProps = {
label: '', label: '',
labelClassName: '', labelClassName: '',
labelStyle: {}, labelStyle: {},
noErrorsDescription: false,
placeholder: 'app.utils.placeholder.defaultMessage', placeholder: 'app.utils.placeholder.defaultMessage',
style: {}, style: {},
tabIndex: '0', tabIndex: '0',
@ -217,6 +231,7 @@ InputTextWithErrors.propTypes = {
labelClassName: PropTypes.string, labelClassName: PropTypes.string,
labelStyle: PropTypes.object, labelStyle: PropTypes.object,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
noErrorsDescription: PropTypes.bool,
onBlur: PropTypes.oneOfType([ onBlur: PropTypes.oneOfType([
PropTypes.bool, PropTypes.bool,
PropTypes.func, PropTypes.func,

View File

@ -3,3 +3,7 @@
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
font-size: 1.3rem; font-size: 1.3rem;
} }
.spacer {
height: .5rem;
}

View File

@ -54,12 +54,19 @@ class InputToggleWithErrors extends React.Component {
labelClassName, labelClassName,
labelStyle, labelStyle,
name, name,
noErrorsDescription,
onChange, onChange,
style, style,
tabIndex, tabIndex,
value, value,
} = this.props; } = this.props;
let spacer = !isEmpty(inputDescription) ? <div className={styles.spacer} /> : <div />;
if (!noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = <div />;
}
return ( return (
<div className={cn( <div className={cn(
styles.container, styles.container,
@ -95,9 +102,10 @@ class InputToggleWithErrors extends React.Component {
/> />
<InputErrors <InputErrors
className={errorsClassName} className={errorsClassName}
errors={this.state.errors} errors={!noErrorsDescription && this.state.errors || []}
style={errorsStyle} style={errorsStyle}
/> />
{spacer}
</div> </div>
); );
} }
@ -121,6 +129,7 @@ InputToggleWithErrors.defaultProps = {
label: '', label: '',
labelClassName: '', labelClassName: '',
labelStyle: {}, labelStyle: {},
noErrorsDescription: false,
style: {}, style: {},
tabIndex: '0', tabIndex: '0',
value: true, value: true,
@ -161,6 +170,7 @@ InputToggleWithErrors.propTypes = {
labelClassName: PropTypes.string, labelClassName: PropTypes.string,
labelStyle: PropTypes.object, labelStyle: PropTypes.object,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
noErrorsDescription: PropTypes.bool,
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
style: PropTypes.object, style: PropTypes.object,
tabIndex: PropTypes.string, tabIndex: PropTypes.string,

View File

@ -7,3 +7,7 @@
margin-bottom: 0 !important; margin-bottom: 0 !important;
font-weight: 500 !important; font-weight: 500 !important;
} }
.spacer {
height: .5rem;
}

View File

@ -8,7 +8,10 @@ import PropTypes from 'prop-types';
// Design // Design
import InputCheckboxWithErrors from 'components/InputCheckboxWithErrors'; import InputCheckboxWithErrors from 'components/InputCheckboxWithErrors';
import InputEmailWithErrors from 'components/InputEmailWithErrors';
import InputNumberWithErrors from 'components/InputNumberWithErrors'; import InputNumberWithErrors from 'components/InputNumberWithErrors';
import InputSelectWithErrors from 'components/InputSelectWithErrors';
import InputPasswordWithErrors from 'components/InputPasswordWithErrors';
import InputTextAreaWithErrors from 'components/InputTextAreaWithErrors'; import InputTextAreaWithErrors from 'components/InputTextAreaWithErrors';
import InputTextWithErrors from 'components/InputTextWithErrors'; import InputTextWithErrors from 'components/InputTextWithErrors';
import InputToggleWithErrors from 'components/InputToggleWithErrors'; import InputToggleWithErrors from 'components/InputToggleWithErrors';
@ -17,7 +20,10 @@ const DefaultInputError = ({ type }) => <div>Your input type: <b>{type}</b> does
const inputs = { const inputs = {
checkbox: InputCheckboxWithErrors, checkbox: InputCheckboxWithErrors,
email: InputEmailWithErrors,
number: InputNumberWithErrors, number: InputNumberWithErrors,
password: InputPasswordWithErrors,
select: InputSelectWithErrors,
string: InputTextWithErrors, string: InputTextWithErrors,
text: InputTextWithErrors, text: InputTextWithErrors,
textarea: InputTextAreaWithErrors, textarea: InputTextAreaWithErrors,
@ -37,7 +43,10 @@ InputsIndex.propTypes = {
export default InputsIndex; export default InputsIndex;
export { export {
InputCheckboxWithErrors, InputCheckboxWithErrors,
InputEmailWithErrors,
InputNumberWithErrors, InputNumberWithErrors,
InputPasswordWithErrors,
InputSelectWithErrors,
InputTextWithErrors, InputTextWithErrors,
InputTextAreaWithErrors, InputTextAreaWithErrors,
InputToggleWithErrors, InputToggleWithErrors,

View File

@ -0,0 +1,49 @@
/**
*
* SelectOption
*
*/
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { isEmpty } from 'lodash';
import PropTypes from 'prop-types';
function SelectOption({ id, name, params, value }) {
const messageId = generateMessageId(id, name, value);
return (
<FormattedMessage id={messageId} defaultMessage={messageId} values={params}>
{(message) => <option value={value}>{message}</option>}
</FormattedMessage>
);
}
function generateMessageId(id, name, value) {
if (!isEmpty(id)) {
return id;
}
if (!isEmpty(name)) {
return name;
}
// NOTE: Some plugins uses name to set i18n
return value;
}
SelectOption.defaultProps = {
id: '',
name: '',
params: {},
value: 'app.utils.SelectOption.defaultMessage'
};
SelectOption.propTypes = {
id: PropTypes.string,
name: PropTypes.string,
params: PropTypes.object,
value: PropTypes.string,
};
export default SelectOption;

View File

@ -8,7 +8,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { get } from 'lodash'; import { get } from 'lodash';
import Input from 'components/Input'; import Input from 'components/InputsIndex';
import styles from './styles.scss'; import styles from './styles.scss';
@ -18,13 +18,12 @@ class EditForm extends React.Component { // eslint-disable-line react/prefer-sta
<div className={styles.editForm}> <div className={styles.editForm}>
<div className="row"> <div className="row">
<Input <Input
label="users-permissions.EditForm.inputToggle.label.email" label={{ id: 'users-permissions.EditForm.inputToggle.label.email' }}
inputDescription="users-permissions.EditForm.inputToggle.description.email" inputDescription={{ id: 'users-permissions.EditForm.inputToggle.description.email' }}
name="unique_email" name="unique_email"
onChange={this.props.onChange} onChange={this.props.onChange}
type="toggle" type="toggle"
value={get(this.props.values, 'unique_email')} value={get(this.props.values, 'unique_email')}
validations={{}}
/> />
</div> </div>
<div className={styles.separator} /> <div className={styles.separator} />
@ -56,13 +55,12 @@ class EditForm extends React.Component { // eslint-disable-line react/prefer-sta
*/} */}
<div className="row"> <div className="row">
<Input <Input
label="users-permissions.EditForm.inputToggle.label.sign-up" label={{ id: 'users-permissions.EditForm.inputToggle.label.sign-up' }}
inputDescription="users-permissions.EditForm.inputToggle.description.sign-up" inputDescription={{ id: 'users-permissions.EditForm.inputToggle.description.sign-up' }}
name="allow_register" name="allow_register"
onChange={this.props.onChange} onChange={this.props.onChange}
type="toggle" type="toggle"
value={get(this.props.values, 'allow_register')} value={get(this.props.values, 'allow_register')}
validations={{}}
/> />
</div> </div>
</div> </div>

View File

@ -26,7 +26,7 @@ import {
// Translations // Translations
import en from 'translations/en.json'; import en from 'translations/en.json';
import Input from 'components/Input'; import Input from 'components/InputsIndex';
import styles from './styles.scss'; import styles from './styles.scss';
@ -102,8 +102,8 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
return ( return (
<div className={`row ${styles.providerDisabled}`}> <div className={`row ${styles.providerDisabled}`}>
<Input <Input
inputDescription="users-permissions.PopUpForm.Providers.enabled.description" inputDescription={{ id: 'users-permissions.PopUpForm.Providers.enabled.description' }}
label="users-permissions.PopUpForm.Providers.enabled.label" label={{ id: 'users-permissions.PopUpForm.Providers.enabled.label' }}
name={`${dataToEdit}.enabled`} name={`${dataToEdit}.enabled`}
onChange={this.handleChange} onChange={this.handleChange}
type="toggle" type="toggle"
@ -120,7 +120,7 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
didCheckErrors={this.props.didCheckErrors} didCheckErrors={this.props.didCheckErrors}
errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])} errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])}
key={value} key={value}
label={`users-permissions.PopUpForm.Providers.${ includes(value, 'callback') || includes(value, 'redirect_uri') ? 'redirectURL.front-end' : value}.label`} label={{ id: `users-permissions.PopUpForm.Providers.${ includes(value, 'callback') || includes(value, 'redirect_uri') ? 'redirectURL.front-end' : value}.label` }}
name={`${dataToEdit}.${value}`} name={`${dataToEdit}.${value}`}
onFocus={includes(value, 'callback') || includes(value, 'redirect_uri') ? this.handleFocus : () => {}} onFocus={includes(value, 'callback') || includes(value, 'redirect_uri') ? this.handleFocus : () => {}}
onBlur={includes(value, 'callback') || includes(value, 'redirect_uri') ? this.handleBlur : false} onBlur={includes(value, 'callback') || includes(value, 'redirect_uri') ? this.handleBlur : false}
@ -134,7 +134,7 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
<Input <Input
customBootstrapClass="col-md-12" customBootstrapClass="col-md-12"
disabled disabled
label={`users-permissions.PopUpForm.Providers.${dataToEdit}.providerConfig.redirectURL`} label={{ id: `users-permissions.PopUpForm.Providers.${dataToEdit}.providerConfig.redirectURL` }}
name="noName" name="noName"
type="text" type="text"
onChange={() => {}} onChange={() => {}}
@ -146,6 +146,14 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
); );
} }
const params = {
link: (
<a href="https://github.com/strapi/strapi/blob/master/packages/strapi-plugin-users-permissions/docs/email-templates.md" target="_blank">
<FormattedMessage id="users-permissions.PopUpForm.Email.link.documentation" />
</a>
),
};
return ( return (
<div className="row"> <div className="row">
{map(take(form, 3), (value, key) => ( {map(take(form, 3), (value, key) => (
@ -154,7 +162,7 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
key={value} key={value}
didCheckErrors={this.props.didCheckErrors} didCheckErrors={this.props.didCheckErrors}
errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])} errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])}
label={`users-permissions.PopUpForm.Email.${value}.label`} label={{ id: `users-permissions.PopUpForm.Email.${value}.label` }}
name={`${dataToEdit}.${value}`} name={`${dataToEdit}.${value}`}
onChange={this.props.onChange} onChange={this.props.onChange}
placeholder={`users-permissions.PopUpForm.Email.${value}.placeholder`} placeholder={`users-permissions.PopUpForm.Email.${value}.placeholder`}
@ -170,15 +178,18 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
customBootstrapClass="col-md-12" customBootstrapClass="col-md-12"
didCheckErrors={this.props.didCheckErrors} didCheckErrors={this.props.didCheckErrors}
errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])} errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])}
label={`users-permissions.PopUpForm.Email.${value}.label`} label={{ id: `users-permissions.PopUpForm.Email.${value}.label` }}
name={`${dataToEdit}.${value}`} name={`${dataToEdit}.${value}`}
inputDescription={includes(value, 'object') ? 'users-permissions.PopUpForm.Email.email_templates.inputDescription' : ''} inputDescription={{
linkContent={includes(value, 'object') ? { link: 'https://github.com/strapi/strapi/blob/master/packages/strapi-plugin-users-permissions/docs/email-templates.md', description: 'users-permissions.PopUpForm.Email.link.documentation' } : {}} id: includes(value, 'object') ? 'users-permissions.PopUpForm.Email.email_templates.inputDescription' : '',
params,
}}
onChange={this.props.onChange} onChange={this.props.onChange}
placeholder={`users-permissions.PopUpForm.Email.${this.props.dataToEdit}.${value}.placeholder`} placeholder={`users-permissions.PopUpForm.Email.${this.props.dataToEdit}.${value}.placeholder`}
type={includes(value, 'object') ? 'text' : 'textarea'} type={includes(value, 'object') ? 'text' : 'textarea'}
validations={{ required: true }} validations={{ required: true }}
value={get(values, value)} value={get(values, value)}
inputStyle={!includes(value, 'object') ? { height: '16rem' } : {}}
/> />
))} ))}
</div> </div>

View File

@ -168,6 +168,6 @@
"PopUpForm.Providers.twitter.providerConfig.redirectURL": "The redirect URL to add in your Twitter application configurations", "PopUpForm.Providers.twitter.providerConfig.redirectURL": "The redirect URL to add in your Twitter application configurations",
"PopUpForm.Providers.callback.placeholder": "TEXT", "PopUpForm.Providers.callback.placeholder": "TEXT",
"PopUpForm.Email.email_templates.inputDescription": "Don't know how to set variables", "PopUpForm.Email.email_templates.inputDescription": "Don't know how to set variables, {link}",
"PopUpForm.Email.link.documentation": "check out our documentation." "PopUpForm.Email.link.documentation": "check out our documentation."
} }

View File

@ -167,6 +167,6 @@
"PopUpForm.Providers.twitter.providerConfig.redirectURL": "L'URL de redirection à ajouter dans les configurations Twitter de votre application", "PopUpForm.Providers.twitter.providerConfig.redirectURL": "L'URL de redirection à ajouter dans les configurations Twitter de votre application",
"PopUpForm.Providers.callback.placeholder": "TEXT", "PopUpForm.Providers.callback.placeholder": "TEXT",
"PopUpForm.Email.email_templates.inputDescription": "Regardez la documentation des variables", "PopUpForm.Email.email_templates.inputDescription": "Regardez la documentation des variables, {link}",
"PopUpForm.Email.link.documentation": "afin de templeter vos emails" "PopUpForm.Email.link.documentation": "afin de templeter vos emails"
} }