💄(frontend) add page 401

Add a 401 page when user try to access a
doc that need authentication.
This commit is contained in:
Anthony LC
2025-02-17 13:05:20 +01:00
committed by Anthony LC
parent f069329e18
commit 30c5cfab62
8 changed files with 83 additions and 9 deletions

View File

@@ -8,6 +8,10 @@ and this project adheres to
## [Unreleased] ## [Unreleased]
## Added
- 💄(frontend) add error pages #643
## Changed ## Changed
- 🛂(frontend) Restore version visibility #629 - 🛂(frontend) Restore version visibility #629

View File

@@ -100,7 +100,9 @@ test.describe('Doc Visibility: Restricted', () => {
await page.goto(urlDoc); await page.goto(urlDoc);
await expect(page.getByRole('textbox', { name: 'password' })).toBeVisible(); await expect(
page.getByText('Log in to access the document.'),
).toBeVisible();
}); });
test('A doc is not accessible when authentified but not member.', async ({ test('A doc is not accessible when authentified but not member.', async ({
@@ -379,7 +381,10 @@ test.describe('Doc Visibility: Authenticated', () => {
await page.goto(urlDoc); await page.goto(urlDoc);
await expect(page.locator('h2').getByText(docTitle)).toBeHidden(); await expect(page.locator('h2').getByText(docTitle)).toBeHidden();
await expect(page.getByRole('textbox', { name: 'password' })).toBeVisible();
await expect(
page.getByText('Log in to access the document.'),
).toBeVisible();
}); });
test('It checks a authenticated doc in read only mode', async ({ test('It checks a authenticated doc in read only mode', async ({

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

View File

@@ -14,7 +14,11 @@ export const ButtonLogin = () => {
if (!authenticated) { if (!authenticated) {
return ( return (
<Button onClick={gotoLogin} color="primary-text" aria-label={t('Login')}> <Button
onClick={() => gotoLogin()}
color="primary-text"
aria-label={t('Login')}
>
{t('Login')} {t('Login')}
</Button> </Button>
); );
@@ -32,7 +36,7 @@ export const ProConnectButton = () => {
return ( return (
<BoxButton <BoxButton
onClick={gotoLogin} onClick={() => gotoLogin()}
aria-label={t('Proconnect Login')} aria-label={t('Proconnect Login')}
$css={css` $css={css`
background-color: var(--c--theme--colors--primary-text); background-color: var(--c--theme--colors--primary-text);

View File

@@ -16,8 +16,11 @@ export const setAuthUrl = () => {
} }
}; };
export const gotoLogin = () => { export const gotoLogin = (withRedirect = true) => {
setAuthUrl(); if (withRedirect) {
setAuthUrl();
}
window.location.replace(LOGIN_URL); window.location.replace(LOGIN_URL);
}; };

View File

@@ -74,7 +74,7 @@ export default function HomeBanner() {
<ProConnectButton /> <ProConnectButton />
) : ( ) : (
<Button <Button
onClick={gotoLogin} onClick={() => gotoLogin()}
icon={ icon={
<Text $isMaterialIcon $color="white"> <Text $isMaterialIcon $color="white">
bolt bolt

View File

@@ -0,0 +1,57 @@
import { Button } from '@openfun/cunningham-react';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { ReactElement, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import img401 from '@/assets/icons/icon-401.png';
import { Box, Text } from '@/components';
import { gotoLogin, useAuth } from '@/features/auth';
import { PageLayout } from '@/layouts';
import { NextPageWithLayout } from '@/types/next';
const Page: NextPageWithLayout = () => {
const { t } = useTranslation();
const { authenticated } = useAuth();
const { replace } = useRouter();
useEffect(() => {
if (authenticated) {
void replace(`/`);
}
}, [authenticated, replace]);
return (
<Box
$align="center"
$margin="auto"
$gap="1rem"
$padding={{ bottom: '2rem' }}
>
<Image
src={img401}
alt={t('Image 401')}
style={{
maxWidth: '100%',
height: 'auto',
}}
/>
<Box $align="center" $gap="0.8rem">
<Text as="p" $textAlign="center" $maxWidth="350px" $theme="primary">
{t('Log in to access the document.')}
</Text>
<Button onClick={() => gotoLogin(false)} aria-label={t('Login')}>
{t('Login')}
</Button>
</Box>
</Box>
);
};
Page.getLayout = function getLayout(page: ReactElement) {
return <PageLayout withFooter={false}>{page}</PageLayout>;
};
export default Page;

View File

@@ -5,7 +5,7 @@ import { useRouter } from 'next/router';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Box, Text, TextErrors } from '@/components'; import { Box, Text, TextErrors } from '@/components';
import { gotoLogin } from '@/features/auth'; import { setAuthUrl } from '@/features/auth';
import { DocEditor } from '@/features/docs/doc-editor'; import { DocEditor } from '@/features/docs/doc-editor';
import { import {
Doc, Doc,
@@ -110,7 +110,8 @@ const DocPage = ({ id }: DocProps) => {
} }
if (error.status === 401) { if (error.status === 401) {
gotoLogin(); setAuthUrl();
void replace(`/401`);
return null; return null;
} }