1
1
import React , { useState , useRef , useEffect , useCallback } from 'react' ;
2
- import { type To , useLocation , useNavigate } from 'react-router-dom' ;
2
+ import { useLocation , useNavigate } from 'react-router-dom' ;
3
3
import { useTranslation } from 'react-i18next' ;
4
4
import { Button , InlineLoading , InlineNotification , PasswordInput , TextInput , Tile } from '@carbon/react' ;
5
5
import {
6
- ArrowLeftIcon ,
7
6
ArrowRightIcon ,
8
7
getCoreTranslation ,
9
- navigate as openmrsNavigate ,
10
8
refetchCurrentUser ,
9
+ navigate as openmrsNavigate ,
11
10
useConfig ,
12
11
useConnectivity ,
13
12
useSession ,
@@ -21,13 +20,6 @@ export interface LoginReferrer {
21
20
referrer ?: string ;
22
21
}
23
22
24
- const hidden : React . CSSProperties = {
25
- height : 0 ,
26
- width : 0 ,
27
- border : 0 ,
28
- padding : 0 ,
29
- } ;
30
-
31
23
const Login : React . FC = ( ) => {
32
24
const { showPasswordOnSeparateScreen, provider : loginProvider , links : loginLinks } = useConfig < ConfigSchema > ( ) ;
33
25
const isLoginEnabled = useConnectivity ( ) ;
@@ -36,26 +28,16 @@ const Login: React.FC = () => {
36
28
const location = useLocation ( ) as unknown as Omit < Location , 'state' > & {
37
29
state : LoginReferrer ;
38
30
} ;
39
-
40
- const rawNavigate = useNavigate ( ) ;
41
- const navigate = useCallback (
42
- ( to : To ) => {
43
- rawNavigate ( to , { state : location . state } ) ;
44
- } ,
45
- [ rawNavigate , location . state ] ,
46
- ) ;
31
+ const navigate = useNavigate ( ) ;
47
32
48
33
const [ errorMessage , setErrorMessage ] = useState ( '' ) ;
49
34
const [ isLoggingIn , setIsLoggingIn ] = useState ( false ) ;
50
35
const [ password , setPassword ] = useState ( '' ) ;
51
36
const [ username , setUsername ] = useState ( '' ) ;
52
- const formRef = useRef < HTMLFormElement > ( null ) ;
37
+ const [ showPasswordField , setShowPasswordField ] = useState ( false ) ;
53
38
const passwordInputRef = useRef < HTMLInputElement > ( null ) ;
54
39
const usernameInputRef = useRef < HTMLInputElement > ( null ) ;
55
40
56
- const showUsername = location . pathname === '/login' ;
57
- const showPassword = ! showPasswordOnSeparateScreen || location . pathname === '/login/confirm' ;
58
-
59
41
useEffect ( ( ) => {
60
42
if ( ! user ) {
61
43
if ( loginProvider . type === 'oauth2' ) {
@@ -67,45 +49,49 @@ const Login: React.FC = () => {
67
49
} , [ username , navigate , location , user , loginProvider ] ) ;
68
50
69
51
useEffect ( ( ) => {
70
- const fieldToFocus =
71
- showPasswordOnSeparateScreen && showPassword ? passwordInputRef . current : usernameInputRef . current ;
72
-
73
- fieldToFocus ?. focus ( ) ;
74
- } , [ showPassword , showPasswordOnSeparateScreen ] ) ;
52
+ if ( showPasswordOnSeparateScreen ) {
53
+ if ( showPasswordField ) {
54
+ passwordInputRef . current ?. focus ( ) ;
55
+ } else {
56
+ usernameInputRef . current ?. focus ( ) ;
57
+ }
58
+ }
59
+ } , [ showPasswordField , showPasswordOnSeparateScreen ] ) ;
75
60
76
61
const continueLogin = useCallback ( ( ) => {
77
62
const usernameField = usernameInputRef . current ;
78
63
79
- if ( usernameField . value && usernameField . value . trim ( ) ) {
80
- navigate ( '/login/confirm' ) ;
64
+ if ( usernameField ? .value . trim ( ) ) {
65
+ setShowPasswordField ( true ) ;
81
66
} else {
82
- usernameField . focus ( ) ;
67
+ usernameField ? .focus ( ) ;
83
68
}
84
- } , [ location . state , navigate ] ) ;
69
+ } , [ ] ) ;
85
70
86
71
const changeUsername = useCallback ( ( evt : React . ChangeEvent < HTMLInputElement > ) => setUsername ( evt . target . value ) , [ ] ) ;
87
-
88
72
const changePassword = useCallback ( ( evt : React . ChangeEvent < HTMLInputElement > ) => setPassword ( evt . target . value ) , [ ] ) ;
89
73
90
74
const handleSubmit = useCallback (
91
75
async ( evt : React . FormEvent < HTMLFormElement > ) => {
92
76
evt . preventDefault ( ) ;
93
77
evt . stopPropagation ( ) ;
94
78
95
- if ( ! showPassword ) {
79
+ if ( showPasswordOnSeparateScreen && ! showPasswordField ) {
96
80
continueLogin ( ) ;
97
81
return false ;
98
- } else if ( ! password || ! password . trim ( ) ) {
99
- passwordInputRef . current . focus ( ) ;
82
+ }
83
+
84
+ if ( ! password || ! password . trim ( ) ) {
85
+ passwordInputRef . current ?. focus ( ) ;
100
86
return false ;
101
87
}
102
88
103
89
try {
104
90
setIsLoggingIn ( true ) ;
105
-
106
91
const sessionStore = await refetchCurrentUser ( username , password ) ;
107
92
const session = sessionStore . session ;
108
93
const authenticated = sessionStore ?. session ?. authenticated ;
94
+
109
95
if ( authenticated ) {
110
96
if ( session . sessionLocation ) {
111
97
let to = loginLinks ?. loginSuccess || '/home' ;
@@ -125,9 +111,8 @@ const Login: React.FC = () => {
125
111
setErrorMessage ( t ( 'invalidCredentials' , 'Invalid username or password' ) ) ;
126
112
setUsername ( '' ) ;
127
113
setPassword ( '' ) ;
128
-
129
114
if ( showPasswordOnSeparateScreen ) {
130
- navigate ( '/login' ) ;
115
+ setShowPasswordField ( false ) ;
131
116
}
132
117
}
133
118
@@ -138,24 +123,19 @@ const Login: React.FC = () => {
138
123
} else {
139
124
setErrorMessage ( t ( 'invalidCredentials' , 'Invalid username or password' ) ) ;
140
125
}
141
-
142
126
setUsername ( '' ) ;
143
127
setPassword ( '' ) ;
144
-
145
128
if ( showPasswordOnSeparateScreen ) {
146
- navigate ( '/login' ) ;
129
+ setShowPasswordField ( false ) ;
147
130
}
148
131
} finally {
149
132
setIsLoggingIn ( false ) ;
150
133
}
151
-
152
- return false ;
153
134
} ,
154
-
155
- [ showPassword , username , password , navigate ] ,
135
+ [ username , password , navigate , showPasswordOnSeparateScreen ] ,
156
136
) ;
157
137
158
- if ( ! loginProvider || loginProvider . type === 'basic' ) {
138
+ if ( ! loginProvider || loginProvider . type === 'basic' ) {
159
139
return (
160
140
< div className = { styles . container } >
161
141
< Tile className = { styles . loginCard } >
@@ -169,109 +149,96 @@ const Login: React.FC = () => {
169
149
/>
170
150
</ div >
171
151
) }
172
- { showPasswordOnSeparateScreen && showPassword ? (
173
- < div className = { styles . backButtonDiv } >
174
- < Button
175
- className = { styles . backButton }
176
- iconDescription = { t ( 'backToUserNameIconLabel' , 'Back to username' ) }
177
- kind = "ghost"
178
- onClick = { ( ) => navigate ( '/login' ) }
179
- renderIcon = { ( props ) => < ArrowLeftIcon { ...props } size = { 24 } /> }
180
- >
181
- < span > { t ( 'back' , 'Back' ) } </ span >
182
- </ Button >
183
- </ div >
184
- ) : null }
185
152
< div className = { styles . center } >
186
153
< Logo t = { t } />
187
154
</ div >
188
- < form onSubmit = { handleSubmit } ref = { formRef } >
189
- { showUsername && (
190
- < div className = { styles . inputGroup } >
191
- < TextInput
192
- id = "username"
193
- type = "text"
194
- name = "username"
195
- labelText = { t ( 'username' , 'Username' ) }
196
- value = { username }
197
- onChange = { changeUsername }
198
- ref = { usernameInputRef }
199
- autoFocus
200
- required
201
- />
202
- { /* For password managers */ }
203
- { showPasswordOnSeparateScreen && (
204
- < input
205
- id = "password"
206
- style = { hidden }
207
- type = "password"
208
- name = "password"
209
- value = { password }
210
- onChange = { changePassword }
211
- />
212
- ) }
213
- { showPasswordOnSeparateScreen && (
155
+ < form onSubmit = { handleSubmit } >
156
+ < div className = { styles . inputGroup } >
157
+ < TextInput
158
+ id = "username"
159
+ type = "text"
160
+ labelText = { t ( 'username' , 'Username' ) }
161
+ value = { username }
162
+ onChange = { changeUsername }
163
+ ref = { usernameInputRef }
164
+ required
165
+ autoFocus
166
+ />
167
+ { showPasswordOnSeparateScreen ? (
168
+ showPasswordField ? (
169
+ < >
170
+ < PasswordInput
171
+ id = "password"
172
+ labelText = { t ( 'password' , 'Password' ) }
173
+ name = "password"
174
+ onChange = { changePassword }
175
+ ref = { passwordInputRef }
176
+ required
177
+ value = { password }
178
+ showPasswordLabel = { t ( 'showPassword' , 'Show password' ) }
179
+ invalidText = { t ( 'validValueRequired' , 'A valid value is required' ) }
180
+ />
181
+ < Button
182
+ type = "submit"
183
+ className = { styles . continueButton }
184
+ renderIcon = { ( props ) => < ArrowRightIcon size = { 24 } { ...props } /> }
185
+ iconDescription = "Log in"
186
+ disabled = { ! isLoginEnabled || isLoggingIn }
187
+ >
188
+ { isLoggingIn ? (
189
+ < InlineLoading className = { styles . loader } description = { t ( 'loggingIn' , 'Logging in' ) + '...' } />
190
+ ) : (
191
+ t ( 'login' , 'Log in' )
192
+ ) }
193
+ </ Button >
194
+ </ >
195
+ ) : (
214
196
< Button
215
197
className = { styles . continueButton }
216
198
renderIcon = { ( props ) => < ArrowRightIcon size = { 24 } { ...props } /> }
217
- type = "submit"
218
- iconDescription = "Continue to login"
199
+ iconDescription = "Continue to password"
219
200
onClick = { continueLogin }
220
201
disabled = { ! isLoginEnabled }
221
202
>
222
203
{ t ( 'continue' , 'Continue' ) }
223
204
</ Button >
224
- ) }
225
- </ div >
226
- ) }
227
- { showPassword && (
228
- < div className = { styles . inputGroup } >
229
- < PasswordInput
230
- id = "password"
231
- invalidText = { t ( 'validValueRequired' , 'A valid value is required' ) }
232
- labelText = { t ( 'password' , 'Password' ) }
233
- name = "password"
234
- onChange = { changePassword }
235
- ref = { passwordInputRef }
236
- required
237
- showPasswordLabel = { t ( 'showPassword' , 'Show password' ) }
238
- value = { password }
239
- />
240
- { /* For password managers */ }
241
- { showPasswordOnSeparateScreen && (
242
- < input
243
- id = "username"
244
- type = "text"
245
- name = "username"
246
- style = { hidden }
247
- value = { username }
248
- onChange = { changeUsername }
205
+ )
206
+ ) : (
207
+ < >
208
+ < PasswordInput
209
+ id = "password"
210
+ labelText = { t ( 'password' , 'Password' ) }
211
+ name = "password"
212
+ onChange = { changePassword }
213
+ ref = { passwordInputRef }
249
214
required
215
+ value = { password }
216
+ showPasswordLabel = { t ( 'showPassword' , 'Show password' ) }
217
+ invalidText = { t ( 'validValueRequired' , 'A valid value is required' ) }
250
218
/>
251
- ) }
252
- < Button
253
- type = "submit"
254
- className = { styles . continueButton }
255
- renderIcon = { ( props ) => < ArrowRightIcon size = { 24 } { ... props } /> }
256
- iconDescription = "Log in"
257
- disabled = { ! isLoginEnabled || isLoggingIn }
258
- >
259
- { isLoggingIn ? (
260
- < InlineLoading className = { styles . loader } description = { t ( 'loggingIn' , 'Logging in' ) + '...' } />
261
- ) : (
262
- < span > { t ( 'login' , 'Log in' ) } </ span >
263
- ) }
264
- </ Button >
265
- </ div >
266
- ) }
219
+ < Button
220
+ type = "submit"
221
+ className = { styles . continueButton }
222
+ renderIcon = { ( props ) => < ArrowRightIcon size = { 24 } { ... props } /> }
223
+ iconDescription = "Log in"
224
+ disabled = { ! isLoginEnabled || isLoggingIn }
225
+ >
226
+ { isLoggingIn ? (
227
+ < InlineLoading className = { styles . loader } description = { t ( 'loggingIn' , 'Logging in' ) + '...' } />
228
+ ) : (
229
+ t ( 'login' , 'Log in' )
230
+ ) }
231
+ </ Button >
232
+ </ >
233
+ ) }
234
+ </ div >
267
235
</ form >
268
236
</ Tile >
269
- < Footer />
237
+ < Footer />
270
238
</ div >
271
239
) ;
272
240
}
273
-
274
- return null ;
241
+ return null ;
275
242
} ;
276
243
277
244
export default Login ;
0 commit comments