Skip to content

feat: Add GitHub and Google OAuth Login#223

Merged
DevanshuNEU merged 6 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:feature/oauth-social-login
Jan 26, 2026
Merged

feat: Add GitHub and Google OAuth Login#223
DevanshuNEU merged 6 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:feature/oauth-social-login

Conversation

@DevanshuNEU

@DevanshuNEU DevanshuNEU commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds GitHub and Google OAuth login via Supabase, plus fixes for dashboard layout and mobile responsiveness.

Changes

OAuth

  • Added signInWithGitHub() and signInWithGoogle() to AuthContext
  • Updated Login and Signup pages with working OAuth buttons
  • Proper loading states and accessibility (aria-labels, sr-only text)

Layout Fixes

  • Fixed content being hidden behind fixed navbar
  • Replaced hardcoded Tailwind classes with CSS variables for maintainability:
    • --navbar-height, --sidebar-width, --sidebar-width-collapsed

Mobile Responsiveness

  • Sidebar hidden by default on mobile, opens as overlay
  • Hamburger menu, dark backdrop, auto-close on navigation
  • Escape key and backdrop click to close
  • Body scroll lock when menu open

Testing

  • Build passes
  • GitHub OAuth flow
  • Google OAuth flow
  • Desktop layout (sidebar collapse/expand)
  • Mobile layout (hamburger menu, overlay)

Supabase Config Required

  • GitHub and Google providers enabled
  • Redirect URLs: https://opencodeintel.com/*, http://localhost:3000/*

- 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.
@vercel

vercel Bot commented Jan 26, 2026

Copy link
Copy Markdown

@DevanshuNEU is attempting to deploy a commit to the Dev's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jan 26, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds GitHub and Google OAuth sign-in to LoginForm/SignupForm and exposes signInWithGitHub/signInWithGoogle in AuthContext (Supabase OAuth redirect to /dashboard). Also moves layout spacing to CSS variables and updates dashboard sidebar/topnav for mobile overlay and collapse behavior.

Changes

Cohort / File(s) Summary
Auth Form Components
frontend/src/components/auth/LoginForm.tsx, frontend/src/components/auth/SignupForm.tsx
Added per-provider handlers (handleGitHubSignIn, handleGoogleSignIn), oauthLoading state, per-provider error handling, two-button OAuth UI (GitHub + Google) with per-button spinners/disable logic, and updated divider text.
Auth Context
frontend/src/contexts/AuthContext.tsx
Added and exposed signInWithGitHub() and signInWithGoogle() on AuthContextType and implemented them in AuthProvider using Supabase OAuth with redirect to /dashboard.
Dashboard Layout & Sidebar
frontend/src/components/dashboard/DashboardLayout.tsx, frontend/src/components/dashboard/Sidebar.tsx, frontend/src/components/dashboard/TopNav.tsx, frontend/src/components/dashboard/DashboardHome.tsx
Introduced mobile menu overlay state and close behavior, persisted/collapsible sidebar logic, adjusted top-nav height usage, removed top padding in DashboardHome, and updated Sidebar props to accept mobileOpen/onMobileClose.
Styles
frontend/src/index.css
Added CSS custom properties: --navbar-height, --sidebar-width, --sidebar-width-collapsed, and --mobile-breakpoint for responsive/layout sizing.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Form as LoginForm/SignupForm
    participant Auth as AuthContext
    participant Supabase as Supabase OAuth

    User->>Form: Click "GitHub" or "Google"
    Form->>Form: set oauthLoading(provider), clear provider error
    Form->>Auth: call signInWithGitHub()/signInWithGoogle()
    Auth->>Supabase: initiate OAuth sign-in (provider, redirect:/dashboard)
    Supabase->>Supabase: redirect to provider for authorization
    Supabase-->>Auth: callback with session/token
    Auth-->>Form: return result (success or error)
    Form->>Form: clear oauthLoading
    Form->>User: navigate to /dashboard on success
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped to the login gate, bright and swift,
Two buttons gleam — GitHub and Google, a gift,
Spinners spin as errors fade away,
A hop, a redirect — dashboard-bound today,
Carrot tucked, I cheer the OAuth shift.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Add GitHub and Google OAuth Login' accurately summarizes the main change—adding OAuth social login functionality for GitHub and Google providers across the authentication system.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@frontend/src/components/auth/LoginForm.tsx`:
- Around line 35-55: The handlers handleGitHubSignIn and handleGoogleSignIn can
leave oauthLoading set if the OAuth flow returns without navigation; move the
setOauthLoading(null) into a finally block so it always runs regardless of
success or error, keeping the existing setError behavior in the catch; ensure
you call signInWithGitHub and signInWithGoogle inside the try and clear
oauthLoading in finally to prevent the buttons from remaining disabled.
- Around line 148-198: The social sign-in buttons lose their accessible name
when showing only the Loader2 icon (because the visible text is removed); update
the Button rendering for both GitHub and Google in LoginForm.tsx to preserve an
accessible label when oauthLoading === 'github' or 'google' by either (a) adding
an aria-label prop on the Button (e.g., aria-label={`Signing in with GitHub`} /
`Signing in with Google`) or (b) keeping a visually-hidden text node (sr-only
span) next to the Loader2 that reads "Signing in with GitHub" / "Signing in with
Google"; target the Button elements and Loader2 usage and ensure the label text
reflects the provider and only appears during loading.

In `@frontend/src/components/auth/SignupForm.tsx`:
- Around line 46-66: The oauthLoading state is not cleared if signInWithGitHub
or signInWithGoogle throws before navigation, leaving buttons disabled; update
handleGitHubSignIn and handleGoogleSignIn to clear setOauthLoading(null) in a
finally block (after the try/catch) so oauthLoading is reset regardless of
success or error, keeping the existing setError behavior in the catch.
- Around line 176-226: The Github/Google buttons drop their textual accessible
name when showing only the Loader2 icon; update the Button rendering logic in
SignupForm.tsx (the buttons using oauthLoading, handleGitHubSignIn,
handleGoogleSignIn) so that when oauthLoading === 'github' or 'google' you still
provide an accessible label—either add an aria-label that reflects the loading
state (e.g., "Signing in with GitHub"/"Signing in with Google") or render a
visually-hidden span with the provider name alongside the Loader2
spinner—ensuring the Button always exposes an accessible name while preserving
the visual spinner.

Comment thread frontend/src/components/auth/LoginForm.tsx
Comment thread frontend/src/components/auth/LoginForm.tsx
Comment thread frontend/src/components/auth/SignupForm.tsx
Comment thread frontend/src/components/auth/SignupForm.tsx
- 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
- 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.
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
@vercel

vercel Bot commented Jan 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
opencodeintel Ready Ready Preview, Comment Jan 26, 2026 4:48am

Mobile behavior (< 1024px / lg breakpoint):
- Sidebar hidden by default
- Hamburger menu in navbar opens sidebar as overlay
- Dark backdrop behind sidebar when open
- Tap backdrop or press Escape to close
- Auto-closes when navigating to a new page
- Body scroll locked when menu is open
- Full-width sidebar with close button

Desktop behavior (>= 1024px):
- Sidebar always visible
- Can be collapsed to icon-only mode
- Collapse toggle in sidebar footer

Also:
- Added --mobile-breakpoint CSS variable for consistency
- Reduced padding on mobile (p-4) vs desktop (md:p-6)
- Main content has no left margin on mobile
- Fixed main content margin: use ternary to apply only ONE lg:ml-* class
  (before: both classes were applied, causing conflicts)
- Removed invalid CSS comment from Sidebar className

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@frontend/src/components/dashboard/DashboardLayout.tsx`:
- Around line 110-116: The main element's className currently adds both
"lg:ml-[var(--sidebar-width)]" and conditionally
"lg:ml-[var(--sidebar-width-collapsed)]", which can conflict; update the
className expression in the DashboardLayout component so the lg:ml-* is chosen
via a single ternary tied to sidebarCollapsed (e.g., use sidebarCollapsed ?
'lg:ml-[var(--sidebar-width-collapsed)]' : 'lg:ml-[var(--sidebar-width)]') so
only one lg:ml class is rendered; keep the other classes (flex-1,
transition-all, duration-300, pt-[var(--navbar-height)], ml-0) unchanged.

In `@frontend/src/components/dashboard/Sidebar.tsx`:
- Around line 108-118: The string passed to the aside element's className
contains a CSS-style comment which will be rendered literally; remove the "/*
Mobile: hidden by default, shown when mobileOpen */" from the template literal
(or convert it to a JS/TS comment above the template literal) so the comment
isn't included in the generated class attribute; update the className
construction that uses getWidthClass() and mobileOpen accordingly (or place
explanatory text in a separate comment line before the aside or in a const
variable) to preserve intent without injecting literal text into the className.
🧹 Nitpick comments (1)
frontend/src/components/dashboard/DashboardLayout.tsx (1)

75-83: Consider extracting the breakpoint constant.

The hardcoded 1024 matches the --mobile-breakpoint CSS variable and Tailwind's lg: breakpoint, but this relationship is implicit. Consider extracting a shared constant to prevent accidental drift.

Suggested approach
// At top of file or in a shared constants file
const MOBILE_BREAKPOINT = 1024

const handleToggleSidebar = () => {
  if (window.innerWidth < MOBILE_BREAKPOINT) {
    setMobileMenuOpen(!mobileMenuOpen)
  } else {
    setSidebarCollapsed(!sidebarCollapsed)
  }
}

Comment thread frontend/src/components/dashboard/DashboardLayout.tsx
Comment thread frontend/src/components/dashboard/Sidebar.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/components/dashboard/DashboardLayout.tsx (1)

48-83: Close mobile menu on viewport resize to prevent locked scroll and update state toggles using functional updates.

The code has two issues:

  1. Viewport breakpoint not handled: If the mobile menu opens on mobile and the viewport crosses the lg breakpoint (1024px), mobileMenuOpen remains true, keeping body scroll locked and the full-width sidebar forced on desktop until Escape or route change.

  2. State toggles use captured state: Lines 79 and 81 capture mobileMenuOpen and sidebarCollapsed directly instead of functional updates. React batching can cause stale state issues. (Line 72 already correctly uses the functional pattern.)

Add a resize listener to close the menu when crossing the breakpoint, and convert the state setters to use functional updates:

Proposed fix
   // Prevent body scroll when mobile menu is open
   useEffect(() => {
     if (mobileMenuOpen) {
       document.body.style.overflow = 'hidden'
     } else {
       document.body.style.overflow = ''
     }
     return () => { document.body.style.overflow = '' }
   }, [mobileMenuOpen])

+  // Close mobile menu when switching to desktop breakpoint
+  useEffect(() => {
+    const handleResize = () => {
+      if (window.innerWidth >= 1024) setMobileMenuOpen(false)
+    }
+    window.addEventListener('resize', handleResize)
+    handleResize()
+    return () => window.removeEventListener('resize', handleResize)
+  }, [])
+
   const handleToggleSidebar = () => {
     // On mobile: toggle overlay menu
     // On desktop: toggle collapsed state
     if (window.innerWidth < 1024) {
-      setMobileMenuOpen(!mobileMenuOpen)
+      setMobileMenuOpen((prev) => !prev)
     } else {
-      setSidebarCollapsed(!sidebarCollapsed)
+      setMobileMenuOpen(false)
+      setSidebarCollapsed((prev) => !prev)
     }
   }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant