♻️(frontend) Refactor Auth component for improved redirection logic

Move redirects from render
to a guarded useEffect
to avoid triggering multiple redirects
on every re-render.
This commit is contained in:
rvveber
2025-10-08 16:40:37 +02:00
committed by Anthony LC
parent af01c6e466
commit 546f97c956
5 changed files with 92 additions and 46 deletions

View File

@@ -12,6 +12,7 @@ and this project adheres to
### Changed
- ♻️(frontend) Refactor Auth component for improved redirection logic #1461
- ♻️(frontend) replace Arial font-family with token font #1411
- ♿(frontend) improve accessibility:
- ♿(frontend) enable enter key to open documentss #1354

View File

@@ -1,8 +1,7 @@
import { Loader } from '@openfun/cunningham-react';
import { useRouter } from 'next/router';
import { PropsWithChildren } from 'react';
import { PropsWithChildren, useEffect, useState } from 'react';
import { Box } from '@/components';
import { Loading } from '@/components';
import { useConfig } from '@/core';
import { HOME_URL } from '../conf';
@@ -14,57 +13,65 @@ export const Auth = ({ children }: PropsWithChildren) => {
useAuth();
const { replace, pathname } = useRouter();
const { data: config } = useConfig();
if (isLoading && !isFetchedAfterMount) {
return (
<Box $height="100vh" $width="100vw" $align="center" $justify="center">
<Loader />
</Box>
);
}
const [isRedirecting, setIsRedirecting] = useState(false);
/**
* If the user is authenticated and wanted initially to access a document,
* we redirect to the document page.
* If the user is authenticated and initially wanted to access a specific page, redirect him to that page now.
*/
if (authenticated) {
useEffect(() => {
if (!authenticated || isRedirecting) {
return;
}
const authUrl = getAuthUrl();
if (authUrl) {
void replace(authUrl);
return (
<Box $height="100vh" $width="100vw" $align="center" $justify="center">
<Loader />
</Box>
);
setIsRedirecting(true);
void replace(authUrl).then(() => setIsRedirecting(false));
}
}, [authenticated, isRedirecting, pathname, replace]);
/**
* If the user is not authenticated and not on a allowed pages
*/
useEffect(() => {
if (isLoading || authenticated || pathAllowed || isRedirecting) {
return;
}
/**
* If the user is not authenticated and the path is not allowed, we redirect to the login page.
* The homepage feature is enabled, redirect them to the homepage
*/
if (!authenticated && !pathAllowed) {
if (config?.FRONTEND_HOMEPAGE_FEATURE_ENABLED) {
void replace(HOME_URL);
} else {
gotoLogin();
if (pathname !== HOME_URL) {
setIsRedirecting(true);
void replace(HOME_URL).then(() => setIsRedirecting(false));
}
return (
<Box $height="100vh" $width="100vw" $align="center" $justify="center">
<Loader />
</Box>
);
return;
}
/**
* If the user is authenticated and the path is the home page, we redirect to the index.
* Redirect them to login page
*/
if (pathname === HOME_URL && authenticated) {
void replace('/');
return (
<Box $height="100vh" $width="100vw" $align="center" $justify="center">
<Loader />
</Box>
);
setIsRedirecting(true);
gotoLogin();
}, [
authenticated,
pathAllowed,
config?.FRONTEND_HOMEPAGE_FEATURE_ENABLED,
replace,
isLoading,
isRedirecting,
pathname,
]);
const shouldShowLoader =
(isLoading && !isFetchedAfterMount) ||
isRedirecting ||
(!authenticated && !pathAllowed);
if (shouldShowLoader) {
return <Loading $height="100vh" $width="100vw" />;
}
return children;

View File

@@ -1,6 +1,6 @@
import { baseApiUrl } from '@/api';
export const HOME_URL = '/home';
export const HOME_URL: string = '/home';
export const LOGIN_URL = `${baseApiUrl()}authenticate/`;
export const LOGOUT_URL = `${baseApiUrl()}logout/`;
export const PATH_AUTH_LOCAL_STORAGE = 'docs-path-auth';

View File

@@ -1,7 +1,15 @@
import { terminateCrispSession } from '@/services/Crisp';
import { LOGIN_URL, LOGOUT_URL, PATH_AUTH_LOCAL_STORAGE } from './conf';
import {
HOME_URL,
LOGIN_URL,
LOGOUT_URL,
PATH_AUTH_LOCAL_STORAGE,
} from './conf';
/**
* Get the stored auth URL from local storage
*/
export const getAuthUrl = () => {
const path_auth = localStorage.getItem(PATH_AUTH_LOCAL_STORAGE);
if (path_auth) {
@@ -10,8 +18,15 @@ export const getAuthUrl = () => {
}
};
/**
* Store the current path in local storage if it's not the homepage or root
* so we can redirect the user to this path after login
*/
export const setAuthUrl = () => {
if (window.location.pathname !== '/') {
if (
window.location.pathname !== '/' &&
window.location.pathname !== `${HOME_URL}/`
) {
localStorage.setItem(PATH_AUTH_LOCAL_STORAGE, window.location.pathname);
}
};

View File

@@ -1,7 +1,30 @@
import { useRouter } from 'next/router';
import { useEffect } from 'react';
import { Loading } from '@/components';
import { useAuth } from '@/features/auth';
import { HomeContent } from '@/features/home';
import { NextPageWithLayout } from '@/types/next';
const Page: NextPageWithLayout = () => {
const { authenticated } = useAuth();
const { replace } = useRouter();
/**
* If the user is authenticated we redirect him to the index page (grid).
*/
useEffect(() => {
if (!authenticated) {
return;
}
void replace('/');
}, [authenticated, replace]);
if (authenticated) {
return <Loading $height="100vh" $width="100vw" />;
}
return <HomeContent />;
};