refactoring: setup wizard pages with simple architecture.

This commit is contained in:
Ahmed Bouhuolia
2020-10-11 20:35:01 +02:00
parent b98ecb7569
commit e15a48dcdd
29 changed files with 608 additions and 513 deletions

View File

@@ -19,18 +19,15 @@ import Icon from 'components/Icon';
import { If } from 'components';
import withAuthenticationActions from './withAuthenticationActions';
import withOrganizationsActions from 'containers/Organization/withOrganizationActions';
import { compose } from 'utils';
const ERRORS_TYPES = {
INVALID_DETAILS: 'INVALID_DETAILS',
USER_INACTIVE: 'USER_INACTIVE',
};
function Login({
requestLogin,
requestOrganizationsList,
}) {
const { formatMessage } = useIntl();
const history = useHistory();
@@ -105,7 +102,7 @@ function Login({
<div className={'authentication-page__label-section'}>
<h3><T id={'log_in'} /></h3>
<T id={'need_bigcapital_account'} />
<Link to='/register'> <T id={'create_an_account'} /></Link>
<Link to='/auth/register'> <T id={'create_an_account'} /></Link>
</div>
<form onSubmit={handleSubmit} className={'authentication-page__form'}>
@@ -170,5 +167,4 @@ function Login({
export default compose(
withAuthenticationActions,
withOrganizationsActions,
)(Login);

View File

@@ -0,0 +1,284 @@
import React, { useMemo, useState, useCallback } from 'react';
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Row, Col } from 'react-grid-system';
import { Link, useHistory } from 'react-router-dom';
import {
Button,
InputGroup,
Intent,
FormGroup,
Spinner,
} from '@blueprintjs/core';
import { FormattedMessage as T, useIntl } from 'react-intl';
import AppToaster from 'components/AppToaster';
import AuthInsider from 'containers/Authentication/AuthInsider';
import ErrorMessage from 'components/ErrorMessage';
import Icon from 'components/Icon';
import { If } from 'components';
import withAuthenticationActions from 'containers/Authentication/withAuthenticationActions';
import { compose } from 'utils';
function RegisterUserForm({ requestRegister, requestLogin }) {
const { formatMessage } = useIntl();
const history = useHistory();
const [shown, setShown] = useState(false);
const passwordRevealer = useCallback(() => {
setShown(!shown);
}, [shown]);
const ValidationSchema = Yup.object().shape({
first_name: Yup.string()
.required()
.label(formatMessage({ id: 'first_name_' })),
last_name: Yup.string()
.required()
.label(formatMessage({ id: 'last_name_' })),
email: Yup.string()
.email()
.required()
.label(formatMessage({ id: 'email' })),
phone_number: Yup.string()
.matches()
.required()
.label(formatMessage({ id: 'phone_number_' })),
password: Yup.string()
.min(4)
.required()
.label(formatMessage({ id: 'password' })),
});
const initialValues = useMemo(
() => ({
first_name: '',
last_name: '',
email: '',
phone_number: '',
password: '',
}),
[],
);
const {
errors,
touched,
handleSubmit,
getFieldProps,
isSubmitting,
} = useFormik({
enableReinitialize: true,
validationSchema: ValidationSchema,
initialValues: {
...initialValues,
country: 'libya',
},
onSubmit: (values, { setSubmitting, setErrors }) => {
requestRegister(values)
.then((response) => {
requestLogin({
crediential: values.email,
password: values.password,
})
.then(() => {
history.push('/register/subscription');
setSubmitting(false);
})
.catch((errors) => {
AppToaster.show({
message: formatMessage({ id: 'something_wentwrong' }),
intent: Intent.SUCCESS,
});
});
})
.catch((errors) => {
if (errors.some((e) => e.type === 'PHONE_NUMBER_EXISTS')) {
setErrors({
phone_number: formatMessage({
id: 'the_phone_number_already_used_in_another_account',
}),
});
}
if (errors.some((e) => e.type === 'EMAIL_EXISTS')) {
setErrors({
email: formatMessage({
id: 'the_email_already_used_in_another_account',
}),
});
}
setSubmitting(false);
});
},
});
const passwordRevealerTmp = useMemo(
() => (
<span class="password-revealer" onClick={() => passwordRevealer()}>
<If condition={shown}>
<>
<Icon icon="eye-slash" />{' '}
<span class="text">
<T id={'hide'} />
</span>
</>
</If>
<If condition={!shown}>
<>
<Icon icon="eye" />{' '}
<span class="text">
<T id={'show'} />
</span>
</>
</If>
</span>
),
[shown, passwordRevealer],
);
return (
<AuthInsider>
<div className={'register-form'}>
<div className={'authentication-page__label-section'}>
<h3>
<T id={'register_a_new_organization'} />
</h3>
<T id={'you_have_a_bigcapital_account'} />
<Link to="/auth/login">
{' '}
<T id={'login'} />
</Link>
</div>
<form onSubmit={handleSubmit} className={'authentication-page__form'}>
<Row className={'name-section'}>
<Col md={6}>
<FormGroup
label={<T id={'first_name'} />}
intent={
errors.first_name && touched.first_name && Intent.DANGER
}
helperText={
<ErrorMessage name={'first_name'} {...{ errors, touched }} />
}
className={'form-group--first-name'}
>
<InputGroup
intent={
errors.first_name && touched.first_name && Intent.DANGER
}
{...getFieldProps('first_name')}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup
label={<T id={'last_name'} />}
intent={errors.last_name && touched.last_name && Intent.DANGER}
helperText={
<ErrorMessage name={'last_name'} {...{ errors, touched }} />
}
className={'form-group--last-name'}
>
<InputGroup
intent={
errors.last_name && touched.last_name && Intent.DANGER
}
{...getFieldProps('last_name')}
/>
</FormGroup>
</Col>
</Row>
<FormGroup
label={<T id={'phone_number'} />}
intent={
errors.phone_number && touched.phone_number && Intent.DANGER
}
helperText={
<ErrorMessage name={'phone_number'} {...{ errors, touched }} />
}
className={'form-group--phone-number'}
>
<InputGroup
intent={
errors.phone_number && touched.phone_number && Intent.DANGER
}
{...getFieldProps('phone_number')}
/>
</FormGroup>
<FormGroup
label={<T id={'email'} />}
intent={errors.email && touched.email && Intent.DANGER}
helperText={
<ErrorMessage name={'email'} {...{ errors, touched }} />
}
className={'form-group--email'}
>
<InputGroup
intent={errors.email && touched.email && Intent.DANGER}
{...getFieldProps('email')}
/>
</FormGroup>
<FormGroup
label={<T id={'password'} />}
labelInfo={passwordRevealerTmp}
intent={errors.password && touched.password && Intent.DANGER}
helperText={
<ErrorMessage name={'password'} {...{ errors, touched }} />
}
className={'form-group--password has-password-revealer'}
>
<InputGroup
lang={true}
type={shown ? 'text' : 'password'}
intent={errors.password && touched.password && Intent.DANGER}
{...getFieldProps('password')}
/>
</FormGroup>
<div className={'register-form__agreement-section'}>
<p>
<T id={'signing_in_or_creating'} /> <br />
<Link>
<T id={'terms_conditions'} />
</Link>{' '}
<T id={'and'} />
<Link>
{' '}
<T id={'privacy_statement'} />
</Link>
</p>
</div>
<div className={'authentication-page__submit-button-wrap'}>
<Button
className={'btn-register'}
intent={Intent.PRIMARY}
type="submit"
fill={true}
loading={isSubmitting}
>
<T id={'register'} />
</Button>
</div>
</form>
<If condition={isSubmitting}>
<div class="authentication-page__loading-overlay">
<Spinner size={50} />
</div>
</If>
</div>
</AuthInsider>
);
}
export default compose(
withAuthenticationActions,
)(RegisterUserForm);

View File

@@ -1,74 +0,0 @@
import React, { useState, useCallback } from 'react';
import { Icon, If } from 'components';
import { FormattedMessage as T } from 'react-intl';
import withAuthentication from 'containers/Authentication/withAuthentication';
import withAuthenticationActions from 'containers/Authentication/withAuthenticationActions';
import { compose } from 'utils';
function RegisterLeftSection({
requestLogout,
isAuthorized
}) {
const [org] = useState('LibyanSpider');
const onClickLogout = useCallback(() => {
requestLogout();
}, [requestLogout]);
return (
<section className={'register-page__left-section'}>
<div className={'content'}>
<div className={'content-logo'}>
<Icon
icon={'bigcapital'}
width={165}
height={28}
className="bigcapital--alt"
/>
</div>
<h1 className={'content-title'}>
<T id={'register_a_new_organization_now'} />
</h1>
<p className={'content-text'}>
<T id={'you_have_a_bigcapital_account'} />
</p>
<If condition={!!isAuthorized}>
<div className={'content-org'}>
<span>
<T id={'welcome'} />
{org},
</span>
<span>
<a onClick={onClickLogout} href="#"><T id={'sign_out'} /></a>
</span>
</div>
</If>
<div className={'content-contact'}>
<a href={'#!'}>
<p>
<T id={'we_re_here_to_help'} /> {'+21892-791-8381'}
</p>
</a>
<a href={'#!'}>
<p>
<T id={'contact_us_technical_support'} />
</p>
</a>
</div>
</div>
</section>
)
}
export default compose(
withAuthentication(({ isAuthorized }) => ({ isAuthorized })),
withAuthenticationActions,
)(RegisterLeftSection);

View File

@@ -1,418 +0,0 @@
import React, { useMemo, useState, useCallback } from 'react';
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Row, Col } from 'react-grid-system';
import {
Button,
Intent,
FormGroup,
InputGroup,
MenuItem,
Classes,
Position,
} from '@blueprintjs/core';
import moment from 'moment';
import classNames from 'classnames';
import { TimezonePicker } from '@blueprintjs/timezone';
import { FormattedMessage as T, useIntl } from 'react-intl';
import { DateInput } from '@blueprintjs/datetime';
import { momentFormatter, tansformDateValue } from 'utils';
import AppToaster from 'components/AppToaster';
import { ListSelect, ErrorMessage, FieldRequiredHint } from 'components';
import { useHistory } from 'react-router-dom';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import withRegisterOrganizationActions from 'containers/Authentication/withRegisterOrganizationActions';
import { compose, optionsMapToArray } from 'utils';
function RegisterOrganizationForm({ requestSubmitOptions, requestSeedTenant }) {
const { formatMessage } = useIntl();
const [selected, setSelected] = useState();
const history = useHistory();
const baseCurrency = [
{ id: 0, name: 'LYD - Libyan Dinar', value: 'LYD' },
{ id: 1, name: 'USD - American Dollar', value: 'USD' },
];
const languages = [
{ id: 0, name: 'English', value: 'en' },
{ id: 1, name: 'Arabic', value: 'ar' },
];
const fiscalYear = [
{
id: 0,
name: `${formatMessage({ id: 'january' })} - ${formatMessage({
id: 'december',
})}`,
value: 'january',
},
{
id: 1,
name: `${formatMessage({ id: 'february' })} - ${formatMessage({
id: 'january',
})}`,
value: 'february',
},
{
id: 2,
name: `${formatMessage({ id: 'march' })} - ${formatMessage({
id: 'february',
})}`,
value: 'March',
},
{
id: 3,
name: `${formatMessage({ id: 'april' })} - ${formatMessage({
id: 'march',
})}`,
value: 'april',
},
{
id: 4,
name: `${formatMessage({ id: 'may' })} - ${formatMessage({
id: 'april',
})}`,
value: 'may',
},
{
id: 5,
name: `${formatMessage({ id: 'june' })} - ${formatMessage({
id: 'may',
})}`,
value: 'june',
},
{
id: 6,
name: `${formatMessage({ id: 'july' })} - ${formatMessage({
id: 'june',
})}`,
value: 'july',
},
{
id: 7,
name: `${formatMessage({ id: 'august' })} - ${formatMessage({
id: 'july',
})}`,
value: 'August',
},
{
id: 8,
name: `${formatMessage({ id: 'september' })} - ${formatMessage({
id: 'august',
})}`,
value: 'september',
},
{
id: 9,
name: `${formatMessage({ id: 'october' })} - ${formatMessage({
id: 'november',
})}`,
value: 'october',
},
{
id: 10,
name: `${formatMessage({ id: 'november' })} - ${formatMessage({
id: 'october',
})}`,
value: 'november',
},
{
id: 11,
name: `${formatMessage({ id: 'december' })} - ${formatMessage({
id: 'november',
})}`,
value: 'december',
},
];
const ValidationSchema = Yup.object().shape({
name: Yup.string()
.required()
.label(formatMessage({ id: 'organization_name_' })),
date_start: Yup.date()
.required()
.label(formatMessage({ id: 'date_start_' })),
base_currency: Yup.string()
.required()
.label(formatMessage({ id: 'base_currency_' })),
language: Yup.string()
.required()
.label(formatMessage({ id: 'language' })),
fiscal_year: Yup.string()
.required()
.label(formatMessage({ id: 'fiscal_year_' })),
time_zone: Yup.string(),
});
const initialValues = useMemo(
() => ({
name: '',
date_start: moment(new Date()).format('YYYY-MM-DD'),
base_currency: '',
language: '',
fiscal_year: '',
time_zone: '',
}),
[],
);
const {
values,
errors,
touched,
handleSubmit,
setFieldValue,
getFieldProps,
isSubmitting,
} = useFormik({
enableReinitialize: true,
validationSchema: ValidationSchema,
initialValues: {
...initialValues,
},
onSubmit: (values, { setSubmitting, setErrors }) => {
const options = optionsMapToArray(values).map((option) => {
return { key: option.key, ...option, group: 'organization' };
});
requestSubmitOptions({ options })
.then((response) => {
requestSeedTenant().then(() => {
setSubmitting(false);
});
})
.catch((erros) => {
setSubmitting(false);
});
},
});
const onItemsSelect = (filedName) => {
return (filed) => {
setSelected({
...selected,
[filedName]: filed,
});
setFieldValue(filedName, filed.value);
};
};
const filterItems = (query, item, _index, exactMatch) => {
const normalizedTitle = item.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return normalizedTitle.indexOf(normalizedQuery) >= 0;
}
};
const onItemRenderer = (item, { handleClick }) => (
<MenuItem key={item.id} text={item.name} onClick={handleClick} />
);
const handleTimeZoneChange = useCallback(
(time_zone) => {
setFieldValue('time_zone', time_zone);
},
[setFieldValue],
);
const handleDateChange = useCallback(
(date) => {
const formatted = moment(date).format('YYYY-MM-DD');
setFieldValue('date_start', formatted);
},
[setFieldValue],
);
return (
<div className={'register-organizaton-form'}>
<div className={'register-org-title'}>
<h2>
<T id={'let_s_get_started'} />
</h2>
<p>
<T id={'tell_the_system_a_little_bit_about_your_organization'} />
</p>
</div>
<form onClick={handleSubmit}>
<h3>
<T id={'organization_details'} />
</h3>
<FormGroup
label={<T id={'name'} />}
labelInfo={<FieldRequiredHint />}
className={'form-group--name'}
intent={errors.name && touched.name && Intent.DANGER}
helperText={<ErrorMessage {...{ errors, touched }} name={'name'} />}
>
<InputGroup
intent={errors.name && touched.name && Intent.DANGER}
{...getFieldProps('name')}
/>
</FormGroup>
{/* financial starting date */}
<FormGroup
label={<T id={'financial_starting_date'} />}
labelInfo={<FieldRequiredHint />}
intent={errors.date_start && touched.date_start && Intent.DANGER}
helperText={
<ErrorMessage name="date_start" {...{ errors, touched }} />
}
className={classNames('form-group--select-list', Classes.FILL)}
>
<DateInput
{...momentFormatter('MMMM Do YYYY')}
value={tansformDateValue(values.date_start)}
onChange={handleDateChange}
popoverProps={{ position: Position.BOTTOM, minimal: true }}
/>
</FormGroup>
<Row>
{/* base currency */}
<Col width={300}>
<FormGroup
label={<T id={'base_currency'} />}
labelInfo={<FieldRequiredHint />}
className={classNames(
'form-group--base-currency',
'form-group--select-list',
Classes.LOADING,
Classes.FILL,
)}
intent={
errors.base_currency && touched.base_currency && Intent.DANGER
}
helperText={
<ErrorMessage name={'base_currency'} {...{ errors, touched }} />
}
>
<ListSelect
items={baseCurrency}
noResults={<MenuItem disabled={true} text="No results." />}
itemRenderer={onItemRenderer}
popoverProps={{ minimal: true }}
onItemSelect={onItemsSelect('base_currency')}
itemPredicate={filterItems}
selectedItem={values.base_currency}
selectedItemProp={'value'}
// defaultText={<T id={'select_base_currency'} />}
defaultText={'LYD - Libyan Dinar'}
labelProp={'name'}
/>
</FormGroup>
</Col>
{/* language */}
<Col width={300}>
<FormGroup
label={<T id={'language'} />}
labelInfo={<FieldRequiredHint />}
className={classNames(
'form-group--language',
'form-group--select-list',
Classes.FILL,
)}
intent={errors.language && touched.language && Intent.DANGER}
helperText={
<ErrorMessage name={'language'} {...{ errors, touched }} />
}
>
<ListSelect
items={languages}
noResults={<MenuItem disabled={true} text="No results." />}
itemRenderer={onItemRenderer}
popoverProps={{ minimal: true }}
onItemSelect={onItemsSelect('language')}
itemPredicate={filterItems}
selectedItem={values.language}
selectedItemProp={'value'}
defaultText={'English'}
// defaultText={<T id={'select_language'} />}
labelProp={'name'}
/>
</FormGroup>
</Col>
</Row>
{/* fiscal Year */}
<FormGroup
label={<T id={'fiscal_year'} />}
labelInfo={<FieldRequiredHint />}
className={classNames(
'form-group--fiscal_year',
'form-group--select-list',
Classes.FILL,
)}
intent={errors.fiscal_year && touched.fiscal_year && Intent.DANGER}
helperText={
<ErrorMessage name={'fiscal_year'} {...{ errors, touched }} />
}
>
<ListSelect
items={fiscalYear}
noResults={<MenuItem disabled={true} text="No results." />}
itemRenderer={onItemRenderer}
popoverProps={{ minimal: true }}
onItemSelect={onItemsSelect('fiscal_year')}
itemPredicate={filterItems}
selectedItem={values.fiscal_year}
selectedItemProp={'value'}
defaultText={'January - December'}
// defaultText={<T id={'select_fiscal_year'} />}
labelProp={'name'}
/>
</FormGroup>
{/* Time zone */}
<FormGroup
label={<T id={'time_zone'} />}
className={classNames(
'form-group--time-zone',
'form-group--select-list',
Classes.FILL,
)}
intent={errors.time_zone && touched.time_zone && Intent.DANGER}
helperText={
<ErrorMessage {...{ errors, touched }} name={'time_zone'} />
}
>
<TimezonePicker
value={values.time_zone}
onChange={handleTimeZoneChange}
valueDisplayFormat="composite"
showLocalTimezone={true}
placeholder={<T id={'select_time_zone'} />}
/>
</FormGroup>
<p className={'register-org-note'}>
<T
id={
'note_you_can_change_your_preferences_later_in_dashboard_if_needed'
}
/>
</p>
<div className={'register-org-button'}>
<Button
intent={Intent.PRIMARY}
loading={isSubmitting}
type="submit"
// loading={isSubmitting}
>
<T id={'save_continue'} />
</Button>
</div>
</form>
</div>
);
}
export default compose(
withSettingsActions,
withRegisterOrganizationActions,
)(RegisterOrganizationForm);

View File

@@ -1,14 +0,0 @@
import React from 'react';
import RegisterRightSection from './RegisterRightSection';
import RegisterLeftSection from './RegisterLeftSection';
function RegisterWizardPage() {
return (
<div class="register-page">
<RegisterLeftSection />
<RegisterRightSection />
</div>
);
}
export default RegisterWizardPage;

View File

@@ -1,55 +0,0 @@
import React from 'react';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import { Wizard, Steps, Step } from 'react-albus';
import { useHistory } from "react-router-dom";
import RegisterWizardSteps from './RegisterWizardSteps';
import PrivateRoute from 'components/PrivateRoute';
import RegisterUserForm from 'containers/Authentication/Register/RegisterUserForm';
import RegisterSubscriptionForm from 'containers/Authentication/Register/RegisterSubscriptionForm';
import RegisterOrganizationForm from 'containers/Authentication/Register/RegisterOrganizationForm';
export default function RegisterRightSection () {
const history = useHistory();
return (
<section className={'register-page__right-section'}>
<Wizard
basename={'/register'}
history={history}
render={({ step, steps }) => (
<div>
<RegisterWizardSteps currentStep={steps.indexOf(step) + 1} />
<TransitionGroup>
<CSSTransition
key={step.id}
classNames="example"
timeout={{ enter: 500, exit: 500 }}
>
<div class="register-page-form">
<Steps key={step.id} step={step}>
<Step id="user">
<RegisterUserForm />
</Step>
<Step id="subscription">
<PrivateRoute component={RegisterSubscriptionForm} />
</Step>
<Step id="organization">
<PrivateRoute component={RegisterOrganizationForm} />
</Step>
<Step id="congratulations">
<h1 className="text-align-center">Ice King</h1>
</Step>
</Steps>
</div>
</CSSTransition>
</TransitionGroup>
</div>
)} />
</section>
)
}

View File

@@ -1,40 +0,0 @@
import React, { useMemo } from 'react';
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { FormattedMessage as T, useIntl } from 'react-intl';
import { Button, Intent } from '@blueprintjs/core';
import BillingTab from 'containers/Subscriptions/BillingTab';
function RegisterSubscriptionForm({}) {
const ValidationSchema = Yup.object().shape({});
const initialValues = useMemo(() => ({}), []);
const formik = useFormik({
enableReinitialize: true,
validationSchema: ValidationSchema,
initialValues: {
...initialValues,
},
onSubmit: (values, { setSubmitting, setErrors }) => {},
});
return (
<div className={'register-subscription-form'}>
<form className={'billing-form'}>
<BillingTab formik={formik} />
<div className={'subscribe-button'}>
<Button
intent={Intent.PRIMARY}
type="submit"
loading={formik.isSubmitting}
>
<T id={'subscribe'} />
</Button>
</div>
</form>
</div>
);
}
export default RegisterSubscriptionForm;

View File

@@ -1,281 +0,0 @@
import React, { useMemo, useState, useCallback } from 'react';
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Row, Col } from 'react-grid-system';
import { Link, useHistory } from 'react-router-dom';
import {
Button,
InputGroup,
Intent,
FormGroup,
Spinner,
} from '@blueprintjs/core';
import { FormattedMessage as T, useIntl } from 'react-intl';
import AppToaster from 'components/AppToaster';
import ErrorMessage from 'components/ErrorMessage';
import Icon from 'components/Icon';
import { If } from 'components';
import withAuthenticationActions from 'containers/Authentication/withAuthenticationActions';
import { compose } from 'utils';
function RegisterUserForm({ requestRegister, requestLogin }) {
const { formatMessage } = useIntl();
const history = useHistory();
const [shown, setShown] = useState(false);
const passwordRevealer = useCallback(() => {
setShown(!shown);
}, [shown]);
const ValidationSchema = Yup.object().shape({
first_name: Yup.string()
.required()
.label(formatMessage({ id: 'first_name_' })),
last_name: Yup.string()
.required()
.label(formatMessage({ id: 'last_name_' })),
email: Yup.string()
.email()
.required()
.label(formatMessage({ id: 'email' })),
phone_number: Yup.string()
.matches()
.required()
.label(formatMessage({ id: 'phone_number_' })),
password: Yup.string()
.min(4)
.required()
.label(formatMessage({ id: 'password' })),
});
const initialValues = useMemo(
() => ({
first_name: '',
last_name: '',
email: '',
phone_number: '',
password: '',
}),
[],
);
const {
errors,
touched,
handleSubmit,
getFieldProps,
isSubmitting,
} = useFormik({
enableReinitialize: true,
validationSchema: ValidationSchema,
initialValues: {
...initialValues,
country: 'libya',
},
onSubmit: (values, { setSubmitting, setErrors }) => {
requestRegister(values)
.then((response) => {
requestLogin({
crediential: values.email,
password: values.password,
})
.then(() => {
history.push('/register/subscription');
setSubmitting(false);
})
.catch((errors) => {
AppToaster.show({
message: formatMessage({
id: 'something_wentwrong',
}),
intent: Intent.SUCCESS,
});
});
})
.catch((errors) => {
if (errors.some((e) => e.type === 'PHONE_NUMBER_EXISTS')) {
setErrors({
phone_number: formatMessage({
id: 'the_phone_number_already_used_in_another_account',
}),
});
}
if (errors.some((e) => e.type === 'EMAIL_EXISTS')) {
setErrors({
email: formatMessage({
id: 'the_email_already_used_in_another_account',
}),
});
}
setSubmitting(false);
});
},
});
const passwordRevealerTmp = useMemo(
() => (
<span class="password-revealer" onClick={() => passwordRevealer()}>
<If condition={shown}>
<>
<Icon icon="eye-slash" />{' '}
<span class="text">
<T id={'hide'} />
</span>
</>
</If>
<If condition={!shown}>
<>
<Icon icon="eye" />{' '}
<span class="text">
<T id={'show'} />
</span>
</>
</If>
</span>
),
[shown, passwordRevealer],
);
return (
<div className={'register-form'}>
<div className={'authentication-page__label-section'}>
<h3>
<T id={'register_a_new_organization'} />
</h3>
<T id={'you_have_a_bigcapital_account'} />
<Link to="/auth/login">
{' '}
<T id={'login'} />
</Link>
</div>
<form onSubmit={handleSubmit} className={'authentication-page__form'}>
<Row className={'name-section'}>
<Col md={6}>
<FormGroup
label={<T id={'first_name'} />}
intent={
errors.first_name && touched.first_name && Intent.DANGER
}
helperText={
<ErrorMessage name={'first_name'} {...{ errors, touched }} />
}
className={'form-group--first-name'}
>
<InputGroup
intent={
errors.first_name && touched.first_name && Intent.DANGER
}
{...getFieldProps('first_name')}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup
label={<T id={'last_name'} />}
intent={errors.last_name && touched.last_name && Intent.DANGER}
helperText={
<ErrorMessage name={'last_name'} {...{ errors, touched }} />
}
className={'form-group--last-name'}
>
<InputGroup
intent={
errors.last_name && touched.last_name && Intent.DANGER
}
{...getFieldProps('last_name')}
/>
</FormGroup>
</Col>
</Row>
<FormGroup
label={<T id={'phone_number'} />}
intent={
errors.phone_number && touched.phone_number && Intent.DANGER
}
helperText={
<ErrorMessage name={'phone_number'} {...{ errors, touched }} />
}
className={'form-group--phone-number'}
>
<InputGroup
intent={
errors.phone_number && touched.phone_number && Intent.DANGER
}
{...getFieldProps('phone_number')}
/>
</FormGroup>
<FormGroup
label={<T id={'email'} />}
intent={errors.email && touched.email && Intent.DANGER}
helperText={
<ErrorMessage name={'email'} {...{ errors, touched }} />
}
className={'form-group--email'}
>
<InputGroup
intent={errors.email && touched.email && Intent.DANGER}
{...getFieldProps('email')}
/>
</FormGroup>
<FormGroup
label={<T id={'password'} />}
labelInfo={passwordRevealerTmp}
intent={errors.password && touched.password && Intent.DANGER}
helperText={
<ErrorMessage name={'password'} {...{ errors, touched }} />
}
className={'form-group--password has-password-revealer'}
>
<InputGroup
lang={true}
type={shown ? 'text' : 'password'}
intent={errors.password && touched.password && Intent.DANGER}
{...getFieldProps('password')}
/>
</FormGroup>
<div className={'register-form__agreement-section'}>
<p>
<T id={'signing_in_or_creating'} /> <br />
<Link>
<T id={'terms_conditions'} />
</Link>{' '}
<T id={'and'} />
<Link>
{' '}
<T id={'privacy_statement'} />
</Link>
</p>
</div>
<div className={'authentication-page__submit-button-wrap'}>
<Button
className={'btn-register'}
intent={Intent.PRIMARY}
type="submit"
fill={true}
loading={isSubmitting}
>
<T id={'register'} />
</Button>
</div>
</form>
<If condition={isSubmitting}>
<div class="authentication-page__loading-overlay">
<Spinner size={50} />
</div>
</If>
</div>
);
}
export default compose(withAuthenticationActions)(RegisterUserForm);

View File

@@ -1,36 +0,0 @@
import React from 'react';
import classNames from 'classnames';
import { FormattedMessage as T } from 'react-intl';
import { registerWizardSteps } from 'common/registerWizard'
function RegisterWizardStep({
label,
isActive = false
}) {
return (
<li className={classNames({ 'is-active': isActive })}>
<p className={'wizard-info'}><T id={label} /></p>
</li>
);
}
function RegisterWizardSteps({
currentStep = 1,
}) {
return (
<div className={'register-wizard-steps'}>
<div className={'wizard-container'}>
<ul className={'wizard-wrapper'}>
{registerWizardSteps.map((step, index) => (
<RegisterWizardStep
label={step.label}
isActive={(index + 1) <= currentStep}
/>
))}
</ul>
</div>
</div>
);
}
export default RegisterWizardSteps;

View File

@@ -6,6 +6,7 @@ export default (mapState) => {
const mapped = {
isAuthorized: isAuthenticated(state),
user: state.authentication.user,
currentOrganizationId: state.authentication?.tenant?.organization_id,
};
return mapState ? mapState(mapped, state, props) : mapped;
};

View File

@@ -1,12 +0,0 @@
import {
buildTenant,
seedTenant,
} from 'store/organization/organization.actions';
import { connect } from 'react-redux';
const mapDispatchToProps = (dispatch) => ({
requestBuildTenant: (id, token) => dispatch(buildTenant({ id, token })),
requestSeedTenant: (id, token) => dispatch(seedTenant({ id, token })),
});
export default connect(null, mapDispatchToProps);