diff --git a/.vscode/settings.json b/.vscode/settings.json index 24cb38a19a..03a41077b2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,11 @@ "^@mui/[^/]+$", "(?=^|[^/])shared/((?!api)|api/(?!endpoints/testing)).+" ], - "codescene.enableTelemetry": false + "codescene.enableTelemetry": false, + "jest.virtualFolders": [ + { "name": "web", "rootPath": "web" }, + { "name": "native", "rootPath": "native" }, + { "name": "shared", "rootPath": "shared" }, + { "name": "translations", "rootPath": "translations" } + ] } diff --git a/translations/translations.json b/translations/translations.json index 2162650f26..774b8ff8fe 100644 --- a/translations/translations.json +++ b/translations/translations.json @@ -7738,7 +7738,8 @@ "skipToContent": "Zum Inhalt springen", "shareQrCodeTitle": "Über QR-Code teilen", "shareQrCodeDescription": "Teile diese Seite einfach, indem du den QR-Code auf einem anderen Gerät scannst.", - "qrCode": "QR-Code" + "qrCode": "QR-Code", + "backToContent": "Zurück zum Inhalt" }, "am": { "imprint": "ዕትም", @@ -8053,7 +8054,8 @@ "skipToContent": "Skip to content", "shareQrCodeTitle": "Share via QR code", "shareQrCodeDescription": "Share this page easily by scanning the QR code on another device.", - "qrCode": "QR code" + "qrCode": "QR code", + "backToContent": "Back to content" }, "es": { "imprint": "Aviso legal", diff --git a/web/src/components/BackToRegionButton.tsx b/web/src/components/BackToRegionButton.tsx new file mode 100644 index 0000000000..73dd97c1cd --- /dev/null +++ b/web/src/components/BackToRegionButton.tsx @@ -0,0 +1,38 @@ +import Button from '@mui/material/Button' +import { styled } from '@mui/material/styles' +import React, { ReactElement, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useNavigate } from 'react-router' + +import useDimensions from '../hooks/useDimensions' +import { DirectionDependentBackIcon } from './base/Dialog' + +const StyledButton = styled(Button)({ + textTransform: 'none', + alignSelf: 'flex-start', +}) + +const BackToRegionButton = (): ReactElement | null => { + const navigate = useNavigate() + const { mobile } = useDimensions() + const { t } = useTranslation('layout') + const currentHistoryIndex = window.history.state?.idx ?? 0 + + // Initial history index to account for language changes or other user interactions on this page. + const [initialHistoryIndex] = useState(currentHistoryIndex) + + if (!mobile || initialHistoryIndex === 0) { + return null + } + + return ( + navigate(initialHistoryIndex - currentHistoryIndex - 1)} + startIcon={} + color='inherit'> + {t('backToContent')} + + ) +} + +export default BackToRegionButton diff --git a/web/src/components/__tests__/BackToRegionButton.spec.tsx b/web/src/components/__tests__/BackToRegionButton.spec.tsx new file mode 100644 index 0000000000..a7fa857b84 --- /dev/null +++ b/web/src/components/__tests__/BackToRegionButton.spec.tsx @@ -0,0 +1,42 @@ +import { fireEvent } from '@testing-library/react' +import React from 'react' + +import { mockDimensions } from '../../__mocks__/useDimensions' +import useDimensions from '../../hooks/useDimensions' +import { renderWithRouterAndTheme } from '../../testing/render' +import BackToRegionButton from '../BackToRegionButton' + +const mockNavigate = jest.fn() +jest.mock('react-i18next') +jest.mock('../../hooks/useDimensions') +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + useNavigate: () => mockNavigate, +})) + +describe('BackToRegionButton', () => { + const { mocked } = jest + + const setHistoryIndex = (idx: number) => window.history.replaceState({ idx }, '') + + beforeEach(() => { + jest.clearAllMocks() + mocked(useDimensions).mockImplementation(() => ({ ...mockDimensions, mobile: true })) + setHistoryIndex(1) + }) + + it('should render on mobile and navigate back on click', () => { + const { getByText } = renderWithRouterAndTheme() + + fireEvent.click(getByText('layout:backToContent')) + + expect(mockNavigate).toHaveBeenCalledWith(-1) + }) + + it('should render nothing when there is no history to go back to', () => { + setHistoryIndex(0) + const { queryByText } = renderWithRouterAndTheme() + + expect(queryByText('layout:backToContent')).toBeFalsy() + }) +}) diff --git a/web/src/routes/RegionsPage.tsx b/web/src/routes/RegionsPage.tsx index 2fa8d5373d..0da124a325 100644 --- a/web/src/routes/RegionsPage.tsx +++ b/web/src/routes/RegionsPage.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next' import { createRegionsEndpoint } from 'shared/api' +import BackToRegionButton from '../components/BackToRegionButton' import FailureSwitcherWithHelmet from '../components/FailureSwitcherWithHelmet' import Footer from '../components/Footer' import GeneralHeader from '../components/GeneralHeader' @@ -44,6 +45,7 @@ const RegionsPage = ({ languageCode }: RegionsPageProps): ReactElement => { }> + )