Merge pull request #235 from sharetribe/auth-page-styles

Login and Signup pages
This commit is contained in:
Kimmo Puputti 2017-06-21 20:44:09 +03:00 committed by GitHub
commit 6f85193dad
11 changed files with 138 additions and 85 deletions

View file

@ -1,3 +1,5 @@
@import '../../marketplace.css';
.root {
&::after {
content: ".";
@ -10,9 +12,7 @@
.tab {
float: left;
margin-left: 1rem;
font-size: 20px;
letter-spacing: -0.5px;
margin-left: 24px;
&:first-child {
margin-left: 0;
@ -20,12 +20,13 @@
}
.link {
text-decoration: underline;
@apply --marketplaceH3FontStyles;
color: var(--matterColor);
}
.selectedLink {
font-weight: bold;
text-decoration: none;
color: var(--matterColorDark);
text-decoration: underline;
}
.disabled {

View file

@ -1,29 +1,17 @@
@import '../../marketplace.css';
.root {
display: flex;
flex-direction: column;
flex: 1;
padding: 34px 24px 98px 24px;
}
.form {
margin-top: 39px;
}
.error {
margin-top: 24px;
margin-left: 20px;
margin-right: 20px;
}
.tabs {
margin-bottom: 1rem;
}
.tab {
float: left;
margin-left: 1rem;
font-size: 20px;
letter-spacing: -0.5px;
text-decoration: none;
&:first-child {
margin-left: 0;
}
}
.activeTab {
font-weight: bold;
color: var(--failColor);
}

View file

@ -3,8 +3,7 @@ import { compose } from 'redux';
import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import classNames from 'classnames';
import { PageLayout, NamedRedirect, NamedLink } from '../../components';
import { PageLayout, NamedRedirect, TabNav } from '../../components';
import { LoginForm, SignupForm } from '../../containers';
import { login, authenticationInProgress, signup } from '../../ducks/Auth.duck';
@ -60,39 +59,53 @@ export const AuthenticationPageComponent = props => {
/* eslint-enable no-console */
const loginErrorMessage = (
<div style={{ color: 'red' }}>
<div className={css.error}>
<FormattedMessage id="AuthenticationPage.loginFailed" />
</div>
);
const signupErrorMessage = (
<div style={{ color: 'red' }}>
<div className={css.error}>
{isEmailTakenApiError(signupError)
? <FormattedMessage id="AuthenticationPage.signupFailedEmailAlreadyTaken" />
: <FormattedMessage id="AuthenticationPage.signupFailed" />}
</div>
);
const loginLinkClasses = classNames(css.tab, isLogin ? css.activeTab : null);
const signupLinkClasses = classNames(css.tab, !isLogin ? css.activeTab : null);
const fromState = { state: from ? { from } : null };
const tabs = [
{
text: intl.formatMessage({
id: 'AuthenticationPage.signupLinkText',
}),
selected: !isLogin,
linkProps: {
name: 'SignupPage',
to: fromState,
},
},
{
text: intl.formatMessage({
id: 'AuthenticationPage.loginLinkText',
}),
selected: isLogin,
linkProps: {
name: 'LoginPage',
to: fromState,
},
},
];
return (
<PageLayout title={title}>
<div className={css.root}>
<nav className={css.tabs}>
<NamedLink className={signupLinkClasses} name="SignupPage" to={fromState}>
<FormattedMessage id="AuthenticationPage.signupLinkText" />
</NamedLink>
<NamedLink className={loginLinkClasses} name="LoginPage" to={fromState}>
<FormattedMessage id="AuthenticationPage.loginLinkText" />
</NamedLink>
</nav>
<TabNav tabs={tabs} />
{loginError ? loginErrorMessage : null}
{signupError ? signupErrorMessage : null}
{isLogin
? <LoginForm onSubmit={submitLogin} inProgress={authInProgress} />
: <SignupForm onSubmit={submitSignup} inProgress={authInProgress} />}
? <LoginForm className={css.form} onSubmit={submitLogin} inProgress={authInProgress} />
: <SignupForm className={css.form} onSubmit={submitSignup} inProgress={authInProgress} />}
</div>
</PageLayout>
);

View file

@ -2,36 +2,36 @@ exports[`AuthenticationPageComponent matches snapshot 1`] = `
<Connect(withRouter(PageLayout))
title="AuthenticationPage.loginPageTitle">
<div>
<nav>
<withFlattenedRoutes(withRouter(NamedLink))
className=""
name="SignupPage"
to={
<TabNav
className=""
tabs={
Array [
Object {
"state": Object {
"from": "/protected",
"linkProps": Object {
"name": "SignupPage",
"to": Object {
"state": Object {
"from": "/protected",
},
},
},
}
}>
<FormattedMessage
id="AuthenticationPage.signupLinkText"
values={Object {}} />
</withFlattenedRoutes(withRouter(NamedLink))>
<withFlattenedRoutes(withRouter(NamedLink))
className=""
name="LoginPage"
to={
"selected": false,
"text": "AuthenticationPage.signupLinkText",
},
Object {
"state": Object {
"from": "/protected",
"linkProps": Object {
"name": "LoginPage",
"to": Object {
"state": Object {
"from": "/protected",
},
},
},
}
}>
<FormattedMessage
id="AuthenticationPage.loginLinkText"
values={Object {}} />
</withFlattenedRoutes(withRouter(NamedLink))>
</nav>
"selected": true,
"text": "AuthenticationPage.loginLinkText",
},
]
} />
<ReduxForm
inProgress={false}
onSubmit={[Function]} />

View file

@ -1,4 +1,4 @@
.form {
.root {
display: flex;
flex-direction: column;
flex: 1;
@ -11,6 +11,6 @@
}
.button {
margin-top: 24px;
align-self: stretch;
margin-bottom: 24px;
}

View file

@ -2,18 +2,22 @@ import React, { PropTypes } from 'react';
import { compose } from 'redux';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import { reduxForm, propTypes as formPropTypes } from 'redux-form';
import classNames from 'classnames';
import { Button, TextInputField } from '../../components';
import * as validators from '../../util/validators';
import css from './LoginForm.css';
const LoginFormComponent = props => {
const { form, handleSubmit, submitting, inProgress, intl } = props;
const { rootClassName, className, form, handleSubmit, submitting, inProgress, intl } = props;
// email
const emailLabel = intl.formatMessage({
id: 'LoginForm.emailLabel',
});
const emailPlaceholder = intl.formatMessage({
id: 'LoginForm.emailPlaceholder',
});
const emailRequiredMessage = intl.formatMessage({
id: 'LoginForm.emailRequired',
});
@ -23,20 +27,26 @@ const LoginFormComponent = props => {
const passwordLabel = intl.formatMessage({
id: 'LoginForm.passwordLabel',
});
const passwordPlaceholder = intl.formatMessage({
id: 'LoginForm.passwordPlaceholder',
});
const passwordRequiredMessage = intl.formatMessage({
id: 'LoginForm.passwordRequired',
});
const passwordRequired = validators.required(passwordRequiredMessage);
const classes = classNames(rootClassName || css.root, className);
const submitDisabled = submitting || inProgress;
return (
<form className={css.form} onSubmit={handleSubmit}>
<form className={classes} onSubmit={handleSubmit}>
<div>
<TextInputField
type="email"
name="email"
id={`${form}.email`}
label={emailLabel}
placeholder={emailPlaceholder}
validate={emailRequired}
/>
<TextInputField
@ -45,6 +55,7 @@ const LoginFormComponent = props => {
name="password"
id={`${form}.password`}
label={passwordLabel}
placeholder={passwordPlaceholder}
validate={passwordRequired}
/>
</div>
@ -55,12 +66,18 @@ const LoginFormComponent = props => {
);
};
LoginFormComponent.defaultProps = { inProgress: false };
LoginFormComponent.defaultProps = {
rootClassName: null,
className: null,
inProgress: false,
};
const { bool } = PropTypes;
const { string, bool } = PropTypes;
LoginFormComponent.propTypes = {
...formPropTypes,
rootClassName: string,
className: string,
inProgress: bool,
intl: intlShape.isRequired,
};

View file

@ -1,6 +1,6 @@
exports[`LoginForm matches snapshot 1`] = `
<form
className={undefined}
className=""
onSubmit={[Function]}>
<div>
<div
@ -18,6 +18,7 @@ exports[`LoginForm matches snapshot 1`] = `
onDragStart={[Function]}
onDrop={[Function]}
onFocus={[Function]}
placeholder="john.doe@example.com"
type="email"
value="" />
</div>
@ -36,6 +37,7 @@ exports[`LoginForm matches snapshot 1`] = `
onDragStart={[Function]}
onDrop={[Function]}
onFocus={[Function]}
placeholder="Enter your password..."
type="password"
value="" />
</div>

View file

@ -12,9 +12,12 @@
margin-top: 24px;
}
.firstNameRoot,
.firstNameRoot {
width: calc(34% - 9px);
}
.lastNameRoot {
width: calc(50% - 0.5rem);
width: calc(66% - 9px);
}
.password {
@ -22,6 +25,6 @@
}
.button {
margin-top: 24px;
align-self: stretch;
margin-bottom: 24px;
}

View file

@ -2,18 +2,22 @@ import React, { PropTypes } from 'react';
import { compose } from 'redux';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import { reduxForm, propTypes as formPropTypes } from 'redux-form';
import classNames from 'classnames';
import { Button, TextInputField } from '../../components';
import * as validators from '../../util/validators';
import css from './SignupForm.css';
const SignupFormComponent = props => {
const { form, handleSubmit, submitting, inProgress, intl } = props;
const { rootClassName, className, form, handleSubmit, submitting, inProgress, intl } = props;
// email
const emailLabel = intl.formatMessage({
id: 'SignupForm.emailLabel',
});
const emailPlaceholder = intl.formatMessage({
id: 'SignupForm.emailPlaceholder',
});
const emailRequiredMessage = intl.formatMessage({
id: 'SignupForm.emailRequired',
});
@ -23,6 +27,9 @@ const SignupFormComponent = props => {
const passwordLabel = intl.formatMessage({
id: 'SignupForm.passwordLabel',
});
const passwordPlaceholder = intl.formatMessage({
id: 'SignupForm.passwordPlaceholder',
});
const passwordRequiredMessage = intl.formatMessage({
id: 'SignupForm.passwordRequired',
});
@ -32,6 +39,9 @@ const SignupFormComponent = props => {
const firstNameLabel = intl.formatMessage({
id: 'SignupForm.firstNameLabel',
});
const firstNamePlaceholder = intl.formatMessage({
id: 'SignupForm.firstNamePlaceholder',
});
const firstNameRequiredMessage = intl.formatMessage({
id: 'SignupForm.firstNameRequired',
});
@ -41,20 +51,26 @@ const SignupFormComponent = props => {
const lastNameLabel = intl.formatMessage({
id: 'SignupForm.lastNameLabel',
});
const lastNamePlaceholder = intl.formatMessage({
id: 'SignupForm.lastNamePlaceholder',
});
const lastNameRequiredMessage = intl.formatMessage({
id: 'SignupForm.lastNameRequired',
});
const lastNameRequired = validators.required(lastNameRequiredMessage);
const classes = classNames(rootClassName || css.root, className);
const submitDisabled = submitting || inProgress;
return (
<form className={css.root} onSubmit={handleSubmit}>
<form className={classes} onSubmit={handleSubmit}>
<div>
<TextInputField
type="email"
name="email"
id={`${form}.email`}
label={emailLabel}
placeholder={emailPlaceholder}
validate={emailRequired}
/>
<div className={css.name}>
@ -64,6 +80,7 @@ const SignupFormComponent = props => {
name="firstName"
id={`${form}.firstName`}
label={firstNameLabel}
placeholder={firstNamePlaceholder}
validate={firstNameRequired}
/>
<TextInputField
@ -72,6 +89,7 @@ const SignupFormComponent = props => {
name="lastName"
id={`${form}.lastName`}
label={lastNameLabel}
placeholder={lastNamePlaceholder}
validate={lastNameRequired}
/>
</div>
@ -81,6 +99,7 @@ const SignupFormComponent = props => {
name="password"
id={`${form}.password`}
label={passwordLabel}
placeholder={passwordPlaceholder}
validate={passwordRequired}
/>
</div>

View file

@ -1,6 +1,6 @@
exports[`SignupForm matches snapshot 1`] = `
<form
className={undefined}
className=""
onSubmit={[Function]}>
<div>
<div
@ -18,6 +18,7 @@ exports[`SignupForm matches snapshot 1`] = `
onDragStart={[Function]}
onDrop={[Function]}
onFocus={[Function]}
placeholder="john.doe@example.com"
type="email"
value="" />
</div>
@ -38,6 +39,7 @@ exports[`SignupForm matches snapshot 1`] = `
onDragStart={[Function]}
onDrop={[Function]}
onFocus={[Function]}
placeholder="John"
type="text"
value="" />
</div>
@ -56,6 +58,7 @@ exports[`SignupForm matches snapshot 1`] = `
onDragStart={[Function]}
onDrop={[Function]}
onFocus={[Function]}
placeholder="Doe"
type="text"
value="" />
</div>
@ -75,6 +78,7 @@ exports[`SignupForm matches snapshot 1`] = `
onDragStart={[Function]}
onDrop={[Function]}
onFocus={[Function]}
placeholder="Enter your password..."
type="password"
value="" />
</div>

View file

@ -74,10 +74,12 @@
"ListingPage.noListingData": "Could not find listing data",
"ListingPage.perNight": "/ night",
"LoginForm.emailLabel": "Email",
"LoginForm.emailRequired": "required",
"LoginForm.emailPlaceholder": "john.doe@example.com",
"LoginForm.emailRequired": "This field is required",
"LoginForm.logIn": "Log in",
"LoginForm.passwordLabel": "Password",
"LoginForm.passwordRequired": "required",
"LoginForm.passwordPlaceholder": "Enter your password...",
"LoginForm.passwordRequired": "This field is required",
"Modal.close": "CLOSE",
"Modal.closeModal": "Close modal",
"OrderDetailsPanel.orderAcceptedStatus": "{providerName} accepted the booking.",
@ -143,12 +145,16 @@
"SearchResultsPanel.nextPage": "Next page",
"SearchResultsPanel.previousPage": "Previous page",
"SignupForm.emailLabel": "Email",
"SignupForm.emailPlaceholder": "john.doe@example.com",
"SignupForm.emailRequired": "You need to add an email.",
"SignupForm.firstNameLabel": "First name",
"SignupForm.firstNamePlaceholder": "John",
"SignupForm.firstNameRequired": "You need to add a first name.",
"SignupForm.lastNameLabel": "Last name",
"SignupForm.lastNamePlaceholder": "Doe",
"SignupForm.lastNameRequired": "You need to add a last name.",
"SignupForm.passwordLabel": "Password",
"SignupForm.passwordPlaceholder": "Enter your password...",
"SignupForm.passwordRequired": "You need to add a password.",
"SignupForm.signUp": "Sign up",
"SignupForm.stripeConnectedAccountAgreementLinkText": "Stripe Connected Account Agreement",