Skip to content

Commit b93b40b

Browse files
committed
Begin working on password reset page
1 parent d9f3029 commit b93b40b

File tree

8 files changed

+120
-11
lines changed

8 files changed

+120
-11
lines changed

resources/assets/styles/components/animations.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,13 @@
1616
@apply .opacity-0;
1717
transition: opacity 150ms;
1818
}
19+
20+
/** @todo fix this, hides footer stuff */
21+
div.route-transition-group {
22+
@apply .relative;
23+
24+
& section {
25+
@apply .absolute .w-full .pin-t .pin-l;
26+
}
27+
}
1928
/*! purgecss end ignore */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import http from '@/api/http';
2+
3+
export default (email: string): Promise<void> => {
4+
return new Promise((resolve, reject) => {
5+
http.post('/auth/password', { email })
6+
.then(() => resolve())
7+
.catch(reject);
8+
});
9+
};

resources/scripts/api/http.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const http: AxiosInstance = axios.create({
99
'X-Requested-With': 'XMLHttpRequest',
1010
'Accept': 'application/json',
1111
'Content-Type': 'application/json',
12+
'X-CSRF-Token': (window as any).X_CSRF_TOKEN as string || '',
1213
},
1314
});
1415

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import * as React from 'react';
2+
import OpenInputField from '@/components/forms/OpenInputField';
3+
import { Link } from 'react-router-dom';
4+
import requestPasswordResetEmail from '@/api/auth/requestPasswordResetEmail';
5+
6+
type Props = Readonly<{
7+
8+
}>;
9+
10+
type State = Readonly<{
11+
email: string;
12+
isSubmitting: boolean;
13+
}>;
14+
15+
export default class ForgotPasswordContainer extends React.PureComponent<Props, State> {
16+
state: State = {
17+
email: '',
18+
isSubmitting: false,
19+
};
20+
21+
handleFieldUpdate = (e: React.ChangeEvent<HTMLInputElement>) => this.setState({
22+
email: e.target.value,
23+
});
24+
25+
handleSubmission = (e: React.FormEvent<HTMLFormElement>) => this.setState({ isSubmitting: true }, () => {
26+
e.preventDefault();
27+
28+
requestPasswordResetEmail(this.state.email)
29+
.then(() => {
30+
31+
})
32+
.catch(console.error)
33+
.then(() => this.setState({ isSubmitting: false }));
34+
});
35+
36+
render () {
37+
return (
38+
<React.Fragment>
39+
<form className={'login-box'} onSubmit={this.handleSubmission}>
40+
<div className={'-mx-3'}>
41+
<OpenInputField
42+
id={'email'}
43+
type={'email'}
44+
label={'Email'}
45+
description={'Enter your account email address to receive instructions on resetting your password.'}
46+
autoFocus={true}
47+
required={true}
48+
onChange={this.handleFieldUpdate}
49+
/>
50+
</div>
51+
<div className={'mt-6'}>
52+
<button
53+
className={'btn btn-primary btn-jumbo'}
54+
disabled={this.state.isSubmitting || this.state.email.length < 5}
55+
>
56+
{this.state.isSubmitting ?
57+
<span className={'spinner white'}>&nbsp;</span>
58+
:
59+
'Send Email'
60+
}
61+
</button>
62+
</div>
63+
<div className={'mt-6 text-center'}>
64+
<Link
65+
to={'/login'}
66+
className={'text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700'}
67+
>
68+
Return to Login
69+
</Link>
70+
</div>
71+
</form>
72+
</React.Fragment>
73+
);
74+
}
75+
}

resources/scripts/components/auth/LoginContainer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export default class LoginContainer extends React.PureComponent<{}, State> {
9898
</div>
9999
<div className={'mt-6 text-center'}>
100100
<Link
101-
to={'/auth/forgot-password'}
101+
to={'/forgot-password'}
102102
className={'text-xs text-neutral-500 tracking-wide no-underline uppercase hover:text-neutral-600'}
103103
>
104104
Forgot password?

resources/scripts/components/forms/OpenInputField.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import classNames from 'classnames';
33

44
type Props = React.InputHTMLAttributes<HTMLInputElement> & {
55
label: string;
6+
description?: string;
67
};
78

8-
export default ({ className, onChange, label, ...props }: Props) => {
9+
export default ({ className, description, onChange, label, ...props }: Props) => {
910
const [ value, setValue ] = React.useState('');
1011

1112
const classes = classNames('input open-label', {
@@ -25,6 +26,11 @@ export default ({ className, onChange, label, ...props }: Props) => {
2526
{...props}
2627
/>
2728
<label htmlFor={props.id}>{label}</label>
29+
{description &&
30+
<p className={'text-xs text-neutral-500'}>
31+
{description}
32+
</p>
33+
}
2834
</div>
2935
);
3036
};

resources/scripts/routers/AuthenticationRouter.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,32 @@ import * as React from 'react';
22
import { BrowserRouter, Route, Switch } from 'react-router-dom';
33
import LoginContainer from '@/components/auth/LoginContainer';
44
import { CSSTransition, TransitionGroup } from 'react-transition-group';
5+
import ForgotPasswordContainer from '@/components/auth/ForgotPasswordContainer';
56

67
export default class AuthenticationRouter extends React.PureComponent {
78
render () {
89
return (
910
<BrowserRouter basename={'/auth'}>
1011
<Route
1112
render={({ location }) => (
12-
<TransitionGroup>
13+
<TransitionGroup className={'route-transition-group'}>
1314
<CSSTransition key={location.key} timeout={150} classNames={'fade'}>
14-
<Switch location={location}>
15-
<Route path={'/login'} component={LoginContainer}/>
16-
<Route path={'/forgot-password'}/>
17-
<Route path={'/checkpoint'}/>
18-
</Switch>
15+
<section>
16+
<Switch location={location}>
17+
<Route path={'/login'} component={LoginContainer}/>
18+
<Route path={'/forgot-password'} component={ForgotPasswordContainer}/>
19+
<Route path={'/checkpoint'}/>
20+
</Switch>
21+
<p className={'text-center text-neutral-500 text-xs'}>
22+
&copy; 2015 - 2019&nbsp;
23+
<a
24+
href={'https://pterodactyl.io'}
25+
className={'no-underline text-neutral-500 hover:text-neutral-300'}
26+
>
27+
Pterodactyl Software
28+
</a>
29+
</p>
30+
</section>
1931
</CSSTransition>
2032
</TransitionGroup>
2133
)}

resources/themes/pterodactyl/templates/auth/core.blade.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,5 @@
55
@section('container')
66
<div class="w-full max-w-xs sm:max-w-sm m-auto mt-8">
77
<div id="app"></div>
8-
<p class="text-center text-neutral-500 text-xs">
9-
{!! trans('strings.copyright', ['year' => date('Y')]) !!}
10-
</p>
118
</div>
129
@endsection

0 commit comments

Comments
 (0)