Skip to content

Commit 76f36c7

Browse files
committed
chore: dev environment is wsl - remove secrets because of typo (rookie move)
1 parent 0ec96d1 commit 76f36c7

File tree

10 files changed

+1224
-1079
lines changed

10 files changed

+1224
-1079
lines changed

apps/web/.env.lcoal

Lines changed: 0 additions & 8 deletions
This file was deleted.

apps/web/src/components/auth/UserSync.tsx

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,37 @@
22
* Component that automatically syncs user to Convex when authenticated
33
* Only runs when Convex recognizes the user as authenticated (has auth token)
44
*/
5-
import { useEffect } from 'react'
6-
import { useMutation, useQuery, Authenticated } from 'convex/react'
7-
import { api } from 'convex/_generated/api'
5+
import { useEffect } from "react";
6+
import { useMutation, useQuery, Authenticated } from "convex/react";
7+
import { api } from "convex/_generated/api";
88

99
export function UserSync() {
10-
const ensureUser = useMutation(api.users.ensureCurrentUser)
11-
const currentUser = useQuery(api.users.getCurrent)
12-
10+
const ensureUser = useMutation(api.users.ensureCurrentUser);
11+
const currentUser = useQuery(api.users.getCurrent);
12+
1313
useEffect(() => {
1414
// Only sync if user is authenticated but doesn't exist in database yet
1515
if (currentUser === null) {
16+
console.log(
17+
"[UserSync] User is authenticated but not in DB. Attempting creation...",
18+
);
1619
// Small delay to ensure everything is settled
1720
const timer = setTimeout(() => {
18-
ensureUser().catch(() => {
19-
// Silently ignore - user might already exist or auth might not be ready
20-
// The query will retry automatically
21-
})
22-
}, 200)
23-
24-
return () => clearTimeout(timer)
21+
ensureUser()
22+
.then((id) =>
23+
console.log("[UserSync] User created successfully:", id),
24+
)
25+
.catch((e) => {
26+
console.error("[UserSync] Creation FAILED:", e);
27+
});
28+
}, 200);
29+
30+
return () => clearTimeout(timer);
2531
}
26-
}, [currentUser, ensureUser])
27-
32+
}, [currentUser, ensureUser]);
33+
2834
// This component doesn't render anything
29-
return null
35+
return null;
3036
}
3137

3238
/**
@@ -37,5 +43,5 @@ export function AuthenticatedUserSync() {
3743
<Authenticated>
3844
<UserSync />
3945
</Authenticated>
40-
)
46+
);
4147
}
Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
1-
"use client"
1+
"use client";
22

3-
import { useEffect, useState } from "react"
3+
import { useEffect, useState } from "react";
44
import {
55
Sidebar,
66
SidebarContent,
77
SidebarFooter,
88
SidebarHeader,
99
SidebarRail,
10-
} from "@/components/ui/sidebar"
11-
import { NavGroup } from "./NavGroup"
12-
import { NavUser } from "./NavUser"
13-
import { TeamSwitcher } from "./TeamSwitcher"
14-
import { useSidebarData, sidebarData as staticSidebarData } from "./sidebar-data"
10+
} from "@/components/ui/sidebar";
11+
import { NavGroup } from "./NavGroup";
12+
import { NavUser } from "./NavUser";
13+
import { TeamSwitcher } from "./TeamSwitcher";
14+
import {
15+
useSidebarData,
16+
sidebarData as staticSidebarData,
17+
} from "./sidebar-data";
1518

1619
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
17-
const [isClient, setIsClient] = useState(false)
18-
const [sidebarData, setSidebarData] = useState(staticSidebarData)
19-
20+
// Always call the hook unconditionally to respect Rules of Hooks
21+
const dynamicSidebarData = useSidebarData();
22+
23+
// Handle hydration mismatch by waiting for client mount
24+
const [isMounted, setIsMounted] = useState(false);
25+
2026
useEffect(() => {
21-
setIsClient(true)
22-
}, [])
23-
24-
// Only use the hook on client side to avoid SSR issues with Clerk
25-
if (isClient) {
26-
try {
27-
const data = useSidebarData()
28-
setSidebarData(data)
29-
} catch (error) {
30-
// If hook fails (e.g., Clerk not available), use static data
31-
}
32-
}
33-
27+
setIsMounted(true);
28+
}, []);
29+
30+
// Use static data on server/initial render, dynamic data after mount
31+
const sidebarData = isMounted ? dynamicSidebarData : staticSidebarData;
32+
3433
return (
3534
<div className="relative">
3635
<Sidebar collapsible="icon" {...props}>
@@ -39,9 +38,9 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
3938
</SidebarHeader>
4039
<SidebarContent>
4140
{sidebarData.navGroups.map((props, index) => (
42-
<NavGroup
43-
key={props.title || props.items[0]?.title || `nav-group-${index}`}
44-
{...props}
41+
<NavGroup
42+
key={props.title || props.items[0]?.title || `nav-group-${index}`}
43+
{...props}
4544
/>
4645
))}
4746
</SidebarContent>
@@ -51,5 +50,5 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
5150
<SidebarRail />
5251
</Sidebar>
5352
</div>
54-
)
53+
);
5554
}

apps/web/src/components/dashboard/sidebar-data.tsx

Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -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;
4141
if (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.
5454
function 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
9197
function 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

125135
export 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

Comments
 (0)