Skip to content

fix(ux): empty repo state opens add modal, signup requires email verification#225

Merged
DevanshuNEU merged 7 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:fix/phase1-quick-wins
Jan 27, 2026
Merged

fix(ux): empty repo state opens add modal, signup requires email verification#225
DevanshuNEU merged 7 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:fix/phase1-quick-wins

Conversation

@DevanshuNEU

@DevanshuNEU DevanshuNEU commented Jan 27, 2026

Copy link
Copy Markdown
Collaborator

Description

1. Empty state click not working
Users with no repositories saw a "+" icon but clicking it did nothing. Now clicking anywhere on the empty state opens the Add Repository modal.

2. No email verification on signup
Anyone could sign up with fake emails and start indexing repos, wasting server resources. Now signup shows a "Check your email" screen and requires verification before login.

Changes

  • RepoList.tsx - Empty state is now a clickable button with onAddClick prop
  • AddRepoForm.tsx - Supports controlled open/close state
  • DashboardHome.tsx - Wires empty state click to open the modal
  • SignupForm.tsx - Shows verification screen after signup
  • LoginForm.tsx - Shows "verify your email" error instead of generic failure

Screenshots

Empty state now clickable, signup shows verification screen

Config required

Enable "Confirm email" in Supabase → Authentication → Settings

Summary by CodeRabbit

  • New Features

    • Signup now shows an email verification screen with resend, success feedback, and "use a different email" / return-to-login actions
    • Add Repository form can operate in controlled mode and be opened from other screens
    • Repo list empty state becomes an animated, actionable button with an on-add callback
    • Auth API adds a resend-verification method for email resend flows
  • Bug Fixes

    • Login errors now show clearer, user-friendly messages for common auth problems

✏️ Tip: You can customize this high-level summary in your review settings.

- Add onAddClick prop to RepoList component
- Support controlled mode in AddRepoForm (isOpen, onOpenChange)
- Wire up DashboardHome to pass state between components
- Empty state now opens the add repository modal when clicked
- Show 'Check your email' screen after signup instead of redirecting
- Handle email_not_confirmed error gracefully in login form
- Show helpful error messages for common auth issues
- Prevent fake email signups by requiring verification
@vercel

vercel Bot commented Jan 27, 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 27, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds controlled/uncontrolled visibility to AddRepoForm and wires it from RepoList and DashboardHome; makes RepoList empty state actionable; adds resendVerification to AuthContext; introduces post-signup email verification UI and improves login error messaging.

Changes

Cohort / File(s) Summary
AddRepoForm (visibility control)
frontend/src/components/AddRepoForm.tsx
Introduces discriminated-union props for controlled vs uncontrolled use (isOpen/onOpenChange vs omitted), switches to dual-mode visibility (external isOpen or internal state), hides the trigger in controlled mode, and unifies the setter used on submit.
RepoList (empty-state action & sorting)
frontend/src/components/RepoList.tsx
Adds optional onAddClick?: () => void; computes sortedRepos via useMemo; renders empty-state as actionable motion.button when onAddClick is provided (disabled otherwise) with hover/tap animations and conditional cursor.
DashboardHome (coordinator)
frontend/src/components/dashboard/DashboardHome.tsx
Adds local showAddForm state and an "Add Repository" button; renders AddRepoForm as controlled (isOpen={showAddForm}, onOpenChange={setShowAddForm}) and passes onAddClick={() => setShowAddForm(true)} to RepoList.
Auth: LoginForm (error mapping)
frontend/src/components/auth/LoginForm.tsx
Maps recognized error message substrings (e.g., "email not confirmed", "invalid login credentials") to clearer user-facing messages while preserving other error text.
Auth: SignupForm (email verification UI)
frontend/src/components/auth/SignupForm.tsx
Adds emailSent, resendLoading, resendSuccess; on successful signup shows an animated verification UI instead of navigating; adds resend verification flow, "use different email" action, and back-to-login handling.
AuthContext (resend API)
frontend/src/contexts/AuthContext.tsx
Adds resendVerification(email: string) => Promise<void> to AuthContextType and implements it in the provider (calls supabase.auth.resend with type 'signup').

Sequence Diagrams

sequenceDiagram
    actor User
    participant RepoList as "Repo List"
    participant DashboardHome as "Dashboard Home"
    participant AddRepoForm as "AddRepoForm"

    User->>RepoList: Click empty-state button
    RepoList->>DashboardHome: onAddClick()
    DashboardHome->>DashboardHome: set showAddForm = true
    DashboardHome->>AddRepoForm: isOpen={true}, onOpenChange={setShowAddForm}
    AddRepoForm-->>User: Display modal/form
    User->>AddRepoForm: Submit form
    AddRepoForm->>DashboardHome: onOpenChange(false)
    DashboardHome->>DashboardHome: set showAddForm = false
    AddRepoForm-->>User: Close modal
Loading
sequenceDiagram
    actor User
    participant SignupForm as "Signup Form"
    participant Backend as "Backend Service"
    participant EmailVerif as "Email Verification UI"

    User->>SignupForm: Submit signup
    SignupForm->>Backend: POST /signup
    Backend-->>SignupForm: Success
    SignupForm->>EmailVerif: set emailSent = true
    EmailVerif-->>User: Show verification UI (instructions)
    User->>EmailVerif: Click "Resend" / "Use different email" / "Back to login"
    EmailVerif->>SignupForm: trigger resend/reset/navigation as requested
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I hopped through props and toggled a door,
The list gave a nudge and then asked for more,
An email took flight with a gentle resend,
I nibble the code and bounce back to mend,
Carrots, modals, and joy — my patch is adored 🥕

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main user-facing fixes: empty repo state now opens the add modal, and signup flow requires email verification before login.

✏️ 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: 1

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/RepoList.tsx (1)

122-128: Rules of Hooks violation: useMemo called after conditional returns.

useMemo on line 122 is placed after the early returns on lines 99 and 101-119. React requires hooks to be called in the same order on every render. This will cause runtime errors or unpredictable behavior when the component transitions between empty/loading and populated states.

🐛 Move useMemo before conditional returns
 export function RepoList({ repos, selectedRepo, onSelect, onAddClick, loading }: RepoListProps) {
+  const sortedRepos = useMemo(() => {
+    return [...repos].sort((a, b) => {
+      if (a.status === 'indexed' && b.status !== 'indexed') return -1
+      if (b.status === 'indexed' && a.status !== 'indexed') return 1
+      return (b.file_count || 0) - (a.file_count || 0)
+    })
+  }, [repos])
+
   if (loading) return <RepoGridSkeleton count={3} />
 
   if (repos.length === 0) {
     return (
       <motion.button
         onClick={onAddClick}
         // ... rest of empty state
       </motion.button>
     )
   }
 
-  const sortedRepos = useMemo(() => {
-    return [...repos].sort((a, b) => {
-      if (a.status === 'indexed' && b.status !== 'indexed') return -1
-      if (b.status === 'indexed' && a.status !== 'indexed') return 1
-      return (b.file_count || 0) - (a.file_count || 0)
-    })
-  }, [repos])
-
   return (
     <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
       {sortedRepos.map((repo, index) => (
🤖 Fix all issues with AI agents
In `@frontend/src/components/AddRepoForm.tsx`:
- Around line 20-22: The current controlled/uncontrolled logic misbehaves when
isOpen is provided without onOpenChange because showForm uses isOpen while
setShowForm falls back to setInternalOpen; update the component so that when
isOpen !== undefined and onOpenChange is undefined you either (A) enforce this
at the type level by making onOpenChange required whenever isOpen is passed
(adjust prop types / TS discriminated union to require onOpenChange when isOpen
is present), or (B) add a runtime guard: detect the misconfiguration (isOpen !==
undefined && onOpenChange === undefined) and set setShowForm to a no-op that
calls console.warn (or processLogger) explaining the required pairing, while
ensuring showForm remains driven by isOpen and button/cancel handlers call
onOpenChange if present; reference the variables showForm, setShowForm, isOpen,
onOpenChange, internalOpen, setInternalOpen to locate and update the logic.
🧹 Nitpick comments (3)
frontend/src/components/auth/SignupForm.tsx (1)

95-102: Consider clarifying "try again" behavior or adding resend functionality.

The "try again" button resets to the signup form rather than resending the verification email. Users might expect clicking "try again" to resend the email to the same address. Consider either:

  1. Renaming to "use a different email" for clarity, or
  2. Adding a dedicated "Resend verification email" action that calls the Supabase resend API
frontend/src/components/AddRepoForm.tsx (1)

35-42: Consider hiding the built-in trigger button in controlled mode.

When used in controlled mode (with isOpen/onOpenChange), the parent typically provides its own trigger mechanism. The always-visible "Add Repository" button might be redundant or could cause confusion.

If this dual-trigger behavior is intentional (as it appears to be in DashboardHome), you can disregard this suggestion.

♻️ Optional: hide button in controlled mode
+      {isOpen === undefined && (
        <Button
          onClick={() => setShowForm(true)}
          disabled={loading}
          className="bg-primary hover:bg-primary/90 text-primary-foreground gap-2"
        >
          <Plus className="w-4 h-4" />
          Add Repository
        </Button>
+      )}
frontend/src/components/RepoList.tsx (1)

103-109: Empty state button is clickable but may be a no-op.

When onAddClick is undefined, the button has hover/tap animations and cursor-pointer styling but does nothing on click. Consider either disabling the button or rendering a non-interactive element when onAddClick is not provided.

♻️ Optional: disable button when no handler
       <motion.button
         onClick={onAddClick}
+        disabled={!onAddClick}
         initial={{ opacity: 0 }}
         animate={{ opacity: 1 }}
         whileHover={{ scale: 1.01 }}
         whileTap={{ scale: 0.99 }}
-        className="w-full bg-card border border-dashed border-border hover:border-primary/40 rounded-xl p-16 text-center transition-colors cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary/50"
+        className={`w-full bg-card border border-dashed border-border rounded-xl p-16 text-center transition-colors focus:outline-none focus:ring-2 focus:ring-primary/50 ${onAddClick ? 'hover:border-primary/40 cursor-pointer' : 'cursor-default'}`}
       >

Comment thread frontend/src/components/AddRepoForm.tsx Outdated
- Animated Send icon with spring physics
- Glow effect on icon container
- Staggered fade-in animations for content
- Email displayed in monospace badge
- Better visual hierarchy and spacing
- Move useMemo before conditional returns (React hooks rule violation)
- Disable empty state button when onAddClick handler not provided
- Use discriminated union types for AddRepoForm controlled mode
- Hide trigger button in controlled mode (parent provides trigger)
- Rename 'try again' to 'use a different email' for clarity

@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: 1

🤖 Fix all issues with AI agents
In `@frontend/src/components/auth/SignupForm.tsx`:
- Around line 151-157: The "try again" button currently only toggles emailSent
via setEmailSent(false) which returns users to the signup form without resending
verification; update the behavior so it either triggers the real resend flow or
clearly matches the UI: if you want the minimal fix, change the button to clear
the signup inputs (reset the email/password state variables) and keep
setEmailSent(false) and update the visible copy from "try again" to "Edit email"
or "Go back"; if you prefer to implement resend, call the existing
resendVerificationEmail (or create a new resendVerification function) from the
onClick handler and keep emailSent true while showing appropriate success/error
feedback. Ensure you modify the SignupForm component handlers and reference
setEmailSent, emailSent and the email/password state variables when making this
change.

Comment thread frontend/src/components/auth/SignupForm.tsx Outdated

@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/auth/SignupForm.tsx (1)

19-41: Clear password state after successful signup.
After setEmailSent(true), passwords remain in state and will repopulate if the user goes back. Clearing them avoids retaining sensitive values.

🔧 Proposed fix
     try {
       await signUp(email, password)
       setEmailSent(true)
+      setPassword('')
+      setConfirmPassword('')
     } catch (err: any) {
       setError(err.message || 'Signup failed')
     } finally {

- Add resendVerification to AuthContext using Supabase resend API
- Add proper resend button with loading state in verification screen
- Show success message when email is resent
- Separate 'Resend email' and 'Use different email' actions
- Clear form state when going back to signup form
- Display errors in verification screen

@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: 1

🤖 Fix all issues with AI agents
In `@frontend/src/components/auth/SignupForm.tsx`:
- Around line 25-45: The resend flow leaves stale error state visible across
transitions: update handleResend to clear any existing error at the start
(setError('')), setResendSuccess(false) before awaiting resendVerification, and
clear errors on success (setError('')) so old error messages don't persist after
a successful retry; also ensure handleGoBack clears resend-specific error state
(setResendSuccess(false) and setError('')) to avoid surfacing the resend error
on the main signup form, and disable the “Use different email” action while
resendLoading is true (guard the control/UI using resendLoading) so users cannot
navigate away during an in-flight resend.

Comment thread frontend/src/components/auth/SignupForm.tsx
- Clear error at start of handleResend to remove stale messages
- Clear error on resend success
- Disable 'Use different email' button during resend loading
- Disable 'Back to login' link during resend loading
- Prevents navigation away during in-flight resend request
@vercel

vercel Bot commented Jan 27, 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 27, 2026 1:41am

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