From 0ad59edda0df0728697fd1145b9616bfb1dfc341 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Tue, 27 Jan 2026 09:38:52 +0200 Subject: [PATCH] feat: auto-trigger clone after login redirect --- surfsense_web/app/(home)/login/page.tsx | 7 ++++ .../public-chat/public-chat-footer.tsx | 41 ++++++++++++++----- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/surfsense_web/app/(home)/login/page.tsx b/surfsense_web/app/(home)/login/page.tsx index 7aade8427..a2dadd70c 100644 --- a/surfsense_web/app/(home)/login/page.tsx +++ b/surfsense_web/app/(home)/login/page.tsx @@ -27,6 +27,13 @@ function LoginContent() { const error = searchParams.get("error"); const message = searchParams.get("message"); const logout = searchParams.get("logout"); + const returnUrl = searchParams.get("returnUrl"); + + // Save returnUrl to localStorage so it persists through OAuth flows (e.g., Google) + // This is read by TokenHandler after successful authentication + if (returnUrl) { + localStorage.setItem("surfsense_redirect_path", decodeURIComponent(returnUrl)); + } // Show registration success message if (registered === "true") { diff --git a/surfsense_web/components/public-chat/public-chat-footer.tsx b/surfsense_web/components/public-chat/public-chat-footer.tsx index 06e3d9975..80779b4e6 100644 --- a/surfsense_web/components/public-chat/public-chat-footer.tsx +++ b/surfsense_web/components/public-chat/public-chat-footer.tsx @@ -1,8 +1,8 @@ "use client"; import { Copy, Loader2 } from "lucide-react"; -import { useRouter } from "next/navigation"; -import { useState } from "react"; +import { useRouter, useSearchParams } from "next/navigation"; +import { useCallback, useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { publicChatApiService } from "@/lib/apis/public-chat-api.service"; @@ -14,17 +14,11 @@ interface PublicChatFooterProps { export function PublicChatFooter({ shareToken }: PublicChatFooterProps) { const router = useRouter(); + const searchParams = useSearchParams(); const [isCloning, setIsCloning] = useState(false); + const hasAutoCloned = useRef(false); - const handleCopyAndContinue = async () => { - const token = getBearerToken(); - - if (!token) { - const returnUrl = encodeURIComponent(`/public/${shareToken}`); - router.push(`/login?returnUrl=${returnUrl}&action=clone`); - return; - } - + const triggerClone = useCallback(async () => { setIsCloning(true); try { @@ -43,6 +37,31 @@ export function PublicChatFooter({ shareToken }: PublicChatFooterProps) { } finally { setIsCloning(false); } + }, [shareToken, router]); + + // Auto-trigger clone if user just logged in with action=clone + useEffect(() => { + const action = searchParams.get("action"); + const token = getBearerToken(); + + // Only auto-clone once, if authenticated and action=clone is present + if (action === "clone" && token && !hasAutoCloned.current && !isCloning) { + hasAutoCloned.current = true; + triggerClone(); + } + }, [searchParams, isCloning, triggerClone]); + + const handleCopyAndContinue = async () => { + const token = getBearerToken(); + + if (!token) { + // Include action=clone in the returnUrl so it persists after login + const returnUrl = encodeURIComponent(`/public/${shareToken}?action=clone`); + router.push(`/login?returnUrl=${returnUrl}`); + return; + } + + await triggerClone(); }; return (