Skip to content
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
13 changes: 6 additions & 7 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -73,18 +72,18 @@ function App({ language, isHighContrast, history, ...props }) {

let header = null;
if (!fullscreen && !headless) {
header = <Header slim={location.pathname !== '/'} history={history} locale={locale} setLocale={setLocale} />;
header = <Header slim={location.pathname !== '/'} history={history} />;
}
const mainContainerId = 'main-container';
return (
<IntlProvider locale={locale} language={locale} messages={messages[locale] || {}}>
<IntlProvider locale={language} messages={messages[language] || {}}>
<div className={contrastClass}>
{config.enableCookies && !isCookiebotEnabled() && <CookieBar language={locale} />}
{config.enableCookies && !isCookiebotEnabled() && <CookieBar />}
<InternalLink className='skip-to-main-content' destinationId={mainContainerId}>
<FormattedMessage id='skipToMainContent' />
</InternalLink>
<Helmet titleTemplate='%s - Kerrokantasi' link={favlinks} meta={favmeta}>
<html lang={locale} />
<html lang={language} />
{isCookiebotEnabled() && getCookieBotConsentScripts()}
</Helmet>
{header}
Expand All @@ -97,7 +96,7 @@ function App({ language, isHighContrast, history, ...props }) {
>
<Routes />
</main>
<Footer language={locale} />
<Footer />
<Toast />
</div>
</IntlProvider>
Expand Down
9 changes: 6 additions & 3 deletions src/components/CookieBar/CookieBar.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React, { useState } from 'react';
import React from 'react';
import { CookieModal } from 'hds-react';
import { useDispatch, useSelector } from 'react-redux';

import { getHDSCookieConfig } from '../../utils/cookieUtils';
import config from '../../config';
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 <CookieModal contentSource={getCookieModalConfig()} />;
Expand Down
11 changes: 5 additions & 6 deletions src/components/Footer.jsx
Original file line number Diff line number Diff line change
@@ -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, useIntl } from 'react-intl';
import PropTypes from 'prop-types';
import settings from '@city-assets/settings.json';
import { Footer as HDSFooter, Logo } from 'hds-react';
Expand All @@ -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);
Expand Down Expand Up @@ -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);
12 changes: 7 additions & 5 deletions src/components/Header/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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')));
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
21 changes: 10 additions & 11 deletions src/components/Header/__tests__/Header.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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(),
Expand All @@ -44,10 +51,6 @@ describe('<Header />', () => {
});

it('displays login button when user is not logged in', async () => {
const stateWithoutUser = {
language: 'fi',
user: { data: null },
};

const store = mockStore(stateWithoutUser);

Expand All @@ -59,11 +62,6 @@ describe('<Header />', () => {
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);
Expand All @@ -90,10 +88,11 @@ describe('<Header />', () => {
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();
});
});
16 changes: 11 additions & 5 deletions src/getRoot.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,36 @@ 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,
apiTokensClientSettings: apiTokenClientConfig,
sessionPollerSettings: { pollIntervalInMs: 10000 },
};

const locale = 'fi';

export default function getRoot(store) {
return isIE ? (
<BrowserWarning />
) : (
<LoginProvider {...loginProviderProps}>
<Provider store={store}>
<BrowserRouter history={history}>
<ScrollToTop>
<App history={history} />
</ScrollToTop>
</BrowserRouter>
<IntlProvider locale={locale} language={locale} messages={messages[locale] || {}}>
<BrowserRouter history={history}>
<ScrollToTop>
<App history={history} />
</ScrollToTop>
</BrowserRouter>
</IntlProvider>
</Provider>
</LoginProvider>
);
Expand Down
4 changes: 3 additions & 1 deletion src/hooks/useAuth.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
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();
login({language: locale, state: {returnUrl: window.location.pathname}});
}
const handleLogout = async () => {
logout();
Expand Down
Loading