diff --git a/scripts/fix-sidebar.js b/scripts/fix-sidebar.js
new file mode 100644
index 0000000..0445c46
--- /dev/null
+++ b/scripts/fix-sidebar.js
@@ -0,0 +1,258 @@
+const fs = require('fs')
+const path = require('path')
+
+// Find the actual project root by looking for package.json
+const candidates = [
+ '/vercel/share/v0-project',
+ process.cwd(),
+]
+
+let root = null
+for (const c of candidates) {
+ if (fs.existsSync(path.join(c, 'package.json'))) {
+ root = c
+ break
+ }
+}
+
+if (!root) {
+ // Walk up from cwd
+ let dir = process.cwd()
+ while (dir !== '/') {
+ if (fs.existsSync(path.join(dir, 'package.json'))) { root = dir; break }
+ dir = path.dirname(dir)
+ }
+}
+
+console.log('Project root:', root)
+const target = path.join(root, 'components', 'app-sidebar.tsx')
+console.log('Target file:', target)
+console.log('Exists:', fs.existsSync(target))
+
+if (!fs.existsSync(target)) {
+ // Try to find it
+ function findFile(dir, name) {
+ try {
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
+ for (const e of entries) {
+ if (e.name === 'node_modules' || e.name === '.git') continue
+ const full = path.join(dir, e.name)
+ if (e.isDirectory()) {
+ const found = findFile(full, name)
+ if (found) return found
+ } else if (e.name === name) return full
+ }
+ } catch {}
+ return null
+ }
+ const found = findFile(root || '/', 'app-sidebar.tsx')
+ console.log('Found at:', found)
+ process.exit(1)
+}
+
+let src = fs.readFileSync(target, 'utf8')
+
+// Fix 1: add useEffect to import
+src = src.replace(
+ `import { useState } from 'react'`,
+ `import { useState, useEffect } from 'react'`
+)
+
+// Fix 2: add useEffect after useState call
+src = src.replace(
+ `const [drawerOpen, setDrawerOpen] = useState(false)`,
+ `const [drawerOpen, setDrawerOpen] = useState(false)
+
+ // Auto-close drawer on route change — no onClick needed on nav links
+ useEffect(() => { setDrawerOpen(false) }, [pathname])`
+)
+
+// Fix 3: remove onClick from NavLink interface
+src = src.replace(` onClick?: () => void\n`, '')
+
+// Fix 4: remove onClick from NavLink function params
+src = src.replace(
+ `function NavLink({ href, label, icon: Icon, badge, active, onClick }: NavLinkProps) {`,
+ `function NavLink({ href, label, icon: Icon, badge, active }: NavLinkProps) {`
+)
+
+// Fix 5: remove onClick={onClick} from
+src = src.replace(` onClick={onClick}\n`, '')
+
+// Fix 6: remove onClick from all NavLink usages
+src = src.replace(/ onClick=\{onNav\}/g, '')
+
+fs.writeFileSync(target, src, 'utf8')
+console.log('Done! Wrote', src.length, 'bytes to', target)
+
+
+import Link from 'next/link'
+import { usePathname } from 'next/navigation'
+import { useState, useEffect } from 'react'
+import { cn } from '@/lib/utils'
+import { signOut } from '@/lib/auth-actions'
+import type { SpaceMember, Space } from '@/lib/types'
+import {
+ Menu, X, LayoutDashboard, ListChecks, FolderKanban, Settings2,
+ MessageSquare, Users, CreditCard, BookUser, Download, LogOut,
+} from 'lucide-react'
+
+function NavLink({
+ href, label, icon: Icon, badge, active,
+}: {
+ href: string
+ label: string
+ icon: React.ElementType
+ badge?: number
+ active: boolean
+}) {
+ return (
+
+
+
+ {label}
+
+ {badge && badge > 0 ? (
+
+ {badge}
+
+ ) : null}
+
+ )
+}
+
+interface AppSidebarProps {
+ member: SpaceMember & { spaces: Space }
+ taskBadge?: number
+ commsBadge?: number
+ paymentBadge?: number
+}
+
+export function AppSidebar({ member, taskBadge = 0, commsBadge = 0, paymentBadge = 0 }: AppSidebarProps) {
+ const pathname = usePathname()
+ const space = member.spaces
+ const initials = member.display_name?.split(' ').map((n) => n[0]).join('').toUpperCase().slice(0, 2) || '??'
+ const isAdmin = member.role === 'admin' || member.role === 'board'
+ const [drawerOpen, setDrawerOpen] = useState(false)
+
+ // Auto-close the drawer whenever the route changes
+ useEffect(() => {
+ setDrawerOpen(false)
+ }, [pathname])
+
+ function isActive(href) {
+ return pathname === href || pathname.startsWith(href + '/')
+ }
+
+ async function handleSignOut() {
+ await signOut()
+ }
+
+ const navJsx = (
+ <>
+
+
+
+ {'{'}hs{'}'}
+
+
+
{space?.name || 'My Space'}
+
+
+
+
+
+
+
+ >
+ )
+
+ return (
+ <>
+
+
+
+
+
+ hs
+
+
{space?.name}
+
+
+
+
+ {drawerOpen && (
+
+
setDrawerOpen(false)} />
+
+
+ {space?.name}
+
+
+ {navJsx}
+
+
+ )}
+ >
+ )
+}
+`
+
+fs.writeFileSync('/vercel/share/v0-project/components/app-sidebar.tsx', content, 'utf8')
+console.log('Done. Wrote', content.length, 'bytes')
diff --git a/scripts/fix-sidebar.mjs b/scripts/fix-sidebar.mjs
new file mode 100644
index 0000000..8b1d061
--- /dev/null
+++ b/scripts/fix-sidebar.mjs
@@ -0,0 +1,180 @@
+import fs from 'fs'
+
+const content = `'use client'
+
+import Link from 'next/link'
+import { usePathname } from 'next/navigation'
+import { useState, useEffect } from 'react'
+import { cn } from '@/lib/utils'
+import { signOut } from '@/lib/auth-actions'
+import type { SpaceMember, Space } from '@/lib/types'
+import {
+ Menu, X, LayoutDashboard, ListChecks, FolderKanban, Settings2,
+ MessageSquare, Users, CreditCard, BookUser, Download, LogOut,
+} from 'lucide-react'
+
+function NavLink({
+ href, label, icon: Icon, badge, active,
+}: {
+ href: string
+ label: string
+ icon: React.ElementType
+ badge?: number
+ active: boolean
+}) {
+ return (
+
+
+
+ {label}
+
+ {badge && badge > 0 ? (
+
+ {badge}
+
+ ) : null}
+
+ )
+}
+
+interface AppSidebarProps {
+ member: SpaceMember & { spaces: Space }
+ taskBadge?: number
+ commsBadge?: number
+ paymentBadge?: number
+}
+
+export function AppSidebar({ member, taskBadge = 0, commsBadge = 0, paymentBadge = 0 }: AppSidebarProps) {
+ const pathname = usePathname()
+ const space = member.spaces
+ const initials = member.display_name?.split(' ').map((n: string) => n[0]).join('').toUpperCase().slice(0, 2) || '??'
+ const isAdmin = member.role === 'admin' || member.role === 'board'
+ const [drawerOpen, setDrawerOpen] = useState(false)
+
+ // Auto-close the drawer whenever the route changes
+ useEffect(() => {
+ setDrawerOpen(false)
+ }, [pathname])
+
+ function isActive(href: string) {
+ return pathname === href || pathname.startsWith(href + '/')
+ }
+
+ async function handleSignOut() {
+ await signOut()
+ }
+
+ // navJsx is JSX stored in a variable — NOT a nested component.
+ // This avoids React remounting it on every parent render, which was
+ // causing the drawer to unmount before Next.js
could navigate.
+ const navJsx = (
+ <>
+
+
+
+ {'{'}hs{'}'}
+
+
+
{space?.name || 'My Space'}
+
+
+
+
+
+
+
+ >
+ )
+
+ return (
+ <>
+ {/* Desktop sidebar */}
+
+
+ {/* Mobile: fixed top bar */}
+
+
+
+ hs
+
+
{space?.name}
+
+
+
+
+ {/* Mobile: slide-out drawer */}
+ {drawerOpen && (
+
+
setDrawerOpen(false)} aria-hidden="true" />
+
+
+ {space?.name}
+
+
+ {navJsx}
+
+
+ )}
+ >
+ )
+}
+`
+
+fs.writeFileSync('/vercel/share/v0-project/components/app-sidebar.tsx', content, 'utf8')
+console.log('Wrote app-sidebar.tsx successfully, length:', content.length)