mirror of
https://github.com/wassname/talk.git
synced 2026-08-16 11:29:31 +08:00
Adapt sign up plus validation and translations
This commit is contained in:
@@ -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%;
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 }
|
||||
|
||||
Reference in New Issue
Block a user