From b47637ee27ed366d5aadb637ab40586c04b096e1 Mon Sep 17 00:00:00 2001 From: Devanshu Rajesh Chicholikar Date: Sun, 25 Jan 2026 19:17:25 -0500 Subject: [PATCH 1/6] feat: add GitHub and Google OAuth login - Add signInWithGitHub and signInWithGoogle methods to AuthContext - Update LoginForm with working OAuth buttons (GitHub + Google) - Update SignupForm with same OAuth functionality - Add proper loading states for OAuth flows - Disable buttons during any auth operation to prevent double-clicks - OAuth redirects to /dashboard after successful authentication Supabase handles the OAuth flow automatically via onAuthStateChange listener. --- frontend/src/components/auth/LoginForm.tsx | 88 ++++++++++++++++++--- frontend/src/components/auth/SignupForm.tsx | 88 ++++++++++++++++++--- frontend/src/contexts/AuthContext.tsx | 24 ++++++ 3 files changed, 176 insertions(+), 24 deletions(-) diff --git a/frontend/src/components/auth/LoginForm.tsx b/frontend/src/components/auth/LoginForm.tsx index d9b3a2c..4d635b5 100644 --- a/frontend/src/components/auth/LoginForm.tsx +++ b/frontend/src/components/auth/LoginForm.tsx @@ -13,7 +13,8 @@ export function LoginForm() { const [password, setPassword] = useState('') const [error, setError] = useState('') const [loading, setLoading] = useState(false) - const { signIn } = useAuth() + const [oauthLoading, setOauthLoading] = useState<'github' | 'google' | null>(null) + const { signIn, signInWithGitHub, signInWithGoogle } = useAuth() const navigate = useNavigate() const handleSubmit = async (e: React.FormEvent) => { @@ -31,6 +32,28 @@ export function LoginForm() { } } + const handleGitHubSignIn = async () => { + setError('') + setOauthLoading('github') + try { + await signInWithGitHub() + } catch (err: any) { + setError(err.message || 'GitHub sign in failed') + setOauthLoading(null) + } + } + + const handleGoogleSignIn = async () => { + setError('') + setOauthLoading('google') + try { + await signInWithGoogle() + } catch (err: any) { + setError(err.message || 'Google sign in failed') + setOauthLoading(null) + } + } + return (
@@ -118,20 +141,61 @@ export function LoginForm() {
- or + or continue with
- +
+ + +

diff --git a/frontend/src/components/auth/SignupForm.tsx b/frontend/src/components/auth/SignupForm.tsx index 79bdb94..93977f1 100644 --- a/frontend/src/components/auth/SignupForm.tsx +++ b/frontend/src/components/auth/SignupForm.tsx @@ -14,7 +14,8 @@ export function SignupForm() { const [confirmPassword, setConfirmPassword] = useState('') const [error, setError] = useState('') const [loading, setLoading] = useState(false) - const { signUp } = useAuth() + const [oauthLoading, setOauthLoading] = useState<'github' | 'google' | null>(null) + const { signUp, signInWithGitHub, signInWithGoogle } = useAuth() const navigate = useNavigate() const handleSubmit = async (e: React.FormEvent) => { @@ -42,6 +43,28 @@ export function SignupForm() { } } + const handleGitHubSignIn = async () => { + setError('') + setOauthLoading('github') + try { + await signInWithGitHub() + } catch (err: any) { + setError(err.message || 'GitHub sign in failed') + setOauthLoading(null) + } + } + + const handleGoogleSignIn = async () => { + setError('') + setOauthLoading('google') + try { + await signInWithGoogle() + } catch (err: any) { + setError(err.message || 'Google sign in failed') + setOauthLoading(null) + } + } + return (

@@ -146,20 +169,61 @@ export function SignupForm() {
- or + or continue with
- +
+ + +

diff --git a/frontend/src/contexts/AuthContext.tsx b/frontend/src/contexts/AuthContext.tsx index 758aacb..dfbf272 100644 --- a/frontend/src/contexts/AuthContext.tsx +++ b/frontend/src/contexts/AuthContext.tsx @@ -8,6 +8,8 @@ interface AuthContextType { loading: boolean; signUp: (email: string, password: string) => Promise; signIn: (email: string, password: string) => Promise; + signInWithGitHub: () => Promise; + signInWithGoogle: () => Promise; signOut: () => Promise; } @@ -64,12 +66,34 @@ export function AuthProvider({ children }: { children: ReactNode }) { if (error) throw error; }; + const signInWithGitHub = async () => { + const { error } = await supabase.auth.signInWithOAuth({ + provider: 'github', + options: { + redirectTo: `${window.location.origin}/dashboard`, + }, + }); + if (error) throw error; + }; + + const signInWithGoogle = async () => { + const { error } = await supabase.auth.signInWithOAuth({ + provider: 'google', + options: { + redirectTo: `${window.location.origin}/dashboard`, + }, + }); + if (error) throw error; + }; + const value = { user, session, loading, signUp, signIn, + signInWithGitHub, + signInWithGoogle, signOut, }; From 8830982449d764e511f6463c56ba05a9c97b2072 Mon Sep 17 00:00:00 2001 From: Devanshu Rajesh Chicholikar Date: Sun, 25 Jan 2026 20:16:09 -0500 Subject: [PATCH 2/6] fix: improve OAuth button state handling and accessibility - Move setOauthLoading(null) to finally block in both forms Ensures loading state is always reset, even if OAuth redirects or errors - Add aria-label for screen readers when OAuth buttons show spinner Buttons now have 'Signing in with GitHub/Google' accessible name during loading - Add sr-only span with provider name alongside Loader2 spinner Provides accessible text for assistive technologies --- frontend/src/components/auth/LoginForm.tsx | 14 ++++++++++++-- frontend/src/components/auth/SignupForm.tsx | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/auth/LoginForm.tsx b/frontend/src/components/auth/LoginForm.tsx index 4d635b5..ca40fb0 100644 --- a/frontend/src/components/auth/LoginForm.tsx +++ b/frontend/src/components/auth/LoginForm.tsx @@ -39,6 +39,7 @@ export function LoginForm() { await signInWithGitHub() } catch (err: any) { setError(err.message || 'GitHub sign in failed') + } finally { setOauthLoading(null) } } @@ -50,6 +51,7 @@ export function LoginForm() { await signInWithGoogle() } catch (err: any) { setError(err.message || 'Google sign in failed') + } finally { setOauthLoading(null) } } @@ -152,9 +154,13 @@ export function LoginForm() { className="h-10" onClick={handleGitHubSignIn} disabled={loading || oauthLoading !== null} + aria-label={oauthLoading === 'github' ? 'Signing in with GitHub' : undefined} > {oauthLoading === 'github' ? ( - + <> + + Signing in with GitHub + ) : ( <> @@ -168,9 +174,13 @@ export function LoginForm() { className="h-10" onClick={handleGoogleSignIn} disabled={loading || oauthLoading !== null} + aria-label={oauthLoading === 'google' ? 'Signing in with Google' : undefined} > {oauthLoading === 'google' ? ( - + <> + + Signing in with Google + ) : ( <> diff --git a/frontend/src/components/auth/SignupForm.tsx b/frontend/src/components/auth/SignupForm.tsx index 93977f1..8f4a8b4 100644 --- a/frontend/src/components/auth/SignupForm.tsx +++ b/frontend/src/components/auth/SignupForm.tsx @@ -50,6 +50,7 @@ export function SignupForm() { await signInWithGitHub() } catch (err: any) { setError(err.message || 'GitHub sign in failed') + } finally { setOauthLoading(null) } } @@ -61,6 +62,7 @@ export function SignupForm() { await signInWithGoogle() } catch (err: any) { setError(err.message || 'Google sign in failed') + } finally { setOauthLoading(null) } } @@ -180,9 +182,13 @@ export function SignupForm() { className="h-10" onClick={handleGitHubSignIn} disabled={loading || oauthLoading !== null} + aria-label={oauthLoading === 'github' ? 'Signing in with GitHub' : undefined} > {oauthLoading === 'github' ? ( - + <> + + Signing in with GitHub + ) : ( <> @@ -196,9 +202,13 @@ export function SignupForm() { className="h-10" onClick={handleGoogleSignIn} disabled={loading || oauthLoading !== null} + aria-label={oauthLoading === 'google' ? 'Signing in with Google' : undefined} > {oauthLoading === 'google' ? ( - + <> + + Signing in with Google + ) : ( <> From 55919b6c1383ca284d975b8ce761b6788329a6e3 Mon Sep 17 00:00:00 2001 From: Devanshu Rajesh Chicholikar Date: Sun, 25 Jan 2026 23:21:28 -0500 Subject: [PATCH 3/6] fix: content hidden behind fixed navbar - Add pt-14 to main element in DashboardLayout to account for fixed TopNav - Remove duplicate pt-14 from DashboardHome (layout now handles it) The 'Repositories' heading was being cut off by the fixed navbar because the main content area didn't have top padding. --- frontend/src/components/dashboard/DashboardHome.tsx | 2 +- frontend/src/components/dashboard/DashboardLayout.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/dashboard/DashboardHome.tsx b/frontend/src/components/dashboard/DashboardHome.tsx index 62a4c04..d472877 100644 --- a/frontend/src/components/dashboard/DashboardHome.tsx +++ b/frontend/src/components/dashboard/DashboardHome.tsx @@ -117,7 +117,7 @@ export function DashboardHome() { ] as const return ( -

+
{/* Repository List View */} {!isRepoView && ( diff --git a/frontend/src/components/dashboard/DashboardLayout.tsx b/frontend/src/components/dashboard/DashboardLayout.tsx index 29af84b..f01b71a 100644 --- a/frontend/src/components/dashboard/DashboardLayout.tsx +++ b/frontend/src/components/dashboard/DashboardLayout.tsx @@ -57,7 +57,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) { />
From 9982e3ba1cd8ca4880ead6b17b020ebab2768a40 Mon Sep 17 00:00:00 2001 From: Devanshu Rajesh Chicholikar Date: Sun, 25 Jan 2026 23:23:38 -0500 Subject: [PATCH 4/6] refactor: use CSS variables for layout dimensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced hardcoded Tailwind classes with CSS variables for maintainability: - --navbar-height: 3.5rem (56px) - --sidebar-width: 15rem (240px) - --sidebar-width-collapsed: 4rem (64px) Now if navbar height changes, update ONE variable instead of hunting through multiple files. Uses Tailwind arbitrary values syntax: h-[var(--navbar-height)], pt-[var(--navbar-height)], etc. Files updated: - index.css: Added layout CSS variables - TopNav.tsx: h-14 → h-[var(--navbar-height)] - DashboardLayout.tsx: pt-14, ml-16/60 → CSS variables - Sidebar.tsx: top-14, w-16/60 → CSS variables --- frontend/src/components/dashboard/DashboardLayout.tsx | 4 ++-- frontend/src/components/dashboard/Sidebar.tsx | 4 ++-- frontend/src/components/dashboard/TopNav.tsx | 2 +- frontend/src/index.css | 5 +++++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/dashboard/DashboardLayout.tsx b/frontend/src/components/dashboard/DashboardLayout.tsx index f01b71a..1416ff8 100644 --- a/frontend/src/components/dashboard/DashboardLayout.tsx +++ b/frontend/src/components/dashboard/DashboardLayout.tsx @@ -57,8 +57,8 @@ export function DashboardLayout({ children }: DashboardLayoutProps) { />
diff --git a/frontend/src/components/dashboard/Sidebar.tsx b/frontend/src/components/dashboard/Sidebar.tsx index 154c48e..5c1e841 100644 --- a/frontend/src/components/dashboard/Sidebar.tsx +++ b/frontend/src/components/dashboard/Sidebar.tsx @@ -88,10 +88,10 @@ export function Sidebar({ collapsed, onToggle }: SidebarProps) { return (