@ampath/esm-login-app 8.0.0-next.3 → 8.0.0-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/2310.js +1 -1
- package/dist/2310.js.map +1 -1
- package/dist/esm-login-app.js.buildmanifest.json +6 -6
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/login/login.component.tsx +107 -118
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.2.0"},"pages":[{"component":"root","route":"login","online":true,"offline":true},{"component":"root","route":"logout","online":true,"offline":true},{"component":"root","route":"change-password","online":true,"offline":true}],"extensions":[{"name":"location-picker","slot":"location-picker","component":"locationPicker","online":true,"offline":true},{"name":"logout-button","slot":"user-panel-bottom-slot","component":"logoutButton","online":true,"offline":true},{"name":"password-changer","slot":"user-panel-slot","component":"changePasswordLink","online":true,"offline":true},{"name":"location-changer","slot":"top-nav-info-slot","component":"changeLocationLink","online":true,"offline":true,"order":1}],"modals":[{"name":"change-password-modal","component":"changePasswordModal"}],"version":"8.0.0-next.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.2.0"},"pages":[{"component":"root","route":"login","online":true,"offline":true},{"component":"root","route":"logout","online":true,"offline":true},{"component":"root","route":"change-password","online":true,"offline":true}],"extensions":[{"name":"location-picker","slot":"location-picker","component":"locationPicker","online":true,"offline":true},{"name":"logout-button","slot":"user-panel-bottom-slot","component":"logoutButton","online":true,"offline":true},{"name":"password-changer","slot":"user-panel-slot","component":"changePasswordLink","online":true,"offline":true},{"name":"location-changer","slot":"top-nav-info-slot","component":"changeLocationLink","online":true,"offline":true,"order":1}],"modals":[{"name":"change-password-modal","component":"changePasswordModal"}],"version":"8.0.0-next.4"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect, useCallback } from
|
|
2
|
-
import { useLocation, useNavigate } from
|
|
3
|
-
import { useTranslation } from
|
|
4
|
-
import {
|
|
5
|
-
Button,
|
|
6
|
-
InlineLoading,
|
|
7
|
-
InlineNotification,
|
|
8
|
-
PasswordInput,
|
|
9
|
-
TextInput,
|
|
10
|
-
Tile,
|
|
11
|
-
} from "@carbon/react";
|
|
1
|
+
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
2
|
+
import { useLocation, useNavigate } from 'react-router-dom';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { Button, InlineLoading, InlineNotification, PasswordInput, TextInput, Tile } from '@carbon/react';
|
|
12
5
|
import {
|
|
13
6
|
ArrowRightIcon,
|
|
14
7
|
getCoreTranslation,
|
|
@@ -17,45 +10,43 @@ import {
|
|
|
17
10
|
useConfig,
|
|
18
11
|
useConnectivity,
|
|
19
12
|
useSession,
|
|
20
|
-
} from
|
|
21
|
-
import { type ConfigSchema } from
|
|
22
|
-
import Logo from
|
|
23
|
-
import Footer from
|
|
24
|
-
import styles from
|
|
25
|
-
import { getOtp } from
|
|
13
|
+
} from '@openmrs/esm-framework';
|
|
14
|
+
import { type ConfigSchema } from '../config-schema';
|
|
15
|
+
import Logo from '../logo.component';
|
|
16
|
+
import Footer from '../footer.component';
|
|
17
|
+
import styles from './login.scss';
|
|
18
|
+
import { getOtp } from '../resources/otp.resource';
|
|
19
|
+
import { getOtpEnabledStatus } from '../utils/get-base-url';
|
|
20
|
+
import { boolean } from 'zod';
|
|
26
21
|
|
|
27
22
|
export interface LoginReferrer {
|
|
28
23
|
referrer?: string;
|
|
29
24
|
}
|
|
30
25
|
|
|
31
26
|
const Login: React.FC = () => {
|
|
32
|
-
const {
|
|
33
|
-
showPasswordOnSeparateScreen,
|
|
34
|
-
provider: loginProvider,
|
|
35
|
-
links: loginLinks,
|
|
36
|
-
} = useConfig<ConfigSchema>();
|
|
27
|
+
const { showPasswordOnSeparateScreen, provider: loginProvider, links: loginLinks } = useConfig<ConfigSchema>();
|
|
37
28
|
const isLoginEnabled = useConnectivity();
|
|
38
29
|
const { t } = useTranslation();
|
|
39
30
|
const { user } = useSession();
|
|
40
|
-
const location = useLocation() as unknown as Omit<Location,
|
|
31
|
+
const location = useLocation() as unknown as Omit<Location, 'state'> & {
|
|
41
32
|
state: LoginReferrer;
|
|
42
33
|
};
|
|
43
34
|
const navigate = useNavigate();
|
|
44
35
|
|
|
45
|
-
const [errorMessage, setErrorMessage] = useState(
|
|
36
|
+
const [errorMessage, setErrorMessage] = useState('');
|
|
46
37
|
const [isLoggingIn, setIsLoggingIn] = useState(false);
|
|
47
|
-
const [password, setPassword] = useState(
|
|
48
|
-
const [username, setUsername] = useState(
|
|
38
|
+
const [password, setPassword] = useState('');
|
|
39
|
+
const [username, setUsername] = useState('');
|
|
49
40
|
const [showPasswordField, setShowPasswordField] = useState(false);
|
|
50
41
|
const passwordInputRef = useRef<HTMLInputElement>(null);
|
|
51
42
|
const usernameInputRef = useRef<HTMLInputElement>(null);
|
|
52
43
|
|
|
53
44
|
useEffect(() => {
|
|
54
45
|
if (!user) {
|
|
55
|
-
if (loginProvider.type ===
|
|
46
|
+
if (loginProvider.type === 'oauth2') {
|
|
56
47
|
openmrsNavigate({ to: loginProvider.loginUrl });
|
|
57
|
-
} else if (!username && location.pathname ===
|
|
58
|
-
navigate(
|
|
48
|
+
} else if (!username && location.pathname === '/login/confirm') {
|
|
49
|
+
navigate('/login');
|
|
59
50
|
}
|
|
60
51
|
}
|
|
61
52
|
}, [username, navigate, location, user, loginProvider]);
|
|
@@ -83,14 +74,8 @@ const Login: React.FC = () => {
|
|
|
83
74
|
}
|
|
84
75
|
}, []);
|
|
85
76
|
|
|
86
|
-
const changeUsername = useCallback(
|
|
87
|
-
|
|
88
|
-
[]
|
|
89
|
-
);
|
|
90
|
-
const changePassword = useCallback(
|
|
91
|
-
(evt: React.ChangeEvent<HTMLInputElement>) => setPassword(evt.target.value),
|
|
92
|
-
[]
|
|
93
|
-
);
|
|
77
|
+
const changeUsername = useCallback((evt: React.ChangeEvent<HTMLInputElement>) => setUsername(evt.target.value), []);
|
|
78
|
+
const changePassword = useCallback((evt: React.ChangeEvent<HTMLInputElement>) => setPassword(evt.target.value), []);
|
|
94
79
|
|
|
95
80
|
const handleSubmit = useCallback(
|
|
96
81
|
async (evt: React.FormEvent<HTMLFormElement>) => {
|
|
@@ -98,9 +83,11 @@ const Login: React.FC = () => {
|
|
|
98
83
|
evt.stopPropagation();
|
|
99
84
|
|
|
100
85
|
// If credentials were autofilled, input onChange might not have been called
|
|
101
|
-
const currentUsername =
|
|
102
|
-
usernameInputRef.current?.value?.trim() || username;
|
|
86
|
+
const currentUsername = usernameInputRef.current?.value?.trim() || username;
|
|
103
87
|
const currentPassword = passwordInputRef.current?.value || password;
|
|
88
|
+
const isOtpEnabled: boolean = await getOtpEnabledStatus();
|
|
89
|
+
|
|
90
|
+
console.log('OTPSTATUS: ', isOtpEnabled);
|
|
104
91
|
|
|
105
92
|
if (showPasswordOnSeparateScreen && !showPasswordField) {
|
|
106
93
|
continueLogin();
|
|
@@ -114,41 +101,70 @@ const Login: React.FC = () => {
|
|
|
114
101
|
|
|
115
102
|
try {
|
|
116
103
|
setIsLoggingIn(true);
|
|
117
|
-
const sessionStore = await refetchCurrentUser(
|
|
118
|
-
currentUsername,
|
|
119
|
-
currentPassword
|
|
120
|
-
);
|
|
104
|
+
const sessionStore = await refetchCurrentUser(currentUsername, currentPassword);
|
|
121
105
|
const session = sessionStore.session;
|
|
122
106
|
const authenticated = sessionStore?.session?.authenticated;
|
|
123
107
|
|
|
124
|
-
if (
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (location
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
108
|
+
if (isOtpEnabled === true) {
|
|
109
|
+
if (authenticated) {
|
|
110
|
+
if (session.sessionLocation) {
|
|
111
|
+
let to = loginLinks?.loginSuccess || '/home';
|
|
112
|
+
if (location?.state?.referrer) {
|
|
113
|
+
if (location.state.referrer.startsWith('/')) {
|
|
114
|
+
to = `\${openmrsSpaBase}${location.state.referrer}`;
|
|
115
|
+
} else {
|
|
116
|
+
to = location.state.referrer;
|
|
117
|
+
}
|
|
132
118
|
}
|
|
119
|
+
await getOtp(username, password);
|
|
120
|
+
navigate('otp', {
|
|
121
|
+
state: {
|
|
122
|
+
username,
|
|
123
|
+
password,
|
|
124
|
+
referrer: location?.state?.referrer,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
} else if (!session.sessionLocation) {
|
|
128
|
+
await getOtp(username, password);
|
|
129
|
+
navigate('otp', {
|
|
130
|
+
state: {
|
|
131
|
+
username,
|
|
132
|
+
password,
|
|
133
|
+
referrer: location?.state?.referrer,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
setErrorMessage(t('invalidCredentials', 'Invalid username or password'));
|
|
139
|
+
setUsername('');
|
|
140
|
+
setPassword('');
|
|
141
|
+
if (showPasswordOnSeparateScreen) {
|
|
142
|
+
setShowPasswordField(false);
|
|
133
143
|
}
|
|
134
|
-
|
|
135
|
-
await getOtp(username, password);
|
|
136
|
-
navigate("otp", {
|
|
137
|
-
state: {
|
|
138
|
-
username,
|
|
139
|
-
password,
|
|
140
|
-
referrer: location?.state?.referrer,
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
144
|
}
|
|
144
145
|
} else {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
if (authenticated) {
|
|
147
|
+
if (session.sessionLocation) {
|
|
148
|
+
let to = loginLinks?.loginSuccess || '/home';
|
|
149
|
+
if (location?.state?.referrer) {
|
|
150
|
+
if (location.state.referrer.startsWith('/')) {
|
|
151
|
+
to = `\${openmrsSpaBase}${location.state.referrer}`;
|
|
152
|
+
} else {
|
|
153
|
+
to = location.state.referrer;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
openmrsNavigate({ to });
|
|
158
|
+
} else {
|
|
159
|
+
navigate('/login/location');
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
setErrorMessage(t('invalidCredentials', 'Invalid username or password'));
|
|
163
|
+
setUsername('');
|
|
164
|
+
setPassword('');
|
|
165
|
+
if (showPasswordOnSeparateScreen) {
|
|
166
|
+
setShowPasswordField(false);
|
|
167
|
+
}
|
|
152
168
|
}
|
|
153
169
|
}
|
|
154
170
|
|
|
@@ -157,12 +173,10 @@ const Login: React.FC = () => {
|
|
|
157
173
|
if (error instanceof Error) {
|
|
158
174
|
setErrorMessage(error.message);
|
|
159
175
|
} else {
|
|
160
|
-
setErrorMessage(
|
|
161
|
-
t("invalidCredentials", "Invalid username or password")
|
|
162
|
-
);
|
|
176
|
+
setErrorMessage(t('invalidCredentials', 'Invalid username or password'));
|
|
163
177
|
}
|
|
164
|
-
setUsername(
|
|
165
|
-
setPassword(
|
|
178
|
+
setUsername('');
|
|
179
|
+
setPassword('');
|
|
166
180
|
if (showPasswordOnSeparateScreen) {
|
|
167
181
|
setShowPasswordField(false);
|
|
168
182
|
}
|
|
@@ -180,10 +194,10 @@ const Login: React.FC = () => {
|
|
|
180
194
|
location,
|
|
181
195
|
t,
|
|
182
196
|
continueLogin,
|
|
183
|
-
]
|
|
197
|
+
],
|
|
184
198
|
);
|
|
185
199
|
|
|
186
|
-
if (!loginProvider || loginProvider.type ===
|
|
200
|
+
if (!loginProvider || loginProvider.type === 'basic') {
|
|
187
201
|
return (
|
|
188
202
|
<div className={styles.container}>
|
|
189
203
|
<Tile className={styles.loginCard}>
|
|
@@ -192,8 +206,8 @@ const Login: React.FC = () => {
|
|
|
192
206
|
<InlineNotification
|
|
193
207
|
kind="error"
|
|
194
208
|
subtitle={t(errorMessage)}
|
|
195
|
-
title={getCoreTranslation(
|
|
196
|
-
onClick={() => setErrorMessage(
|
|
209
|
+
title={getCoreTranslation('error')}
|
|
210
|
+
onClick={() => setErrorMessage('')}
|
|
197
211
|
/>
|
|
198
212
|
</div>
|
|
199
213
|
)}
|
|
@@ -207,7 +221,7 @@ const Login: React.FC = () => {
|
|
|
207
221
|
type="text"
|
|
208
222
|
name="username"
|
|
209
223
|
autoComplete="username"
|
|
210
|
-
labelText={t(
|
|
224
|
+
labelText={t('username', 'Username')}
|
|
211
225
|
value={username}
|
|
212
226
|
onChange={changeUsername}
|
|
213
227
|
ref={usernameInputRef}
|
|
@@ -216,25 +230,18 @@ const Login: React.FC = () => {
|
|
|
216
230
|
/>
|
|
217
231
|
{showPasswordOnSeparateScreen ? (
|
|
218
232
|
<>
|
|
219
|
-
<div
|
|
220
|
-
className={
|
|
221
|
-
showPasswordField ? undefined : styles.hiddenPasswordField
|
|
222
|
-
}
|
|
223
|
-
>
|
|
233
|
+
<div className={showPasswordField ? undefined : styles.hiddenPasswordField}>
|
|
224
234
|
<PasswordInput
|
|
225
235
|
id="password"
|
|
226
|
-
labelText={t(
|
|
236
|
+
labelText={t('password', 'Password')}
|
|
227
237
|
name="password"
|
|
228
238
|
autoComplete="current-password"
|
|
229
239
|
onChange={changePassword}
|
|
230
240
|
ref={passwordInputRef}
|
|
231
241
|
required
|
|
232
242
|
value={password}
|
|
233
|
-
showPasswordLabel={t(
|
|
234
|
-
invalidText={t(
|
|
235
|
-
"validValueRequired",
|
|
236
|
-
"A valid value is required"
|
|
237
|
-
)}
|
|
243
|
+
showPasswordLabel={t('showPassword', 'Show password')}
|
|
244
|
+
invalidText={t('validValueRequired', 'A valid value is required')}
|
|
238
245
|
aria-hidden={!showPasswordField}
|
|
239
246
|
tabIndex={showPasswordField ? 0 : -1}
|
|
240
247
|
/>
|
|
@@ -243,31 +250,21 @@ const Login: React.FC = () => {
|
|
|
243
250
|
<Button
|
|
244
251
|
type="submit"
|
|
245
252
|
className={styles.continueButton}
|
|
246
|
-
renderIcon={(props) =>
|
|
247
|
-
|
|
248
|
-
)}
|
|
249
|
-
iconDescription={t(
|
|
250
|
-
"loginButtonIconDescription",
|
|
251
|
-
"Log in button"
|
|
252
|
-
)}
|
|
253
|
+
renderIcon={(props) => <ArrowRightIcon size={24} {...props} />}
|
|
254
|
+
iconDescription={t('loginButtonIconDescription', 'Log in button')}
|
|
253
255
|
disabled={!isLoginEnabled || isLoggingIn}
|
|
254
256
|
>
|
|
255
257
|
{isLoggingIn ? (
|
|
256
|
-
<InlineLoading
|
|
257
|
-
className={styles.loader}
|
|
258
|
-
description={t("loggingIn", "Logging in") + "..."}
|
|
259
|
-
/>
|
|
258
|
+
<InlineLoading className={styles.loader} description={t('loggingIn', 'Logging in') + '...'} />
|
|
260
259
|
) : (
|
|
261
|
-
t(
|
|
260
|
+
t('login', 'Log in')
|
|
262
261
|
)}
|
|
263
262
|
</Button>
|
|
264
263
|
) : (
|
|
265
264
|
<Button
|
|
266
265
|
type="submit"
|
|
267
266
|
className={styles.continueButton}
|
|
268
|
-
renderIcon={(props) =>
|
|
269
|
-
<ArrowRightIcon size={24} {...props} />
|
|
270
|
-
)}
|
|
267
|
+
renderIcon={(props) => <ArrowRightIcon size={24} {...props} />}
|
|
271
268
|
iconDescription="Continue to password"
|
|
272
269
|
onClick={(evt) => {
|
|
273
270
|
evt.preventDefault();
|
|
@@ -275,7 +272,7 @@ const Login: React.FC = () => {
|
|
|
275
272
|
}}
|
|
276
273
|
disabled={!isLoginEnabled}
|
|
277
274
|
>
|
|
278
|
-
{t(
|
|
275
|
+
{t('continue', 'Continue')}
|
|
279
276
|
</Button>
|
|
280
277
|
)}
|
|
281
278
|
</>
|
|
@@ -283,35 +280,27 @@ const Login: React.FC = () => {
|
|
|
283
280
|
<>
|
|
284
281
|
<PasswordInput
|
|
285
282
|
id="password"
|
|
286
|
-
labelText={t(
|
|
283
|
+
labelText={t('password', 'Password')}
|
|
287
284
|
name="password"
|
|
288
285
|
autoComplete="current-password"
|
|
289
286
|
onChange={changePassword}
|
|
290
287
|
ref={passwordInputRef}
|
|
291
288
|
required
|
|
292
289
|
value={password}
|
|
293
|
-
showPasswordLabel={t(
|
|
294
|
-
invalidText={t(
|
|
295
|
-
"validValueRequired",
|
|
296
|
-
"A valid value is required"
|
|
297
|
-
)}
|
|
290
|
+
showPasswordLabel={t('showPassword', 'Show password')}
|
|
291
|
+
invalidText={t('validValueRequired', 'A valid value is required')}
|
|
298
292
|
/>
|
|
299
293
|
<Button
|
|
300
294
|
type="submit"
|
|
301
295
|
className={styles.continueButton}
|
|
302
|
-
renderIcon={(props) =>
|
|
303
|
-
<ArrowRightIcon size={24} {...props} />
|
|
304
|
-
)}
|
|
296
|
+
renderIcon={(props) => <ArrowRightIcon size={24} {...props} />}
|
|
305
297
|
iconDescription="Log in"
|
|
306
298
|
disabled={!isLoginEnabled || isLoggingIn}
|
|
307
299
|
>
|
|
308
300
|
{isLoggingIn ? (
|
|
309
|
-
<InlineLoading
|
|
310
|
-
className={styles.loader}
|
|
311
|
-
description={t("loggingIn", "Logging in") + "..."}
|
|
312
|
-
/>
|
|
301
|
+
<InlineLoading className={styles.loader} description={t('loggingIn', 'Logging in') + '...'} />
|
|
313
302
|
) : (
|
|
314
|
-
t(
|
|
303
|
+
t('login', 'Log in')
|
|
315
304
|
)}
|
|
316
305
|
</Button>
|
|
317
306
|
</>
|