@@ -27,22 +27,22 @@ import {
2727 FileText ,
2828 RadioTower ,
2929 Inbox ,
30- } from "lucide-react"
31- import { type SidebarData } from "./types"
32- import { useQuery } from "convex/react"
33- import { api } from "convex/_generated/api"
34- import type { Doc } from "convex/_generated/dataModel"
30+ } from "lucide-react" ;
31+ import { type SidebarData } from "./types" ;
32+ import { useQuery } from "convex/react" ;
33+ import { api } from "convex/_generated/api" ;
34+ import type { Doc } from "convex/_generated/dataModel" ;
3535
36- const clerkPublishableKey = import . meta. env . VITE_CLERK_PUBLISHABLE_KEY
36+ const clerkPublishableKey = import . meta. env . VITE_CLERK_PUBLISHABLE_KEY ;
3737
3838// Conditionally import useUser - only if Clerk is configured
3939// This avoids bundling Clerk if not needed, but we must handle SSR
40- let useUserHook : ( ( ) => { user : any } | null ) | null = null
40+ let useUserHook : ( ( ) => { user : any } ) | null = null ;
4141if ( clerkPublishableKey && typeof window !== "undefined" ) {
4242 try {
4343 // eslint-disable-next-line @typescript-eslint/no-var-requires
44- const clerkReact = require ( "@clerk/clerk-react" )
45- useUserHook = clerkReact . useUser
44+ const clerkReact = require ( "@clerk/clerk-react" ) ;
45+ useUserHook = clerkReact . useUser ;
4646 } catch {
4747 // Clerk not available
4848 }
@@ -52,91 +52,91 @@ if (clerkPublishableKey && typeof window !== "undefined") {
5252// Note: This hook should only be called on the client side (after mount)
5353// to avoid SSR issues with ClerkProvider. AppSidebar ensures this.
5454function useSidebarUser ( ) {
55- // Check if Convex is configured before calling useQuery
56- const convexUrl = import . meta. env . VITE_CONVEX_URL
57- if ( ! convexUrl ) {
58- return {
59- name : "User" ,
60- email : "" ,
61- avatar : "" ,
62- }
63- }
64-
65- // useQuery will throw if ConvexProvider isn't available
66- // We can't catch this, so the caller must handle it
67- const convexUser = useQuery ( api . users . getCurrent )
68-
55+ // Check if Convex is configured
56+ const convexUrl = import . meta. env . VITE_CONVEX_URL ;
57+ const shouldSkip = ! convexUrl ;
58+
59+ // Always call hooks unconditionally
60+ const convexUser = useQuery ( api . users . getCurrent , shouldSkip ? "skip" : { } ) ;
61+
6962 // If Clerk is not configured or not available, only use Convex user
7063 if ( ! useUserHook ) {
7164 return {
7265 name : convexUser ?. name || "User" ,
7366 email : "" ,
7467 avatar : "" ,
75- }
68+ } ;
7669 }
77-
70+
7871 // Always call the hook if it's available (React rules require unconditional calls)
7972 // This will throw if not in ClerkProvider, but AppSidebar only calls this on client
8073 // where ClerkProvider should be available
81- const { user : clerkUser } = useUserHook ( )
82-
74+ const { user : clerkUser } = useUserHook ( ) ;
75+
76+ if ( shouldSkip ) {
77+ return {
78+ name : "User" ,
79+ email : "" ,
80+ avatar : "" ,
81+ } ;
82+ }
83+
8384 return {
84- name : clerkUser ?. firstName || convexUser ?. name || clerkUser ?. fullName || clerkUser ?. primaryEmailAddress ?. emailAddress ?. split ( "@" ) [ 0 ] || "User" ,
85+ name :
86+ clerkUser ?. firstName ||
87+ convexUser ?. name ||
88+ clerkUser ?. fullName ||
89+ clerkUser ?. primaryEmailAddress ?. emailAddress ?. split ( "@" ) [ 0 ] ||
90+ "User" ,
8591 email : clerkUser ?. primaryEmailAddress ?. emailAddress || "" ,
8692 avatar : clerkUser ?. imageUrl || "" ,
87- }
93+ } ;
8894}
8995
9096// Helper hook to get organizations from Clerk
9197function useSidebarTeams ( ) {
92- // Check if Convex is configured before calling useQuery
93- const convexUrl = import . meta. env . VITE_CONVEX_URL
94- if ( ! convexUrl ) {
98+ // Check if Convex is configured
99+ const convexUrl = import . meta. env . VITE_CONVEX_URL ;
100+ const shouldSkip = ! convexUrl ;
101+
102+ // Always call hooks unconditionally
103+ const organizations = useQuery (
104+ api . organizations . list ,
105+ shouldSkip ? "skip" : { } ,
106+ ) ;
107+
108+ if ( shouldSkip ) {
95109 return [
96110 {
97111 name : "StackDock" ,
98112 logo : Building2 ,
99113 plan : "Free" ,
100114 } ,
101- ]
115+ ] ;
102116 }
103-
104- // useQuery will throw if ConvexProvider isn't available
105- // We can't catch this, so the caller must handle it
106- const organizations = useQuery ( api . organizations . list )
107-
117+
108118 if ( ! organizations || organizations . length === 0 ) {
109119 return [
110120 {
111121 name : "StackDock" ,
112122 logo : Building2 ,
113123 plan : "Free" ,
114124 } ,
115- ]
125+ ] ;
116126 }
117-
127+
118128 return organizations . map ( ( org : Doc < "organizations" > ) => ( {
119129 name : org . name ,
120130 logo : Building2 ,
121131 plan : "Active" ,
122- } ) )
132+ } ) ) ;
123133}
124134
125135export function useSidebarData ( ) : SidebarData {
126- // Check if Convex is configured
127- const convexUrl = import . meta. env . VITE_CONVEX_URL
128-
129- // If Convex is not configured, return static data
130- if ( ! convexUrl ) {
131- return sidebarData
132- }
133-
134- // Try to use hooks, but fall back to static data if ConvexProvider isn't available
135- // Note: We can't wrap hooks in try-catch, so if useQuery throws, it will propagate
136- // The component using this hook should handle the error or ensure ConvexProvider is available
137- const user = useSidebarUser ( )
138- const teams = useSidebarTeams ( )
139-
136+ // Always call hooks unconditionally
137+ const user = useSidebarUser ( ) ;
138+ const teams = useSidebarTeams ( ) ;
139+
140140 return {
141141 user,
142142 teams,
@@ -233,27 +233,27 @@ export function useSidebarData(): SidebarData {
233233 {
234234 title : "" ,
235235 items : [
236- {
237- title : "Monitoring" ,
238- icon : BarChart3 ,
239- items : [
240- {
241- title : "Uptime" ,
242- url : "/dashboard/monitoring/uptime" ,
243- icon : RadioTower ,
244- } ,
245- {
246- title : "Issues" ,
247- url : "/dashboard/monitoring/issues" ,
248- icon : AlertCircle ,
249- } ,
250- {
251- title : "Logs" ,
252- url : "/dashboard/monitoring/logs" ,
253- icon : FileText ,
254- } ,
255- ] ,
256- } ,
236+ {
237+ title : "Monitoring" ,
238+ icon : BarChart3 ,
239+ items : [
240+ {
241+ title : "Uptime" ,
242+ url : "/dashboard/monitoring/uptime" ,
243+ icon : RadioTower ,
244+ } ,
245+ {
246+ title : "Issues" ,
247+ url : "/dashboard/monitoring/issues" ,
248+ icon : AlertCircle ,
249+ } ,
250+ {
251+ title : "Logs" ,
252+ url : "/dashboard/monitoring/logs" ,
253+ icon : FileText ,
254+ } ,
255+ ] ,
256+ } ,
257257 ] ,
258258 } ,
259259 {
@@ -309,7 +309,7 @@ export function useSidebarData(): SidebarData {
309309 ] ,
310310 } ,
311311 ] ,
312- }
312+ } ;
313313}
314314
315315// Static version for components that can't use hooks
@@ -490,4 +490,4 @@ export const sidebarData: SidebarData = {
490490 ] ,
491491 } ,
492492 ] ,
493- }
493+ } ;
0 commit comments