diff --git a/surfsense_web/components/editor-panel/editor-panel.tsx b/surfsense_web/components/editor-panel/editor-panel.tsx index 308ad158b..eb55b583e 100644 --- a/surfsense_web/components/editor-panel/editor-panel.tsx +++ b/surfsense_web/components/editor-panel/editor-panel.tsx @@ -1,17 +1,23 @@ "use client"; +import dynamic from "next/dynamic"; import { useAtomValue, useSetAtom } from "jotai"; import { AlertCircle, XIcon } from "lucide-react"; import { useCallback, useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { closeEditorPanelAtom, editorPanelAtom } from "@/atoms/editor/editor-panel.atom"; -import { PlateEditor } from "@/components/editor/plate-editor"; import { MarkdownViewer } from "@/components/markdown-viewer"; import { Button } from "@/components/ui/button"; import { Drawer, DrawerContent, DrawerHandle, DrawerTitle } from "@/components/ui/drawer"; +import { Skeleton } from "@/components/ui/skeleton"; import { useMediaQuery } from "@/hooks/use-media-query"; import { authenticatedFetch, getBearerToken, redirectToLogin } from "@/lib/auth-utils"; +const PlateEditor = dynamic( + () => import("@/components/editor/plate-editor").then((m) => ({ default: m.PlateEditor })), + { ssr: false, loading: () => } +); + interface EditorContent { document_id: number; title: string; diff --git a/surfsense_web/components/hitl-edit-panel/hitl-edit-panel.tsx b/surfsense_web/components/hitl-edit-panel/hitl-edit-panel.tsx index a75752217..99f17f976 100644 --- a/surfsense_web/components/hitl-edit-panel/hitl-edit-panel.tsx +++ b/surfsense_web/components/hitl-edit-panel/hitl-edit-panel.tsx @@ -1,5 +1,6 @@ "use client"; +import dynamic from "next/dynamic"; import { format } from "date-fns"; import { TagInput, type Tag as TagType } from "emblor"; import { useAtomValue, useSetAtom } from "jotai"; @@ -7,16 +8,21 @@ import { CalendarIcon, XIcon } from "lucide-react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import type { ExtraField } from "@/atoms/chat/hitl-edit-panel.atom"; import { closeHitlEditPanelAtom, hitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom"; -import { PlateEditor } from "@/components/editor/plate-editor"; import { Button } from "@/components/ui/button"; import { Calendar } from "@/components/ui/calendar"; import { Drawer, DrawerContent, DrawerHandle, DrawerTitle } from "@/components/ui/drawer"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; +import { Skeleton } from "@/components/ui/skeleton"; import { Textarea } from "@/components/ui/textarea"; import { useMediaQuery } from "@/hooks/use-media-query"; +const PlateEditor = dynamic( + () => import("@/components/editor/plate-editor").then((m) => ({ default: m.PlateEditor })), + { ssr: false, loading: () => } +); + function parseEmailsToTags(value: string): TagType[] { if (!value.trim()) return []; return value diff --git a/surfsense_web/components/layout/providers/LayoutDataProvider.tsx b/surfsense_web/components/layout/providers/LayoutDataProvider.tsx index abc73425e..d03a8b5d7 100644 --- a/surfsense_web/components/layout/providers/LayoutDataProvider.tsx +++ b/surfsense_web/components/layout/providers/LayoutDataProvider.tsx @@ -110,9 +110,6 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid const resetTabs = useSetAtom(resetTabsAtom); const removeChatTab = useSetAtom(removeChatTabAtom); - // State for handling new chat navigation when router is out of sync - const [pendingNewChat, setPendingNewChat] = useState(false); - // Key used to force-remount the page component (e.g. after deleting the active chat // when the router is out of sync due to replaceState) const [chatResetKey, setChatResetKey] = useState(0); @@ -262,17 +259,6 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid const [isDeletingSearchSpace, setIsDeletingSearchSpace] = useState(false); const [isLeavingSearchSpace, setIsLeavingSearchSpace] = useState(false); - // Effect to complete new chat navigation after router syncs - // This runs when handleNewChat detected an out-of-sync state and triggered a sync - useEffect(() => { - if (pendingNewChat && params?.chat_id) { - // Router is now synced (chat_id is in params), complete navigation to new-chat - resetCurrentThread(); - router.push(`/dashboard/${searchSpaceId}/new-chat`); - setPendingNewChat(false); - } - }, [pendingNewChat, params?.chat_id, router, searchSpaceId, resetCurrentThread]); - // Reset transient slide-out panels and tabs when switching search spaces. // Use a ref to skip the initial mount — only reset when the space actually changes. const prevSearchSpaceIdRef = useRef(searchSpaceId); @@ -555,14 +541,17 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid if (isOutOfSync) { // First sync Next.js router by navigating to the current chat's actual URL // This updates the router's internal state to match the browser URL + resetCurrentThread(); router.replace(`/dashboard/${searchSpaceId}/new-chat/${currentThreadState.id}`); - // Set flag to trigger navigation to new-chat after params update - setPendingNewChat(true); + // Allow router to sync, then navigate to fresh new-chat + setTimeout(() => { + router.push(`/dashboard/${searchSpaceId}/new-chat`); + }, 0); } else { // Normal navigation - router is in sync router.push(`/dashboard/${searchSpaceId}/new-chat`); } - }, [router, searchSpaceId, currentThreadState.id, params?.chat_id]); + }, [router, searchSpaceId, currentThreadState.id, params?.chat_id, resetCurrentThread]); const handleChatSelect = useCallback( (chat: ChatItem) => { @@ -848,7 +837,7 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid