Localized signup and login
This commit is contained in:
parent
269152ee58
commit
d79a13dc8a
4 changed files with 121 additions and 27 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useState } from 'react'
|
||||
import { useCookies } from 'react-cookie'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { AxiosResponse } from 'axios'
|
||||
|
||||
import * as Dialog from '@radix-ui/react-dialog'
|
||||
|
|
@ -24,6 +25,8 @@ interface ErrorMap {
|
|||
const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
|
||||
const LoginModal = (props: Props) => {
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
// Set up form states and error handling
|
||||
const [formValid, setFormValid] = useState(false)
|
||||
const [errors, setErrors] = useState<ErrorMap>({
|
||||
|
|
@ -49,16 +52,16 @@ const LoginModal = (props: Props) => {
|
|||
switch(name) {
|
||||
case 'email':
|
||||
if (value.length == 0)
|
||||
newErrors.email = 'Please enter your email'
|
||||
newErrors.email = t('modals.login.errors.empty_email')
|
||||
else if (!emailRegex.test(value))
|
||||
newErrors.email = 'That email address is not valid'
|
||||
newErrors.email = t('modals.login.errors.invalid_email')
|
||||
else
|
||||
newErrors.email = ''
|
||||
break
|
||||
|
||||
case 'password':
|
||||
newErrors.password = value.length == 0
|
||||
? 'Please enter your password'
|
||||
? t('modals.login.errors.empty_password')
|
||||
: ''
|
||||
break
|
||||
|
||||
|
|
@ -117,21 +120,22 @@ const LoginModal = (props: Props) => {
|
|||
access_token: response.data.access_token
|
||||
}
|
||||
|
||||
setCookies('account', cookieObj, { path: '/'})
|
||||
setCookies('account', cookieObj, { path: '/' })
|
||||
}
|
||||
|
||||
function storeUserInfo(response: AxiosResponse) {
|
||||
const user = response.data.user
|
||||
|
||||
setCookies('NEXT_LOCALE', user.language, { path: '/' })
|
||||
|
||||
const cookieObj = {
|
||||
picture: user.picture.picture,
|
||||
element: user.picture.element,
|
||||
language: user.language,
|
||||
}
|
||||
|
||||
setCookies('user', cookieObj, { path: '/'})
|
||||
setCookies('user', cookieObj, { path: '/' })
|
||||
|
||||
accountState.account.language = user.language
|
||||
accountState.account.user = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
|
|
@ -155,13 +159,13 @@ const LoginModal = (props: Props) => {
|
|||
<Dialog.Root open={open} onOpenChange={openChange}>
|
||||
<Dialog.Trigger asChild>
|
||||
<li className="MenuItem">
|
||||
<span>Log in</span>
|
||||
<span>{t('menu.login')}</span>
|
||||
</li>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Content className="Login Dialog" onOpenAutoFocus={ (event) => event.preventDefault() }>
|
||||
<div className="DialogHeader">
|
||||
<Dialog.Title className="DialogTitle">Log in</Dialog.Title>
|
||||
<Dialog.Title className="DialogTitle">{t('modals.login.title')}</Dialog.Title>
|
||||
<Dialog.Close className="DialogClose" asChild>
|
||||
<span>
|
||||
<CrossIcon />
|
||||
|
|
@ -172,7 +176,7 @@ const LoginModal = (props: Props) => {
|
|||
<form className="form" onSubmit={login}>
|
||||
<Fieldset
|
||||
fieldName="email"
|
||||
placeholder="Email address"
|
||||
placeholder={t('modals.login.placeholders.email')}
|
||||
onChange={handleChange}
|
||||
error={errors.email}
|
||||
ref={emailInput}
|
||||
|
|
@ -180,13 +184,13 @@ const LoginModal = (props: Props) => {
|
|||
|
||||
<Fieldset
|
||||
fieldName="password"
|
||||
placeholder="Password"
|
||||
placeholder={t('modals.login.placeholders.password')}
|
||||
onChange={handleChange}
|
||||
error={errors.password}
|
||||
ref={passwordInput}
|
||||
/>
|
||||
|
||||
<Button>Log in</Button>
|
||||
<Button>{t('modals.login.buttons.confirm')}</Button>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
<Dialog.Overlay className="Overlay" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useCookies } from 'react-cookie'
|
||||
import { Trans, useTranslation } from 'next-i18next'
|
||||
import { AxiosResponse } from 'axios'
|
||||
|
||||
import * as Dialog from '@radix-ui/react-dialog'
|
||||
|
|
@ -26,6 +27,8 @@ interface ErrorMap {
|
|||
const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
|
||||
const SignupModal = (props: Props) => {
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
// Set up form states and error handling
|
||||
const [formValid, setFormValid] = useState(false)
|
||||
const [errors, setErrors] = useState<ErrorMap>({
|
||||
|
|
@ -95,9 +98,9 @@ const SignupModal = (props: Props) => {
|
|||
language: user.language,
|
||||
}
|
||||
|
||||
// TODO: Set language
|
||||
setCookies('user', cookieObj, { path: '/'})
|
||||
|
||||
accountState.account.language = user.language
|
||||
accountState.account.user = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
|
|
@ -138,7 +141,7 @@ const SignupModal = (props: Props) => {
|
|||
|
||||
validateName(fieldName, value)
|
||||
} else {
|
||||
newErrors[fieldName] = `This ${fieldName} is already in use`
|
||||
newErrors[fieldName] = t('modals.signup.errors.field_in_use', { field: fieldName})
|
||||
setErrors(newErrors)
|
||||
setFormValid(false)
|
||||
}
|
||||
|
|
@ -150,9 +153,9 @@ const SignupModal = (props: Props) => {
|
|||
switch(fieldName) {
|
||||
case 'username':
|
||||
if (value.length < 3)
|
||||
newErrors.username = 'Username must be at least 3 characters'
|
||||
newErrors.username = t('modals.signup.errors.username_too_short')
|
||||
else if (value.length > 20)
|
||||
newErrors.username = 'Username must be less than 20 characters'
|
||||
newErrors.username = t('modals.signup.errors.username_too_long')
|
||||
else
|
||||
newErrors.username = ''
|
||||
|
||||
|
|
@ -161,7 +164,7 @@ const SignupModal = (props: Props) => {
|
|||
case 'email':
|
||||
newErrors.email = emailRegex.test(value)
|
||||
? ''
|
||||
: 'That email address is not valid'
|
||||
: t('modals.signup.errors.invalid_email')
|
||||
break
|
||||
|
||||
default:
|
||||
|
|
@ -180,20 +183,20 @@ const SignupModal = (props: Props) => {
|
|||
switch(name) {
|
||||
case 'password':
|
||||
newErrors.password = passwordInput.current?.value.includes(usernameInput.current?.value!)
|
||||
? 'Your password should not contain your username'
|
||||
? t('modals.signup.errors.password_contains_username')
|
||||
: ''
|
||||
break
|
||||
|
||||
case 'password':
|
||||
newErrors.password = value.length < 8
|
||||
? 'Password must be at least 8 characters'
|
||||
? t('modals.signup.errors.password_too_short')
|
||||
: ''
|
||||
break
|
||||
|
||||
case 'confirm_password':
|
||||
newErrors.passwordConfirmation = passwordInput.current?.value === passwordConfirmationInput.current?.value
|
||||
? ''
|
||||
: 'Your passwords don\'t match'
|
||||
: t('modals.signup.errors.passwords_dont_match')
|
||||
break
|
||||
|
||||
default:
|
||||
|
|
@ -231,13 +234,13 @@ const SignupModal = (props: Props) => {
|
|||
<Dialog.Root open={open} onOpenChange={openChange}>
|
||||
<Dialog.Trigger asChild>
|
||||
<li className="MenuItem">
|
||||
<span>Sign up</span>
|
||||
<span>{t('menu.signup')}</span>
|
||||
</li>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Content className="Signup Dialog" onOpenAutoFocus={ (event) => event.preventDefault() }>
|
||||
<div className="DialogHeader">
|
||||
<Dialog.Title className="DialogTitle">Sign up</Dialog.Title>
|
||||
<Dialog.Title className="DialogTitle">{t('modals.signup.title')}</Dialog.Title>
|
||||
<Dialog.Close className="DialogClose" asChild>
|
||||
<span>
|
||||
<CrossIcon />
|
||||
|
|
@ -248,7 +251,7 @@ const SignupModal = (props: Props) => {
|
|||
<form className="form" onSubmit={register}>
|
||||
<Fieldset
|
||||
fieldName="username"
|
||||
placeholder="Username"
|
||||
placeholder={t('modals.signup.placeholders.username')}
|
||||
onChange={handleNameChange}
|
||||
error={errors.username}
|
||||
ref={usernameInput}
|
||||
|
|
@ -256,7 +259,7 @@ const SignupModal = (props: Props) => {
|
|||
|
||||
<Fieldset
|
||||
fieldName="email"
|
||||
placeholder="Email address"
|
||||
placeholder={t('modals.signup.placeholders.email')}
|
||||
onChange={handleNameChange}
|
||||
error={errors.email}
|
||||
ref={emailInput}
|
||||
|
|
@ -264,7 +267,7 @@ const SignupModal = (props: Props) => {
|
|||
|
||||
<Fieldset
|
||||
fieldName="password"
|
||||
placeholder="Password"
|
||||
placeholder={t('modals.signup.placeholders.password')}
|
||||
onChange={handlePasswordChange}
|
||||
error={errors.password}
|
||||
ref={passwordInput}
|
||||
|
|
@ -272,16 +275,18 @@ const SignupModal = (props: Props) => {
|
|||
|
||||
<Fieldset
|
||||
fieldName="confirm_password"
|
||||
placeholder="Password (again)"
|
||||
placeholder={t('modals.signup.placeholders.password_confirm')}
|
||||
onChange={handlePasswordChange}
|
||||
error={errors.passwordConfirmation}
|
||||
ref={passwordConfirmationInput}
|
||||
/>
|
||||
|
||||
<Button>Sign up</Button>
|
||||
<Button>{t('modals.signup.buttons.confirm')}</Button>
|
||||
|
||||
<Dialog.Description className="terms">
|
||||
By signing up, I agree to the<br /><a href="#">Terms and Conditions</a> and <a href="#">Usage Guidelines</a>.
|
||||
<Trans i18nKey="modals.signup.agreement">
|
||||
By signing up, I agree to the <a href="/privacy">Privacy Policy</a><a href="/usage">Usage Guidelines</a>.
|
||||
</Trans>
|
||||
</Dialog.Description>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
|
|
|
|||
|
|
@ -54,6 +54,22 @@
|
|||
"cancel": "Nevermind"
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
"title": "Log in",
|
||||
"buttons": {
|
||||
"confirm": "Log in"
|
||||
},
|
||||
"errors": {
|
||||
"empty_email": "Please enter your email",
|
||||
"empty_password": "Please enter your password",
|
||||
"invalid_email": "That email address is not valid",
|
||||
"invalid_credentials": "Your email address or password is incorrect"
|
||||
},
|
||||
"placeholders": {
|
||||
"email": "Email address",
|
||||
"password": "Password"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Account Settings",
|
||||
"labels": {
|
||||
|
|
@ -71,14 +87,40 @@
|
|||
"buttons": {
|
||||
"confirm": "Save settings"
|
||||
}
|
||||
},
|
||||
"signup": {
|
||||
"title": "Create an account",
|
||||
"buttons": {
|
||||
"confirm": "Sign up"
|
||||
},
|
||||
"agreement": "By signing up, I agree to the <br/><2>Privacy Policy</2> and <1>Usage Guidelines</1>.",
|
||||
"errors": {
|
||||
"field_in_use": "This {{field}} is already in use",
|
||||
"empty_email": "Please enter your email",
|
||||
"invalid_email": "That email address is not valid",
|
||||
"username_too_short": "Username must be at least 3 characters",
|
||||
"username_too_long": "Username must be less than 20 characters",
|
||||
"empty_password": "Please enter your password",
|
||||
"password_contains_username": "Your password should not contain your username",
|
||||
"password_too_short": "Password must be at least 8 characters",
|
||||
"mismatched_passwords": "Your passwords don't match"
|
||||
},
|
||||
"placeholders": {
|
||||
"username": "Username",
|
||||
"email": "Email address",
|
||||
"password": "Password",
|
||||
"password_confirm": "Password (again)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"menu": {
|
||||
"about": "About",
|
||||
"guides": "Guides",
|
||||
"language": "Language",
|
||||
"login": "Log in",
|
||||
"saved": "Saved",
|
||||
"settings": "Settings",
|
||||
"signup": "Sign up",
|
||||
"teams": "Teams",
|
||||
"logout": "Logout"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -54,6 +54,22 @@
|
|||
"cancel": "キャンセル"
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
"title": "ログイン",
|
||||
"buttons": {
|
||||
"confirm": "ログイン"
|
||||
},
|
||||
"errors": {
|
||||
"empty_email": "メールアドレスを入力して下さい",
|
||||
"empty_password": "パスワードを入力して下さい",
|
||||
"invalid_email": "メールアドレスは有効ではありません",
|
||||
"invalid_credentials": "パスワードまたはメールアドレスが違います"
|
||||
},
|
||||
"placeholders": {
|
||||
"email": "メールアドレス",
|
||||
"password": "パスワード"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "アカウント設定",
|
||||
"labels": {
|
||||
|
|
@ -71,14 +87,41 @@
|
|||
"buttons": {
|
||||
"confirm": "設定を保存する"
|
||||
}
|
||||
},
|
||||
"signup": {
|
||||
"title": "アカウント登録",
|
||||
"buttons": {
|
||||
"confirm": "登録する"
|
||||
},
|
||||
"agreement": "続行することで<1>利用規約</1>に同意し、<br/><1>プライバシーポリシー</1>を読んだものとみなされます。",
|
||||
"errors": {
|
||||
"field_in_use": "入力された{{field}}は既に登録済みです",
|
||||
"empty_email": "メールアドレスを入力して下さい",
|
||||
"invalid_email": "メールアドレスは有効ではありません",
|
||||
"username_too_short": "ユーザーネームは3文字以上で入力してください",
|
||||
"username_too_long": "ユーザーネームは20文字以内で入力してください",
|
||||
"empty_password": "パスワードを入力して下さい",
|
||||
"password_contains_username": "パスワードにはユーザー名を含めないでください",
|
||||
"password_too_short": "パスワードは8文字以上で入力してください",
|
||||
"mismatched_passwords": "パスワードとパスワード確認を確かめてください",
|
||||
"invalid_credentials": "パスワードまたはメールアドレスが違います"
|
||||
},
|
||||
"placeholders": {
|
||||
"username": "ユーザー名",
|
||||
"email": "メールアドレス",
|
||||
"password": "パスワード",
|
||||
"password_confirm": "パスワード確認"
|
||||
}
|
||||
}
|
||||
},
|
||||
"menu": {
|
||||
"about": "このサイトについて",
|
||||
"guides": "攻略",
|
||||
"language": "言語",
|
||||
"login": "ログイン",
|
||||
"saved": "保存した編成",
|
||||
"settings": "アカウント設定",
|
||||
"signup": "登録",
|
||||
"teams": "編成一覧",
|
||||
"logout": "ログアウト"
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue