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:
parent
d9f30294de
commit
b93b40ba31
@ -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 */
|
||||
|
9
resources/scripts/api/auth/requestPasswordResetEmail.ts
Normal file
9
resources/scripts/api/auth/requestPasswordResetEmail.ts
Normal 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);
|
||||
});
|
||||
};
|
@ -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 || '',
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -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'}> </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>
|
||||
);
|
||||
}
|
||||
}
|
@ -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?
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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'}>
|
||||
© 2015 - 2019
|
||||
<a
|
||||
href={'https://pterodactyl.io'}
|
||||
className={'no-underline text-neutral-500 hover:text-neutral-300'}
|
||||
>
|
||||
Pterodactyl Software
|
||||
</a>
|
||||
</p>
|
||||
</section>
|
||||
</CSSTransition>
|
||||
</TransitionGroup>
|
||||
)}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user