mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-09 15:17:59 -05:00
fix(frontend): redirects improvements...
This commit is contained in:
@@ -1,4 +1,11 @@
|
||||
"use client";
|
||||
import { StoreAgentDetails } from "@/lib/autogpt-server-api";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { isEmptyOrWhitespace } from "@/lib/utils";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useOnboarding } from "../../../../providers/onboarding/onboarding-provider";
|
||||
import OnboardingAgentCard from "../components/OnboardingAgentCard";
|
||||
import OnboardingButton from "../components/OnboardingButton";
|
||||
import {
|
||||
OnboardingFooter,
|
||||
@@ -6,24 +13,18 @@ import {
|
||||
OnboardingStep,
|
||||
} from "../components/OnboardingStep";
|
||||
import { OnboardingText } from "../components/OnboardingText";
|
||||
import OnboardingAgentCard from "../components/OnboardingAgentCard";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { StoreAgentDetails } from "@/lib/autogpt-server-api";
|
||||
import { isEmptyOrWhitespace } from "@/lib/utils";
|
||||
import { useOnboarding } from "../../../../providers/onboarding/onboarding-provider";
|
||||
import router from "next/router";
|
||||
|
||||
export default function Page() {
|
||||
const { state, updateState, completeStep } = useOnboarding(4, "INTEGRATIONS");
|
||||
const [agents, setAgents] = useState<StoreAgentDetails[]>([]);
|
||||
const api = useBackendAPI();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
api.getOnboardingAgents().then((agents) => {
|
||||
if (agents.length < 2) {
|
||||
completeStep("CONGRATS");
|
||||
router.push("/onboarding");
|
||||
router.replace("/");
|
||||
}
|
||||
setAgents(agents);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function OnboardingPage() {
|
||||
const router = useRouter();
|
||||
@@ -14,7 +14,7 @@ export default function OnboardingPage() {
|
||||
// Check if onboarding is enabled
|
||||
const isEnabled = await api.isOnboardingEnabled();
|
||||
if (!isEnabled) {
|
||||
router.push("/");
|
||||
router.replace("/");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function OnboardingPage() {
|
||||
|
||||
// Handle completed onboarding
|
||||
if (onboarding.completedSteps.includes("GET_RESULTS")) {
|
||||
router.push("/");
|
||||
router.replace("/");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,13 +33,13 @@ export default function OnboardingPage() {
|
||||
const libraryAgent = await api.addMarketplaceAgentToLibrary(
|
||||
onboarding.selectedStoreListingVersionId,
|
||||
);
|
||||
router.push(`/library/agents/${libraryAgent.id}`);
|
||||
router.replace(`/library/agents/${libraryAgent.id}`);
|
||||
} catch (error) {
|
||||
console.error("Failed to add agent to library:", error);
|
||||
router.push("/library");
|
||||
router.replace("/library");
|
||||
}
|
||||
} else {
|
||||
router.push("/library");
|
||||
router.replace("/library");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export default function OnboardingPage() {
|
||||
router.push("/onboarding/1-welcome");
|
||||
} catch (error) {
|
||||
console.error("Failed to determine onboarding step:", error);
|
||||
router.push("/");
|
||||
router.replace("/");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client";
|
||||
import { Form, FormField } from "@/components/__legacy__/ui/form";
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { Input } from "@/components/atoms/Input/Input";
|
||||
import { Link } from "@/components/atoms/Link/Link";
|
||||
@@ -7,10 +8,9 @@ import AuthFeedback from "@/components/auth/AuthFeedback";
|
||||
import { EmailNotAllowedModal } from "@/components/auth/EmailNotAllowedModal";
|
||||
import { GoogleOAuthButton } from "@/components/auth/GoogleOAuthButton";
|
||||
import Turnstile from "@/components/auth/Turnstile";
|
||||
import { Form, FormField } from "@/components/__legacy__/ui/form";
|
||||
import { environment } from "@/services/environment";
|
||||
import { LoadingLogin } from "./components/LoadingLogin";
|
||||
import { useLoginPage } from "./useLoginPage";
|
||||
import { environment } from "@/services/environment";
|
||||
|
||||
export default function LoginPage() {
|
||||
const {
|
||||
@@ -20,10 +20,8 @@ export default function LoginPage() {
|
||||
turnstile,
|
||||
captchaKey,
|
||||
isLoading,
|
||||
isRedirecting,
|
||||
isCloudEnv,
|
||||
isUserLoading,
|
||||
isGoogleLoading,
|
||||
showNotAllowedModal,
|
||||
isSupabaseAvailable,
|
||||
handleSubmit,
|
||||
@@ -31,7 +29,7 @@ export default function LoginPage() {
|
||||
handleCloseNotAllowedModal,
|
||||
} = useLoginPage();
|
||||
|
||||
if (isUserLoading || user || isRedirecting) {
|
||||
if (isUserLoading || user) {
|
||||
return <LoadingLogin />;
|
||||
}
|
||||
|
||||
@@ -111,7 +109,7 @@ export default function LoginPage() {
|
||||
{isCloudEnv ? (
|
||||
<GoogleOAuthButton
|
||||
onClick={() => handleProviderLogin("google")}
|
||||
isLoading={isGoogleLoading}
|
||||
isLoading={isLoading}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -19,9 +19,7 @@ export function useLoginPage() {
|
||||
const returnUrl = searchParams.get("returnUrl");
|
||||
const { toast } = useToast();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isGoogleLoading, setIsGoogleLoading] = useState(false);
|
||||
const [showNotAllowedModal, setShowNotAllowedModal] = useState(false);
|
||||
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||
const isCloudEnv = environment.isCloud();
|
||||
const isVercelPreview = process.env.NEXT_PUBLIC_VERCEL_ENV === "preview";
|
||||
|
||||
@@ -45,7 +43,7 @@ export function useLoginPage() {
|
||||
}, [turnstile]);
|
||||
|
||||
async function handleProviderLogin(provider: LoginProvider) {
|
||||
setIsGoogleLoading(true);
|
||||
setIsLoading(true);
|
||||
|
||||
if (isCloudEnv && !turnstile.verified && !isVercelPreview) {
|
||||
toast({
|
||||
@@ -53,7 +51,7 @@ export function useLoginPage() {
|
||||
variant: "info",
|
||||
});
|
||||
|
||||
setIsGoogleLoading(false);
|
||||
setIsLoading(false);
|
||||
resetCaptcha();
|
||||
return;
|
||||
}
|
||||
@@ -67,24 +65,14 @@ export function useLoginPage() {
|
||||
|
||||
if (!response.ok) {
|
||||
const { error } = await response.json();
|
||||
if (error === "not_allowed") {
|
||||
setShowNotAllowedModal(true);
|
||||
} else {
|
||||
setFeedback(error || "Failed to start OAuth flow");
|
||||
}
|
||||
resetCaptcha();
|
||||
setIsGoogleLoading(false);
|
||||
return;
|
||||
throw new Error(error || "Failed to start OAuth flow");
|
||||
}
|
||||
|
||||
const { url } = await response.json();
|
||||
if (url) {
|
||||
setIsRedirecting(true);
|
||||
window.location.href = url as string;
|
||||
}
|
||||
if (url) window.location.href = url as string;
|
||||
} catch (error) {
|
||||
resetCaptcha();
|
||||
setIsGoogleLoading(false);
|
||||
setIsLoading(false);
|
||||
setFeedback(
|
||||
error instanceof Error ? error.message : "Failed to start OAuth flow",
|
||||
);
|
||||
@@ -93,6 +81,7 @@ export function useLoginPage() {
|
||||
|
||||
async function handleLogin(data: z.infer<typeof loginFormSchema>) {
|
||||
setIsLoading(true);
|
||||
|
||||
if (isCloudEnv && !turnstile.verified && !isVercelPreview) {
|
||||
toast({
|
||||
title: "Please complete the CAPTCHA challenge.",
|
||||
@@ -129,26 +118,12 @@ export function useLoginPage() {
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
toast({
|
||||
title: result?.error || "Login failed",
|
||||
variant: "destructive",
|
||||
});
|
||||
setIsLoading(false);
|
||||
resetCaptcha();
|
||||
turnstile.reset();
|
||||
return;
|
||||
throw new Error(result?.error || "Login failed");
|
||||
}
|
||||
|
||||
await supabase?.auth.refreshSession();
|
||||
setIsLoading(false);
|
||||
setFeedback(null);
|
||||
|
||||
// Prioritize returnUrl from query params over backend's onboarding logic
|
||||
const next = computeReturnURL(returnUrl, result);
|
||||
if (next) {
|
||||
setIsRedirecting(true);
|
||||
router.push(next);
|
||||
}
|
||||
if (next) router.replace(next);
|
||||
} catch (error) {
|
||||
toast({
|
||||
title:
|
||||
@@ -170,10 +145,8 @@ export function useLoginPage() {
|
||||
captchaKey,
|
||||
user,
|
||||
isLoading,
|
||||
isRedirecting,
|
||||
isCloudEnv,
|
||||
isUserLoading,
|
||||
isGoogleLoading,
|
||||
showNotAllowedModal,
|
||||
isSupabaseAvailable: !!supabase,
|
||||
handleSubmit: form.handleSubmit(handleLogin),
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Checkbox } from "@/components/__legacy__/ui/checkbox";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
} from "@/components/__legacy__/ui/form";
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { Input } from "@/components/atoms/Input/Input";
|
||||
import { Link } from "@/components/atoms/Link/Link";
|
||||
@@ -9,18 +17,10 @@ import AuthFeedback from "@/components/auth/AuthFeedback";
|
||||
import { EmailNotAllowedModal } from "@/components/auth/EmailNotAllowedModal";
|
||||
import { GoogleOAuthButton } from "@/components/auth/GoogleOAuthButton";
|
||||
import Turnstile from "@/components/auth/Turnstile";
|
||||
import { Checkbox } from "@/components/__legacy__/ui/checkbox";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
} from "@/components/__legacy__/ui/form";
|
||||
import { environment } from "@/services/environment";
|
||||
import { WarningOctagonIcon } from "@phosphor-icons/react/dist/ssr";
|
||||
import { LoadingSignup } from "./components/LoadingSignup";
|
||||
import { useSignupPage } from "./useSignupPage";
|
||||
import { environment } from "@/services/environment";
|
||||
|
||||
export default function SignupPage() {
|
||||
const {
|
||||
@@ -32,8 +32,6 @@ export default function SignupPage() {
|
||||
isLoading,
|
||||
isCloudEnv,
|
||||
isUserLoading,
|
||||
isRedirecting,
|
||||
isGoogleLoading,
|
||||
showNotAllowedModal,
|
||||
isSupabaseAvailable,
|
||||
handleSubmit,
|
||||
@@ -41,7 +39,7 @@ export default function SignupPage() {
|
||||
handleCloseNotAllowedModal,
|
||||
} = useSignupPage();
|
||||
|
||||
if (isUserLoading || isLoggedIn || isRedirecting) {
|
||||
if (isUserLoading || isLoggedIn) {
|
||||
return <LoadingSignup />;
|
||||
}
|
||||
|
||||
@@ -189,7 +187,7 @@ export default function SignupPage() {
|
||||
{isCloudEnv ? (
|
||||
<GoogleOAuthButton
|
||||
onClick={() => handleProviderSignup("google")}
|
||||
isLoading={isGoogleLoading}
|
||||
isLoading={isLoading}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { useTurnstile } from "@/hooks/useTurnstile";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { environment } from "@/services/environment";
|
||||
import { LoginProvider, signupFormSchema } from "@/types/auth";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import z from "zod";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { environment } from "@/services/environment";
|
||||
|
||||
export function useSignupPage() {
|
||||
const { supabase, user, isUserLoading } = useSupabase();
|
||||
@@ -16,9 +16,8 @@ export function useSignupPage() {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isGoogleLoading, setIsGoogleLoading] = useState(false);
|
||||
const [showNotAllowedModal, setShowNotAllowedModal] = useState(false);
|
||||
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||
const [isCreatingAccount, setIsCreatingAccount] = useState(false);
|
||||
const isCloudEnv = environment.isCloud();
|
||||
const isVercelPreview = process.env.NEXT_PUBLIC_VERCEL_ENV === "preview";
|
||||
|
||||
@@ -44,19 +43,21 @@ export function useSignupPage() {
|
||||
});
|
||||
|
||||
async function handleProviderSignup(provider: LoginProvider) {
|
||||
setIsGoogleLoading(true);
|
||||
setIsLoading(true);
|
||||
|
||||
if (isCloudEnv && !turnstile.verified && !isVercelPreview) {
|
||||
toast({
|
||||
title: "Please complete the CAPTCHA challenge.",
|
||||
variant: "default",
|
||||
});
|
||||
setIsGoogleLoading(false);
|
||||
setIsLoading(false);
|
||||
resetCaptcha();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsCreatingAccount(true);
|
||||
|
||||
const response = await fetch("/api/auth/provider", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -65,29 +66,19 @@ export function useSignupPage() {
|
||||
|
||||
if (!response.ok) {
|
||||
const { error } = await response.json();
|
||||
setIsGoogleLoading(false);
|
||||
resetCaptcha();
|
||||
|
||||
if (error === "not_allowed") {
|
||||
setShowNotAllowedModal(true);
|
||||
return;
|
||||
}
|
||||
|
||||
toast({
|
||||
title: error || "Failed to start OAuth flow",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
throw new Error(error || "Failed to start OAuth flow");
|
||||
}
|
||||
|
||||
const { url } = await response.json();
|
||||
if (url) {
|
||||
setIsRedirecting(true);
|
||||
setFeedback(null);
|
||||
window.location.href = url as string;
|
||||
}
|
||||
if (url) window.location.href = url as string;
|
||||
} catch (error) {
|
||||
setIsGoogleLoading(false);
|
||||
setIsLoading(false);
|
||||
resetCaptcha();
|
||||
toast({
|
||||
title:
|
||||
@@ -158,15 +149,11 @@ export function useSignupPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
setFeedback(null);
|
||||
|
||||
const next = result?.next || "/";
|
||||
if (next) {
|
||||
setIsRedirecting(true);
|
||||
router.push(next);
|
||||
}
|
||||
if (next) router.replace(next);
|
||||
} catch (error) {
|
||||
setIsLoading(false);
|
||||
setIsCreatingAccount(false);
|
||||
toast({
|
||||
title:
|
||||
error instanceof Error
|
||||
@@ -186,10 +173,9 @@ export function useSignupPage() {
|
||||
captchaKey,
|
||||
isLoggedIn: !!user,
|
||||
isLoading,
|
||||
isRedirecting,
|
||||
isCreatingAccount,
|
||||
isCloudEnv,
|
||||
isUserLoading,
|
||||
isGoogleLoading,
|
||||
showNotAllowedModal,
|
||||
isSupabaseAvailable: !!supabase,
|
||||
handleSubmit: form.handleSubmit(handleSignup),
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
"use client";
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function Page() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { environment } from "@/services/environment";
|
||||
import { Key, storage } from "@/services/storage/local-storage";
|
||||
import { type CookieOptions } from "@supabase/ssr";
|
||||
import { SupabaseClient } from "@supabase/supabase-js";
|
||||
import { Key, storage } from "@/services/storage/local-storage";
|
||||
import { environment } from "@/services/environment";
|
||||
|
||||
export const PROTECTED_PAGES = [
|
||||
"/monitor",
|
||||
@@ -14,8 +14,6 @@ export const PROTECTED_PAGES = [
|
||||
|
||||
export const ADMIN_PAGES = ["/admin"] as const;
|
||||
|
||||
export const AUTHENTICATION_PAGES = ["/login", "/signup"] as const;
|
||||
|
||||
export function getCookieSettings(): Partial<CookieOptions> {
|
||||
return {
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
@@ -33,12 +31,6 @@ export function isAdminPage(pathname: string): boolean {
|
||||
return ADMIN_PAGES.some((page) => pathname.startsWith(page));
|
||||
}
|
||||
|
||||
export function isAuthenticationPage(pathname: string): boolean {
|
||||
return AUTHENTICATION_PAGES.some(
|
||||
(page) => pathname === page || pathname.startsWith(`${page}/`),
|
||||
);
|
||||
}
|
||||
|
||||
export function shouldRedirectOnLogout(pathname: string): boolean {
|
||||
return isProtectedPage(pathname) || isAdminPage(pathname);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { environment } from "@/services/environment";
|
||||
import { createServerClient } from "@supabase/ssr";
|
||||
import { NextResponse, type NextRequest } from "next/server";
|
||||
import {
|
||||
getCookieSettings,
|
||||
isAdminPage,
|
||||
isAuthenticationPage,
|
||||
isProtectedPage,
|
||||
} from "./helpers";
|
||||
import { environment } from "@/services/environment";
|
||||
import { getCookieSettings, isAdminPage, isProtectedPage } from "./helpers";
|
||||
|
||||
export async function updateSession(request: NextRequest) {
|
||||
let supabaseResponse = NextResponse.next({
|
||||
@@ -67,13 +62,7 @@ export async function updateSession(request: NextRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Check if user is authenticated but trying to access unauthenticated pages
|
||||
if (user && isAuthenticationPage(pathname)) {
|
||||
url.pathname = "/marketplace";
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
|
||||
// 3. Check if user is authenticated but lacks admin role when accessing admin pages
|
||||
// 2. Check if user is authenticated but lacks admin role when accessing admin pages
|
||||
if (user && userRole !== "admin" && isAdminPage(pathname)) {
|
||||
url.pathname = "/marketplace";
|
||||
return NextResponse.redirect(url);
|
||||
|
||||
Reference in New Issue
Block a user