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

feat: add not found page #169

Merged
merged 2 commits into from
Jan 24, 2025
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
22 changes: 20 additions & 2 deletions website/src/app/[lang]/layout.tsx → website/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { match } from '@formatjs/intl-localematcher';
import {
AVAILABLE_LOCALES,
type AvailableLocale,
DEFAULT_LOCALE,
} from '@i18n/locales';
import { Nunito_Sans } from 'next/font/google';
import { headers } from 'next/headers';

const nunitoSans = Nunito_Sans({
display: 'swap',
Expand All @@ -13,7 +20,6 @@ import '@styles/main.scss';
import { ApolloWrapper } from '@app/apollo-wrapper';
import Footer from '@components/footer';
import Header from '@components/header';
import { AVAILABLE_LOCALES } from '@i18n/locales';
import type { PagePropsWithLocale } from '@shared/types/page-with-locale-params';

export const metadata = {
Expand All @@ -39,7 +45,19 @@ interface RootLayoutProps extends PagePropsWithLocale {
}

const RootLayout: React.FC<RootLayoutProps> = async ({ children, params }) => {
const { lang } = await params;
let { lang } = await params;

if (!lang) {
const headersList = await headers();
const acceptLanguagesHeader = headersList.get('accept-language');

lang = match(
(acceptLanguagesHeader ?? '').split(', '),
AVAILABLE_LOCALES,
DEFAULT_LOCALE,
) as AvailableLocale;
}

return (
<html lang={lang} className={nunitoSans.variable}>
<body>
Expand Down
38 changes: 38 additions & 0 deletions website/src/app/not-found.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@use '@styles/text-styles';
@use '@styles/layout';
@use '@styles/buttons';
@use '@styles/breakpoints';

.notfound {
&__content_wrapper {
@include layout.content-max-width-7xl;
padding: var(--spacing-20) var(--spacing-16) var(--spacing-24);

@include breakpoints.medium-screen {
padding: var(--spacing-6) var(--spacing-12) var(--spacing-12);
}

@include breakpoints.small-screen {
padding: var(--spacing-6) var(--spacing-6) var(--spacing-8);
}
}

h1 {
@include text-styles.header-1;
margin: 0;
margin-block-end: var(--spacing-6);
@include breakpoints.from-small-to-medium-screen {
@include text-styles.header-1--mobile;
}
}

p {
@include text-styles.text-base;
margin: 0;
margin-block-end: var(--spacing-4);

& > span {
@include text-styles.header-4;
}
}
}
68 changes: 68 additions & 0 deletions website/src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import styles from './not-found.module.scss';

import SupportBanner from '@components/support-banner';
import { match } from '@formatjs/intl-localematcher';
import {
AVAILABLE_LOCALES,
type AvailableLocale,
DEFAULT_LOCALE,
} from '@i18n/locales';
import { headers } from 'next/headers';
import Link from 'next/link';

const translations: Record<AvailableLocale, Record<string, string>> = {
en: {
title: 'Sorry, this page isn’t available',
description:
'The link you followed may be broken, or the page may have been removed.',
cta: 'Back to homepage',
},
fr: {
title: 'Désolé, cette page n’est pas disponible',
description:
'Le lien que vous avez suivi peut être cassé ou la page a peut-être été supprimée.',
cta: 'Retour à la page d’accueil',
},
de: {
title: 'Entschuldigung, diese Seite ist nicht verfügbar',
description:
'Der Link, dem Sie gefolgt sind, ist möglicherweise defekt oder die Seite wurde möglicherweise entfernt.',
cta: 'Zurück zur Startseite',
},
es: {
title: 'Lo sentimos, esta página no está disponible',
description:
'El enlace que seguiste puede estar roto o es posible que se haya eliminado la página.',
cta: 'Volver a la página de inicio',
},
};

export default async function NotFound() {
const headersList = await headers();
const acceptLanguagesHeader = headersList.get('accept-language');

const lang = match(
(acceptLanguagesHeader ?? '').split(', '),
AVAILABLE_LOCALES,
DEFAULT_LOCALE,
) as AvailableLocale;

return (
<div className={styles.notfound}>
<div className={styles.notfound__content_wrapper}>
<article>
<h1>{translations[lang].title}</h1>

<p>
<span>404 error</span>: {translations[lang].description}
</p>

<Link href={`/${lang}`} className="button button--on-light">
{translations[lang].cta}
</Link>
</article>
</div>
<SupportBanner lang={lang} />
</div>
);
}
Loading