From 12c41251c17c86d3d40bba83a7e7b174870bc3f1 Mon Sep 17 00:00:00 2001 From: Ben Wheeler <wheeler.benjamin@gmail.com> Date: Sat, 10 Aug 2019 09:55:59 -0400 Subject: [PATCH] Add formik checkbox component, Show password checkbox --- .../formik-forms/formik-checkbox.jsx | 84 +++++++++++++++++++ .../formik-forms/formik-checkbox.scss | 39 +++++++++ src/components/formik-forms/formik-forms.scss | 3 + .../formik-forms/formik-radio-button.jsx | 2 + .../formik-forms/formik-radio-button.scss | 1 - src/components/join-flow/join-flow-steps.scss | 4 + src/components/join-flow/username-step.jsx | 29 ++++--- 7 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 src/components/formik-forms/formik-checkbox.jsx create mode 100644 src/components/formik-forms/formik-checkbox.scss create mode 100644 src/components/formik-forms/formik-forms.scss diff --git a/src/components/formik-forms/formik-checkbox.jsx b/src/components/formik-forms/formik-checkbox.jsx new file mode 100644 index 000000000..6c9d3bd3c --- /dev/null +++ b/src/components/formik-forms/formik-checkbox.jsx @@ -0,0 +1,84 @@ +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); +import {Field} from 'formik'; + +require('./formik-checkbox.scss'); +require('./formik-forms.scss'); +require('../forms/row.scss'); + +const FormikCheckboxSubComponent = ({ + className, + field, + id, + label, + ...props +}) => ( + <div className="checkbox"> + <input + checked={field.value} + className={classNames( + 'formik-checkbox', + className + )} + id={id} + name={field.name} + type="checkbox" + value={field.value} + onBlur={field.onBlur} /* eslint-disable-line react/jsx-handler-names */ + onChange={field.onChange} /* eslint-disable-line react/jsx-handler-names */ + {...props} + /> + {label && ( + <label + className={classNames( + 'formik-label', + 'formik-checkbox-label' + )} + htmlFor={id} + > + {label} + </label> + )} + </div> +); + +FormikCheckboxSubComponent.propTypes = { + className: PropTypes.string, + field: PropTypes.shape({ + name: PropTypes.string, + onBlur: PropTypes.function, + onChange: PropTypes.function, + value: PropTypes.bool + }), + id: PropTypes.string, + label: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) +}; + + +const FormikCheckbox = ({ + className, + id, + label, + name, + ...props +}) => ( + <Field + className={className} + component={FormikCheckboxSubComponent} + id={id} + label={label} + name={name} + {...props} + /> +); + +FormikCheckbox.propTypes = { + className: PropTypes.string, + id: PropTypes.string, + label: PropTypes.string, + name: PropTypes.string +}; + +module.exports = FormikCheckbox; diff --git a/src/components/formik-forms/formik-checkbox.scss b/src/components/formik-forms/formik-checkbox.scss new file mode 100644 index 000000000..66c302587 --- /dev/null +++ b/src/components/formik-forms/formik-checkbox.scss @@ -0,0 +1,39 @@ +@import "../../colors"; + +.formik-checkbox-label { + font-weight: 300; +} + +input[type="checkbox"].formik-checkbox { + display: block; + float: left; + margin-right: .625rem; + border: 1px solid $active-dark-gray; + border-radius: 3px; + width: 1.25rem; + height: 1.25rem; + appearance: none; + + &:focus:checked { + transition: all .5s ease; + outline: none; + box-shadow: 0 0 0 .25rem $ui-blue-25percent; + } + + &:focus:not(:checked) { + outline: none; + } + + &:checked { + background-color: $ui-blue; + text-align: center; + text-indent: .125rem; + line-height: 1.25rem; + font-size: .75rem; + + &:after { + color: $type-white; + content: "\2714"; + } + } +} diff --git a/src/components/formik-forms/formik-forms.scss b/src/components/formik-forms/formik-forms.scss new file mode 100644 index 000000000..a084812cc --- /dev/null +++ b/src/components/formik-forms/formik-forms.scss @@ -0,0 +1,3 @@ +.formik-label { + font-weight: 500; +} diff --git a/src/components/formik-forms/formik-radio-button.jsx b/src/components/formik-forms/formik-radio-button.jsx index d714ed31a..70b27fb9b 100644 --- a/src/components/formik-forms/formik-radio-button.jsx +++ b/src/components/formik-forms/formik-radio-button.jsx @@ -5,6 +5,7 @@ import {Field} from 'formik'; const FormikInput = require('./formik-input.jsx'); +require('./formik-forms.scss'); require('./formik-radio-button.scss'); require('../forms/row.scss'); @@ -34,6 +35,7 @@ const FormikRadioButtonSubComponent = ({ {label && ( <label className={classNames( + 'formik-label', 'formik-radio-label', labelClassName )} diff --git a/src/components/formik-forms/formik-radio-button.scss b/src/components/formik-forms/formik-radio-button.scss index 9fb103a74..c178cf630 100644 --- a/src/components/formik-forms/formik-radio-button.scss +++ b/src/components/formik-forms/formik-radio-button.scss @@ -1,7 +1,6 @@ @import "../../colors"; .formik-radio-label { - font-weight: 300; margin-left: 1rem; } diff --git a/src/components/join-flow/join-flow-steps.scss b/src/components/join-flow/join-flow-steps.scss index 06ff7b4e3..ce124b89e 100644 --- a/src/components/join-flow/join-flow-steps.scss +++ b/src/components/join-flow/join-flow-steps.scss @@ -13,6 +13,10 @@ } } +.join-flow-password-confirm { + margin-bottom: .6875rem; +} + .join-flow-input-tall { height: 3rem; } diff --git a/src/components/join-flow/username-step.jsx b/src/components/join-flow/username-step.jsx index 9d5199787..33092f57c 100644 --- a/src/components/join-flow/username-step.jsx +++ b/src/components/join-flow/username-step.jsx @@ -7,6 +7,7 @@ const {injectIntl, intlShape} = require('react-intl'); const validate = require('../../lib/validate'); const FormikInput = require('../../components/formik-forms/formik-input.jsx'); +const FormikCheckbox = require('../../components/formik-forms/formik-checkbox.jsx'); const JoinFlowStep = require('./join-flow-step.jsx'); require('./join-flow-steps.scss'); @@ -26,9 +27,6 @@ class UsernameStep extends React.Component { 'validateUsernameIfPresent', 'validateForm' ]); - this.state = { - showPassword: false - }; } handleChangeShowPassword () { this.setState({showPassword: !this.state.showPassword}); @@ -88,6 +86,7 @@ class UsernameStep extends React.Component { // called after all validations pass with no errors handleValidSubmit (formData, formikBag) { formikBag.setSubmitting(false); // formik makes us do this ourselves + delete formData.showPassword; this.props.onNextStep(formData); } render () { @@ -96,7 +95,8 @@ class UsernameStep extends React.Component { initialValues={{ username: '', password: '', - passwordConfirm: '' + passwordConfirm: '', + showPassword: false }} validate={this.validateForm} validateOnBlur={false} @@ -154,7 +154,7 @@ class UsernameStep extends React.Component { error={errors.password} id="password" name="password" - type={this.state.showPassword ? 'text' : 'password'} + type={values.showPassword ? 'text' : 'password'} /* eslint-disable react/jsx-no-bind */ validate={password => this.validatePasswordIfPresent(password, values.username)} validationClassName="validation-full-width-input" @@ -167,12 +167,14 @@ class UsernameStep extends React.Component { /> <FormikInput className={classNames( - 'join-flow-input' + 'join-flow-input', + 'join-flow-password-confirm', + {fail: errors.passwordConfirm} )} error={errors.passwordConfirm} id="passwordConfirm" name="passwordConfirm" - type={this.state.showPassword ? 'text' : 'password'} + type={values.showPassword ? 'text' : 'password'} /* eslint-disable react/jsx-no-bind */ validate={() => this.validatePasswordConfirmIfPresent(values.password, @@ -189,14 +191,11 @@ class UsernameStep extends React.Component { /* eslint-enable react/jsx-no-bind */ /> <div className="join-flow-input-title"> - <div - onClick={this.handleChangeShowPassword} - > - {/* TODO: should localize 'Hide password' if we use that */} - {this.state.showPassword ? 'Hide password' : ( - this.props.intl.formatMessage({id: 'registration.showPassword'}) - )} - </div> + <FormikCheckbox + id="showPassword" + label={this.props.intl.formatMessage({id: 'registration.showPassword'})} + name="showPassword" + /> </div> </div> </div>