diff --git a/packages/apps/esm-help-menu-app/src/help-menu/help.component.tsx b/packages/apps/esm-help-menu-app/src/help-menu/help.component.tsx index 1fc153f89..6628ea3e3 100644 --- a/packages/apps/esm-help-menu-app/src/help-menu/help.component.tsx +++ b/packages/apps/esm-help-menu-app/src/help-menu/help.component.tsx @@ -1,10 +1,12 @@ import React, { useState, useEffect, useRef } from 'react'; import classNames from 'classnames'; import { Help } from '@carbon/react/icons'; +import { useSession } from '@openmrs/esm-framework' import HelpMenuPopup from './help-popup.component'; import styles from './help.styles.scss'; export default function HelpMenu() { + const { user } = useSession(); const [helpMenuOpen, setHelpMenuOpen] = useState(false); const helpMenuButtonRef = useRef(null); const popupRef = useRef(null); @@ -35,15 +37,17 @@ export default function HelpMenu() { return ( <> - + {user && ( + + )} {helpMenuOpen && (
diff --git a/packages/apps/esm-login-app/src/footer.component.tsx b/packages/apps/esm-login-app/src/footer.component.tsx index 130753f67..85540fffc 100644 --- a/packages/apps/esm-login-app/src/footer.component.tsx +++ b/packages/apps/esm-login-app/src/footer.component.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { interpolateUrl, useConfig } from '@openmrs/esm-framework'; +import { useConfig, ArrowRightIcon } from '@openmrs/esm-framework'; +import { Tile, Button } from '@carbon/react'; import { useTranslation } from 'react-i18next'; import { type ConfigSchema } from './config-schema'; import styles from './login/login.scss'; @@ -11,11 +12,28 @@ const Footer: React.FC = () => { return (
-

{t('poweredBy', 'Powered by')}

+ +
+ {t('builtWith', 'Built with')} + + + + + {t('poweredBySubtext', 'An open-source medical record system and global community')} + + +
+
+
- - - {logos.map((logo, index) => ( { const { showPasswordOnSeparateScreen, provider: loginProvider, links: loginLinks } = useConfig(); const isLoginEnabled = useConnectivity(); @@ -36,26 +28,16 @@ const Login: React.FC = () => { const location = useLocation() as unknown as Omit & { state: LoginReferrer; }; - - const rawNavigate = useNavigate(); - const navigate = useCallback( - (to: To) => { - rawNavigate(to, { state: location.state }); - }, - [rawNavigate, location.state], - ); + const navigate = useNavigate(); const [errorMessage, setErrorMessage] = useState(''); const [isLoggingIn, setIsLoggingIn] = useState(false); const [password, setPassword] = useState(''); const [username, setUsername] = useState(''); - const formRef = useRef(null); + const [showPasswordField, setShowPasswordField] = useState(false); const passwordInputRef = useRef(null); const usernameInputRef = useRef(null); - const showUsername = location.pathname === '/login'; - const showPassword = !showPasswordOnSeparateScreen || location.pathname === '/login/confirm'; - useEffect(() => { if (!user) { if (loginProvider.type === 'oauth2') { @@ -67,24 +49,26 @@ const Login: React.FC = () => { }, [username, navigate, location, user, loginProvider]); useEffect(() => { - const fieldToFocus = - showPasswordOnSeparateScreen && showPassword ? passwordInputRef.current : usernameInputRef.current; - - fieldToFocus?.focus(); - }, [showPassword, showPasswordOnSeparateScreen]); + if (showPasswordOnSeparateScreen) { + if (showPasswordField) { + passwordInputRef.current?.focus(); + } else { + usernameInputRef.current?.focus(); + } + } + }, [showPasswordField, showPasswordOnSeparateScreen]); const continueLogin = useCallback(() => { const usernameField = usernameInputRef.current; - if (usernameField.value && usernameField.value.trim()) { - navigate('/login/confirm'); + if (usernameField?.value.trim()) { + setShowPasswordField(true); } else { - usernameField.focus(); + usernameField?.focus(); } - }, [location.state, navigate]); + }, []); const changeUsername = useCallback((evt: React.ChangeEvent) => setUsername(evt.target.value), []); - const changePassword = useCallback((evt: React.ChangeEvent) => setPassword(evt.target.value), []); const handleSubmit = useCallback( @@ -92,20 +76,22 @@ const Login: React.FC = () => { evt.preventDefault(); evt.stopPropagation(); - if (!showPassword) { + if (showPasswordOnSeparateScreen && !showPasswordField) { continueLogin(); return false; - } else if (!password || !password.trim()) { - passwordInputRef.current.focus(); + } + + if (!password || !password.trim()) { + passwordInputRef.current?.focus(); return false; } try { setIsLoggingIn(true); - const sessionStore = await refetchCurrentUser(username, password); const session = sessionStore.session; const authenticated = sessionStore?.session?.authenticated; + if (authenticated) { if (session.sessionLocation) { let to = loginLinks?.loginSuccess || '/home'; @@ -125,9 +111,8 @@ const Login: React.FC = () => { setErrorMessage(t('invalidCredentials', 'Invalid username or password')); setUsername(''); setPassword(''); - if (showPasswordOnSeparateScreen) { - navigate('/login'); + setShowPasswordField(false); } } @@ -138,117 +123,98 @@ const Login: React.FC = () => { } else { setErrorMessage(t('invalidCredentials', 'Invalid username or password')); } - setUsername(''); setPassword(''); - if (showPasswordOnSeparateScreen) { - navigate('/login'); + setShowPasswordField(false); } } finally { setIsLoggingIn(false); } - - return false; }, - - [showPassword, username, password, navigate], + [username, password, navigate, showPasswordOnSeparateScreen], ); - if (!loginProvider || loginProvider.type === 'basic') { - return ( -
- - {errorMessage && ( -
- setErrorMessage('')} - /> -
- )} - {showPasswordOnSeparateScreen && showPassword ? ( -
- -
- ) : null} -
- + return ( +
+ + {errorMessage && ( +
+ setErrorMessage('')} + />
-
- {showUsername && ( -
- - {/* For password managers */} - {showPasswordOnSeparateScreen && ( - + +
+ +
+ + {showPasswordOnSeparateScreen ? ( + showPasswordField ? ( + <> + - )} - {showPasswordOnSeparateScreen && ( - )} -
- )} - {showPassword && ( -
+ + ) : ( + + ) + ) : ( + <> - {/* For password managers */} - {showPasswordOnSeparateScreen && ( - - )} -
+ )} -
-
-
-
- ); - } - - return null; +
+ +
+
+ ); }; -export default Login; +export default Login; \ No newline at end of file diff --git a/packages/apps/esm-login-app/src/login/login.scss b/packages/apps/esm-login-app/src/login/login.scss index e8418be4a..c98b83276 100644 --- a/packages/apps/esm-login-app/src/login/login.scss +++ b/packages/apps/esm-login-app/src/login/login.scss @@ -52,29 +52,59 @@ .footer { display: flex; - flex-direction: column; + justify-content: space-between; align-items: center; - padding: 1.5rem; + padding: 1rem; + position: absolute; + bottom: 0; + flex-wrap: wrap; + gap: 1rem; + width: 100%; +} + +.poweredByTile { + display: flex; + text-align: left; + max-width: fit-content; + min-height: fit-content; + font-size: smaller; + background-color: #ffffff; + padding: 0.5rem 1rem; + border: 1px solid #e0e0e0; + border-radius: 1rem; + flex-wrap: wrap; } .logosContainer { - margin-right: 0; display: flex; - justify-content: center; + max-height: 2rem; + justify-content: flex-end; flex-direction: row; - align-items: center; - flex-wrap: wrap; - gap: 2rem; + gap: 0.5rem; filter: grayscale(100%); - opacity: 1; + opacity: 80%; +} + +.poweredByContainer{ + display: flex; + height: 1.5rem; + align-items: center; + gap: 0.5rem; } .poweredByLogo { - height: 3rem; + height: 2rem; width: auto; - max-width: 8rem; + max-width: 6rem; + border-collapse: collapse; + padding: 0; object-fit: contain; - display: block; + display: block; + flex-shrink: 0; +} + +.poweredByLogo + .poweredByText { + margin-left: 0.25rem; } .loginCard { @@ -83,6 +113,7 @@ background-color: $ui-02; width: 23rem; padding: 2.5rem; + border-radius: 0.5rem; position: relative; min-height: fit-content; } @@ -93,6 +124,30 @@ } } +@media only screen and (max-width: 1024px) { + .footer { + flex-direction: row; + justify-content: center; + padding: 1rem; + } + + .poweredByTile { + padding: 1rem 0.5rem; + font-size: 0.8rem; + align-items: center; + justify-content: center; + } + + .logosContainer { + justify-content: center; + gap: 0.75rem; + } + + .container{ + height: 100vh; + } +} + @media only screen and (max-width: 480px) { .login-card { margin-top: 2.5%; @@ -102,6 +157,25 @@ .container { height: 100vh; } + + .footer { + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 1rem; + } + + .poweredByTile { + flex-direction: row; + align-items: center; + justify-content: center; + padding: 1.2rem 1rem; + font-size: 0.7rem; + height: auto; + max-width: 100%; + border-radius: 0.75rem; + } } .inputGroup { @@ -110,6 +184,7 @@ flex-direction: column; align-items: center; width: 18rem; + gap: 1rem; :global(.cds--text-input) { height: 3rem;