mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-09-23 02:35:43 +00:00
refactor(webui): route auth redirects through lib/routes
Step 3 of the route-registry migration: every /login redirect and post-login landing fallback builds from lib/routes instead of hardcoded strings. - protected-route, axios 401/403 interceptor, user-provider (logout, session-expiry, /login + public-route checks) -> routes.login(...) / routes.login() - oauth-result error redirect -> routes.login() - login-form / public-route / login page post-login fallback -> routes.newFlow getReturnUrlParam now has a single in-app caller (the routes.login builder) plus the logout suffix-override; dropped its now-unused imports from axios and protected-route. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d71feaf854
commit
dc6b3a9e2c
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Navigate, useLocation } from 'react-router-dom';
|
||||
|
||||
import { getReturnUrlParam } from '@/lib/utils/auth';
|
||||
import { routes } from '@/lib/routes';
|
||||
import { useUser } from '@/providers/user-provider';
|
||||
|
||||
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||
@@ -13,12 +13,10 @@ function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
|
||||
if (!isAuthenticated()) {
|
||||
const returnParam = getReturnUrlParam(location.pathname);
|
||||
|
||||
return (
|
||||
<Navigate
|
||||
replace
|
||||
to={`/login${returnParam}`}
|
||||
to={routes.login(location.pathname)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Navigate, useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { routes } from '@/lib/routes';
|
||||
import { getSafeReturnUrl } from '@/lib/utils/auth';
|
||||
import { useUser } from '@/providers/user-provider';
|
||||
|
||||
@@ -29,7 +30,7 @@ function PublicRoute({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
|
||||
const returnUrl = getSafeReturnUrl(searchParams.get('returnUrl'), '/flows/new');
|
||||
const returnUrl = getSafeReturnUrl(searchParams.get('returnUrl'), routes.newFlow);
|
||||
|
||||
return (
|
||||
<Navigate
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '
|
||||
import { FormSubmitButton } from '@/components/ui/form-submit-button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { InputPassword } from '@/components/ui/input-password';
|
||||
import { routes } from '@/lib/routes';
|
||||
import { useUser } from '@/providers/user-provider';
|
||||
|
||||
import { PasswordChangeForm } from './password-change-form';
|
||||
@@ -61,7 +62,7 @@ interface LoginFormProps {
|
||||
returnUrl?: string;
|
||||
}
|
||||
|
||||
function LoginForm({ providers, returnUrl = '/flows/new' }: LoginFormProps) {
|
||||
function LoginForm({ providers, returnUrl = routes.newFlow }: LoginFormProps) {
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
defaultValues: {
|
||||
mail: '',
|
||||
|
||||
@@ -5,7 +5,7 @@ import Axios from 'axios';
|
||||
import { AUTH_STORAGE_KEY } from '@/providers/user-provider';
|
||||
|
||||
import { Log } from './log';
|
||||
import { getReturnUrlParam } from './utils/auth';
|
||||
import { routes } from './routes';
|
||||
|
||||
// ── shared API protocol types ────────────────────────────────────────────────
|
||||
//
|
||||
@@ -106,9 +106,8 @@ axios.interceptors.response.use(
|
||||
|
||||
const currentPath = window.location.pathname;
|
||||
|
||||
if (currentPath !== '/login') {
|
||||
const returnParam = getReturnUrlParam(currentPath);
|
||||
window.location.href = `/login${returnParam}`;
|
||||
if (currentPath !== routes.login()) {
|
||||
window.location.href = routes.login(currentPath);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -129,9 +128,8 @@ axios.interceptors.response.use(
|
||||
|
||||
const currentPath = window.location.pathname;
|
||||
|
||||
if (currentPath !== '/login') {
|
||||
const returnParam = getReturnUrlParam(currentPath);
|
||||
window.location.href = `/login${returnParam}`;
|
||||
if (currentPath !== routes.login()) {
|
||||
window.location.href = routes.login(currentPath);
|
||||
}
|
||||
} else {
|
||||
Log.warn(err.response?.data);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useLocation, useSearchParams } from 'react-router-dom';
|
||||
|
||||
import Logo from '@/components/icons/logo';
|
||||
import LoginForm from '@/features/authentication/login-form';
|
||||
import { routes } from '@/lib/routes';
|
||||
import { getSafeReturnUrl } from '@/lib/utils/auth';
|
||||
import { useUser } from '@/providers/user-provider';
|
||||
|
||||
@@ -12,7 +13,7 @@ function Login() {
|
||||
const { authInfo, isLoading } = useUser();
|
||||
const authProviders = authInfo?.providers || [];
|
||||
|
||||
const returnUrl = getSafeReturnUrl((location.state?.from as string) || searchParams.get('returnUrl'), '/flows/new');
|
||||
const returnUrl = getSafeReturnUrl((location.state?.from as string) || searchParams.get('returnUrl'), routes.newFlow);
|
||||
|
||||
return (
|
||||
<div className="flex h-dvh w-full items-center justify-center">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
|
||||
import Logo from '@/components/icons/logo';
|
||||
import { routes } from '@/lib/routes';
|
||||
|
||||
function OAuthResult() {
|
||||
const [statusMessage, setStatusMessage] = useState('Authentication in progress...');
|
||||
@@ -79,7 +80,7 @@ function OAuthResult() {
|
||||
}
|
||||
} else {
|
||||
updateMessage('Authentication window opened directly. Redirecting to login page...');
|
||||
handleRedirect('/login', errorDelay / 2);
|
||||
handleRedirect(routes.login(), errorDelay / 2);
|
||||
handleClose(errorDelay);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { AuthInfo } from '@/models/info';
|
||||
import type { User } from '@/models/user';
|
||||
|
||||
import { api } from '@/lib/axios';
|
||||
import { routes } from '@/lib/routes';
|
||||
import { getReturnUrlParam } from '@/lib/utils/auth';
|
||||
import { baseUrl } from '@/models/api';
|
||||
|
||||
@@ -147,7 +148,7 @@ export function UserProvider({ children }: { children: ReactNode }) {
|
||||
}, [setAuth, clearAuth]);
|
||||
|
||||
useEffect(() => {
|
||||
if (location.pathname === '/login' && !isLoading) {
|
||||
if (location.pathname === routes.login() && !isLoading) {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- refreshAuthInfo's setState runs after an async fetch, not synchronously
|
||||
refreshAuthInfo();
|
||||
}
|
||||
@@ -165,7 +166,7 @@ export function UserProvider({ children }: { children: ReactNode }) {
|
||||
toast.error('Logout failed, but clearing local session');
|
||||
} finally {
|
||||
clearAuth();
|
||||
window.location.href = `/login${finalReturnUrl}`;
|
||||
window.location.href = `${routes.login()}${finalReturnUrl}`;
|
||||
}
|
||||
},
|
||||
[clearAuth, location.pathname],
|
||||
@@ -328,7 +329,7 @@ export function UserProvider({ children }: { children: ReactNode }) {
|
||||
|
||||
useEffect(() => {
|
||||
const updateAuth = async () => {
|
||||
const publicRoutes = ['/login', '/oauth/result'];
|
||||
const publicRoutes = [routes.login(), routes.oauthResult];
|
||||
|
||||
if (publicRoutes.includes(location.pathname)) {
|
||||
return;
|
||||
@@ -350,8 +351,7 @@ export function UserProvider({ children }: { children: ReactNode }) {
|
||||
} else {
|
||||
clearAuth();
|
||||
toast.error('Session expired. Please login again.');
|
||||
const returnParam = getReturnUrlParam(location.pathname);
|
||||
navigate(`/login${returnParam}`);
|
||||
navigate(routes.login(location.pathname));
|
||||
}
|
||||
} catch {
|
||||
// A transient /info failure on navigation must not log the user out — a network
|
||||
|
||||
Reference in New Issue
Block a user