🚸(app-desk) 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:
17
src/frontend/apps/desk/src/core/PageLayout.tsx
Normal file
17
src/frontend/apps/desk/src/core/PageLayout.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './AppProvider';
|
export * from './AppProvider';
|
||||||
export * from './MainLayout';
|
export * from './MainLayout';
|
||||||
|
export * from './PageLayout';
|
||||||
|
|||||||
@@ -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: non-compliant'),
|
||||||
|
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"
|
||||||
|
$css={`
|
||||||
|
transition: box-shadow 0.3s;
|
||||||
|
&: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"
|
||||||
|
|||||||
135
src/frontend/apps/desk/src/pages/accessibility/index.tsx
Normal file
135
src/frontend/apps/desk/src/pages/accessibility/index.tsx
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import { PropsWithChildren, ReactElement } from 'react';
|
||||||
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { Box, Text, TextStyled, TextType } from '@/components';
|
||||||
|
import { PageLayout } from '@/core';
|
||||||
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
import { NextPageWithLayout } from '@/types/next';
|
||||||
|
|
||||||
|
const Inline = ({ children, ...props }: PropsWithChildren<TextType>) => {
|
||||||
|
return (
|
||||||
|
<Text as="p" $display="inline" {...props}>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Page: NextPageWithLayout = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { colorsTokens } = useCunninghamTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Box
|
||||||
|
as="h1"
|
||||||
|
$background={colorsTokens()['primary-100']}
|
||||||
|
$margin="none"
|
||||||
|
$padding="large"
|
||||||
|
>
|
||||||
|
{t('Accessibility statement')}
|
||||||
|
</Box>
|
||||||
|
<Box $padding={{ horizontal: 'large', vertical: 'big' }}>
|
||||||
|
<Inline>{t('Declaration established on June 25, 2024.')}</Inline>
|
||||||
|
<Inline>
|
||||||
|
{t(`The National Agency for Territorial Cohesion undertakes to make its
|
||||||
|
service accessible, in accordance with article 47 of law no. 2005-102
|
||||||
|
of February 11, 2005.`)}
|
||||||
|
<br />
|
||||||
|
{t(
|
||||||
|
`This accessibility statement applies to La Régie (Suite Territoriale)`,
|
||||||
|
)}{' '}
|
||||||
|
(https://regie.numerique.gouv.fr/).
|
||||||
|
</Inline>
|
||||||
|
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||||
|
{t('Compliance status')}
|
||||||
|
</Text>
|
||||||
|
<Inline>
|
||||||
|
{t(
|
||||||
|
'La Régie (Suite Territoriale) is non-compliant with the RGAA. The site has not yet been audited.',
|
||||||
|
)}
|
||||||
|
</Inline>
|
||||||
|
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||||
|
{t('Improvement and contact')}
|
||||||
|
</Text>
|
||||||
|
<Box $margin={{ top: '1rem' }}>
|
||||||
|
{t(
|
||||||
|
`If you are unable to access content or a service, you can contact the manager of La Régie (Suite Territoriale)
|
||||||
|
to be directed to an accessible alternative or obtain the content in another form.`,
|
||||||
|
)}
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
{t(
|
||||||
|
`Address: National Agency for Territorial Cohesion - 20, avenue de Ségur TSA 10717 75 334 Paris Cedex 07 Paris`,
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{t('E-mail:')}{' '}
|
||||||
|
<TextStyled
|
||||||
|
as="a"
|
||||||
|
href="mailto:suiteterritoriale@anct.gouv.fr"
|
||||||
|
$display="inline"
|
||||||
|
>
|
||||||
|
suiteterritoriale@anct.gouv.fr
|
||||||
|
</TextStyled>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</Box>
|
||||||
|
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||||
|
{t('Remedy')}
|
||||||
|
</Text>
|
||||||
|
<Inline>
|
||||||
|
{t(
|
||||||
|
`This procedure is to be used in the following case: you have reported to the website
|
||||||
|
manager an accessibility defect which prevents you from accessing content or one of the
|
||||||
|
portal's services and you have not obtained a satisfactory response.`,
|
||||||
|
)}
|
||||||
|
</Inline>
|
||||||
|
<Box>
|
||||||
|
{t('You can:')}
|
||||||
|
<Box as="ul" $margin={{ top: 'tiny' }}>
|
||||||
|
<li>
|
||||||
|
<Trans t={t} i18nKey="accessibility-form-defenseurdesdroits">
|
||||||
|
Write a message to the
|
||||||
|
<TextStyled
|
||||||
|
as="a"
|
||||||
|
href="https://formulaire.defenseurdesdroits.fr/formulaire_saisine/"
|
||||||
|
$display="inline"
|
||||||
|
$margin={{ left: '4px' }}
|
||||||
|
>
|
||||||
|
Defender of Rights
|
||||||
|
</TextStyled>
|
||||||
|
</Trans>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Trans t={t} i18nKey="accessibility-contact-defenseurdesdroits">
|
||||||
|
Contact the delegate of the
|
||||||
|
<TextStyled
|
||||||
|
as="a"
|
||||||
|
href="https://www.defenseurdesdroits.fr/carte-des-delegues"
|
||||||
|
$display="inline"
|
||||||
|
$margin={{ left: '4px' }}
|
||||||
|
>
|
||||||
|
Defender of Rights in your region
|
||||||
|
</TextStyled>
|
||||||
|
</Trans>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{t('Send a letter by post (free of charge, no stamp needed):')}{' '}
|
||||||
|
<strong>
|
||||||
|
{t(
|
||||||
|
'Defender of Rights - Free response - 71120 75342 Paris CEDEX 07',
|
||||||
|
)}
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Page.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return <PageLayout>{page}</PageLayout>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Page;
|
||||||
72
src/frontend/apps/desk/src/pages/legal-notice/index.tsx
Normal file
72
src/frontend/apps/desk/src/pages/legal-notice/index.tsx
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { ReactElement } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { Box, Text, TextStyled } from '@/components';
|
||||||
|
import { PageLayout } from '@/core';
|
||||||
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
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' }}>
|
||||||
|
{t('Publisher')}
|
||||||
|
</Text>
|
||||||
|
<Text as="p">
|
||||||
|
{t(
|
||||||
|
'French Interministerial Directorate for Digital Affairs (DINUM), 20 avenue de Ségur 75007 Paris.',
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||||
|
{t('Publication Director')}
|
||||||
|
</Text>
|
||||||
|
<Text as="p">
|
||||||
|
{t('Stéphanie Schaer: Interministerial Digital Director (DINUM).')}
|
||||||
|
</Text>
|
||||||
|
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||||
|
{t('Copyright')}
|
||||||
|
</Text>
|
||||||
|
<Text as="p" $display="inline">
|
||||||
|
{t('Illustration:')}{' '}
|
||||||
|
<Text $weight="bold" $display="inline">
|
||||||
|
DINUM
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||||
|
{t('More info?')}
|
||||||
|
</Text>
|
||||||
|
<Text as="p" $display="inline">
|
||||||
|
{t(
|
||||||
|
'The team in charge of the digital workspace "La Suite numérique" can be contacted directly at',
|
||||||
|
)}{' '}
|
||||||
|
<TextStyled
|
||||||
|
as="a"
|
||||||
|
href="mailto: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;
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { ReactElement } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { Box, Text } from '@/components';
|
||||||
|
import { PageLayout } from '@/core';
|
||||||
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
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' }}>
|
||||||
|
{t('Cookies placed')}
|
||||||
|
</Text>
|
||||||
|
<Text as="p">
|
||||||
|
{t(
|
||||||
|
'This site places a small text file (a "cookie") on your computer when you visit it.',
|
||||||
|
)}
|
||||||
|
{t(
|
||||||
|
'This allows us to measure the number of visits and understand which pages are the most viewed.',
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
<Text as="p">
|
||||||
|
{t('You can oppose the tracking of your browsing on this website.')}{' '}
|
||||||
|
{t(
|
||||||
|
'This will protect your privacy, but will also prevent the owner from learning from your actions and creating a better experience for you and other users.',
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||||
|
{t('This site does not display a cookie consent banner, why?')}
|
||||||
|
</Text>
|
||||||
|
<Text as="p">
|
||||||
|
{t(
|
||||||
|
"It's true, you didn't have to click on a block that covers half the page to say you agree to the placement of cookies — even if you don't know what it means!",
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
<Text as="p">
|
||||||
|
{t(
|
||||||
|
'Nothing exceptional, no special privileges related to a .gouv.fr.',
|
||||||
|
)}{' '}
|
||||||
|
{t(
|
||||||
|
'We simply comply with the law, which states that certain audience measurement tools, properly configured to respect privacy, are exempt from prior authorization.',
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Page.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return <PageLayout>{page}</PageLayout>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -33,10 +33,56 @@ 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',
|
'Unless otherwise stated, all content on this site is under',
|
||||||
),
|
),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const legalPages = [
|
||||||
|
{
|
||||||
|
linkName: 'Legal Notice',
|
||||||
|
pageName: 'Legal Notice',
|
||||||
|
url: '/legal-notice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
linkName: 'Personal data and cookies',
|
||||||
|
pageName: 'Personal data and cookies',
|
||||||
|
url: '/personal-data-cookies',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
linkName: 'Accessibility: non-compliant',
|
||||||
|
pageName: 'Accessibility statement',
|
||||||
|
url: '/accessibility',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
for (const { linkName, url, pageName } of legalPages) {
|
||||||
|
test(`checks ${linkName} page`, async ({ page }) => {
|
||||||
|
const footer = page.locator('footer').first();
|
||||||
|
await footer.getByRole('link', { name: linkName }).click();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
page
|
||||||
|
.getByRole('heading', {
|
||||||
|
name: pageName,
|
||||||
|
})
|
||||||
|
.first(),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user