1
1
mirror of https://github.com/pterodactyl/panel.git synced 2024-11-23 01:22:30 +01:00

Begin working on password reset page

This commit is contained in:
Dane Everitt 2019-06-11 22:02:18 -07:00
parent d9f30294de
commit b93b40ba31
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
8 changed files with 120 additions and 11 deletions

View File

@ -16,4 +16,13 @@
@apply .opacity-0;
transition: opacity 150ms;
}
/** @todo fix this, hides footer stuff */
div.route-transition-group {
@apply .relative;
& section {
@apply .absolute .w-full .pin-t .pin-l;
}
}
/*! purgecss end ignore */

View File

@ -0,0 +1,9 @@
import http from '@/api/http';
export default (email: string): Promise<void> => {
return new Promise((resolve, reject) => {
http.post('/auth/password', { email })
.then(() => resolve())
.catch(reject);
});
};

View File

@ -9,6 +9,7 @@ const http: AxiosInstance = axios.create({
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-Token': (window as any).X_CSRF_TOKEN as string || '',
},
});

View File

@ -0,0 +1,75 @@
import * as React from 'react';
import OpenInputField from '@/components/forms/OpenInputField';
import { Link } from 'react-router-dom';
import requestPasswordResetEmail from '@/api/auth/requestPasswordResetEmail';
type Props = Readonly<{
}>;
type State = Readonly<{
email: string;
isSubmitting: boolean;
}>;
export default class ForgotPasswordContainer extends React.PureComponent<Props, State> {
state: State = {
email: '',
isSubmitting: false,
};
handleFieldUpdate = (e: React.ChangeEvent<HTMLInputElement>) => this.setState({
email: e.target.value,
});
handleSubmission = (e: React.FormEvent<HTMLFormElement>) => this.setState({ isSubmitting: true }, () => {
e.preventDefault();
requestPasswordResetEmail(this.state.email)
.then(() => {
})
.catch(console.error)
.then(() => this.setState({ isSubmitting: false }));
});
render () {
return (
<React.Fragment>
<form className={'login-box'} onSubmit={this.handleSubmission}>
<div className={'-mx-3'}>
<OpenInputField
id={'email'}
type={'email'}
label={'Email'}
description={'Enter your account email address to receive instructions on resetting your password.'}
autoFocus={true}
required={true}
onChange={this.handleFieldUpdate}
/>
</div>
<div className={'mt-6'}>
<button
className={'btn btn-primary btn-jumbo'}
disabled={this.state.isSubmitting || this.state.email.length < 5}
>
{this.state.isSubmitting ?
<span className={'spinner white'}>&nbsp;</span>
:
'Send Email'
}
</button>
</div>
<div className={'mt-6 text-center'}>
<Link
to={'/login'}
className={'text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700'}
>
Return to Login
</Link>
</div>
</form>
</React.Fragment>
);
}
}

View File

@ -98,7 +98,7 @@ export default class LoginContainer extends React.PureComponent<{}, State> {
</div>
<div className={'mt-6 text-center'}>
<Link
to={'/auth/forgot-password'}
to={'/forgot-password'}
className={'text-xs text-neutral-500 tracking-wide no-underline uppercase hover:text-neutral-600'}
>
Forgot password?

View File

@ -3,9 +3,10 @@ import classNames from 'classnames';
type Props = React.InputHTMLAttributes<HTMLInputElement> & {
label: string;
description?: string;
};
export default ({ className, onChange, label, ...props }: Props) => {
export default ({ className, description, onChange, label, ...props }: Props) => {
const [ value, setValue ] = React.useState('');
const classes = classNames('input open-label', {
@ -25,6 +26,11 @@ export default ({ className, onChange, label, ...props }: Props) => {
{...props}
/>
<label htmlFor={props.id}>{label}</label>
{description &&
<p className={'text-xs text-neutral-500'}>
{description}
</p>
}
</div>
);
};

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import LoginContainer from '@/components/auth/LoginContainer';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import ForgotPasswordContainer from '@/components/auth/ForgotPasswordContainer';
export default class AuthenticationRouter extends React.PureComponent {
render () {
@ -9,13 +10,24 @@ export default class AuthenticationRouter extends React.PureComponent {
<BrowserRouter basename={'/auth'}>
<Route
render={({ location }) => (
<TransitionGroup>
<TransitionGroup className={'route-transition-group'}>
<CSSTransition key={location.key} timeout={150} classNames={'fade'}>
<Switch location={location}>
<Route path={'/login'} component={LoginContainer}/>
<Route path={'/forgot-password'}/>
<Route path={'/checkpoint'}/>
</Switch>
<section>
<Switch location={location}>
<Route path={'/login'} component={LoginContainer}/>
<Route path={'/forgot-password'} component={ForgotPasswordContainer}/>
<Route path={'/checkpoint'}/>
</Switch>
<p className={'text-center text-neutral-500 text-xs'}>
&copy; 2015 - 2019&nbsp;
<a
href={'https://pterodactyl.io'}
className={'no-underline text-neutral-500 hover:text-neutral-300'}
>
Pterodactyl Software
</a>
</p>
</section>
</CSSTransition>
</TransitionGroup>
)}

View File

@ -5,8 +5,5 @@
@section('container')
<div class="w-full max-w-xs sm:max-w-sm m-auto mt-8">
<div id="app"></div>
<p class="text-center text-neutral-500 text-xs">
{!! trans('strings.copyright', ['year' => date('Y')]) !!}
</p>
</div>
@endsection