From 420ce3e153126ee5e3aa2dce44dcec976edbf93c Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:26:32 +0530 Subject: [PATCH] feat(chats): implement ChatsPage component and update layout for all chats functionality --- .../dashboard/[workspace_id]/chats/page.tsx | 11 +++ .../layout/providers/LayoutDataProvider.tsx | 34 ++++++---- .../layout/ui/shell/LayoutShell.tsx | 48 ++----------- .../layout/ui/sidebar/AllChatsSidebar.tsx | 67 +++---------------- .../layout/ui/sidebar/MobileSidebar.tsx | 6 +- .../components/layout/ui/sidebar/Sidebar.tsx | 8 +-- .../components/layout/ui/sidebar/index.ts | 2 +- 7 files changed, 57 insertions(+), 119 deletions(-) create mode 100644 surfsense_web/app/dashboard/[workspace_id]/chats/page.tsx diff --git a/surfsense_web/app/dashboard/[workspace_id]/chats/page.tsx b/surfsense_web/app/dashboard/[workspace_id]/chats/page.tsx new file mode 100644 index 000000000..8186018ea --- /dev/null +++ b/surfsense_web/app/dashboard/[workspace_id]/chats/page.tsx @@ -0,0 +1,11 @@ +import { AllChatsWorkspaceContent } from "@/components/layout/ui/sidebar"; + +export default async function ChatsPage({ params }: { params: Promise<{ workspace_id: string }> }) { + const { workspace_id } = await params; + + return ( +
+ +
+ ); +} diff --git a/surfsense_web/components/layout/providers/LayoutDataProvider.tsx b/surfsense_web/components/layout/providers/LayoutDataProvider.tsx index 6775e9af0..f41e318d4 100644 --- a/surfsense_web/components/layout/providers/LayoutDataProvider.tsx +++ b/surfsense_web/components/layout/providers/LayoutDataProvider.tsx @@ -126,7 +126,7 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid }); // Unified slide-out panel state (only one can be open at a time) - type SlideoutPanel = "inbox" | "chats" | null; + type SlideoutPanel = "inbox" | null; const [activeSlideoutPanel, setActiveSlideoutPanel] = useState(null); const isInboxSidebarOpen = activeSlideoutPanel === "inbox"; @@ -631,10 +631,6 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid } }, [router]); - const handleViewAllChats = useCallback(() => { - setActiveSlideoutPanel((prev) => (prev === "chats" ? null : "chats")); - }, []); - // Delete handlers const confirmDeleteChat = useCallback(async () => { if (!chatToDelete) return; @@ -713,6 +709,13 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid const isSearchSpaceSettingsPage = pathname?.includes("/search-space-settings") === true; const isTeamPage = pathname?.endsWith("/team") === true; const isAutomationsPage = pathname?.includes("/automations") === true; + const isAllChatsPage = pathname?.endsWith("/chats") === true; + const handleViewAllChats = useCallback(() => { + setActiveSlideoutPanel(null); + router.push( + isAllChatsPage ? `/dashboard/${searchSpaceId}/new-chat` : `/dashboard/${searchSpaceId}/chats` + ); + }, [isAllChatsPage, router, searchSpaceId]); const useWorkspacePanel = pathname?.endsWith("/buy-more") === true || pathname?.endsWith("/earn-credits") === true || @@ -720,7 +723,8 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid isUserSettingsPage || isSearchSpaceSettingsPage || isTeamPage || - isAutomationsPage; + isAutomationsPage || + isAllChatsPage; return ( <> @@ -757,18 +761,25 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid theme={theme} setTheme={setTheme} isChatPage={isChatPage} + isAllChatsPage={isAllChatsPage} useWorkspacePanel={useWorkspacePanel} workspacePanelViewportClassName={ - isUserSettingsPage || isSearchSpaceSettingsPage || isTeamPage || isAutomationsPage + isUserSettingsPage || + isSearchSpaceSettingsPage || + isTeamPage || + isAutomationsPage || + isAllChatsPage ? "items-start justify-center px-6 py-8 md:px-10 md:py-10" : undefined } workspacePanelContentClassName={ isAutomationsPage ? "max-w-none select-none" - : isUserSettingsPage || isSearchSpaceSettingsPage || isTeamPage - ? "max-w-5xl" - : undefined + : isAllChatsPage + ? "max-w-3xl" + : isUserSettingsPage || isSearchSpaceSettingsPage || isTeamPage + ? "max-w-5xl" + : undefined } isLoadingChats={isLoadingThreads} activeSlideoutPanel={activeSlideoutPanel} @@ -797,9 +808,6 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid markAllAsRead: statusInbox.markAllAsRead, }, }} - allChatsPanel={{ - searchSpaceId, - }} documentsPanel={{ open: isDocumentsSidebarOpen, onOpenChange: setIsDocumentsSidebarOpen, diff --git a/surfsense_web/components/layout/ui/shell/LayoutShell.tsx b/surfsense_web/components/layout/ui/shell/LayoutShell.tsx index 1c076a254..c437a3e3b 100644 --- a/surfsense_web/components/layout/ui/shell/LayoutShell.tsx +++ b/surfsense_web/components/layout/ui/shell/LayoutShell.tsx @@ -27,7 +27,6 @@ import { RightPanelToggleButton, } from "../right-panel/RightPanel"; import { - AllChatsSidebarContent, DocumentsSidebar, InboxSidebarContent, MobileSidebar, @@ -93,7 +92,7 @@ interface TabDataSource { markAllAsRead: () => Promise; } -export type ActiveSlideoutPanel = "inbox" | "chats" | null; +export type ActiveSlideoutPanel = "inbox" | null; // Inbox-related props — per-tab data sources with independent loading/pagination interface InboxProps { @@ -134,6 +133,7 @@ interface LayoutShellProps { setTheme?: (theme: "light" | "dark" | "system") => void; defaultCollapsed?: boolean; isChatPage?: boolean; + isAllChatsPage?: boolean; useWorkspacePanel?: boolean; workspacePanelViewportClassName?: string; workspacePanelContentClassName?: string; @@ -145,10 +145,6 @@ interface LayoutShellProps { // Inbox props inbox?: InboxProps; isLoadingChats?: boolean; - // All chats panel props - allChatsPanel?: { - searchSpaceId: string; - }; documentsPanel?: { open: boolean; onOpenChange: (open: boolean) => void; @@ -245,6 +241,7 @@ export function LayoutShell({ setTheme, defaultCollapsed = false, isChatPage = false, + isAllChatsPage = false, useWorkspacePanel = false, workspacePanelViewportClassName, workspacePanelContentClassName, @@ -254,7 +251,6 @@ export function LayoutShell({ onSlideoutPanelChange, inbox, isLoadingChats = false, - allChatsPanel, documentsPanel, onTabSwitch, onTabPrefetch, @@ -285,8 +281,7 @@ export function LayoutShell({ const anySlideOutOpen = activeSlideoutPanel !== null; - const panelAriaLabel = - activeSlideoutPanel === "inbox" ? "Inbox" : activeSlideoutPanel === "chats" ? "Chats" : "Panel"; + const panelAriaLabel = activeSlideoutPanel === "inbox" ? "Inbox" : "Panel"; // Mobile layout if (isMobile) { @@ -317,7 +312,7 @@ export function LayoutShell({ onChatDelete={onChatDelete} onChatArchive={onChatArchive} onViewAllChats={onViewAllChats} - isChatsPanelOpen={activeSlideoutPanel === "chats"} + isAllChatsActive={isAllChatsPage} user={user} onSettings={onSettings} onManageMembers={onManageMembers} @@ -369,22 +364,6 @@ export function LayoutShell({ /> )} - {activeSlideoutPanel === "chats" && allChatsPanel && ( - - closeSlideout(open)} - searchSpaceId={allChatsPanel.searchSpaceId} - onCloseMobileSidebar={() => setMobileMenuOpen(false)} - /> - - )} @@ -460,7 +439,7 @@ export function LayoutShell({ onChatDelete={onChatDelete} onChatArchive={onChatArchive} onViewAllChats={onViewAllChats} - isChatsPanelOpen={activeSlideoutPanel === "chats"} + isAllChatsActive={isAllChatsPage} user={user} onSettings={onSettings} onManageMembers={onManageMembers} @@ -526,21 +505,6 @@ export function LayoutShell({ /> )} - {activeSlideoutPanel === "chats" && allChatsPanel && ( - - closeSlideout(open)} - searchSpaceId={allChatsPanel.searchSpaceId} - /> - - )} diff --git a/surfsense_web/components/layout/ui/sidebar/AllChatsSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/AllChatsSidebar.tsx index 3b6970513..0a15ecde5 100644 --- a/surfsense_web/components/layout/ui/sidebar/AllChatsSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/AllChatsSidebar.tsx @@ -4,7 +4,6 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useSetAtom } from "jotai"; import { ArchiveIcon, - ChevronLeft, MessageCircleMore, MoreHorizontal, Pencil, @@ -48,23 +47,13 @@ import { useArchiveThread, useDeleteThread, useRenameThread } from "@/hooks/use- import { fetchThreads, searchThreads, type ThreadListItem } from "@/lib/chat/thread-persistence"; import { formatThreadTimestamp } from "@/lib/format-date"; import { cn } from "@/lib/utils"; -import { SidebarSlideOutPanel } from "./SidebarSlideOutPanel"; -export interface AllChatsSidebarContentProps { - onOpenChange: (open: boolean) => void; +interface AllChatsContentProps { searchSpaceId: string; - onCloseMobileSidebar?: () => void; + className?: string; } -interface AllChatsSidebarProps extends AllChatsSidebarContentProps { - open: boolean; -} - -export function AllChatsSidebarContent({ - onOpenChange, - searchSpaceId, - onCloseMobileSidebar, -}: AllChatsSidebarContentProps) { +function AllChatsContent({ searchSpaceId, className }: AllChatsContentProps) { const t = useTranslations("sidebar"); const router = useRouter(); const params = useParams(); @@ -150,10 +139,8 @@ export function AllChatsSidebarContent({ searchSpaceId, visibility: thread.visibility, }); - onOpenChange(false); - onCloseMobileSidebar?.(); }, - [activateChatThread, onOpenChange, searchSpaceId, onCloseMobileSidebar] + [activateChatThread, searchSpaceId] ); const handleDeleteThread = useCallback( @@ -165,7 +152,6 @@ export function AllChatsSidebarContent({ toast.success(t("chat_deleted") || "Chat deleted successfully"); if (currentChatId === threadId) { - onOpenChange(false); setTimeout(() => { if ( fallbackTab?.type === "chat" && @@ -196,16 +182,7 @@ export function AllChatsSidebarContent({ setDeletingThreadId(null); } }, - [ - activateChatThread, - deleteThread, - t, - currentChatId, - router, - onOpenChange, - removeChatTab, - searchSpaceId, - ] + [activateChatThread, deleteThread, t, currentChatId, router, removeChatTab, searchSpaceId] ); const handleToggleArchive = useCallback( @@ -266,20 +243,9 @@ export function AllChatsSidebarContent({ const archivedCount = archivedChats.length; return ( - <> +
- {isMobile && ( - - )}

{t("chats") || "Chats"}

@@ -584,25 +550,14 @@ export function AllChatsSidebarContent({ - +
); } -export function AllChatsSidebar({ - open, - onOpenChange, - searchSpaceId, - onCloseMobileSidebar, -}: AllChatsSidebarProps) { - const t = useTranslations("sidebar"); - +export function AllChatsWorkspaceContent({ searchSpaceId }: { searchSpaceId: string }) { return ( - - - +
+ +
); } diff --git a/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx index cb192ba37..40a563ab2 100644 --- a/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx @@ -27,7 +27,7 @@ interface MobileSidebarProps { onChatDelete?: (chat: ChatItem) => void; onChatArchive?: (chat: ChatItem) => void; onViewAllChats?: () => void; - isChatsPanelOpen?: boolean; + isAllChatsActive?: boolean; user: User; onSettings?: () => void; onManageMembers?: () => void; @@ -75,7 +75,7 @@ export function MobileSidebar({ onChatDelete, onChatArchive, onViewAllChats, - isChatsPanelOpen = false, + isAllChatsActive = false, user, onSettings, onManageMembers, @@ -166,7 +166,7 @@ export function MobileSidebar({ } : undefined } - isChatsPanelOpen={isChatsPanelOpen} + isAllChatsActive={isAllChatsActive} user={user} onSettings={ onSettings diff --git a/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx b/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx index 6044508b0..6f17a95ce 100644 --- a/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx @@ -75,7 +75,7 @@ interface SidebarProps { onChatDelete?: (chat: ChatItem) => void; onChatArchive?: (chat: ChatItem) => void; onViewAllChats?: () => void; - isChatsPanelOpen?: boolean; + isAllChatsActive?: boolean; user: User; onSettings?: () => void; onManageMembers?: () => void; @@ -112,7 +112,7 @@ export function Sidebar({ onChatDelete, onChatArchive, onViewAllChats, - isChatsPanelOpen = false, + isAllChatsActive = false, user, onSettings, onManageMembers, @@ -281,7 +281,7 @@ export function Sidebar({ title={t("recents")} defaultOpen={true} fillHeight={true} - alwaysShowAction={!disableTooltips && isChatsPanelOpen} + alwaysShowAction={!disableTooltips && isAllChatsActive} action={ onViewAllChats ? ( ) : undefined } diff --git a/surfsense_web/components/layout/ui/sidebar/index.ts b/surfsense_web/components/layout/ui/sidebar/index.ts index fcfe2252d..8a61633b8 100644 --- a/surfsense_web/components/layout/ui/sidebar/index.ts +++ b/surfsense_web/components/layout/ui/sidebar/index.ts @@ -1,4 +1,4 @@ -export { AllChatsSidebar, AllChatsSidebarContent } from "./AllChatsSidebar"; +export { AllChatsWorkspaceContent } from "./AllChatsSidebar"; export { ChatListItem } from "./ChatListItem"; export { CreditBalanceDisplay } from "./CreditBalanceDisplay"; export { DocumentsSidebar } from "./DocumentsSidebar";