Skip to content

Commit e4591df

Browse files
authored
Fix sign in glitch (#49)
* fix sign in glitch * fix stars glitch
1 parent 383039d commit e4591df

File tree

5 files changed

+114
-39
lines changed

5 files changed

+114
-39
lines changed

app/layout.tsx

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ReactFlowProvider } from "@xyflow/react";
44
import { Provider } from "jotai";
55
import type { ReactNode } from "react";
66
import { AuthProvider } from "@/components/auth/provider";
7+
import { GitHubStarsProvider } from "@/components/github-stars-provider";
78
import { ThemeProvider } from "@/components/theme-provider";
89
import { Toaster } from "@/components/ui/sonner";
910
import { PersistentCanvas } from "@/components/workflow/persistent-canvas";
@@ -24,33 +25,67 @@ export const viewport: Viewport = {
2425
viewportFit: "cover",
2526
};
2627

28+
const GITHUB_REPO = "vercel-labs/workflow-builder-template";
29+
30+
async function getGitHubStars(): Promise<number | null> {
31+
try {
32+
const response = await fetch(
33+
`https://api.github.com/repos/${GITHUB_REPO}`,
34+
{
35+
headers: {
36+
Accept: "application/vnd.github.v3+json",
37+
...(process.env.GITHUB_TOKEN && {
38+
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
39+
}),
40+
},
41+
next: { revalidate: 3600 }, // Cache for 1 hour
42+
}
43+
);
44+
45+
if (!response.ok) {
46+
return null;
47+
}
48+
49+
const data = await response.json();
50+
return data.stargazers_count;
51+
} catch {
52+
return null;
53+
}
54+
}
55+
2756
type RootLayoutProps = {
2857
children: ReactNode;
2958
};
3059

31-
const RootLayout = ({ children }: RootLayoutProps) => (
32-
<html lang="en" suppressHydrationWarning>
33-
<body className={cn(sans.variable, mono.variable, "antialiased")}>
34-
<ThemeProvider
35-
attribute="class"
36-
defaultTheme="system"
37-
disableTransitionOnChange
38-
enableSystem
39-
>
40-
<Provider>
41-
<AuthProvider>
42-
<ReactFlowProvider>
43-
<PersistentCanvas />
44-
<div className="pointer-events-none relative z-10">
45-
{children}
46-
</div>
47-
</ReactFlowProvider>
48-
<Toaster />
49-
</AuthProvider>
50-
</Provider>
51-
</ThemeProvider>
52-
</body>
53-
</html>
54-
);
60+
const RootLayout = async ({ children }: RootLayoutProps) => {
61+
const stars = await getGitHubStars();
62+
63+
return (
64+
<html lang="en" suppressHydrationWarning>
65+
<body className={cn(sans.variable, mono.variable, "antialiased")}>
66+
<ThemeProvider
67+
attribute="class"
68+
defaultTheme="system"
69+
disableTransitionOnChange
70+
enableSystem
71+
>
72+
<Provider>
73+
<AuthProvider>
74+
<GitHubStarsProvider stars={stars}>
75+
<ReactFlowProvider>
76+
<PersistentCanvas />
77+
<div className="pointer-events-none relative z-10">
78+
{children}
79+
</div>
80+
</ReactFlowProvider>
81+
</GitHubStarsProvider>
82+
<Toaster />
83+
</AuthProvider>
84+
</Provider>
85+
</ThemeProvider>
86+
</body>
87+
</html>
88+
);
89+
};
5590

5691
export default RootLayout;

components/auth/dialog.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,17 +401,33 @@ type SingleProviderButtonProps = {
401401
onSignIn: (provider: "github" | "google" | "vercel") => Promise<void>;
402402
};
403403

404+
// Module-level flag to persist sign-in loading state across component remounts
405+
// This prevents the flash of normal state when OAuth triggers session refresh
406+
let singleProviderSignInInitiated = false;
407+
408+
export const isSingleProviderSignInInitiated = () =>
409+
singleProviderSignInInitiated;
410+
404411
const SingleProviderButton = ({
405412
provider,
406413
loadingProvider,
407414
onSignIn,
408415
}: SingleProviderButtonProps) => {
409-
const isLoading = loadingProvider === provider;
416+
// Use state to trigger re-renders, but sync with module-level flag
417+
const [isInitiated, setIsInitiated] = useState(singleProviderSignInInitiated);
418+
const isLoading = loadingProvider === provider || isInitiated;
419+
420+
const handleClick = () => {
421+
singleProviderSignInInitiated = true;
422+
setIsInitiated(true);
423+
onSignIn(provider as "github" | "google" | "vercel");
424+
};
425+
410426
return (
411427
<Button
412-
className="h-9 gap-1.5 px-2 sm:px-3"
413-
disabled={loadingProvider !== null}
414-
onClick={() => onSignIn(provider as "github" | "google" | "vercel")}
428+
className="h-9 gap-1.5 px-2 disabled:opacity-100 sm:px-3"
429+
disabled={isLoading}
430+
onClick={handleClick}
415431
size="sm"
416432
variant="default"
417433
>

components/github-stars-button.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
"use client";
22

3-
import { useEffect, useState } from "react";
43
import { GitHubIcon } from "@/components/icons/github-icon";
54
import { Button } from "@/components/ui/button";
65
import { formatAbbreviatedNumber } from "@/lib/utils/format-number";
6+
import { useGitHubStars } from "./github-stars-provider";
77

88
const GITHUB_REPO_URL =
99
"https://github.com/vercel-labs/workflow-builder-template";
1010

1111
export function GitHubStarsButton() {
12-
const [stars, setStars] = useState<number | null>(null);
13-
14-
useEffect(() => {
15-
fetch("https://api.github.com/repos/vercel-labs/workflow-builder-template")
16-
.then((res) => res.json())
17-
.then((data) => setStars(data.stargazers_count))
18-
.catch(() => setStars(null));
19-
}, []);
12+
const stars = useGitHubStars();
2013

2114
return (
2215
<Button
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"use client";
2+
3+
import { createContext, type ReactNode, useContext } from "react";
4+
5+
const GitHubStarsContext = createContext<number | null>(null);
6+
7+
type GitHubStarsProviderProps = {
8+
children: ReactNode;
9+
stars: number | null;
10+
};
11+
12+
export function GitHubStarsProvider({
13+
children,
14+
stars,
15+
}: GitHubStarsProviderProps) {
16+
return (
17+
<GitHubStarsContext.Provider value={stars}>
18+
{children}
19+
</GitHubStarsContext.Provider>
20+
);
21+
}
22+
23+
export function useGitHubStars() {
24+
return useContext(GitHubStarsContext);
25+
}

components/workflows/user-menu.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import { LogOut, Moon, Plug, Settings, Sun } from "lucide-react";
44
import { useTheme } from "next-themes";
55
import { useEffect, useState } from "react";
6-
import { AuthDialog } from "@/components/auth/dialog";
6+
import {
7+
AuthDialog,
8+
isSingleProviderSignInInitiated,
9+
} from "@/components/auth/dialog";
710
import { SettingsDialog } from "@/components/settings";
811
import { IntegrationsDialog } from "@/components/settings/integrations-dialog";
912
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
@@ -66,8 +69,11 @@ export const UserMenu = () => {
6669
return "U";
6770
};
6871

72+
const signInInProgress = isSingleProviderSignInInitiated();
73+
6974
// Don't render anything while session is loading to prevent flash
70-
if (isPending) {
75+
// BUT if sign-in is in progress, keep showing the AuthDialog with loading state
76+
if (isPending && !signInInProgress) {
7177
return (
7278
<div className="h-9 w-9" /> // Placeholder to maintain layout
7379
);

0 commit comments

Comments
 (0)