Refacto error page

pull/2869/head
Jérémy Rialland 2023-09-28 12:55:10 +02:00 committed by Johan Girod
parent 1d435353c0
commit f0b633a976
4 changed files with 226 additions and 209 deletions

View File

@ -1,7 +1,6 @@
import { ErrorBoundary } from '@sentry/react'
import { FallbackRender } from '@sentry/react/types/errorboundary'
import rules from 'modele-social'
import { ComponentProps, StrictMode, useMemo } from 'react'
import { StrictMode, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Route, Routes } from 'react-router-dom'
import { css, styled } from 'styled-components'
@ -30,7 +29,7 @@ import Documentation from '@/pages/Documentation'
import Iframes from '@/pages/iframes'
import Integration from '@/pages/integration/index'
import Nouveautés from '@/pages/nouveautés/index'
import Offline from '@/pages/Offline'
import { CatchOffline } from '@/pages/Offline'
import Plan from '@/pages/Plan'
import Simulateurs from '@/pages/simulateurs'
import SimulateursEtAssistants from '@/pages/simulateurs-et-assistants'
@ -65,7 +64,9 @@ export default function Root({
<EngineProvider value={engine}>
<Provider basename={basename}>
<Redirections>
<Router />
<ErrorBoundary fallback={CatchOffline}>
<Router />
</ErrorBoundary>
</Redirections>
</Provider>
</EngineProvider>
@ -86,14 +87,6 @@ const Router = () => {
)
}
const CatchOffline = ({ error }: ComponentProps<FallbackRender>) => {
if (error.message.includes('dynamically imported module')) {
return <Offline />
} else {
throw error
}
}
const App = () => {
const { relativeSitePaths } = useSitePaths()
@ -133,56 +126,51 @@ const App = () => {
{t('Aller directement au pied de page')}
</a>
<Container>
<ErrorBoundary fallback={CatchOffline}>
<Routes>
<Route index element={<Landing />} />
<Routes>
<Route index element={<Landing />} />
<Route
path={relativeSitePaths.assistants.index + '/*'}
element={<Assistants />}
/>
<Route
path={relativeSitePaths.simulateurs.index + '/*'}
element={<Simulateurs />}
/>
<Route
path={relativeSitePaths.simulateursEtAssistants + '/*'}
element={<SimulateursEtAssistants />}
/>
<Route
path={relativeSitePaths.documentation.index + '/*'}
element={
<Documentation
documentationPath={documentationPath}
engine={engine}
/>
}
/>
<Route
path={relativeSitePaths.développeur.index + '/*'}
element={<Integration />}
/>
<Route
path={relativeSitePaths.nouveautés.index + '/*'}
element={<Nouveautés />}
/>
<Route path={relativeSitePaths.stats} element={<Stats />} />
<Route path={relativeSitePaths.budget} element={<Budget />} />
<Route
path={relativeSitePaths.accessibilité}
element={<Accessibilité />}
/>
<Route
path={relativeSitePaths.assistants.index + '/*'}
element={<Assistants />}
/>
<Route
path={relativeSitePaths.simulateurs.index + '/*'}
element={<Simulateurs />}
/>
<Route
path={relativeSitePaths.simulateursEtAssistants + '/*'}
element={<SimulateursEtAssistants />}
/>
<Route
path={relativeSitePaths.documentation.index + '/*'}
element={
<Documentation
documentationPath={documentationPath}
engine={engine}
/>
}
/>
<Route
path={relativeSitePaths.développeur.index + '/*'}
element={<Integration />}
/>
<Route
path={relativeSitePaths.nouveautés.index + '/*'}
element={<Nouveautés />}
/>
<Route path={relativeSitePaths.stats} element={<Stats />} />
<Route path={relativeSitePaths.budget} element={<Budget />} />
<Route
path={relativeSitePaths.accessibilité}
element={<Accessibilité />}
/>
<Route
path="/dev/integration-test"
element={<IntegrationTest />}
/>
<Route path="/dev/integration-test" element={<IntegrationTest />} />
<Route path={relativeSitePaths.plan} element={<Plan />} />
<Route path={relativeSitePaths.plan} element={<Plan />} />
<Route path="*" element={<Page404 />} />
</Routes>
</ErrorBoundary>
<Route path="*" element={<Page404 />} />
</Routes>
</Container>
</main>

View File

@ -0,0 +1,141 @@
import { ReactNode } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { styled } from 'styled-components'
import FeedbackForm from '@/components/Feedback/FeedbackForm'
import { Container, Grid } from '@/design-system/layout'
import { H1, H4 } from '@/design-system/typography/heading'
import { Link } from '@/design-system/typography/link'
import { Body, Intro } from '@/design-system/typography/paragraphs'
import { Message } from '../design-system'
import { Logo } from './Logo'
const StyledLogo = styled.div`
height: 3rem;
@media (max-width: ${({ theme }) => theme.breakpointsWidth.sm}) {
height: 2.5rem;
}
`
export const ErrorLayout = ({ children }: { children: ReactNode }) => {
const { t } = useTranslation()
return (
<main style={{ height: '100vh' }}>
<Container>
<Link
href="/"
aria-label={t('error.back', "Retourner à la page d'accueil")}
>
<StyledLogo>
<Logo />
</StyledLogo>
</Link>
<H1>
<Trans i18nKey="error.title">Une erreur est survenue</Trans>
</H1>
{children}
</Container>
</main>
)
}
export const ErrorFallback = (props: {
error: Error
componentStack: string | null
eventId: string | null
resetError(): void
showFeedbackForm?: boolean
}) => {
const { t } = useTranslation()
const additionalData = JSON.stringify(
{
name: props.error.name,
message: props.error.message,
stack: props.error.stack,
componentStack: props.componentStack,
},
null,
2
)
return (
<ErrorLayout>
<Intro>
<Trans i18nKey="error.intro">
L'équipe technique mon-entreprise a été prévenue automatiquement,
veuillez nous excuser pour la gêne occasionnée.
</Trans>
</Intro>
<Grid container spacing={3}>
<Grid item xs={12} lg={8}>
{props.showFeedbackForm ? (
<FeedbackForm
infoSlot={
<Trans i18nKey="error.body0">
<Body>
Si vous souhaitez nous aider à corriger ce problème, vous
pouvez décrire les actions ont conduit à cette erreur via le
formulaire ci-dessous ou à l'adresse :{' '}
<Link
href="mailto:contact@mon-entreprise.beta.gouv.fr"
aria-label={t(
'error.contact',
'Envoyer un courriel à contact@mon-entreprise.beta.gouv.fr, nouvelle fenêtre'
)}
>
contact@mon-entreprise.beta.gouv.fr
</Link>
.
</Body>
</Trans>
}
description={
<Trans i18nKey="error.description">
Décrivez les actions qui ont conduit à cette erreur :
</Trans>
}
placeholder={t(
'error.placeholder',
`Bonjour, j'ai rencontré une erreur après avoir cliqué sur...`
)}
tags={['error']}
additionalData={additionalData}
/>
) : (
<Trans i18nKey="error.body1">
<Body>
Si vous souhaitez nous aider à corriger ce problème, vous pouvez
décrire les actions ont conduit à cette erreur à l'adresse :{' '}
<Link
href="mailto:contact@mon-entreprise.beta.gouv.fr"
aria-label={t(
'error.contact',
'Envoyer un courriel à contact@mon-entreprise.beta.gouv.fr, nouvelle fenêtre'
)}
>
contact@mon-entreprise.beta.gouv.fr
</Link>
.
</Body>
</Trans>
)}
</Grid>
<Grid item xs={12} lg={8}>
<Message type="info">
<H4>Cause de l'erreur :</H4>
<Body>
{props.error.name} : {props.error.message}
</Body>
</Message>
</Grid>
</Grid>
</ErrorLayout>
)
}

View File

@ -3,26 +3,20 @@ import { ErrorBoundary } from '@sentry/react'
import i18next from 'i18next'
import { createContext, ReactNode } from 'react'
import { HelmetProvider } from 'react-helmet-async'
import { I18nextProvider, Trans, useTranslation } from 'react-i18next'
import { I18nextProvider } from 'react-i18next'
import { Provider as ReduxProvider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import logo from '@/assets/images/logo-monentreprise.svg'
import FeedbackForm from '@/components/Feedback/FeedbackForm'
import { ThemeColorsProvider } from '@/components/utils/colors'
import { DisableAnimationOnPrintProvider } from '@/components/utils/DisableAnimationContext'
import { Container, Grid } from '@/design-system/layout'
import DesignSystemThemeProvider from '@/design-system/root'
import { H1, H4 } from '@/design-system/typography/heading'
import { Link } from '@/design-system/typography/link'
import { Body, Intro } from '@/design-system/typography/paragraphs'
import { EmbededContextProvider } from '@/hooks/useIsEmbedded'
import { Message } from '../design-system'
import * as safeLocalStorage from '../storage/safeLocalStorage'
import { store } from '../store/store'
import { TrackingContext } from './ATInternetTracking'
import { createTracker } from './ATInternetTracking/Tracker'
import { ErrorFallback } from './ErrorPage'
import { IframeResizer } from './IframeResizer'
import { ServiceWorker } from './ServiceWorker'
import BrowserOnly from './utils/BrowserOnly'
@ -45,10 +39,7 @@ export default function Provider({
<EmbededContextProvider>
<DarkModeProvider>
<DesignSystemThemeProvider>
<ErrorBoundary
// eslint-disable-next-line react/jsx-props-no-spreading
fallback={(errorData) => <ErrorFallback {...errorData} />}
>
<ErrorBoundary fallback={ErrorFallback}>
<I18nextProvider i18n={i18next}>
<ReduxProvider store={store}>
<BrowserRouterProvider basename={basename}>
@ -84,122 +75,6 @@ export default function Provider({
)
}
const ErrorFallback = (props: {
error: Error
componentStack: string | null
eventId: string | null
resetError(): void
showFeedbackForm?: boolean
}) => {
const { t } = useTranslation()
const additionalData = JSON.stringify(
{
name: props.error.name,
message: props.error.message,
stack: props.error.stack,
componentStack: props.componentStack,
},
null,
2
)
return (
<main style={{ height: '100vh' }}>
<Container>
<Link
href="/"
aria-label={t('error.back', "Retourner à la page d'accueil")}
>
<img
src={logo}
alt="Logo mon-entreprise"
style={{
maxWidth: '200px',
width: '100%',
marginTop: '1rem',
}}
></img>
</Link>
<H1>
<Trans i18nKey="error.title">Une erreur est survenue</Trans>
</H1>
<Intro>
<Trans i18nKey="error.intro">
L'équipe technique mon-entreprise a été prévenue automatiquement,
veuillez nous excuser pour la gêne occasionnée.
</Trans>
</Intro>
<Grid container spacing={3}>
<Grid item xs={12} lg={8}>
{props.showFeedbackForm ? (
<FeedbackForm
infoSlot={
<Trans i18nKey="error.body0">
<Body>
Si vous souhaitez nous aider à corriger ce problème, vous
pouvez décrire les actions ont conduit à cette erreur via
le formulaire ci-dessous ou à l'adresse :{' '}
<Link
href="mailto:contact@mon-entreprise.beta.gouv.fr"
aria-label={t(
'error.contact',
'Envoyer un courriel à contact@mon-entreprise.beta.gouv.fr, nouvelle fenêtre'
)}
>
contact@mon-entreprise.beta.gouv.fr
</Link>
.
</Body>
</Trans>
}
description={
<Trans i18nKey="error.description">
Décrivez les actions qui ont conduit à cette erreur :
</Trans>
}
placeholder={t(
'error.placeholder',
`Bonjour, j'ai rencontré une erreur après avoir cliqué sur...`
)}
tags={['error']}
additionalData={additionalData}
/>
) : (
<Trans i18nKey="error.body1">
<Body>
Si vous souhaitez nous aider à corriger ce problème, vous
pouvez décrire les actions ont conduit à cette erreur à
l'adresse :{' '}
<Link
href="mailto:contact@mon-entreprise.beta.gouv.fr"
aria-label={t(
'error.contact',
'Envoyer un courriel à contact@mon-entreprise.beta.gouv.fr, nouvelle fenêtre'
)}
>
contact@mon-entreprise.beta.gouv.fr
</Link>
.
</Body>
</Trans>
)}
</Grid>
<Grid item xs={12} lg={8}>
<Message type="info">
<H4>Cause de l'erreur :</H4>
<Body>
{props.error.name} : {props.error.message}
</Body>
</Message>
</Grid>
</Grid>
</Container>
</main>
)
}
function BrowserRouterProvider({
children,
basename,

View File

@ -1,36 +1,49 @@
import { FallbackRender } from '@sentry/react'
import { ComponentProps } from 'react'
import { useTranslation } from 'react-i18next'
import { ErrorLayout } from '@/components/ErrorPage'
import Meta from '@/components/utils/Meta'
import { Message } from '@/design-system'
import { Grid } from '@/design-system/layout'
import { Body, Intro } from '@/design-system/typography/paragraphs'
export default function Offline() {
export const CatchOffline = ({ error }: ComponentProps<FallbackRender>) => {
if (error.message.includes('dynamically imported module')) {
return <Offline />
} else {
throw error
}
}
function Offline() {
const { t } = useTranslation()
return (
<Grid
container
style={{ justifyContent: 'center', margin: '10rem 0' }}
role="main"
>
<Grid item md={8} sm={12}>
<Meta
title={t('pages.offline.title', 'Hors ligne')}
description={t(
'pages.offline.description',
'Vous êtes actuellement hors ligne.'
)}
/>
<Message type="info" style={{ margin: '1rem 0' }}>
<Intro>Vous êtes actuellement hors ligne.</Intro>
<Body>
Cette page n'a pas encore été téléchargée et n'est donc pas
disponible sans internet, pour y accéder vérifiez votre connexion
puis rechargez la page.
</Body>
</Message>
<ErrorLayout>
<Grid
container
style={{ justifyContent: 'center', margin: '10rem 0' }}
role="main"
>
<Grid item md={8} sm={12}>
<Meta
title={t('pages.offline.title', 'Hors ligne')}
description={t(
'pages.offline.description',
'Vous êtes actuellement hors ligne.'
)}
/>
<Message type="info" style={{ margin: '1rem 0' }}>
<Intro>Vous êtes actuellement hors ligne.</Intro>
<Body>
Cette page n'a pas encore été téléchargée et n'est donc pas
disponible sans internet, pour y accéder vérifiez votre connexion
puis rechargez la page.
</Body>
</Message>
</Grid>
</Grid>
</Grid>
</ErrorLayout>
)
}