@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/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.3"}
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@ampath/esm-login-app",
3
- "version": "8.0.0-next.3",
3
+ "version": "8.0.0-next.4",
4
4
  "license": "MPL-2.0",
5
5
  "description": "The login microfrontend for the OpenMRS SPA",
6
6
  "browser": "dist/esm-login-app.js",
@@ -1,14 +1,7 @@
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 {
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 "@openmrs/esm-framework";
21
- import { type ConfigSchema } from "../config-schema";
22
- import Logo from "../logo.component";
23
- import Footer from "../footer.component";
24
- import styles from "./login.scss";
25
- import { getOtp } from "../resources/otp.resource";
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, "state"> & {
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 === "oauth2") {
46
+ if (loginProvider.type === 'oauth2') {
56
47
  openmrsNavigate({ to: loginProvider.loginUrl });
57
- } else if (!username && location.pathname === "/login/confirm") {
58
- navigate("/login");
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
- (evt: React.ChangeEvent<HTMLInputElement>) => setUsername(evt.target.value),
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 (authenticated) {
125
- if (session.sessionLocation) {
126
- let to = loginLinks?.loginSuccess || "/home";
127
- if (location?.state?.referrer) {
128
- if (location.state.referrer.startsWith("/")) {
129
- to = `\${openmrsSpaBase}${location.state.referrer}`;
130
- } else {
131
- to = location.state.referrer;
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
- setErrorMessage(
146
- t("invalidCredentials", "Invalid username or password")
147
- );
148
- setUsername("");
149
- setPassword("");
150
- if (showPasswordOnSeparateScreen) {
151
- setShowPasswordField(false);
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 === "basic") {
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("error")}
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("username", "Username")}
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("password", "Password")}
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("showPassword", "Show password")}
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
- <ArrowRightIcon size={24} {...props} />
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("login", "Log in")
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("continue", "Continue")}
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("password", "Password")}
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("showPassword", "Show password")}
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("login", "Log in")
303
+ t('login', 'Log in')
315
304
  )}
316
305
  </Button>
317
306
  </>