Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(refactor) Improve footer component and a11y #1240

Merged
merged 1 commit into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 30 additions & 20 deletions packages/apps/esm-login-app/src/footer.component.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,54 @@
import React from 'react';
import { useConfig, ArrowRightIcon } from '@openmrs/esm-framework';
import { Tile, Button } from '@carbon/react';
import React, { useCallback } from 'react';
import { Link, Tile } from '@carbon/react';
import { useTranslation } from 'react-i18next';
import { useConfig, ArrowRightIcon } from '@openmrs/esm-framework';
import { type ConfigSchema } from './config-schema';
import styles from './login/login.scss';
import styles from './footer.scss';

interface Logo {
src: string;
alt?: string;
}

const Footer: React.FC = () => {
const {t} = useTranslation();
const { t } = useTranslation();
const config = useConfig<ConfigSchema>();
const logos = config.footer.additionalLogos || [];
const logos: Logo[] = config.footer.additionalLogos || [];

const handleImageLoadError = useCallback((error: React.SyntheticEvent<HTMLImageElement, Event>) => {
console.error('Failed to load image', error);
}, []);

return (
<div className={styles.footer}>
<Tile className={styles.poweredByTile}>
<div className={styles.poweredByContainer}>
<span className={styles.poweredByText}>{t('builtWith', 'Built with')}</span>
<svg role="img" className={styles.poweredByLogo}>
<use href="#omrs-logo-full-color"></use>
</svg>
<svg aria-label={t('openmrsLogo', 'OpenMRS Logo')} className={styles.poweredByLogo} role="img">
<use href="#omrs-logo-full-color"></use>
</svg>
<span className={styles.poweredByText}>
{t('poweredBySubtext', 'An open-source medical record system and global community')}
</span>
<Button
className={styles.learnMore}
iconDescription={t('learnMore', 'Learn More')}
kind="ghost"
onClick={() => window.open('https://openmrs.org', '_blank')}
renderIcon={(props) => <ArrowRightIcon {...props} size={20} className={styles.arrowRightIcon}/>}
<Link
className={styles.learnMoreButton}
href="https://openmrs.org"
rel="noopener noreferrer"
renderIcon={() => <ArrowRightIcon size={16} aria-label="Arrow right icon" />}
target="_blank"
>
<span>{t('learnMore', 'Learn More')}</span>
</Button>
{t('learnMore', 'Learn more')}
</Link>
</div>
</Tile>

<div className={styles.logosContainer}>
{logos.map((logo, index) => (
{logos.map((logo) => (
<img
key={index}
alt={logo.alt ? t(logo.alt) : t('footerlogo', 'Footer Logo')}
className={styles.poweredByLogo}
key={logo.src}
onError={handleImageLoadError}
src={logo.src}
/>
))}
Expand All @@ -47,4 +57,4 @@ const Footer: React.FC = () => {
);
};

export default Footer;
export default Footer;
58 changes: 58 additions & 0 deletions packages/apps/esm-login-app/src/footer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@use '@carbon/colors';
@use '@carbon/layout';

.footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: layout.$spacing-05;
position: absolute;
bottom: 0;
flex-wrap: wrap;
gap: layout.$spacing-05;
width: 100%;
}

.poweredByTile {
display: flex;
text-align: left;
max-width: fit-content;
min-height: fit-content;
font-size: smaller;
background-color: colors.$white;
padding: layout.$spacing-03 layout.$spacing-05;
border: 1px solid colors.$gray-20;
border-radius: layout.$spacing-04;
flex-wrap: wrap;
}

.poweredByContainer {
display: flex;
height: layout.$spacing-06;
align-items: center;
gap: layout.$spacing-03;
}

.poweredByLogo {
height: layout.$spacing-07;
width: auto;
max-width: layout.$spacing-12;
border-collapse: collapse;
padding: 0;
object-fit: contain;
display: block;
flex-shrink: 0;
}

.poweredByLogo + .poweredByText {
margin-left: layout.$spacing-02;
}

.learnMoreButton {
display: flex;
align-items: center;

svg {
fill: colors.$blue-60;
}
}
10 changes: 5 additions & 5 deletions packages/apps/esm-login-app/src/login/login.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ const Login: React.FC = () => {
useEffect(() => {
if (showPasswordOnSeparateScreen) {
if (showPasswordField) {
passwordInputRef.current?.focus();
passwordInputRef.current?.focus();
} else {
usernameInputRef.current?.focus();
usernameInputRef.current?.focus();
}
}
}, [showPasswordField, showPasswordOnSeparateScreen]);
Expand Down Expand Up @@ -135,7 +135,7 @@ const Login: React.FC = () => {
[username, password, navigate, showPasswordOnSeparateScreen],
);

if (!loginProvider || loginProvider.type === 'basic'){
if (!loginProvider || loginProvider.type === 'basic') {
return (
<div className={styles.container}>
<Tile className={styles.loginCard}>
Expand Down Expand Up @@ -182,7 +182,7 @@ const Login: React.FC = () => {
type="submit"
className={styles.continueButton}
renderIcon={(props) => <ArrowRightIcon size={24} {...props} />}
iconDescription="Log in"
iconDescription={t('loginButtonIconDescription', 'Log in button')}
disabled={!isLoginEnabled || isLoggingIn}
>
{isLoggingIn ? (
Expand Down Expand Up @@ -238,7 +238,7 @@ const Login: React.FC = () => {
</div>
);
}
return null;
return null;
};

export default Login;
59 changes: 6 additions & 53 deletions packages/apps/esm-login-app/src/login/login.scss
Original file line number Diff line number Diff line change
Expand Up @@ -50,31 +50,6 @@
margin-left: 0.5rem;
}

.footer {
display: flex;
justify-content: space-between;
align-items: center;
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 {
display: flex;
max-height: 2rem;
Expand All @@ -85,28 +60,6 @@
opacity: 80%;
}

.poweredByContainer{
display: flex;
height: 1.5rem;
align-items: center;
gap: 0.5rem;
}

.poweredByLogo {
height: 2rem;
width: auto;
max-width: 6rem;
border-collapse: collapse;
padding: 0;
object-fit: contain;
display: block;
flex-shrink: 0;
}

.poweredByLogo + .poweredByText {
margin-left: 0.25rem;
}

.loginCard {
border-radius: 0;
border: 1px solid $ui-03;
Expand All @@ -127,7 +80,7 @@
@media only screen and (max-width: 1024px) {
.footer {
flex-direction: row;
justify-content: center;
justify-content: center;
padding: 1rem;
}

Expand All @@ -143,7 +96,7 @@
gap: 0.75rem;
}

.container{
.container {
height: 100vh;
}
}
Expand All @@ -160,9 +113,9 @@

.footer {
flex-direction: column;
align-items: center;
align-items: center;
justify-content: center;
gap: 0.5rem;
gap: 0.5rem;
padding: 1rem;
}

Expand All @@ -171,8 +124,8 @@
align-items: center;
justify-content: center;
padding: 1.2rem 1rem;
font-size: 0.7rem;
height: auto;
font-size: 0.7rem;
height: auto;
max-width: 100%;
border-radius: 0.75rem;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/apps/esm-login-app/src/login/login.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ describe('Login', () => {
renderWithRouter(
Login,
{},
{
{
route: '/login',
},
);

screen.getByRole('img', { name: /OpenMRS logo/i });
expect(screen.getAllByRole('img', { name: /OpenMRS logo/i })).toHaveLength(2);
expect(screen.queryByAltText(/^logo$/i)).not.toBeInTheDocument();
screen.getByRole('textbox', { name: /Username/i });
screen.getByRole('button', { name: /Continue/i });
Expand Down
7 changes: 4 additions & 3 deletions packages/apps/esm-login-app/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"back": "Back",
"backToUserNameIconLabel": "Back to username",
"builtWith": "Built with",
"cancel": "Cancel",
"change": "Change",
"changePassword": "Change password",
Expand All @@ -10,6 +9,7 @@
"errorChangingPassword": "Error changing password",
"footerlogo": "Footer Logo",
"invalidCredentials": "Invalid username or password",
"learnMore": "Learn more",
"locationPreferenceRemoved": "Login location preference removed",
"locationPreferenceRemovedMessage": "You will need to select a location on each login",
"locationSaved": "Location saved",
Expand All @@ -18,6 +18,7 @@
"locationUpdateMessage": "Your preferred login location has been updated",
"loggingIn": "Logging in",
"login": "Log in",
"loginButtonIconDescription": "Log in button",
"Logout": "Logout",
"newPassword": "New password",
"newPasswordRequired": "New password is required",
Expand All @@ -28,7 +29,7 @@
"passwordChangedSuccessfully": "Password changed successfully",
"passwordConfirmationRequired": "Password confirmation is required",
"passwordsDoNotMatch": "Passwords do not match",
"poweredBy": "Powered by",
"poweredBySubtext": "An open-source medical record system and global community",
"rememberLocationForFutureLogins": "Remember my location for future logins",
"selectYourLocation": "Select your location from the list below. Use the search bar to find your location.",
"showPassword": "Show password",
Expand Down
Loading