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;
|
@apply .opacity-0;
|
||||||
transition: opacity 150ms;
|
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 */
|
/*! 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',
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
'Content-Type': '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>
|
||||||
<div className={'mt-6 text-center'}>
|
<div className={'mt-6 text-center'}>
|
||||||
<Link
|
<Link
|
||||||
to={'/auth/forgot-password'}
|
to={'/forgot-password'}
|
||||||
className={'text-xs text-neutral-500 tracking-wide no-underline uppercase hover:text-neutral-600'}
|
className={'text-xs text-neutral-500 tracking-wide no-underline uppercase hover:text-neutral-600'}
|
||||||
>
|
>
|
||||||
Forgot password?
|
Forgot password?
|
||||||
|
@ -3,9 +3,10 @@ import classNames from 'classnames';
|
|||||||
|
|
||||||
type Props = React.InputHTMLAttributes<HTMLInputElement> & {
|
type Props = React.InputHTMLAttributes<HTMLInputElement> & {
|
||||||
label: string;
|
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 [ value, setValue ] = React.useState('');
|
||||||
|
|
||||||
const classes = classNames('input open-label', {
|
const classes = classNames('input open-label', {
|
||||||
@ -25,6 +26,11 @@ export default ({ className, onChange, label, ...props }: Props) => {
|
|||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
<label htmlFor={props.id}>{label}</label>
|
<label htmlFor={props.id}>{label}</label>
|
||||||
|
{description &&
|
||||||
|
<p className={'text-xs text-neutral-500'}>
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@ import * as React from 'react';
|
|||||||
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
||||||
import LoginContainer from '@/components/auth/LoginContainer';
|
import LoginContainer from '@/components/auth/LoginContainer';
|
||||||
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
||||||
|
import ForgotPasswordContainer from '@/components/auth/ForgotPasswordContainer';
|
||||||
|
|
||||||
export default class AuthenticationRouter extends React.PureComponent {
|
export default class AuthenticationRouter extends React.PureComponent {
|
||||||
render () {
|
render () {
|
||||||
@ -9,13 +10,24 @@ export default class AuthenticationRouter extends React.PureComponent {
|
|||||||
<BrowserRouter basename={'/auth'}>
|
<BrowserRouter basename={'/auth'}>
|
||||||
<Route
|
<Route
|
||||||
render={({ location }) => (
|
render={({ location }) => (
|
||||||
<TransitionGroup>
|
<TransitionGroup className={'route-transition-group'}>
|
||||||
<CSSTransition key={location.key} timeout={150} classNames={'fade'}>
|
<CSSTransition key={location.key} timeout={150} classNames={'fade'}>
|
||||||
|
<section>
|
||||||
<Switch location={location}>
|
<Switch location={location}>
|
||||||
<Route path={'/login'} component={LoginContainer}/>
|
<Route path={'/login'} component={LoginContainer}/>
|
||||||
<Route path={'/forgot-password'}/>
|
<Route path={'/forgot-password'} component={ForgotPasswordContainer}/>
|
||||||
<Route path={'/checkpoint'}/>
|
<Route path={'/checkpoint'}/>
|
||||||
</Switch>
|
</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>
|
</CSSTransition>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
)}
|
)}
|
||||||
|
@ -5,8 +5,5 @@
|
|||||||
@section('container')
|
@section('container')
|
||||||
<div class="w-full max-w-xs sm:max-w-sm m-auto mt-8">
|
<div class="w-full max-w-xs sm:max-w-sm m-auto mt-8">
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<p class="text-center text-neutral-500 text-xs">
|
|
||||||
{!! trans('strings.copyright', ['year' => date('Y')]) !!}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
Loading…
Reference in New Issue
Block a user