"use client" import { useState, useCallback, useEffect } from "react" import { Header } from "@/components/new/header" import { ChatSidebar } from "@/components/new/chat" import { MemoriesGrid } from "@/components/new/memories-grid" import { AnimatedGradientBackground } from "@/components/new/animated-gradient-background" import { AddDocumentModal } from "@/components/new/add-document" import { MCPModal } from "@/components/new/mcp-modal" import { DocumentModal } from "@/components/new/document-modal" import { DocumentsCommandPalette } from "@/components/new/documents-command-palette" import { FullscreenNoteModal } from "@/components/new/fullscreen-note-modal" import type { HighlightItem } from "@/components/new/highlights-card" import { HotkeysProvider } from "react-hotkeys-hook" import { useHotkeys } from "react-hotkeys-hook" import { AnimatePresence } from "motion/react" import { useIsMobile } from "@hooks/use-mobile" import { useProject } from "@/stores" import { useQuickNoteDraftReset, useQuickNoteDraft, } from "@/stores/quick-note-draft" import { analytics } from "@/lib/analytics" import { useDocumentMutations } from "@/hooks/use-document-mutations" import { useQuery } from "@tanstack/react-query" import type { DocumentsWithMemoriesResponseSchema } from "@repo/validation/api" import type { z } from "zod" type DocumentsResponse = z.infer type DocumentWithMemories = DocumentsResponse["documents"][0] export default function NewPage() { const isMobile = useIsMobile() const { selectedProject } = useProject() const [isAddDocumentOpen, setIsAddDocumentOpen] = useState(false) const [isMCPModalOpen, setIsMCPModalOpen] = useState(false) const [isSearchOpen, setIsSearchOpen] = useState(false) const [selectedDocument, setSelectedDocument] = useState(null) const [isDocumentModalOpen, setIsDocumentModalOpen] = useState(false) const [isFullScreenNoteOpen, setIsFullScreenNoteOpen] = useState(false) const [fullscreenInitialContent, setFullscreenInitialContent] = useState("") const [queuedChatSeed, setQueuedChatSeed] = useState(null) const [searchPrefill, setSearchPrefill] = useState("") const resetDraft = useQuickNoteDraftReset(selectedProject) const { draft: quickNoteDraft } = useQuickNoteDraft(selectedProject || "") const { noteMutation } = useDocumentMutations({ onClose: () => { resetDraft() setIsFullScreenNoteOpen(false) }, }) // Fetch space highlights (highlights + suggested questions) type SpaceHighlightsResponse = { highlights: HighlightItem[] questions: string[] generatedAt: string } const { data: highlightsData, isLoading: isLoadingHighlights } = useQuery({ queryKey: ["space-highlights", selectedProject], queryFn: async (): Promise => { const response = await fetch( `${process.env.NEXT_PUBLIC_BACKEND_URL}/v3/space-highlights`, { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ spaceId: selectedProject || "sm_project_default", highlightsCount: 3, questionsCount: 4, includeHighlights: true, includeQuestions: true, }), }, ) if (!response.ok) { throw new Error("Failed to fetch space highlights") } return response.json() }, staleTime: 4 * 60 * 60 * 1000, // 4 hours (matches backend cache) refetchOnWindowFocus: false, }) useHotkeys("c", () => { analytics.addDocumentModalOpened() setIsAddDocumentOpen(true) }) useHotkeys("mod+k", (e) => { e.preventDefault() analytics.searchOpened({ source: "hotkey" }) setIsSearchOpen(true) }) const [isChatOpen, setIsChatOpen] = useState(!isMobile) useEffect(() => { setIsChatOpen(!isMobile) }, [isMobile]) const handleOpenDocument = useCallback((document: DocumentWithMemories) => { if (document.id) { analytics.documentModalOpened({ document_id: document.id }) } setSelectedDocument(document) setIsDocumentModalOpen(true) }, []) const handleQuickNoteSave = useCallback( (content: string) => { if (content.trim()) { const hadPreviousContent = quickNoteDraft.trim().length > 0 noteMutation.mutate( { content, project: selectedProject }, { onSuccess: () => { if (hadPreviousContent) { analytics.quickNoteEdited() } else { analytics.quickNoteCreated() } }, }, ) } }, [selectedProject, noteMutation, quickNoteDraft], ) const handleFullScreenSave = useCallback( (content: string) => { if (content.trim()) { const hadInitialContent = fullscreenInitialContent.trim().length > 0 noteMutation.mutate( { content, project: selectedProject }, { onSuccess: () => { if (hadInitialContent) { analytics.quickNoteEdited() } else { analytics.quickNoteCreated() } }, }, ) } }, [selectedProject, noteMutation, fullscreenInitialContent], ) const handleMaximize = useCallback((content: string) => { analytics.fullscreenNoteModalOpened() setFullscreenInitialContent(content) setIsFullScreenNoteOpen(true) }, []) const handleHighlightsChat = useCallback((seed: string) => { setQueuedChatSeed(seed) setIsChatOpen(true) }, []) const handleHighlightsShowRelated = useCallback((query: string) => { analytics.searchOpened({ source: "highlight_related" }) setSearchPrefill(query) setIsSearchOpen(true) }, []) return (
{ analytics.addDocumentModalOpened() setIsAddDocumentOpen(true) }} onOpenMCP={() => { analytics.mcpModalOpened() setIsMCPModalOpen(true) }} onOpenChat={() => setIsChatOpen(true)} onOpenSearch={() => { analytics.searchOpened({ source: "header" }) setIsSearchOpen(true) }} />
setQueuedChatSeed(null)} emptyStateSuggestions={highlightsData?.questions} />
{isMobile && ( setQueuedChatSeed(null)} emptyStateSuggestions={highlightsData?.questions} /> )} setIsAddDocumentOpen(false)} /> setIsMCPModalOpen(false)} /> { setIsSearchOpen(open) if (!open) setSearchPrefill("") }} projectId={selectedProject} onOpenDocument={handleOpenDocument} initialSearch={searchPrefill} /> setIsDocumentModalOpen(false)} /> setIsFullScreenNoteOpen(false)} initialContent={fullscreenInitialContent} onSave={handleFullScreenSave} isSaving={noteMutation.isPending} />
) }