Merge pull request #3144 from benjiwheeler/join-flow-add-birth-date-step

Join flow add birth date step
This commit is contained in:
Benjamin Wheeler 2019-07-22 14:18:53 -04:00 committed by GitHub
commit 4ae69e1b49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 181 additions and 9 deletions

View file

@ -24,10 +24,9 @@ const FormikSelect = ({
</option> </option>
)); ));
return ( return (
<div className="col-sm-9 row"> <div className="select">
<Field <Field
className={classNames( className={classNames(
'select',
className className
)} )}
component="select" component="select"

View file

@ -0,0 +1,143 @@
const bindAll = require('lodash.bindall');
const classNames = require('classnames');
const React = require('react');
const PropTypes = require('prop-types');
import {Formik} from 'formik';
const {injectIntl, intlShape} = require('react-intl');
const FormikSelect = require('../../components/formik-forms/formik-select.jsx');
const JoinFlowStep = require('./join-flow-step.jsx');
require('./join-flow-steps.scss');
const getBirthMonthOptions = intl => ([
{value: 'null', label: intl.formatMessage({id: 'general.month'})},
{value: '1', label: intl.formatMessage({id: 'general.monthJanuary'})},
{value: '2', label: intl.formatMessage({id: 'general.monthFebruary'})},
{value: '3', label: intl.formatMessage({id: 'general.monthMarch'})},
{value: '4', label: intl.formatMessage({id: 'general.monthApril'})},
{value: '5', label: intl.formatMessage({id: 'general.monthMay'})},
{value: '6', label: intl.formatMessage({id: 'general.monthJune'})},
{value: '7', label: intl.formatMessage({id: 'general.monthJuly'})},
{value: '8', label: intl.formatMessage({id: 'general.monthAugust'})},
{value: '9', label: intl.formatMessage({id: 'general.monthSeptember'})},
{value: '10', label: intl.formatMessage({id: 'general.monthOctober'})},
{value: '11', label: intl.formatMessage({id: 'general.monthNovember'})},
{value: '12', label: intl.formatMessage({id: 'general.monthDecember'})}
]);
const getBirthYearOptions = intl => {
const curYearRaw = (new Date()).getYear();
const curYear = curYearRaw + 1900;
// including both 1900 and current year, there are (curYearRaw + 1) options.
const numYearOptions = curYearRaw + 1;
const birthYearOptions = Array(numYearOptions).fill()
.map((defaultVal, i) => (
{value: String(curYear - i), label: String(curYear - i)}
));
birthYearOptions.unshift({
value: 'null',
label: intl.formatMessage({id: 'general.year'})
});
return birthYearOptions;
};
class BirthDateStep extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'handleValidSubmit',
'validateForm',
'validateSelect'
]);
}
validateSelect (selection) {
if (selection === 'null') {
return this.props.intl.formatMessage({id: 'form.validationRequired'});
}
return null;
}
validateForm () {
return {};
}
handleValidSubmit (formData, formikBag) {
formikBag.setSubmitting(false);
this.props.onNextStep(formData);
}
render () {
const birthMonthOptions = getBirthMonthOptions(this.props.intl);
const birthYearOptions = getBirthYearOptions(this.props.intl);
return (
<Formik
initialValues={{
birth_month: 'null',
birth_year: 'null'
}}
validate={this.validateForm}
validateOnBlur={false}
validateOnChange={false}
onSubmit={this.handleValidSubmit}
>
{props => {
const {
errors,
handleSubmit,
isSubmitting
} = props;
return (
<JoinFlowStep
description={this.props.intl.formatMessage({id: 'registration.birthDateStepDescription'})}
headerImgSrc="/images/hoc/getting-started.jpg"
title={this.props.intl.formatMessage({id: 'general.joinScratch'})}
waiting={isSubmitting}
onSubmit={handleSubmit}
>
<div
className={classNames(
'col-sm-9',
'row',
'birthdate-select-row'
)}
>
<FormikSelect
className={classNames(
'join-flow-select',
'join-flow-select-month',
{fail: errors.birth_month}
)}
error={errors.birth_month}
id="birth_month"
name="birth_month"
options={birthMonthOptions}
validate={this.validateSelect}
validationClassName="validation-full-width-input"
/>
<FormikSelect
className={classNames(
'join-flow-select',
{fail: errors.birth_year}
)}
error={errors.birth_year}
id="birth_year"
name="birth_year"
options={birthYearOptions}
validate={this.validateSelect}
validationClassName="validation-full-width-input"
/>
</div>
</JoinFlowStep>
);
}}
</Formik>
);
}
}
BirthDateStep.propTypes = {
intl: intlShape,
onNextStep: PropTypes.func
};
const IntlBirthDateStep = injectIntl(BirthDateStep);
module.exports = IntlBirthDateStep;

View file

@ -10,11 +10,17 @@ require('./join-flow-step.scss');
const JoinFlowStep = ({ const JoinFlowStep = ({
children, children,
description, description,
headerImgSrc,
onSubmit, onSubmit,
title, title,
waiting waiting
}) => ( }) => (
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
{headerImgSrc && (
<div className="join-flow-header-image">
<img src={headerImgSrc} />
</div>
)}
<div> <div>
<ModalInnerContent className="join-flow-inner-content"> <ModalInnerContent className="join-flow-inner-content">
{title && ( {title && (
@ -38,6 +44,7 @@ const JoinFlowStep = ({
JoinFlowStep.propTypes = { JoinFlowStep.propTypes = {
children: PropTypes.node, children: PropTypes.node,
description: PropTypes.string, description: PropTypes.string,
headerImgSrc: PropTypes.string,
onSubmit: PropTypes.func, onSubmit: PropTypes.func,
title: PropTypes.string, title: PropTypes.string,
waiting: PropTypes.bool waiting: PropTypes.bool

View file

@ -21,3 +21,13 @@
padding: 2.3125rem 0 2.5rem; padding: 2.3125rem 0 2.5rem;
font-size: .875rem; font-size: .875rem;
} }
/* overflow will only work if this class is set on parent of img, not img itself */
.join-flow-header-image {
width: 100%;
height: 7.5rem;
overflow: hidden;
margin: 0;
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
}

View file

@ -22,6 +22,19 @@
transform: translate(21.5625rem, 0); transform: translate(21.5625rem, 0);
} }
select.join-flow-select {
width: 9.125rem;
}
.join-flow-select-month {
margin-right: .5rem;
}
.join-flow-password-section { .join-flow-password-section {
margin-top: 1.125rem; margin-top: 1.125rem;
} }
.birthdate-select-row {
display: flex;
margin: 0 auto;
}

View file

@ -7,7 +7,8 @@ const injectIntl = require('../../lib/intl.jsx').injectIntl;
const intlShape = require('../../lib/intl.jsx').intlShape; const intlShape = require('../../lib/intl.jsx').intlShape;
const Progression = require('../progression/progression.jsx'); const Progression = require('../progression/progression.jsx');
const JoinFlowSteps = require('./join-flow-steps.jsx'); const UsernameStep = require('./username-step.jsx');
const BirthDateStep = require('./birthdate-step.jsx');
/* /*
eslint-disable react/prefer-stateless-function, react/no-unused-prop-types, no-useless-constructor eslint-disable react/prefer-stateless-function, react/no-unused-prop-types, no-useless-constructor
@ -35,9 +36,8 @@ class JoinFlow extends React.Component {
return ( return (
<React.Fragment> <React.Fragment>
<Progression step={this.state.step}> <Progression step={this.state.step}>
<JoinFlowSteps.UsernameStep <UsernameStep onNextStep={this.handleAdvanceStep} />
onNextStep={this.handleAdvanceStep} <BirthDateStep onNextStep={this.handleAdvanceStep} />
/>
</Progression> </Progression>
</React.Fragment> </React.Fragment>
); );

View file

@ -1,4 +1,3 @@
/* eslint-disable react/no-multi-comp */
const bindAll = require('lodash.bindall'); const bindAll = require('lodash.bindall');
const classNames = require('classnames'); const classNames = require('classnames');
const React = require('react'); const React = require('react');
@ -190,11 +189,12 @@ class UsernameStep extends React.Component {
); );
} }
} }
/* eslint-enable */
UsernameStep.propTypes = { UsernameStep.propTypes = {
intl: intlShape, intl: intlShape,
onNextStep: PropTypes.func onNextStep: PropTypes.func
}; };
module.exports.UsernameStep = injectIntl(UsernameStep); const IntlUsernameStep = injectIntl(UsernameStep);
module.exports = IntlUsernameStep;