Adapt sign up plus validation and translations

This commit is contained in:
Chi Vinh Le
2018-08-27 16:49:58 +02:00
parent 39edec79cb
commit 5a26b319d8
8 changed files with 218 additions and 123 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ const SignIn: StatelessComponent<SignInForm> = props => {
<InputLabel>Email Address</InputLabel>
</Localized>
<Localized
id="signIn-emailAddressTextfield"
id="signIn-emailAddressTextField"
attrs={{ placeholder: true }}
>
<TextField
@@ -1,7 +0,0 @@
.root {
}
.subFooter {
padding-top: var(--spacing-unit);
width: 100%;
}
+127 -96
View File
@@ -1,3 +1,4 @@
import { Localized } from "fluent-react/compat";
import * as React from "react";
import { StatelessComponent } from "react";
import { Field, Form } from "react-final-form";
@@ -15,6 +16,7 @@ import {
CallOut,
Flex,
FormField,
HorizontalGutter,
InputDescription,
InputLabel,
TextField,
@@ -23,7 +25,6 @@ import {
} from "talk-ui/components";
import AutoHeightContainer from "../containers/AutoHeightContainer";
import * as styles from "./SignUp.css";
interface FormProps {
email: string;
@@ -43,127 +44,151 @@ const SignUp: StatelessComponent<SignUpForm> = props => {
{({ handleSubmit, submitError }) => (
<form autoComplete="off" onSubmit={handleSubmit}>
<AutoHeightContainer />
<Flex itemGutter="double" direction="column" className={styles.root}>
<Flex direction="column">
<HorizontalGutter size="double">
<Localized id="signUp-signUpToJoinHeader">
<Typography variant="heading1" align="center">
Sign up to join the conversation
</Typography>
{submitError && (
<CallOut color="error" fullWidth>
{submitError}
</CallOut>
)}
<Field
name="email"
validate={composeValidators(required, validateEmail)}
>
{({ input, meta }) => (
<FormField>
</Localized>
{submitError && (
<CallOut color="error" fullWidth>
{submitError}
</CallOut>
)}
<Field
name="email"
validate={composeValidators(required, validateEmail)}
>
{({ input, meta }) => (
<FormField>
<Localized id="signUp-emailAddressLabel">
<InputLabel>Email Address</InputLabel>
</Localized>
<Localized
id="signUp-emailAddressTextField"
attrs={{ placeholder: true }}
>
<TextField
name={input.name}
onChange={input.onChange}
value={input.value}
placeholder="Email Address"
fullWidth
/>
{meta.touched &&
(meta.error || meta.submitError) && (
<ValidationMessage>
{meta.error || meta.submitError}
</ValidationMessage>
)}
</FormField>
)}
</Field>
<Field
name="username"
validate={composeValidators(required, validateUsername)}
>
{({ input, meta }) => (
<FormField>
</Localized>
{meta.touched &&
(meta.error || meta.submitError) && (
<ValidationMessage fullWidth>
{meta.error || meta.submitError}
</ValidationMessage>
)}
</FormField>
)}
</Field>
<Field
name="username"
validate={composeValidators(required, validateUsername)}
>
{({ input, meta }) => (
<FormField>
<Localized id="signUp-usernameLabel">
<InputLabel>Username</InputLabel>
</Localized>
<Localized id="signUp-usernameDescription">
<InputDescription>
A unique identifier displayed on your comments. You may
use _ and .
</InputDescription>
</Localized>
<Localized
id="signUp-usernameTextField"
attrs={{ placeholder: true }}
>
<TextField
name={input.name}
onChange={input.onChange}
value={input.value}
placeholder="Username"
fullWidth
/>
{meta.touched &&
(meta.error || meta.submitError) && (
<ValidationMessage>
{meta.error || meta.submitError}
</ValidationMessage>
)}
</FormField>
)}
</Field>
<Field
name="password"
validate={composeValidators(required, validatePassword)}
>
{({ input, meta }) => (
<FormField>
</Localized>
{meta.touched &&
(meta.error || meta.submitError) && (
<ValidationMessage fullWidth>
{meta.error || meta.submitError}
</ValidationMessage>
)}
</FormField>
)}
</Field>
<Field
name="password"
validate={composeValidators(required, validatePassword)}
>
{({ input, meta }) => (
<FormField>
<Localized id="signUp-passwordLabel">
<InputLabel>Password</InputLabel>
</Localized>
<Localized id="signUp-passwordDescription" $minLength={8}>
<InputDescription>
Must be at least 8 characters
{"Must be at least {$minLength} characters"}
</InputDescription>
</Localized>
<Localized
id="signUp-passwordTextField"
attrs={{ placeholder: true }}
>
<TextField
name={input.name}
onChange={input.onChange}
value={input.value}
placeholder="Password"
type="password"
fullWidth
/>
{meta.touched &&
(meta.error || meta.submitError) && (
<ValidationMessage>
{meta.error || meta.submitError}
</ValidationMessage>
)}
</FormField>
)}
</Field>
<Field
name="confirmPassword"
validate={composeValidators(
required,
validatePassword,
validateEqualPasswords
)}
>
{({ input, meta }) => (
<FormField>
</Localized>
{meta.touched &&
(meta.error || meta.submitError) && (
<ValidationMessage fullWidth>
{meta.error || meta.submitError}
</ValidationMessage>
)}
</FormField>
)}
</Field>
<Field
name="confirmPassword"
validate={composeValidators(required, validateEqualPasswords)}
>
{({ input, meta }) => (
<FormField>
<Localized id="signUp-confirmPasswordLabel">
<InputLabel>Confirm Password</InputLabel>
<InputDescription>
Must be at least 8 characters
</InputDescription>
</Localized>
<Localized
id="signUp-confirmPasswordTextField"
attrs={{ placeholder: true }}
>
<TextField
name={input.name}
onChange={input.onChange}
value={input.value}
placeholder="Confirm Password"
type="password"
fullWidth
/>
{meta.touched &&
(meta.error || meta.submitError) && (
<ValidationMessage>
{meta.error || meta.submitError}
</ValidationMessage>
)}
</FormField>
)}
</Field>
</Flex>
<div>
</Localized>
{meta.touched &&
(meta.error || meta.submitError) && (
<ValidationMessage fullWidth>
{meta.error || meta.submitError}
</ValidationMessage>
)}
</FormField>
)}
</Field>
<Localized id="signUp-signUpAndJoinButton">
<Button
variant="filled"
color="primary"
@@ -173,19 +198,25 @@ const SignUp: StatelessComponent<SignUpForm> = props => {
>
Sign up and join the conversation
</Button>
<Flex itemGutter="half" justifyContent="center">
<Typography>Already have an account?</Typography>
<Button
variant="underlined"
size="small"
color="primary"
onClick={props.onGotoSignIn}
>
Sign In
</Button>
</Flex>
</div>
</Flex>
</Localized>
<Flex justifyContent="center">
<Localized
id="signUp-accountAvailableSignIn"
button={
<Button
variant="underlined"
size="small"
color="primary"
onClick={props.onGotoSignIn}
/>
}
>
<Typography variant="bodyCopy" container={Flex}>
{"Already have an account? <button>Sign In </button>"}
</Typography>
</Localized>
</Flex>
</HorizontalGutter>
</form>
)}
</Form>
@@ -1,12 +1,12 @@
import { mapValues, once } from "lodash";
import { ReactNode } from "react";
import { VALIDATION_REQUIRED, VALIDATION_TOO_SHORT } from "../messages";
import { VALIDATION_REQUIRED } from "../messages";
/**
* ValidationError represents all possible string values
* that is responded by the server.
*/
type ValidationError = "TOO_SHORT";
type ValidationError = "REQUIRED";
/**
* InvalidArgsMap as responded by the server.
@@ -36,7 +36,6 @@ interface BadUserInputExtension {
* Map server `ValidationError` to a translation message.
*/
const validationMap = {
TOO_SHORT: VALIDATION_TOO_SHORT,
REQUIRED: VALIDATION_REQUIRED,
};
+20 -8
View File
@@ -12,9 +12,9 @@ export const VALIDATION_REQUIRED = () => (
</Localized>
);
export const VALIDATION_TOO_SHORT = () => (
export const VALIDATION_TOO_SHORT = (minLength: number) => (
<Localized id="framework-validation-tooShort">
<span>This field is too short.</span>
<span>{"This field must contain at least {$minLength} characters."}</span>
</Localized>
);
@@ -24,15 +24,27 @@ export const INVALID_EMAIL = () => (
</Localized>
);
export const INVALID_USERNAME = () => (
<Localized id="framework-validation-invalidUsername">
<span>Please enter a valid username.</span>
export const INVALID_CHARACTERS = () => (
<Localized id="framework-validation-invalidCharacters">
<span>Invalid characters. Try again.</span>
</Localized>
);
export const INVALID_PASSWORD = () => (
<Localized id="framework-validation-invalidUsername">
<span>Please enter a valid password.</span>
export const USERNAME_TOO_SHORT = (minLength: number) => (
<Localized id="framework-validation-usernameTooShort" $minLength={minLength}>
<span>{"Usernames must contain at least {$minLength} characters."}</span>
</Localized>
);
export const USERNAME_TOO_LONG = (maxLength: number) => (
<Localized id="framework-validation-usernameTooLong" $maxLength={maxLength}>
<span>{"Usernames cannot be longer than {$maxLength} characters."}</span>
</Localized>
);
export const PASSWORD_TOO_SHORT = (minLength: number) => (
<Localized id="framework-validation-passwordTooShort" $minLength={minLength}>
<span>{"Password must contain at least {$minLength} characters."}</span>
</Localized>
);
+34 -7
View File
@@ -1,9 +1,11 @@
import { ReactNode } from "react";
import {
INVALID_CHARACTERS,
INVALID_EMAIL,
INVALID_PASSWORD,
INVALID_USERNAME,
PASSWORD_TOO_SHORT,
PASSWORDS_DO_NOT_MATCH,
USERNAME_TOO_LONG,
USERNAME_TOO_SHORT,
VALIDATION_REQUIRED,
} from "./messages";
@@ -47,19 +49,44 @@ export const validateEmail = createValidator(
);
/**
* validateUsername is a Validator that checks that the value is a valid username.
* validateUsernameCharacters is a Validator that checks that the username only contains valid characters.
*/
export const validateUsername = createValidator(
export const validateUsernameCharacters = createValidator(
v => /^[a-zA-Z0-9_.]+$/.test(v),
INVALID_USERNAME()
INVALID_CHARACTERS()
);
/**
* validateUsernameMinLength is a Validator that checks that the username has a min length of characters
*/
export const validateUsernameMinLength = createValidator(
v => v.length >= 3,
USERNAME_TOO_SHORT(3)
);
/**
* validateUsernameMaxLength is a Validator that checks that the username has a max length of characters
*/
export const validateUsernameMaxLength = createValidator(
v => v.length <= 20,
USERNAME_TOO_LONG(20)
);
/**
* validateUsername is a Validator that checks that the username is valid.
*/
export const validateUsername = composeValidators(
validateUsernameCharacters,
validateUsernameMinLength,
validateUsernameMaxLength
);
/**
* validateUsername is a Validator that checks that the value is a valid username.
*/
export const validatePassword = createValidator(
v => /^(?=.{8,}).*$/.test(v),
INVALID_PASSWORD()
v => v.length >= 8,
PASSWORD_TOO_SHORT(8)
);
/**s
+27 -1
View File
@@ -7,7 +7,7 @@ signIn-signInToJoinHeader = Sign in to join the conversation
signIn-signInAndJoinButton = Sign in and join the conversation
signIn-emailAddressLabel = Email Address
signIn-emailAddressTextfield =
signIn-emailAddressTextField =
.placeholder = Email Address
signIn-passwordLabel = Password
@@ -17,3 +17,29 @@ signIn-passwordTextfield =
signIn-forgotYourPassword = Forgot your password?
signIn-noAccountSignUp = Don't have an account? <button>Sign Up</button>
## Sign Up
signUp-signUpToJoinHeader = Sign up to join the conversation
signUp-signUpAndJoinButton = Sign up and join the conversation
signUp-emailAddressLabel = Email Address
signUp-emailAddressTextField
.placeholder = Email Address
signUp-usernameLabel = Username
signUp-usernameDescription = A unique identifier displayed on your comments. You may use “_” and “.”
signUp-usernameTextField
.placeholder = Username
signUp-passwordLabel = Password
signUp-passwordDescription = Must be at least {$minLength} characters
signUp-passwordTextField
.placeholder = Password
signUp-confirmPasswordLabel = Confirm Password
signUp-confirmPasswordTextField
.placeholder = Confirm Password
signUp-accountAvailableSignIn = Already have an account? <button>Sign In</button>
+7
View File
@@ -5,6 +5,13 @@
## Validation
framework-validation-required = This field is required.
framework-validation-tooShort = The field must contain at least {$minLength} characters.
framework-validation-passwordTooShort = Password must contain at least {$minLength} characters.
framework-validation-usernameTooShort = Username must contain at least {$minLength} characters.
framework-validation-usernameTooLong = Usernames cannot be longer than {$maxLength} characters.
framework-validation-invalidCharacters = Invalid characters. Try again.
framework-validation-invalidEmail = Please enter a valid email address.
framework-validation-passwordsDoNotMatch = Passwords do not match. Try again.
framework-timeago-time =
{ $value }