diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5faa6dfb..6d88eab1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,11 @@ and this project adheres to
## [Unreleased]
+## Added
+
+- 🛂(frontend) access public docs without being logged #235
+
+
## [1.3.0] - 2024-09-05
## Added
diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts
index 1d602a9a..e7d2f51d 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts
@@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
-import { keyCloakSignIn } from './common';
+import { createDoc, keyCloakSignIn } from './common';
test.describe('Doc Routing', () => {
test.beforeEach(async ({ page }) => {
@@ -47,4 +47,43 @@ test.describe('Doc Routing: Not loggued', () => {
await keyCloakSignIn(page, browserName);
await expect(page).toHaveURL(/\/docs\/mocked-document-id\/$/);
});
+
+ test('The homepage redirects to login.', async ({ page }) => {
+ await page.goto('/');
+ await expect(
+ page.getByRole('button', {
+ name: 'Sign In',
+ }),
+ ).toBeVisible();
+ });
+
+ test('A public doc is accessible even when not authentified.', async ({
+ page,
+ browserName,
+ }) => {
+ await page.goto('/');
+ await keyCloakSignIn(page, browserName);
+
+ const [docTitle] = await createDoc(
+ page,
+ 'My new doc',
+ browserName,
+ 1,
+ true,
+ );
+
+ const urlDoc = page.url();
+
+ await page
+ .getByRole('button', {
+ name: 'Logout',
+ })
+ .click();
+
+ await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
+
+ await page.goto(urlDoc);
+
+ await expect(page.locator('h2').getByText(docTitle)).toBeVisible();
+ });
});
diff --git a/src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts
index 6dc2a4c5..e2508a69 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts
@@ -22,6 +22,12 @@ test.describe('Header', () => {
/Marianne/i,
);
+ await expect(
+ header.getByRole('button', {
+ name: 'Logout',
+ }),
+ ).toBeVisible();
+
await expect(header.getByAltText('Language Icon')).toBeVisible();
await expect(
@@ -68,12 +74,6 @@ test.describe('Header: Log out', () => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
- await page
- .getByRole('button', {
- name: 'My account',
- })
- .click();
-
await page
.getByRole('button', {
name: 'Logout',
diff --git a/src/frontend/apps/impress/src/api/__tests__/fetchApi.test.tsx b/src/frontend/apps/impress/src/api/__tests__/fetchApi.test.tsx
index 67c57869..05dc0b13 100644
--- a/src/frontend/apps/impress/src/api/__tests__/fetchApi.test.tsx
+++ b/src/frontend/apps/impress/src/api/__tests__/fetchApi.test.tsx
@@ -1,7 +1,6 @@
import fetchMock from 'fetch-mock';
import { fetchAPI } from '@/api';
-import { useAuthStore } from '@/core/auth';
describe('fetchAPI', () => {
beforeEach(() => {
@@ -30,19 +29,6 @@ describe('fetchAPI', () => {
});
});
- it('logout if 401 response', async () => {
- const logoutMock = jest.fn();
- jest
- .spyOn(useAuthStore.getState(), 'logout')
- .mockImplementation(logoutMock);
-
- fetchMock.mock('http://test.jest/api/v1.0/some/url', 401);
-
- await fetchAPI('some/url');
-
- expect(logoutMock).toHaveBeenCalled();
- });
-
it('check the versionning', () => {
fetchMock.mock('http://test.jest/api/v2.0/some/url', 200);
diff --git a/src/frontend/apps/impress/src/api/fetchApi.ts b/src/frontend/apps/impress/src/api/fetchApi.ts
index 03fad1f6..208f5e81 100644
--- a/src/frontend/apps/impress/src/api/fetchApi.ts
+++ b/src/frontend/apps/impress/src/api/fetchApi.ts
@@ -1,4 +1,4 @@
-import { baseApiUrl, useAuthStore } from '@/core';
+import { baseApiUrl } from '@/core';
import { getCSRFToken } from './utils';
@@ -30,10 +30,5 @@ export const fetchAPI = async (
headers,
});
- if (response.status === 401) {
- const { logout } = useAuthStore.getState();
- logout();
- }
-
return response;
};
diff --git a/src/frontend/apps/impress/src/core/AppProvider.tsx b/src/frontend/apps/impress/src/core/AppProvider.tsx
index 663cea2d..a578c9b8 100644
--- a/src/frontend/apps/impress/src/core/AppProvider.tsx
+++ b/src/frontend/apps/impress/src/core/AppProvider.tsx
@@ -4,7 +4,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useCunninghamTheme } from '@/cunningham';
import '@/i18n/initI18n';
-import { Auth } from './auth/Auth';
+import { Auth } from './auth/';
/**
* QueryClient:
diff --git a/src/frontend/apps/impress/src/core/auth/AccountDropdown.tsx b/src/frontend/apps/impress/src/core/auth/AccountDropdown.tsx
new file mode 100644
index 00000000..43344d4b
--- /dev/null
+++ b/src/frontend/apps/impress/src/core/auth/AccountDropdown.tsx
@@ -0,0 +1,34 @@
+import { Button } from '@openfun/cunningham-react';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import { useAuthStore } from '@/core/auth';
+
+export const AccountDropdown = () => {
+ const { t } = useTranslation();
+ const { logout, authenticated, login } = useAuthStore();
+
+ if (!authenticated) {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+};
diff --git a/src/frontend/apps/impress/src/core/auth/Auth.tsx b/src/frontend/apps/impress/src/core/auth/Auth.tsx
index 865a815f..0e5d0131 100644
--- a/src/frontend/apps/impress/src/core/auth/Auth.tsx
+++ b/src/frontend/apps/impress/src/core/auth/Auth.tsx
@@ -1,18 +1,47 @@
import { Loader } from '@openfun/cunningham-react';
-import { PropsWithChildren, useEffect } from 'react';
+import { useRouter } from 'next/router';
+import { PropsWithChildren, useEffect, useState } from 'react';
import { Box } from '@/components';
import { useAuthStore } from './useAuthStore';
+/**
+ * TODO: Remove this restriction when we will have a homepage design for non-authenticated users.
+ *
+ * We define the paths that are not allowed without authentication.
+ * Actually, only the home page and the docs page are not allowed without authentication.
+ * When we will have a homepage design for non-authenticated users, we will remove this restriction to have
+ * the full website accessible without authentication.
+ */
+const regexpUrlsAuth = [/\/docs\/$/g, /^\/$/g];
+
export const Auth = ({ children }: PropsWithChildren) => {
- const { authenticated, initAuth } = useAuthStore();
+ const { initAuth, initiated, authenticated, login } = useAuthStore();
+ const { asPath } = useRouter();
+
+ const [pathAllowed, setPathAllowed] = useState