🚸(app-impress) footer legales pages

- Add legales pages.
- Add links to the footer for the new pages.

Legales pages are based from
https://lasuite.numerique.gouv.fr/
This commit is contained in:
Anthony LC
2024-05-14 11:46:13 +02:00
committed by Anthony LC
parent 88d6d8977c
commit c1dd34512b
8 changed files with 426 additions and 8 deletions

View File

@@ -33,10 +33,44 @@ test.describe('Footer', () => {
footer.getByRole('link', { name: 'data.gouv.fr' }), footer.getByRole('link', { name: 'data.gouv.fr' }),
).toBeVisible(); ).toBeVisible();
await expect(
footer.getByRole('link', { name: 'Legal Notice' }),
).toBeVisible();
await expect(
footer.getByRole('link', { name: 'Personal data and cookies' }),
).toBeVisible();
await expect(
footer.getByRole('link', { name: 'Accessibility' }),
).toBeVisible();
await expect( await expect(
footer.getByText( footer.getByText(
'Unless otherwise stated, all content on this site is under licence', 'Unless otherwise stated, all content on this site is under licence',
), ),
).toBeVisible(); ).toBeVisible();
}); });
const legalPages = [
{ name: 'Legal Notice', url: '/legal-notice/' },
{ name: 'Personal data and cookies', url: '/personal-data-cookies/' },
{ name: 'Accessibility', url: '/accessibility/' },
];
for (const { name, url } of legalPages) {
test(`checks ${name} page`, async ({ page }) => {
const footer = page.locator('footer').first();
await footer.getByRole('link', { name }).click();
await expect(
page
.getByRole('heading', {
name,
})
.first(),
).toBeVisible();
await expect(page).toHaveURL(url);
});
}
}); });

View File

@@ -37,6 +37,7 @@ export const Footer = () => {
$gap="1.5rem" $gap="1.5rem"
$align="center" $align="center"
$justify="space-between" $justify="space-between"
$css="flex-wrap: wrap;"
> >
<Box> <Box>
<Box $align="center" $gap="6rem" $direction="row"> <Box $align="center" $gap="6rem" $direction="row">
@@ -50,7 +51,6 @@ export const Footer = () => {
</Box> </Box>
<Box <Box
$direction="row" $direction="row"
$justify="flex-end"
$css={` $css={`
column-gap: 1.5rem; column-gap: 1.5rem;
row-gap: .5rem; row-gap: .5rem;
@@ -93,6 +93,56 @@ export const Footer = () => {
))} ))}
</Box> </Box>
</Box> </Box>
<Box
$direction="row"
$margin={{ top: 'big' }}
$padding={{ top: 'tiny' }}
$css={`
flex-wrap: wrap;
border-top: 1px solid var(--c--theme--colors--greyscale-200);
column-gap: 1rem;
row-gap: .5rem;
`}
>
{[
{
label: t('Legal Notice'),
href: '/legal-notice',
},
{
label: t('Personal data and cookies'),
href: '/personal-data-cookies',
},
{
label: t('Accessibility'),
href: '/accessibility',
},
].map(({ label, href }) => (
<StyledLink
key={label}
href={href}
$css={`
padding-right: 1rem;
&:not(:last-child) {
box-shadow: inset -1px 0px 0px 0px var(--c--theme--colors--greyscale-200);
}
`}
>
<Text
$variation="600"
$size="m"
$transition="box-shadow 0.3s"
$css={`
&:hover {
box-shadow: 0px 2px 0 0 var(--c--theme--colors--greyscale-text);
}
`}
>
{label}
</Text>
</StyledLink>
))}
</Box>
<Text <Text
as="p" as="p"
$size="m" $size="m"

View File

@@ -5,7 +5,7 @@ import styled from 'styled-components';
import { default as IconGouv } from '@/assets/icons/icon-gouv.svg?url'; import { default as IconGouv } from '@/assets/icons/icon-gouv.svg?url';
import { default as IconMarianne } from '@/assets/icons/icon-marianne.svg?url'; import { default as IconMarianne } from '@/assets/icons/icon-marianne.svg?url';
import { Box, Text } from '@/components/'; import { Box, StyledLink, Text } from '@/components/';
import { LanguagePicker } from '../language/'; import { LanguagePicker } from '../language/';
@@ -53,12 +53,14 @@ export const Header = () => {
src={IconGouv} src={IconGouv}
alt={t('Freedom Equality Fraternity Logo')} alt={t('Freedom Equality Fraternity Logo')}
/> />
<Box $align="center" $gap="1rem" $direction="row"> <StyledLink href="/">
<Image priority src={IconImpress} alt={t('Impress Logo')} /> <Box $align="center" $gap="1rem" $direction="row">
<Text $margin="none" as="h2" $theme="primary"> <Image priority src={IconImpress} alt={t('Impress Logo')} />
{t('Impress')} <Text $margin="none" as="h2" $theme="primary">
</Text> {t('Impress')}
</Box> </Text>
</Box>
</StyledLink>
</Box> </Box>
</Box> </Box>
<Box <Box

View File

@@ -0,0 +1,17 @@
import { PropsWithChildren } from 'react';
import { Box } from '@/components';
import { Footer } from '@/features/footer/Footer';
import { Header } from '@/features/header';
export function PageLayout({ children }: PropsWithChildren) {
return (
<Box>
<Header />
<Box as="main" $width="100%">
{children}
</Box>
<Footer />
</Box>
);
}

View File

@@ -1,2 +1,3 @@
export * from './MainLayout'; export * from './MainLayout';
export * from './PadLayout'; export * from './PadLayout';
export * from './PageLayout';

View File

@@ -0,0 +1,137 @@
import { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Text, TextStyled } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { PageLayout } from '@/layouts';
import { NextPageWithLayout } from '@/types/next';
const Page: NextPageWithLayout = () => {
const { t } = useTranslation();
const { colorsTokens } = useCunninghamTheme();
return (
<Box>
<Box
as="h1"
$background={colorsTokens()['primary-100']}
$margin="none"
$padding="large"
>
{t('Accessibility')}
</Box>
<Box $padding={{ horizontal: 'large', vertical: 'big' }}>
<Text as="p" $display="inline">
<Text $weight="bold" $display="inline">
La Suite numérique
</Text>{' '}
s&apos;engage à rendre ses services numériques accessibles,
conformément à l&apos;article 47 de la loi n° 2005-102 du 11 février
2005.
</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Déclaration d&apos;accessibilité
</Text>
<Text as="p">Établie le 20 décembre 2023.</Text>
<Text as="p" $display="inline">
Cette déclaration d&apos;accessibilité s&apos;applique au site{' '}
<Text $weight="bold" $display="inline">
lasuite.numerique.gouv.fr
</Text>
.
</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
État de conformité
</Text>
<Text as="p" $display="inline">
<Text $weight="bold" $display="inline">
lasuite.numerique.gouv.fr
</Text>{' '}
est non conforme avec le RGAA 4.1. Le site n&apos;a{' '}
<Text $weight="bold" $display="inline">
pas encore é audité.
</Text>
</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Amélioration et contact
</Text>
<Text as="p" $display="inline">
Si vous n&apos;arrivez pas à accéder à un contenu ou à un service,
vous pouvez contacter le responsable de lasuite.numerique.gouv.fr pour
être orienté vers une alternative accessible ou obtenir le contenu
sous une autre forme.
</Text>
<Text as="p" $display="inline">
<li>
E-mail :{' '}
<TextStyled
as="a"
href="mailto:lasuite@modernisation.gouv.fr"
$display="inline"
>
lasuite@modernisation.gouv.fr
</TextStyled>
</li>
<li>
Adresse :{' '}
<Text $weight="bold" $display="inline">
DINUM
</Text>
, 20 avenue de Ségur 75007 Paris
</li>
</Text>
<Text as="p" $display="inline">
Nous essayons de répondre dans les 2 jours ouvrés.
</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Voie de recours
</Text>
<Text as="p" $display="inline">
Cette procédure est à utiliser dans le cas suivant : vous avez signalé
au responsable du site internet un défaut d&apos;accessibilité qui
vous empêche d&apos;accéder à un contenu ou à un des services du
portail et vous n&apos;avez pas obtenu de réponse satisfaisante.
</Text>
<Text as="p" $display="inline" $margin={{ bottom: 'tiny' }}>
Vous pouvez :
</Text>
<Text as="p" $display="inline" $margin={{ top: 'tiny' }}>
<li>
Écrire un message au{' '}
<TextStyled
as="a"
href="https://formulaire.defenseurdesdroits.fr/formulaire_saisine/"
$display="inline"
>
Défenseur des droits
</TextStyled>
</li>
<li>
Contacter le délégué du{' '}
<TextStyled
as="a"
href="https://www.defenseurdesdroits.fr/carte-des-delegues"
$display="inline"
>
Défenseur des droits dans votre région
</TextStyled>
</li>
<li>
Envoyer un courrier par la poste (gratuit, ne pas mettre de timbre)
:{' '}
<Text $weight="bold" $display="inline">
Défenseur des droits Libre réponse 71120 75342 Paris CEDEX 07
</Text>
</li>
</Text>
</Box>
</Box>
);
};
Page.getLayout = function getLayout(page: ReactElement) {
return <PageLayout>{page}</PageLayout>;
};
export default Page;

View File

@@ -0,0 +1,67 @@
import { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Text, TextStyled } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { PageLayout } from '@/layouts';
import { NextPageWithLayout } from '@/types/next';
const Page: NextPageWithLayout = () => {
const { t } = useTranslation();
const { colorsTokens } = useCunninghamTheme();
return (
<Box>
<Box
as="h1"
$background={colorsTokens()['primary-100']}
$margin="none"
$padding="large"
>
{t('Legal notice')}
</Box>
<Box $padding={{ horizontal: 'large', vertical: 'big' }}>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Éditeur
</Text>
<Text as="p">
Équipe La Suite Numérique de la Direction interministérielle du
numérique DINUM, 20 avenue de Ségur 75007 Paris.
</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Directeur de la publication
</Text>
<Text as="p">Directeur interministériel du numérique.</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Copyright
</Text>
<Text as="p" $display="inline">
Illustration :{' '}
<Text $weight="bold" $display="inline">
DINUM
</Text>
</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Plus d&apos;infos ?
</Text>
<Text as="p" $display="inline">
L&apos;équipe de La Suite Numérique peut être contactée directement à{' '}
<TextStyled
as="a"
href="lasuite@modernisation.gouv.fr"
$display="inline"
>
lasuite@modernisation.gouv.fr
</TextStyled>
.
</Text>
</Box>
</Box>
);
};
Page.getLayout = function getLayout(page: ReactElement) {
return <PageLayout>{page}</PageLayout>;
};
export default Page;

View File

@@ -0,0 +1,110 @@
import { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Text, TextStyled } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { PageLayout } from '@/layouts';
import { NextPageWithLayout } from '@/types/next';
const Page: NextPageWithLayout = () => {
const { t } = useTranslation();
const { colorsTokens } = useCunninghamTheme();
return (
<Box>
<Box
as="h1"
$background={colorsTokens()['primary-100']}
$margin="none"
$padding="large"
>
{t('Personal data and cookies')}
</Box>
<Box $padding={{ horizontal: 'large', vertical: 'big' }}>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Cookies déposés
</Text>
<Text as="p">
Ce site dépose un petit fichier texte (un « cookie ») sur votre
ordinateur lorsque vous le consultez. Cela nous permet de mesurer le
nombre de visites et de comprendre quelles sont les pages les plus
consultées.
</Text>
<Text as="p">
Vous pouvez vous opposer au suivi de votre navigation sur ce site web.
Cela protégera votre vie privée, mais empêchera également le
propriétaire d&apos;apprendre de vos actions et de créer une meilleure
expérience pour vous et les autres utilisateurs.
</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Ce site n&apos;affiche pas de bannière de consentement aux cookies,
pourquoi ?
</Text>
<Text as="p">
C&apos;est vrai, vous n&apos;avez pas eu à cliquer sur un bloc qui
recouvre la moitié de la page pour dire que vous êtes d&apos;accord
avec le dépôt de cookies même si vous ne savez pas ce que ça veut
dire !
</Text>
<Text as="p">
Rien d&apos;exceptionnel, pas de passe-droit lié à un .gouv.fr . Nous
respectons simplement la loi, qui dit que certains outils de suivi
d&apos;audience, correctement configurés pour respecter la vie privée,
sont exemptés d&apos;autorisation préalable.
</Text>
<Text as="p" $display="inline">
Nous utilisons pour cela{' '}
<TextStyled as="a" href="https://matomo.org/" $display="inline">
Matomo
</TextStyled>
, un outil{' '}
<TextStyled
as="a"
href="https://matomo.org/free-software/"
$display="inline"
>
libre
</TextStyled>
, paramétré pour être en conformité avec la{' '}
<TextStyled
as="a"
href="https://www.cnil.fr/fr/cookies-et-autres-traceurs/regles/cookies-solutions-pour-les-outils-de-mesure-daudience"
$display="inline"
>
recommandation « Cookies »
</TextStyled>{' '}
de la{' '}
<span
style={{
textDecorationStyle: 'dotted',
textDecorationLine: 'underline',
}}
>
CNIL
</span>
. Cela signifie que votre adresse IP, par exemple, est anonymisée
avant d&apos;être enregistrée. Il est donc impossible d&apos;associer
vos visites sur ce site à votre personne.
</Text>
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
Je contribue à enrichir vos données, puis-je y accéder ?
</Text>
<p>
Bien sûr ! Les statistiques d&apos;usage de la majorité de nos
produits, dont lasuite.numerique.gouv.fr, sont disponibles en accès
libre sur{' '}
<TextStyled as="a" href="stats.data.gouv.fr" $display="inline">
stats.data.gouv.fr
</TextStyled>
.
</p>
</Box>
</Box>
);
};
Page.getLayout = function getLayout(page: ReactElement) {
return <PageLayout>{page}</PageLayout>;
};
export default Page;