From 4f69297fad34a4c04e6da251eca8126101278fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arto=20P=C3=A4rssinen?= Date: Thu, 20 Feb 2025 15:15:42 +0200 Subject: [PATCH 1/2] fix: fixed login to use current language --- src/App.jsx | 11 +++++----- src/components/CookieBar/CookieBar.jsx | 9 +++++--- src/components/Footer.jsx | 11 +++++----- src/components/Header/Header.jsx | 12 ++++++----- .../Header/__tests__/Header.test.jsx | 21 +++++++++---------- src/getRoot.jsx | 16 +++++++++----- src/hooks/useAuth.js | 5 ++++- 7 files changed, 48 insertions(+), 37 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 994d11511..fc299969c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -29,7 +29,6 @@ function App({ language, isHighContrast, history, ...props }) { const { user, dispatchSetOidcUser, dispatchEnrichUser } = props; const { fullscreen } = useParams(); const location = useLocation(); - const [locale, setLocale] = useState(language); getCookieScripts(); if (config.enableCookies) { @@ -73,18 +72,18 @@ function App({ language, isHighContrast, history, ...props }) { let header = null; if (!fullscreen && !headless) { - header =
; + header =
; } const mainContainerId = 'main-container'; return ( - +
- {config.enableCookies && !isCookiebotEnabled() && } + {config.enableCookies && !isCookiebotEnabled() && } - + {isCookiebotEnabled() && getCookieBotConsentScripts()} {header} @@ -97,7 +96,7 @@ function App({ language, isHighContrast, history, ...props }) { > -
+
diff --git a/src/components/CookieBar/CookieBar.jsx b/src/components/CookieBar/CookieBar.jsx index eb96d2e59..dd863a3fd 100644 --- a/src/components/CookieBar/CookieBar.jsx +++ b/src/components/CookieBar/CookieBar.jsx @@ -1,12 +1,15 @@ -import React, { useState } from 'react'; +import React from 'react'; import { CookieModal } from 'hds-react'; import { getHDSCookieConfig } from '../../utils/cookieUtils'; -import config from '../../config'; +import { useDispatch, useSelector } from 'react-redux'; +import { setLanguage as setLanguageDispatch } from '../../actions'; function CookieBar() { + const dispatch = useDispatch(); const siteName = document.querySelector("meta[property='og:title']").getAttribute('content'); - const [language, setLanguage] = useState(config.activeLanguage); + const language = useSelector(state => state.language) + const setLanguage = (newLocale) => dispatch(setLanguageDispatch(newLocale)); const getCookieModalConfig = () => getHDSCookieConfig(siteName, language, setLanguage); return ; diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx index 62ebe9c5e..7cc44c762 100644 --- a/src/components/Footer.jsx +++ b/src/components/Footer.jsx @@ -1,7 +1,7 @@ /* eslint-disable import/no-unresolved */ /* eslint-disable react/forbid-prop-types */ import React from 'react'; -import { FormattedMessage, injectIntl } from 'react-intl'; +import { FormattedMessage, injectIntl, useIntl } from 'react-intl'; import PropTypes from 'prop-types'; import settings from '@city-assets/settings.json'; import { Footer as HDSFooter, Logo } from 'hds-react'; @@ -17,8 +17,9 @@ import getUser from '../selectors/user'; import { isAdmin } from '../utils/user'; const Footer = (props) => { - const { language, user, intl } = props; - + const { user } = props; + const intl = useIntl(); + const language = intl.locale; const userIsAdmin = isAdmin(user); const scrollToFn = () => window.scrollTo(0, 0); @@ -93,11 +94,9 @@ const Footer = (props) => { }; Footer.propTypes = { - language: PropTypes.string, user: PropTypes.object, - intl: PropTypes.object, }; export default connect((state) => ({ user: getUser(state), -}))(injectIntl(Footer)); +}))(Footer); diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 95828d146..96a7f6308 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -14,8 +14,9 @@ import getUser from '../../selectors/user'; import useAuthHook from '../../hooks/useAuth'; import { addToast } from '../../actions/toast'; import { createLocalizedNotificationPayload, NOTIFICATION_TYPES } from '../../utils/notify'; +import { setLanguage } from '../../actions'; -const Header = ({ user, locale, setLocale }) => { +const Header = ({ user }) => { const { authenticated, login, logout } = useAuthHook(); const location = useLocation(); const dispatch = useDispatch(); @@ -24,6 +25,10 @@ const Header = ({ user, locale, setLocale }) => { const language = intl.locale; + const setLocale = (newLocale) => { + dispatch(setLanguage(newLocale)); + }; + const doLogin = async () => { if (config.maintenanceDisableLogin) { dispatch(addToast(createLocalizedNotificationPayload(NOTIFICATION_TYPES.error, 'maintenanceNotificationText'))); @@ -53,7 +58,7 @@ const Header = ({ user, locale, setLocale }) => { useEffect(() => { const langParam = searchParams.get('lang'); - if (langParam && langParam !== locale) { + if (langParam && langParam !== language) { setLocale(langParam); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -142,11 +147,8 @@ const Header = ({ user, locale, setLocale }) => { Header.propTypes = { user: PropTypes.object, - locale: PropTypes.string, - setLocale: PropTypes.func, }; export default connect((state) => ({ user: getUser(state), - language: state.language, }))(Header); diff --git a/src/components/Header/__tests__/Header.test.jsx b/src/components/Header/__tests__/Header.test.jsx index 370276121..dff479789 100644 --- a/src/components/Header/__tests__/Header.test.jsx +++ b/src/components/Header/__tests__/Header.test.jsx @@ -9,6 +9,7 @@ import Header from '../Header'; import renderWithProviders from '../../../utils/renderWithProviders'; import { mockUser } from '../../../../test-utils'; import * as useAuthMock from '../../../hooks/useAuth'; +import * as actionsMock from '../../../actions'; const middlewares = [thunk]; const mockStore = configureStore(middlewares); @@ -20,8 +21,14 @@ const defaultState = { language: defaultLocale, user: { data: { ...mockUser } }, }; +const stateWithoutUser = { + language: 'fi', + user: { data: null }, +}; const renderComponent = (storeOverride, authMock = {}) => { + jest.spyOn(actionsMock, 'setLanguage').mockImplementation(() => (jest.fn())); + jest.spyOn(useAuthMock, 'default').mockImplementation(() => ({ authenticated: authMock.authenticated ?? false, login: authMock.login ?? jest.fn(), @@ -44,10 +51,6 @@ describe('
', () => { }); it('displays login button when user is not logged in', async () => { - const stateWithoutUser = { - language: 'fi', - user: { data: null }, - }; const store = mockStore(stateWithoutUser); @@ -59,11 +62,6 @@ describe('
', () => { it('calls login function when login button is clicked', async () => { const user = userEvent.setup(); - const stateWithoutUser = { - language: 'fi', - user: { data: null }, - }; - const mockLogin = jest.fn(); const store = mockStore(stateWithoutUser); @@ -90,10 +88,11 @@ describe('
', () => { it('changes language when language selector is used', async () => { const user = userEvent.setup(); - renderComponent(); + const store = mockStore(stateWithoutUser) + renderComponent(store); await user.click(await screen.findByRole('button', { name: 'English' })); - expect(mockSetLocale).toHaveBeenCalled(); + expect(actionsMock.setLanguage).toHaveBeenCalled(); }); }); diff --git a/src/getRoot.jsx b/src/getRoot.jsx index 3ad5df2c4..b07b6561a 100644 --- a/src/getRoot.jsx +++ b/src/getRoot.jsx @@ -3,12 +3,14 @@ import { Provider } from 'react-redux'; import { isIE } from 'react-device-detect'; import { LoginProvider } from 'hds-react'; import { BrowserRouter } from 'react-router-dom'; +import { IntlProvider } from 'react-intl'; import { history } from './createStore'; import App from './App'; import ScrollToTop from './scrollToTop'; import BrowserWarning from './views/BrowserWarning'; import { userOidcConfig, apiTokenClientConfig } from './utils/oidcConfig'; +import messages from './i18n'; const loginProviderProps = { userManagerSettings: userOidcConfig, @@ -16,17 +18,21 @@ const loginProviderProps = { sessionPollerSettings: { pollIntervalInMs: 10000 }, }; +const locale = 'fi'; + export default function getRoot(store) { return isIE ? ( ) : ( - - - - - + + + + + + + ); diff --git a/src/hooks/useAuth.js b/src/hooks/useAuth.js index eeb967a81..3944d0b87 100644 --- a/src/hooks/useAuth.js +++ b/src/hooks/useAuth.js @@ -1,10 +1,13 @@ import { useOidcClient } from "hds-react" +import { useSelector } from "react-redux"; export const useAuth = () => { const { isAuthenticated, getUser, login, logout } = useOidcClient(); + const locale = useSelector(state => state.language); const handleLogin = async () => { - login(); + console.debug('Logging in with locale', locale); + login({language: locale, state: {returnUrl: window.location.pathname}}); } const handleLogout = async () => { logout(); From 0d8b81c489af2804444a78391693639653b5c6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arto=20P=C3=A4rssinen?= Date: Fri, 21 Feb 2025 12:01:34 +0200 Subject: [PATCH 2/2] chore: linter fixes --- src/App.jsx | 2 +- src/components/CookieBar/CookieBar.jsx | 2 +- src/components/Footer.jsx | 2 +- src/hooks/useAuth.js | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index fc299969c..d03e1d56c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,5 +1,5 @@ /* eslint-disable react/forbid-prop-types */ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { FormattedMessage, IntlProvider } from 'react-intl'; diff --git a/src/components/CookieBar/CookieBar.jsx b/src/components/CookieBar/CookieBar.jsx index dd863a3fd..10cec3a47 100644 --- a/src/components/CookieBar/CookieBar.jsx +++ b/src/components/CookieBar/CookieBar.jsx @@ -1,8 +1,8 @@ import React from 'react'; import { CookieModal } from 'hds-react'; +import { useDispatch, useSelector } from 'react-redux'; import { getHDSCookieConfig } from '../../utils/cookieUtils'; -import { useDispatch, useSelector } from 'react-redux'; import { setLanguage as setLanguageDispatch } from '../../actions'; function CookieBar() { diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx index 7cc44c762..9b5a47b30 100644 --- a/src/components/Footer.jsx +++ b/src/components/Footer.jsx @@ -1,7 +1,7 @@ /* eslint-disable import/no-unresolved */ /* eslint-disable react/forbid-prop-types */ import React from 'react'; -import { FormattedMessage, injectIntl, useIntl } from 'react-intl'; +import { FormattedMessage, useIntl } from 'react-intl'; import PropTypes from 'prop-types'; import settings from '@city-assets/settings.json'; import { Footer as HDSFooter, Logo } from 'hds-react'; diff --git a/src/hooks/useAuth.js b/src/hooks/useAuth.js index 3944d0b87..10557f542 100644 --- a/src/hooks/useAuth.js +++ b/src/hooks/useAuth.js @@ -6,7 +6,6 @@ export const useAuth = () => { const locale = useSelector(state => state.language); const handleLogin = async () => { - console.debug('Logging in with locale', locale); login({language: locale, state: {returnUrl: window.location.pathname}}); } const handleLogout = async () => {