Skip to content

Conversation

@thisisharsh7
Copy link

@thisisharsh7 thisisharsh7 commented Oct 26, 2025

Adds email validation to the team member invitation dialog to prevent invalid email addresses from being submitted.

Problem

Users could submit any text (numbers, special characters, invalid formats) in the email field, causing failed invitations.

Fixes

  • Added email validation with regex pattern
  • Disabled submit button when email is empty or invalid
  • Added validation check before API call

Summary by CodeRabbit

  • Bug Fixes
    • Email validation now prevents invalid submissions in the invite dialog.
    • Inline error messages display when email format is incorrect.
    • Invite button becomes disabled when email is empty, invalid, or while an invite is pending.
    • Dialog form state automatically resets when the dialog opens or closes.

@vercel
Copy link

vercel bot commented Oct 26, 2025

@thisisharsh7 is attempting to deploy a commit to the Agentset Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Oct 26, 2025

Walkthrough

Added client-side email validation to an invite dialog component. Implemented email validation utility, error state management, form reset on dialog close, enhanced email input with validation feedback, and button disable logic based on validation state.

Changes

Cohort / File(s) Summary
Email Validation in Invite Dialog
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx
Added isValidEmail utility and emailError state; implemented client-side email validation in handleInvite; created handleOpenChange to reset form state on dialog close; enhanced email input with type, onChange handler, and conditional error styling; added inline error message display; disabled Invite button when email is empty, invalid, or invite is pending

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Dialog
    participant Handler
    participant Validator
    participant UI

    User->>Dialog: Opens invite dialog
    Dialog->>Handler: onOpenChange triggered
    Handler->>UI: Reset email, emailError, role

    User->>UI: Types email
    UI->>Handler: onChange triggered
    Handler->>Validator: isValidEmail(email)
    Validator-->>Handler: valid/invalid result
    Handler->>UI: Update email & emailError state
    UI->>UI: Show/hide error message & update border

    User->>UI: Clicks Invite button
    alt Email Valid
        Handler->>Handler: Proceed with invite
    else Email Invalid
        UI->>User: Button disabled, error shown
    end

    User->>Dialog: Closes dialog
    Dialog->>Handler: onOpenChange triggered
    Handler->>UI: Reset form state
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

  • Single file modification with focused, cohesive changes
  • Email validation logic is straightforward and follows standard patterns
  • Form state management and UI updates are conventional implementations
  • No complex interdependencies or branching logic

Poem

🐰 A fuzzy tale of validation,
Email checks bring celebration!
Form resets when dialogs close,
Errors vanish, success flows.
Validation guards the way—
Clean invites, hip-hop hooray! 🎉

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "fix: Add email validation to invite member form" is directly aligned with the PR's primary objective and the changes made. The title clearly identifies the main change: email validation is being added to the invite member form/dialog. This is supported by the raw summary, which shows the implementation of email validation logic including an isValidEmail utility, client-side validation in handleInvite, form state management, and UI enhancements to display validation errors and disable the button when appropriate. The title is concise, uses specific terminology ("email validation" and "invite member form"), and avoids generic or vague language.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx (2)

79-84: Validation logic is duplicated.

The email validation check here duplicates the logic in the onChange handler (lines 136-140). This creates maintenance burden and potential inconsistency.

If adopting Zod as suggested, this validation would be centralized. Otherwise, extract the validation logic to avoid duplication:

  const handleInvite = () => {
-    
    if (!email || !isValidEmail(email)) {
      setEmailError("Please enter a valid email address");
      return;
    }

128-146: Inline validation provides good UX but could be simplified.

The immediate validation feedback on keystroke is good for user experience. However, this manual approach with conditional styling and error state management would be significantly simplified by using react-hook-form with Zod, which provides:

  • Automatic error message rendering
  • Built-in styling hooks
  • Centralized validation logic
  • Better accessibility attributes

As per coding guidelines

With react-hook-form, this would become:

<FormField
  control={form.control}
  name="email"
  render={({ field }) => (
    <FormItem>
      <FormLabel>Email</FormLabel>
      <FormControl>
        <Input type="email" placeholder="Email" {...field} />
      </FormControl>
      <FormMessage />
    </FormItem>
  )}
/>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 357afc9 and 1099451.

📒 Files selected for processing (1)
  • apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx (5 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/nextjs.mdc)

apps/web/**/*.{ts,tsx}: Place static content (consts) and TypeScript interfaces at the end of the file
Minimize use of useEffect and setState
Use Zod for form validation
Minimize client-side state
Prefer server state when possible

Import UI components from the @agentset/ui alias instead of relative paths

Files:

  • apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Use kebab-case for file names (e.g., auth-provider.tsx, user-settings.ts)

Files:

  • apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Use package import aliases (e.g., @agentset/ui) and avoid relative paths into other packages

Files:

  • apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx
apps/web/src/**

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Organize the web app by feature, then by type under src/{app,components,lib,hooks,types,services}

Files:

  • apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx
🧬 Code graph analysis (1)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx (1)
apps/web/src/hooks/use-organization.ts (1)
  • useOrganization (5-33)
🔇 Additional comments (3)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx (3)

99-107: Good: Form state reset on dialog close.

Properly resets all form fields and error state when the dialog closes, preventing stale data on subsequent opens.

Note: Using react-hook-form would simplify this to a single reset() call.


110-110: LGTM: Dialog properly wired for state management.


163-169: LGTM: Button correctly disabled during validation and loading states.

The disable logic properly prevents submission when the email is empty, invalid, or when an invite is already in progress.

Comment on lines +33 to +38
// Email validation helper
const isValidEmail = (email: string): boolean => {
if (!email) return false;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use Zod for validation and move static content to end of file.

This implementation violates two coding guidelines:

  1. Form validation: The guidelines specify "Use Zod for form validation" for files matching apps/web/**/*.{ts,tsx}. Using regex for email validation is fragile and doesn't provide the type safety and composability that Zod offers.

  2. Code organization: The guidelines require "Place static content (consts) and TypeScript interfaces at the end of the file" for files in apps/web/**/*.{ts,tsx}.

As per coding guidelines

Consider refactoring to use Zod with react-hook-form for better validation and error handling:

+import { z } from "zod";
+import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+
+const inviteSchema = z.object({
+  email: z.string().email("Please enter a valid email address"),
+  role: z.enum(["admin", "member"]),
+});
+
+type InviteFormData = z.infer<typeof inviteSchema>;

Then move any remaining static helpers to the end of the file, after the component definition.

Committable suggestion skipped: line range outside the PR's diff.


const [email, setEmail] = useState("");
const [role, setRole] = useState("member");
const [emailError, setEmailError] = useState("");
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Manual error state increases complexity.

This manual error state contradicts the guideline to "Minimize client-side state." Using Zod with react-hook-form would eliminate the need for this separate state variable, as the form library manages validation state internally.

As per coding guidelines

🤖 Prompt for AI Agents
In apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/team/invite-dialog.tsx
around line 46, the component uses a manual emailError useState which duplicates
validation state; replace this with react-hook-form + Zod validation: define a
Zod schema for the email field, pass zodResolver(schema) into useForm, remove
the emailError state and any manual setEmailError calls, and rely on
formState.errors.email to show validation messages and control submit flow so
validation is centralized and client state minimized.

@ahmedriad1
Copy link
Member

@thisisharsh7 The fix got merged in better-auth, thanks a lot for spotting it!

@ahmedriad1 ahmedriad1 closed this Oct 27, 2025
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.

2 participants