import { useState, type FormEvent } from "react" import { createFileRoute } from "@tanstack/react-router" import { authClient } from "@/lib/auth-client" import { useAccount } from "jazz-tools/react" import { ViewerAccount, BrowserSession, BrowserSessionList, type BrowserTab, } from "@/lib/jazz/schema" import { Layers, Plus, Trash2, ExternalLink, ChevronDown, ChevronRight, Upload, Clock, Tag, Search, } from "lucide-react" import { JazzProvider } from "@/lib/jazz/provider" export const Route = createFileRoute("/sessions")({ component: SessionsPageWrapper, ssr: false, }) function SessionsPageWrapper() { return ( ) } function SessionsPage() { const { data: session, isPending: authPending } = authClient.useSession() const me = useAccount(ViewerAccount) const [isAdding, setIsAdding] = useState(false) const [isImporting, setIsImporting] = useState(false) const [expandedSessions, setExpandedSessions] = useState>(new Set()) const [searchQuery, setSearchQuery] = useState("") // New session form state const [newName, setNewName] = useState("") const [newDescription, setNewDescription] = useState("") const [newBrowser, setNewBrowser] = useState<"safari" | "chrome" | "firefox" | "arc" | "other">("safari") const [newTags, setNewTags] = useState("") const [newTabs, setNewTabs] = useState([]) const [tabUrl, setTabUrl] = useState("") const [tabTitle, setTabTitle] = useState("") // Import state const [importJson, setImportJson] = useState("") if (authPending) { return
} if (!session?.user) { return (

Please sign in to save browser sessions

Sign in
) } const root = me.$isLoaded ? me.root : null if (!me.$isLoaded || !root?.$isLoaded) { return
} // Initialize browserSessions if not present if (!root.browserSessions) { root.$jazz.set("browserSessions", BrowserSessionList.create([])) } const sessionsList = root.browserSessions?.$isLoaded ? root.browserSessions : null const allSessions = sessionsList?.$isLoaded ? [...sessionsList] : [] // Filter sessions by search query const sessions = searchQuery ? allSessions.filter((s) => { const q = searchQuery.toLowerCase() return ( s.name?.toLowerCase().includes(q) || s.description?.toLowerCase().includes(q) || s.tags?.some((t) => t.toLowerCase().includes(q)) || s.tabs?.some( (tab) => tab.title?.toLowerCase().includes(q) || tab.url?.toLowerCase().includes(q) ) ) }) : allSessions const toggleExpanded = (index: number) => { const newExpanded = new Set(expandedSessions) if (newExpanded.has(index)) { newExpanded.delete(index) } else { newExpanded.add(index) } setExpandedSessions(newExpanded) } const handleAddTab = () => { if (!tabUrl.trim()) return setNewTabs([ ...newTabs, { url: tabUrl.trim(), title: tabTitle.trim() || tabUrl.trim(), favicon: null }, ]) setTabUrl("") setTabTitle("") } const handleRemoveTab = (index: number) => { setNewTabs(newTabs.filter((_, i) => i !== index)) } const handleSaveSession = (e: FormEvent) => { e.preventDefault() if (!newName.trim() || newTabs.length === 0 || !root?.browserSessions?.$isLoaded) return const newSession = BrowserSession.create({ name: newName.trim(), description: newDescription.trim() || null, tabs: newTabs, browserType: newBrowser, createdAt: Date.now(), tags: newTags .split(",") .map((t) => t.trim()) .filter(Boolean), }) root.browserSessions.$jazz.push(newSession) // Reset form setNewName("") setNewDescription("") setNewBrowser("safari") setNewTags("") setNewTabs([]) setIsAdding(false) } const handleImport = (e: FormEvent) => { e.preventDefault() if (!importJson.trim() || !root?.browserSessions?.$isLoaded) return try { const data = JSON.parse(importJson) let tabs: BrowserTab[] = [] // Support both array format and object with tabs property if (Array.isArray(data)) { tabs = data.map((item: { title?: string; url: string }) => ({ title: item.title || item.url, url: item.url, favicon: null, })) } else if (data.tabs && Array.isArray(data.tabs)) { tabs = data.tabs.map((item: { title?: string; url: string }) => ({ title: item.title || item.url, url: item.url, favicon: null, })) } if (tabs.length === 0) { alert("No valid tabs found in JSON") return } const sessionName = data.name || `Imported ${new Date().toLocaleDateString()}` const newSession = BrowserSession.create({ name: sessionName, description: data.description || null, tabs, browserType: data.browserType || "other", createdAt: Date.now(), tags: data.tags || [], }) root.browserSessions.$jazz.push(newSession) setImportJson("") setIsImporting(false) } catch { alert("Invalid JSON format") } } const handleDeleteSession = (index: number) => { if (!root?.browserSessions?.$isLoaded) return root.browserSessions.$jazz.splice(index, 1) } const formatDate = (timestamp: number) => { return new Date(timestamp).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }) } return (

Browser Sessions

({allSessions.length})
{/* Search */}
setSearchQuery(e.target.value)} placeholder="Search sessions, tabs, or tags..." className="w-full pl-10 pr-4 py-2.5 bg-white/5 border border-white/10 rounded-xl text-white placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-teal-500" />
{/* Import Modal */} {isImporting && (

Import Session from JSON

Paste JSON with format: {`[{title, url}, ...]`} or {`{name, tabs: [{title, url}, ...]}`}