|
1 | 1 | import * as React from 'react'; |
2 | 2 | import { Link } from 'react-router-dom'; |
3 | 3 | import requestPasswordResetEmail from '@/api/auth/requestPasswordResetEmail'; |
4 | | -import { connect } from 'react-redux'; |
5 | | -import { pushFlashMessage, clearAllFlashMessages } from '@/redux/actions/flash'; |
6 | 4 | import { httpErrorToHuman } from '@/api/http'; |
7 | 5 | import LoginFormContainer from '@/components/auth/LoginFormContainer'; |
| 6 | +import { Actions, useStoreActions } from 'easy-peasy'; |
| 7 | +import { ApplicationState } from '@/state/types'; |
| 8 | +import FlashMessageRender from '@/components/FlashMessageRender'; |
8 | 9 |
|
9 | | -type Props = Readonly<{ |
10 | | - pushFlashMessage: typeof pushFlashMessage; |
11 | | - clearAllFlashMessages: typeof clearAllFlashMessages; |
12 | | -}>; |
| 10 | +export default () => { |
| 11 | + const [ isSubmitting, setSubmitting ] = React.useState(false); |
| 12 | + const [ email, setEmail ] = React.useState(''); |
13 | 13 |
|
14 | | -type State = Readonly<{ |
15 | | - email: string; |
16 | | - isSubmitting: boolean; |
17 | | -}>; |
| 14 | + const { clearFlashes, addFlash } = useStoreActions((actions: Actions<ApplicationState>) => actions.flashes); |
18 | 15 |
|
19 | | -class ForgotPasswordContainer extends React.PureComponent<Props, State> { |
20 | | - emailField = React.createRef<HTMLInputElement>(); |
| 16 | + const handleFieldUpdate = (e: React.ChangeEvent<HTMLInputElement>) => setEmail(e.target.value); |
21 | 17 |
|
22 | | - state: State = { |
23 | | - email: '', |
24 | | - isSubmitting: false, |
25 | | - }; |
26 | | - |
27 | | - handleFieldUpdate = (e: React.ChangeEvent<HTMLInputElement>) => this.setState({ |
28 | | - email: e.target.value, |
29 | | - }); |
30 | | - |
31 | | - handleSubmission = (e: React.FormEvent<HTMLFormElement>) => { |
| 18 | + const handleSubmission = (e: React.FormEvent<HTMLFormElement>) => { |
32 | 19 | e.preventDefault(); |
33 | 20 |
|
34 | | - this.setState({ isSubmitting: true }, () => { |
35 | | - this.props.clearAllFlashMessages(); |
36 | | - requestPasswordResetEmail(this.state.email) |
37 | | - .then(response => { |
38 | | - if (this.emailField.current) { |
39 | | - this.emailField.current.value = ''; |
40 | | - } |
41 | | - |
42 | | - this.props.pushFlashMessage({ |
43 | | - type: 'success', title: 'Success', message: response, |
44 | | - }); |
45 | | - }) |
46 | | - .catch(error => { |
47 | | - console.error(error); |
48 | | - this.props.pushFlashMessage({ |
49 | | - type: 'error', |
50 | | - title: 'Error', |
51 | | - message: httpErrorToHuman(error), |
52 | | - }); |
53 | | - }) |
54 | | - .then(() => this.setState({ isSubmitting: false })); |
55 | | - }); |
| 21 | + setSubmitting(true); |
| 22 | + clearFlashes(); |
| 23 | + requestPasswordResetEmail(email) |
| 24 | + .then(response => { |
| 25 | + setEmail(''); |
| 26 | + addFlash({ type: 'success', title: 'Success', message: response }); |
| 27 | + }) |
| 28 | + .catch(error => { |
| 29 | + console.error(error); |
| 30 | + addFlash({ type: 'error', title: 'Error', message: httpErrorToHuman(error) }); |
| 31 | + }) |
| 32 | + .then(() => setSubmitting(false)); |
56 | 33 | }; |
57 | 34 |
|
58 | | - render () { |
59 | | - return ( |
60 | | - <div> |
61 | | - <h2 className={'text-center text-neutral-100 font-medium py-4'}> |
62 | | - Request Password Reset |
63 | | - </h2> |
64 | | - <LoginFormContainer onSubmit={this.handleSubmission}> |
65 | | - <label htmlFor={'email'}>Email</label> |
66 | | - <input |
67 | | - ref={this.emailField} |
68 | | - id={'email'} |
69 | | - type={'email'} |
70 | | - required={true} |
71 | | - className={'input'} |
72 | | - onChange={this.handleFieldUpdate} |
73 | | - autoFocus={true} |
74 | | - /> |
75 | | - <p className={'input-help'}> |
76 | | - Enter your account email address to receive instructions on resetting your password. |
77 | | - </p> |
78 | | - <div className={'mt-6'}> |
79 | | - <button |
80 | | - className={'btn btn-primary btn-jumbo flex justify-center'} |
81 | | - disabled={this.state.isSubmitting || this.state.email.length < 5} |
82 | | - > |
83 | | - {this.state.isSubmitting ? |
84 | | - <div className={'spinner-circle spinner-sm spinner-white'}></div> |
85 | | - : |
86 | | - 'Send Email' |
87 | | - } |
88 | | - </button> |
89 | | - </div> |
90 | | - <div className={'mt-6 text-center'}> |
91 | | - <Link |
92 | | - to={'/login'} |
93 | | - className={'text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700'} |
94 | | - > |
95 | | - Return to Login |
96 | | - </Link> |
97 | | - </div> |
98 | | - </LoginFormContainer> |
99 | | - </div> |
100 | | - ); |
101 | | - } |
102 | | -} |
103 | | - |
104 | | -const mapDispatchToProps = { |
105 | | - pushFlashMessage, |
106 | | - clearAllFlashMessages, |
| 35 | + return ( |
| 36 | + <div> |
| 37 | + <h2 className={'text-center text-neutral-100 font-medium py-4'}> |
| 38 | + Request Password Reset |
| 39 | + </h2> |
| 40 | + <FlashMessageRender/> |
| 41 | + <LoginFormContainer onSubmit={handleSubmission}> |
| 42 | + <label htmlFor={'email'}>Email</label> |
| 43 | + <input |
| 44 | + id={'email'} |
| 45 | + type={'email'} |
| 46 | + required={true} |
| 47 | + className={'input'} |
| 48 | + value={email} |
| 49 | + onChange={handleFieldUpdate} |
| 50 | + autoFocus={true} |
| 51 | + /> |
| 52 | + <p className={'input-help'}> |
| 53 | + Enter your account email address to receive instructions on resetting your password. |
| 54 | + </p> |
| 55 | + <div className={'mt-6'}> |
| 56 | + <button |
| 57 | + className={'btn btn-primary btn-jumbo flex justify-center'} |
| 58 | + disabled={isSubmitting || email.length < 5} |
| 59 | + > |
| 60 | + {isSubmitting ? |
| 61 | + <div className={'spinner-circle spinner-sm spinner-white'}></div> |
| 62 | + : |
| 63 | + 'Send Email' |
| 64 | + } |
| 65 | + </button> |
| 66 | + </div> |
| 67 | + <div className={'mt-6 text-center'}> |
| 68 | + <Link |
| 69 | + to={'/login'} |
| 70 | + className={'text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700'} |
| 71 | + > |
| 72 | + Return to Login |
| 73 | + </Link> |
| 74 | + </div> |
| 75 | + </LoginFormContainer> |
| 76 | + </div> |
| 77 | + ); |
107 | 78 | }; |
108 | | - |
109 | | -export default connect(null, mapDispatchToProps)(ForgotPasswordContainer); |
0 commit comments