Client - add password reset - #50

This commit is contained in:
Sam 2020-05-17 18:20:15 +02:00
parent 51d627fa1c
commit 1860cfe320
16 changed files with 348 additions and 83 deletions

View File

@ -69,6 +69,9 @@ lint-react:
lint-react-fix: lint-react-fix:
$(NPM) lint-fix $(NPM) lint-fix
mail:
docker run -d -e "MH_STORAGE=maildir" -v /tmp/maildir:/maildir -p 1025:1025 -p 8025:8025 mailhog/mailhog
migrate-db: migrate-db:
$(FLASK) db migrate --directory $(MIGRATIONS) $(FLASK) db migrate --directory $(MIGRATIONS)

View File

@ -46,15 +46,27 @@ export const getProfile = () => dispatch =>
throw error throw error
}) })
export const loginOrRegister = (target, formData) => dispatch => export const loginOrRegisterOrPasswordReset = (target, formData) => dispatch =>
FitTrackeeApi.loginOrRegister(target, formData) FitTrackeeApi.loginOrRegisterOrPasswordReset(target, formData)
.then(ret => { .then(ret => {
if (ret.status === 'success') { if (ret.status === 'success') {
window.localStorage.setItem('authToken', ret.auth_token) if (target === 'password/reset-request') {
if (target === 'register') { return history.push({
dispatch(getAppData('config')) pathname: '/password-reset/sent',
})
}
if (target === 'password/update') {
return history.push({
pathname: '/updated-password',
})
}
if (target === 'login' || target === 'register') {
window.localStorage.setItem('authToken', ret.auth_token)
if (target === 'register') {
dispatch(getAppData('config'))
}
return dispatch(getProfile())
} }
return dispatch(getProfile())
} }
return dispatch(AuthError(ret.message)) return dispatch(AuthError(ret.message))
}) })
@ -62,9 +74,12 @@ export const loginOrRegister = (target, formData) => dispatch =>
throw error throw error
}) })
const RegisterFormControl = formData => { const RegisterFormControl = (formData, onlyPasswords = false) => {
const errMsg = [] const errMsg = []
if (formData.username.length < 3 || formData.username.length > 12) { if (
!onlyPasswords &&
(formData.username.length < 3 || formData.username.length > 12)
) {
errMsg.push('3 to 12 characters required for username.') errMsg.push('3 to 12 characters required for username.')
} }
if (formData.password !== formData.password_conf) { if (formData.password !== formData.password_conf) {
@ -77,13 +92,13 @@ const RegisterFormControl = formData => {
} }
export const handleUserFormSubmit = (formData, formType) => dispatch => { export const handleUserFormSubmit = (formData, formType) => dispatch => {
if (formType === 'register') { if (formType === 'register' || formType === 'password/update') {
const ret = RegisterFormControl(formData) const ret = RegisterFormControl(formData, formType === 'password/update')
if (ret.length > 0) { if (ret.length > 0) {
return dispatch(AuthErrors(generateIds(ret))) return dispatch(AuthErrors(generateIds(ret)))
} }
} }
return dispatch(loginOrRegister(formType, formData)) return dispatch(loginOrRegisterOrPasswordReset(formType, formData))
} }
export const handleProfileFormSubmit = formData => dispatch => { export const handleProfileFormSubmit = formData => dispatch => {

View File

@ -312,7 +312,6 @@ label {
.dropdown-item { .dropdown-item {
cursor: default; cursor: default;
font-size: 0.9em; font-size: 0.9em;
} }
.dropdown-item-selected { .dropdown-item-selected {
@ -437,6 +436,12 @@ label {
text-align: center; text-align: center;
} }
.password-forget {
margin: 10px;
font-size: .9em;
font-style: italic;
}
.radioLabel { .radioLabel {
text-align: center; text-align: center;
} }
@ -467,6 +472,14 @@ label {
pointer-events: none; pointer-events: none;
} }
.svg-icon {
fill: #405976;
height: 70px;
margin-left: auto;
margin-right: auto;
width: 70px;
}
.time-frames { .time-frames {
align-items: center; align-items: center;
display: inline-flex; display: inline-flex;

View File

@ -12,6 +12,7 @@ import Footer from './Footer'
import Logout from './User/Logout' import Logout from './User/Logout'
import NavBar from './NavBar' import NavBar from './NavBar'
import NotFound from './Others/NotFound' import NotFound from './Others/NotFound'
import PasswordReset from './User/PasswordReset'
import ProfileEdit from './User/ProfileEdit' import ProfileEdit from './User/ProfileEdit'
import Statistics from './Statistics' import Statistics from './Statistics'
import UserForm from './User/UserForm' import UserForm from './User/UserForm'
@ -43,6 +44,27 @@ class App extends React.Component {
path="/login" path="/login"
render={() => <UserForm formType={'login'} />} render={() => <UserForm formType={'login'} />}
/> />
<Route
exact
path="/password-reset"
render={() => <UserForm formType={'password reset'} />}
/>
<Route
exact
path="/password-reset/request"
render={() => <UserForm formType={'reset your password'} />}
/>
<Route
exact
path="/password-reset/sent"
render={() => <PasswordReset action={'sent'} />}
/>
<Route
exact
path="/updated-password"
render={() => <PasswordReset action={'updated'} />}
/>
<Route exact path="/password-reset/sent" component={PasswordReset} />
<Route exact path="/logout" component={Logout} /> <Route exact path="/logout" component={Logout} />
<Route exact path="/profile/edit" component={ProfileEdit} /> <Route exact path="/profile/edit" component={ProfileEdit} />
<Route exact path="/profile" component={CurrentUserProfile} /> <Route exact path="/profile" component={CurrentUserProfile} />

View File

@ -101,7 +101,7 @@ class NavBar extends React.PureComponent {
pathname: '/register', pathname: '/register',
}} }}
> >
{t('common:Register')} {t('user:Register')}
</Link> </Link>
</li> </li>
)} )}
@ -113,7 +113,7 @@ class NavBar extends React.PureComponent {
pathname: '/login', pathname: '/login',
}} }}
> >
{t('common:Login')} {t('user:Login')}
</Link> </Link>
</li> </li>
)} )}
@ -148,7 +148,7 @@ class NavBar extends React.PureComponent {
pathname: '/logout', pathname: '/logout',
}} }}
> >
{t('common:Logout')} {t('user:Logout')}
</Link> </Link>
</li> </li>
</> </>

View File

@ -1,12 +1,13 @@
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import { Link } from 'react-router-dom'
import { history } from '../../index' import { history } from '../../index'
export default function Form(props) { export default function Form(props) {
const { t } = useTranslation() const { t } = useTranslation()
const pageTitle = `common:${props.formType const pageTitle = `user:${props.formType
.charAt(0) .charAt(0)
.toUpperCase()}${props.formType.slice(1)}` .toUpperCase()}${props.formType.slice(1)}`
return ( return (
@ -34,65 +35,86 @@ export default function Form(props) {
</div> </div>
</div> </div>
) : ( ) : (
<form <>
onSubmit={event => <form
props.handleUserFormSubmit(event, props.formType) onSubmit={event =>
} props.handleUserFormSubmit(event, props.formType)
> }
{props.formType === 'register' && ( >
<div className="form-group"> {props.formType === 'register' && (
<input <div className="form-group">
className="form-control input-lg" <input
name="username" className="form-control input-lg"
placeholder={t('user:Enter a username')} name="username"
required placeholder={t('user:Enter a username')}
type="text" required
value={props.userForm.username} type="text"
onChange={props.onHandleFormChange} value={props.userForm.username}
/> onChange={props.onHandleFormChange}
</div> />
)} </div>
<div className="form-group"> )}
{props.formType !== 'password reset' && (
<div className="form-group">
<input
className="form-control input-lg"
name="email"
placeholder={t('user:Enter an email address')}
required
type="email"
value={props.userForm.email}
onChange={props.onHandleFormChange}
/>
</div>
)}
{props.formType !== 'reset your password' && (
<>
<div className="form-group">
<input
className="form-control input-lg"
name="password"
placeholder={t('user:Enter a password')}
required
type="password"
value={props.userForm.password}
onChange={props.onHandleFormChange}
/>
</div>
{props.formType !== 'login' && (
<div className="form-group">
<input
className="form-control input-lg"
name="password_conf"
placeholder={t(
'user:Enter the password confirmation'
)}
required
type="password"
value={props.userForm.password_conf}
onChange={props.onHandleFormChange}
/>
</div>
)}
</>
)}
<input <input
className="form-control input-lg" type="submit"
name="email" className="btn btn-primary btn-lg btn-block"
placeholder={t('user:Enter an email address')} value={t('Submit')}
required
type="email"
value={props.userForm.email}
onChange={props.onHandleFormChange}
/> />
</div> </form>
<div className="form-group"> <p className="password-forget">
<input {props.formType === 'login' && (
className="form-control input-lg" <Link
name="password" to={{
placeholder={t('user:Enter a password')} pathname: '/password-reset/request',
required }}
type="password" >
value={props.userForm.password} {t('user:Forgot password?')}
onChange={props.onHandleFormChange} </Link>
/> )}
</div> </p>
{props.formType === 'register' && ( </>
<div className="form-group">
<input
className="form-control input-lg"
name="password_conf"
placeholder={t('user:Enter the password confirmation')}
required
type="password"
value={props.userForm.password_conf}
onChange={props.onHandleFormChange}
/>
</div>
)}
<input
type="submit"
className="btn btn-primary btn-lg btn-block"
value={t('Submit')}
/>
</form>
)} )}
</div> </div>
<div className="col-md-3" /> <div className="col-md-3" />

View File

@ -0,0 +1,48 @@
import React from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { ReactComponent as Password } from '../../images/password.svg'
import { ReactComponent as MailSend } from '../../images/mail-send.svg'
export default function PasswordReset(props) {
const { t } = useTranslation()
const { action } = props
return (
<div className="container dashboard">
<div className="row">
<div className="col-2" />
<div className="card col-8">
<div className="card-body">
<div className="text-center ">
{action === 'sent' && (
<>
<div className="svg-icon">
<MailSend />
</div>
{t(
// eslint-disable-next-line max-len
"user:Check your email. If your address is in our database, you'll received an email with a link to reset your password."
)}
</>
)}
{action === 'updated' && (
<>
<div className="svg-icon">
<Password />
</div>
<Trans i18nKey="user:updatedPasswordText">
{/* prettier-ignore */}
Your password have been updated. Click
<Link to="/login">here</Link> to log in.
</Trans>
</>
)}
</div>
</div>
</div>
<div className="col-2" />
</div>
</div>
)
}

View File

@ -49,9 +49,10 @@ class UserForm extends React.Component {
t, t,
} = this.props } = this.props
const { formData } = this.state const { formData } = this.state
const { token } = this.props.location.query
return ( return (
<div> <div>
{isLoggedIn() ? ( {isLoggedIn() || (formType === 'password reset' && !token) ? (
<Redirect to="/" /> <Redirect to="/" />
) : ( ) : (
<div> <div>
@ -63,6 +64,9 @@ class UserForm extends React.Component {
onHandleFormChange={event => this.onHandleFormChange(event)} onHandleFormChange={event => this.onHandleFormChange(event)}
handleUserFormSubmit={event => { handleUserFormSubmit={event => {
event.preventDefault() event.preventDefault()
if (formType === 'password reset') {
formData.token = token
}
onHandleUserFormSubmit(formData, formType) onHandleUserFormSubmit(formData, formType)
}} }}
/> />
@ -82,6 +86,12 @@ export default withTranslation()(
}), }),
dispatch => ({ dispatch => ({
onHandleUserFormSubmit: (formData, formType) => { onHandleUserFormSubmit: (formData, formType) => {
formType =
formType === 'password reset'
? 'password/update'
: formType === 'reset your password'
? 'password/reset-request'
: formType
dispatch(handleUserFormSubmit(formData, formType)) dispatch(handleUserFormSubmit(formData, formType))
}, },
}) })

View File

@ -1,7 +1,7 @@
import { createApiRequest } from '../utils' import { createApiRequest } from '../utils'
export default class FitTrackeeApi { export default class FitTrackeeApi {
static loginOrRegister(target, data) { static loginOrRegisterOrPasswordReset(target, data) {
const params = { const params = {
url: `auth/${target}`, url: `auth/${target}`,
method: 'POST', method: 'POST',

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 345.834 345.834" style="enable-background:new 0 0 345.834 345.834;" xml:space="preserve">
<g>
<path d="M339.798,260.429c0.13-0.026,0.257-0.061,0.385-0.094c0.109-0.028,0.219-0.051,0.326-0.084
c0.125-0.038,0.247-0.085,0.369-0.129c0.108-0.039,0.217-0.074,0.324-0.119c0.115-0.048,0.226-0.104,0.338-0.157
c0.109-0.052,0.22-0.1,0.327-0.158c0.107-0.057,0.208-0.122,0.312-0.184c0.107-0.064,0.215-0.124,0.319-0.194
c0.111-0.074,0.214-0.156,0.321-0.236c0.09-0.067,0.182-0.13,0.27-0.202c0.162-0.133,0.316-0.275,0.466-0.421
c0.027-0.026,0.056-0.048,0.083-0.075c0.028-0.028,0.052-0.059,0.079-0.088c0.144-0.148,0.284-0.3,0.416-0.46
c0.077-0.094,0.144-0.192,0.216-0.289c0.074-0.1,0.152-0.197,0.221-0.301c0.074-0.111,0.139-0.226,0.207-0.34
c0.057-0.096,0.118-0.19,0.171-0.289c0.062-0.115,0.114-0.234,0.169-0.351c0.049-0.104,0.101-0.207,0.146-0.314
c0.048-0.115,0.086-0.232,0.128-0.349c0.041-0.114,0.085-0.227,0.12-0.343c0.036-0.118,0.062-0.238,0.092-0.358
c0.029-0.118,0.063-0.234,0.086-0.353c0.028-0.141,0.045-0.283,0.065-0.425c0.014-0.1,0.033-0.199,0.043-0.3
c0.025-0.249,0.038-0.498,0.038-0.748V92.76c0-4.143-3.357-7.5-7.5-7.5h-236.25c-0.066,0-0.13,0.008-0.196,0.01
c-0.143,0.004-0.285,0.01-0.427,0.022c-0.113,0.009-0.225,0.022-0.337,0.037c-0.128,0.016-0.255,0.035-0.382,0.058
c-0.119,0.021-0.237,0.046-0.354,0.073c-0.119,0.028-0.238,0.058-0.356,0.092c-0.117,0.033-0.232,0.069-0.346,0.107
c-0.117,0.04-0.234,0.082-0.349,0.128c-0.109,0.043-0.216,0.087-0.322,0.135c-0.118,0.053-0.235,0.11-0.351,0.169
c-0.099,0.051-0.196,0.103-0.292,0.158c-0.116,0.066-0.23,0.136-0.343,0.208c-0.093,0.06-0.184,0.122-0.274,0.185
c-0.106,0.075-0.211,0.153-0.314,0.235c-0.094,0.075-0.186,0.152-0.277,0.231c-0.09,0.079-0.179,0.158-0.266,0.242
c-0.099,0.095-0.194,0.194-0.288,0.294c-0.047,0.05-0.097,0.094-0.142,0.145c-0.027,0.03-0.048,0.063-0.074,0.093
c-0.094,0.109-0.182,0.223-0.27,0.338c-0.064,0.084-0.13,0.168-0.19,0.254c-0.078,0.112-0.15,0.227-0.222,0.343
c-0.059,0.095-0.12,0.189-0.174,0.286c-0.063,0.112-0.118,0.227-0.175,0.342c-0.052,0.105-0.106,0.21-0.153,0.317
c-0.049,0.113-0.092,0.23-0.135,0.345c-0.043,0.113-0.087,0.225-0.124,0.339c-0.037,0.115-0.067,0.232-0.099,0.349
c-0.032,0.12-0.066,0.239-0.093,0.36c-0.025,0.113-0.042,0.228-0.062,0.342c-0.022,0.13-0.044,0.26-0.06,0.39
c-0.013,0.108-0.019,0.218-0.027,0.328c-0.01,0.14-0.019,0.28-0.021,0.421c-0.001,0.041-0.006,0.081-0.006,0.122v46.252
c0,4.143,3.357,7.5,7.5,7.5s7.5-3.357,7.5-7.5v-29.595l66.681,59.037c-0.348,0.245-0.683,0.516-0.995,0.827l-65.687,65.687v-49.288
c0-4.143-3.357-7.5-7.5-7.5s-7.5,3.357-7.5,7.5v9.164h-38.75c-4.143,0-7.5,3.357-7.5,7.5s3.357,7.5,7.5,7.5h38.75v43.231
c0,4.143,3.357,7.5,7.5,7.5h236.25c0.247,0,0.494-0.013,0.74-0.037c0.115-0.011,0.226-0.033,0.339-0.049
C339.542,260.469,339.67,260.454,339.798,260.429z M330.834,234.967l-65.688-65.687c-0.042-0.042-0.087-0.077-0.13-0.117
l49.383-41.897c3.158-2.68,3.546-7.412,0.866-10.571c-2.678-3.157-7.41-3.547-10.571-0.866l-84.381,71.59l-98.444-87.158h208.965
V234.967z M185.878,179.888c0.535-0.535,0.969-1.131,1.308-1.765l28.051,24.835c1.418,1.255,3.194,1.885,4.972,1.885
c1.726,0,3.451-0.593,4.853-1.781l28.587-24.254c0.26,0.38,0.553,0.743,0.89,1.08l65.687,65.687H120.191L185.878,179.888z"/>
<path d="M7.5,170.676h126.667c4.143,0,7.5-3.357,7.5-7.5s-3.357-7.5-7.5-7.5H7.5c-4.143,0-7.5,3.357-7.5,7.5
S3.357,170.676,7.5,170.676z"/>
<path d="M20.625,129.345H77.5c4.143,0,7.5-3.357,7.5-7.5s-3.357-7.5-7.5-7.5H20.625c-4.143,0-7.5,3.357-7.5,7.5
S16.482,129.345,20.625,129.345z"/>
<path d="M62.5,226.51h-55c-4.143,0-7.5,3.357-7.5,7.5s3.357,7.5,7.5,7.5h55c4.143,0,7.5-3.357,7.5-7.5S66.643,226.51,62.5,226.51z"
/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512.001 512.001" style="enable-background:new 0 0 512.001 512.001;" xml:space="preserve">
<g>
<g>
<path d="M468.683,287.265h-69.07c-4.147,0-7.508,3.361-7.508,7.508c0,4.147,3.361,7.508,7.508,7.508h69.07
c4.147,0,7.508-3.361,7.508-7.508C476.191,290.626,472.83,287.265,468.683,287.265z"/>
</g>
</g>
<g>
<g>
<path d="M105.012,268.377L85.781,256l19.231-12.376c3.487-2.243,4.495-6.888,2.251-10.376c-2.244-3.486-6.888-4.497-10.376-2.25
l-17.471,11.243v-20.776c0-4.147-3.361-7.508-7.508-7.508c-4.147,0-7.508,3.361-7.508,7.508v20.775l-17.47-11.243
c-3.486-2.245-8.132-1.238-10.376,2.25c-2.245,3.487-1.237,8.133,2.25,10.376L58.034,256l-19.231,12.376
c-3.487,2.244-4.495,6.889-2.25,10.376c1.435,2.23,3.852,3.446,6.32,3.446c1.391,0,2.799-0.386,4.056-1.196l17.47-11.243v20.775
c0,4.147,3.361,7.508,7.508,7.508c4.147,0,7.508-3.361,7.508-7.508V269.76l17.471,11.243c1.257,0.809,2.664,1.196,4.056,1.196
c2.467,0,4.885-1.216,6.32-3.446C109.507,275.266,108.499,270.62,105.012,268.377z"/>
</g>
</g>
<g>
<g>
<path d="M194.441,268.377L175.21,256l19.231-12.376c3.487-2.244,4.495-6.889,2.25-10.376c-2.245-3.486-6.888-4.497-10.376-2.25
l-17.47,11.243v-20.775c0-4.147-3.361-7.508-7.508-7.508c-4.147,0-7.508,3.361-7.508,7.508v20.776l-17.471-11.243
c-3.487-2.245-8.133-1.238-10.376,2.25c-2.245,3.487-1.237,8.133,2.25,10.376L147.463,256l-19.231,12.376
c-3.487,2.244-4.495,6.889-2.25,10.376c1.435,2.23,3.852,3.446,6.32,3.446c1.391,0,2.799-0.386,4.056-1.196l17.471-11.243v20.776
c0,4.147,3.361,7.508,7.508,7.508c4.147,0,7.508-3.361,7.508-7.508V269.76l17.47,11.243c1.257,0.809,2.664,1.196,4.056,1.196
c2.467,0,4.885-1.216,6.32-3.446C198.936,275.266,197.928,270.62,194.441,268.377z"/>
</g>
</g>
<g>
<g>
<path d="M283.871,268.377L264.64,256l19.231-12.376c3.487-2.243,4.495-6.888,2.251-10.376c-2.245-3.486-6.888-4.497-10.376-2.25
l-17.471,11.243v-20.775c0-4.147-3.361-7.508-7.508-7.508c-4.147,0-7.508,3.361-7.508,7.508v20.775l-17.471-11.243
c-3.486-2.245-8.134-1.238-10.376,2.25c-2.245,3.487-1.237,8.133,2.25,10.376L236.892,256l-19.231,12.376
c-3.487,2.244-4.495,6.889-2.25,10.376c1.435,2.23,3.852,3.446,6.32,3.446c1.391,0,2.799-0.386,4.056-1.196l17.471-11.243v20.775
c0,4.147,3.361,7.508,7.508,7.508c4.147,0,7.508-3.361,7.508-7.508V269.76l17.471,11.243c1.257,0.809,2.664,1.196,4.056,1.196
c2.467,0,4.886-1.216,6.32-3.446C288.366,275.266,287.358,270.62,283.871,268.377z"/>
</g>
</g>
<g>
<g>
<path d="M373.3,268.377L354.069,256l19.231-12.376c3.487-2.244,4.495-6.889,2.25-10.376c-2.244-3.486-6.888-4.497-10.376-2.25
l-17.471,11.243v-20.776c0-4.147-3.361-7.508-7.508-7.508c-4.147,0-7.508,3.361-7.508,7.508v20.775l-17.47-11.243
c-3.486-2.245-8.132-1.238-10.376,2.25c-2.245,3.487-1.237,8.133,2.25,10.376L326.322,256l-19.231,12.376
c-3.487,2.244-4.495,6.889-2.25,10.376c1.435,2.23,3.852,3.446,6.32,3.446c1.391,0,2.799-0.386,4.056-1.196l17.47-11.243v20.776
c0,4.147,3.361,7.508,7.508,7.508c4.147,0,7.508-3.361,7.508-7.508V269.76l17.471,11.243c1.257,0.809,2.664,1.196,4.056,1.196
c2.467,0,4.885-1.216,6.32-3.446C377.795,275.266,376.787,270.62,373.3,268.377z"/>
</g>
</g>
<g>
<g>
<path d="M271.792,330.359H15.016V181.642h93.1c4.147,0,7.508-3.361,7.508-7.508c0-4.147-3.361-7.508-7.508-7.508H12.513
C5.613,166.626,0,172.24,0,179.14v153.722c0,6.9,5.613,12.513,12.513,12.513h259.278c4.147,0,7.508-3.361,7.508-7.508
C279.299,333.72,275.939,330.359,271.792,330.359z"/>
</g>
</g>
<g>
<g>
<path d="M499.487,166.626H162.174c-4.147,0-7.508,3.361-7.508,7.508c0,4.147,3.361,7.508,7.508,7.508h334.811v148.716H323.848
c-4.147,0-7.508,3.361-7.508,7.508c0,4.147,3.361,7.508,7.508,7.508h175.64c6.9,0,12.513-5.613,12.513-12.513V179.14
C512.001,172.24,506.387,166.626,499.487,166.626z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -12,8 +12,6 @@
"Edit": "Edit", "Edit": "Edit",
"day": "day", "day": "day",
"days": "days", "days": "days",
"Login": "Login",
"Logout": "Logout",
"Next": "Next", "Next": "Next",
"No": "No", "No": "No",
"no": "no", "no": "no",
@ -21,7 +19,6 @@
"No workouts.": "No workouts.", "No workouts.": "No workouts.",
"Page not found": "Page not found", "Page not found": "Page not found",
"Previous": "Prev", "Previous": "Prev",
"Register": "Register",
"registration date": "registration date", "registration date": "registration date",
"Sort": "Sort", "Sort": "Sort",
"Sort by": "Sort by", "Sort by": "Sort by",

View File

@ -4,6 +4,7 @@
"Are you sure you want to delete your account? All data will be deleted, this cannot be undone.": "Are you sure you want to delete your account? All data will be deleted, this cannot be undone.", "Are you sure you want to delete your account? All data will be deleted, this cannot be undone.": "Are you sure you want to delete your account? All data will be deleted, this cannot be undone.",
"Bio": "Bio", "Bio": "Bio",
"Birth Date": "Birth Date", "Birth Date": "Birth Date",
"Check your email. If your address is in our database, you'll received an email with a link to reset your password.": "Check your email. If your address is in our database, you'll received an email with a link to reset your password.",
"Delete my account": "Delete my account", "Delete my account": "Delete my account",
"Delete picture": "Delete picture", "Delete picture": "Delete picture",
"Delete user account": "Delete user account", "Delete user account": "Delete user account",
@ -15,20 +16,30 @@
"Enter the password confirmation": "Enter the password confirmation", "Enter the password confirmation": "Enter the password confirmation",
"First day of week": "First day of week", "First day of week": "First day of week",
"First Name": "First Name", "First Name": "First Name",
"Forgot password?": "Forgot password?",
"Invalid token. Please request a new token.": "Invalid token. Please request a new token.",
"Language": "Language", "Language": "Language",
"Last Name": "Last Name", "Last Name": "Last Name",
"Location": "Location", "Location": "Location",
"loggedOut": "You are now logged out. Click <1>here</1> to log back in.", "loggedOut": "You are now logged out. Click <1>here</1> to log back in.",
"Login": "Login",
"login": "login", "login": "login",
"Logout": "Logout",
"Monday": "Monday", "Monday": "Monday",
"Password": "Password", "Password": "Password",
"Password Confirmation": "Password Confirmation", "Password Confirmation": "Password Confirmation",
"Password reset": "Password reset",
"password reset": "password reset",
"Profile": "Profile", "Profile": "Profile",
"Profile Edition": "Profile Edition", "Profile Edition": "Profile Edition",
"Register": "Register",
"register": "register", "register": "register",
"Registration Date": "Registration Date", "Registration Date": "Registration Date",
"Reset your password": "Reset your password",
"reset your password": "reset your password",
"Send": "Send", "Send": "Send",
"Sunday": "Sunday", "Sunday": "Sunday",
"Timezone": "Timezone", "Timezone": "Timezone",
"updatedPasswordText": "Your password have been updated. Click <1>here</1> to log in." ,
"Username": "Username" "Username": "Username"
} }

View File

@ -12,8 +12,6 @@
"Edit": "Modifier", "Edit": "Modifier",
"day": "jour", "day": "jour",
"days": "jours", "days": "jours",
"Login": "Se connecter",
"Logout": "Se déconnecter",
"Next": "Page suivante", "Next": "Page suivante",
"No": "Non", "No": "Non",
"no": "non", "no": "non",
@ -21,7 +19,6 @@
"No workouts.": "Pas d'activités.", "No workouts.": "Pas d'activités.",
"Page not found": "Page introuvable", "Page not found": "Page introuvable",
"Previous": "Page précédente", "Previous": "Page précédente",
"Register": "S'inscrire",
"registration date": "date d'inscription", "registration date": "date d'inscription",
"Sort": "Tri", "Sort": "Tri",
"Sort by": "Trier par", "Sort by": "Trier par",

View File

@ -4,6 +4,7 @@
"Are you sure you want to delete your account? All data will be deleted, this cannot be undone.": "Etes-vous sûr de vouloir supprimer votre compte ? Toutes les données seront définitivement effacés.", "Are you sure you want to delete your account? All data will be deleted, this cannot be undone.": "Etes-vous sûr de vouloir supprimer votre compte ? Toutes les données seront définitivement effacés.",
"Bio": "Bio", "Bio": "Bio",
"Birth Date": "Date de naissance", "Birth Date": "Date de naissance",
"Check your email. If your address is in our database, you'll received an email with a link to reset your password.": "Vérifiez vore boite mail. Si vote adresse est dans notre base de données, vous recevrez un email avec un lien pour réinitialiser votre mot de passe",
"Delete my account": "Supprimer mon compte", "Delete my account": "Supprimer mon compte",
"Delete picture": "Supprimer l'image", "Delete picture": "Supprimer l'image",
"Delete user account": "Supprimer le compte", "Delete user account": "Supprimer le compte",
@ -15,20 +16,30 @@
"Enter the password confirmation": "Confirmer le mot de passe", "Enter the password confirmation": "Confirmer le mot de passe",
"First day of week": "Premier jour de la semaine", "First day of week": "Premier jour de la semaine",
"First Name": "Prénom", "First Name": "Prénom",
"Forgot password?": "Mot de passe oublié ?",
"Invalid token. Please request a new token.": "Token invalid. Veuillez demander un nouveau token.",
"Language": "Langue", "Language": "Langue",
"Last Name": "Nom", "Last Name": "Nom",
"Location": "Lieu", "Location": "Lieu",
"loggedOut": "Vous êtes déconnecté. Cliquez <1>ici</1> pour vous reconnecter.", "loggedOut": "Vous êtes déconnecté. Cliquez <1>ici</1> pour vous reconnecter.",
"Login": "Se connecter",
"login": "se connecter", "login": "se connecter",
"Logout": "Se déconnecter",
"Monday": "Lundi", "Monday": "Lundi",
"Password": "Mot de passe", "Password": "Mot de passe",
"Password Confirmation": "Confirmation du mot de passe", "Password Confirmation": "Confirmation du mot de passe",
"Password reset": "Réinitialiser votre mot de passe",
"password reset": "réinitialiser votre mot de passe",
"Profile": "Profil", "Profile": "Profil",
"Profile Edition": "Edition du profil", "Profile Edition": "Edition du profil",
"Register": "S'inscrire",
"register": "s'inscrire", "register": "s'inscrire",
"Registration Date": "Date d'inscription", "Registration Date": "Date d'inscription",
"Reset your password": "Réinitialiser votre mot de passe",
"reset your password": "réinitialiser votre mot de passe",
"Send": "Envoyer", "Send": "Envoyer",
"Sunday": "Dimanche", "Sunday": "Dimanche",
"Timezone": "Fuseau horaire", "Timezone": "Fuseau horaire",
"updatedPasswordText": "Votre mot de passe a été mis à jour. Cliquez <1>ici</1> pour vous connecter.",
"Username": "Nom d'utilisateur" "Username": "Nom d'utilisateur"
} }

View File

@ -1,3 +1,12 @@
const routesWithoutAuthentication = [
'/login',
'/register',
'/password-reset',
'/password-reset/request',
'/password-reset/sent',
'/updated-password',
]
const updatePath = (toPath, newPath) => { const updatePath = (toPath, newPath) => {
if (typeof toPath === 'string' || toPath instanceof String) { if (typeof toPath === 'string' || toPath instanceof String) {
toPath = newPath toPath = newPath
@ -10,13 +19,13 @@ const updatePath = (toPath, newPath) => {
const pathInterceptor = toPath => { const pathInterceptor = toPath => {
if ( if (
!window.localStorage.authToken && !window.localStorage.authToken &&
!['/login', '/register'].includes(toPath.pathname) !routesWithoutAuthentication.includes(toPath.pathname)
) { ) {
toPath = updatePath(toPath, '/login') toPath = updatePath(toPath, '/login')
} }
if ( if (
window.localStorage.authToken && window.localStorage.authToken &&
['/login', '/register'].includes(toPath.pathname) routesWithoutAuthentication.includes(toPath.pathname)
) { ) {
toPath = updatePath(toPath, '/') toPath = updatePath(toPath, '/')
} }