Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThis pull request introduces a series of changes across the Mail application. The updates include the removal of the Changes
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (9)
apps/mail/components/create/selectors/text-buttons.tsx (1)
4-6: Unused imports detected.The imported icons (MessageSquare, FileText, Edit) don't appear to be used in the component. These should be removed to avoid unnecessary code bloat.
-import { - MessageSquare, - FileText, - Edit -} from 'lucide-react' +import { } from 'lucide-react'If the Lucide React package is no longer needed at all, you can remove the import completely.
apps/mail/package.json (2)
59-59: Consider pinning dependency version.Using caret (^) versioning allows minor version updates which could potentially introduce breaking changes, especially with UI libraries like framer-motion.
-"framer-motion": "^12.4.10", +"framer-motion": "12.4.10",Pinning the version ensures consistent behavior across different environments and builds.
82-82: Consider pinning dependency version.Similarly, react-use-measure uses caret versioning which might lead to unexpected behavior if breaking changes are released in minor updates.
-"react-use-measure": "^2.1.7", +"react-use-measure": "2.1.7",apps/mail/components/create/editor-buttons.tsx (1)
4-177: MenuBar component is well-structured but could be more modularThe MenuBar implementation provides comprehensive text formatting options, but the repetitive button patterns could be refactored for better maintainability.
Consider extracting the button patterns into a reusable component to reduce repetition:
+ const MenuButton = ({ + onClick, + disabled, + isActive, + children + }: { + onClick: () => void, + disabled?: boolean, + isActive?: boolean, + children: React.ReactNode + }) => ( + <button + onClick={onClick} + disabled={disabled} + className={isActive ? 'is-active' : ''} + > + {children} + </button> + )This would simplify your formatting buttons and make the code more maintainable.
apps/mail/app/globals.css (1)
204-208: Improved gradient animation with infinite loopThe compose-gradient class now uses an enhanced animation pattern with better background sizing and the new gradient-flow animation.
One suggestion: Consider adding a media query to disable or reduce animations for users who prefer reduced motion:
@media (prefers-reduced-motion) { .compose-gradient { animation: none; background-position: 0% 50%; } }apps/mail/components/onboarding/oboarding-flow.tsx (3)
36-40: Enhance URL parameter handling with better validation.The code correctly retrieves the step parameter from the URL, but consider adding more robust error handling for invalid or malformed URLs, especially since this is used to determine the onboarding flow state.
const searchParams = new URLSearchParams( typeof window !== "undefined" ? window.location.search : "", ); const stepParam = searchParams.get("step"); + // Log or handle malformed URLs + if (typeof window !== "undefined" && window.location.search && !stepParam) { + console.warn("Invalid step parameter in URL"); + }
211-257: Use optional chaining for better code conciseness.The static analysis tool suggests using optional chaining here for better readability.
- {connections && connections.map((connection) => ( + {connections?.map((connection) => ( <div key={connection.id} className="flex items-center justify-between"> {/* rest of the code */} </div> ))}🧰 Tools
🪛 Biome (1.9.4)
[error] 211-257: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
103-374: Consider breaking down the large renderStep function into smaller components.The
renderStepfunction is quite large and handles multiple different steps. Consider breaking it down into separate components for each step to improve readability and maintainability.For example:
// Create separate components const LoginStep = ({ isAuthenticating, setIsAuthenticating }) => ( <motion.div key="login-step" /* animations... */ > {/* Login step content */} </motion.div> ); const ConnectStep = ({ connections, isDialogOpen, setIsDialogOpen, router }) => ( <motion.div key="connect-step" /* animations... */ > {/* Connect step content */} </motion.div> ); // Then in renderStep const renderStep = (step: number) => { switch (step) { case 0: return ( <div className="flex flex-col items-center justify-center"> <LoginStep isAuthenticating={isAuthenticating} setIsAuthenticating={setIsAuthenticating} /> {renderNavigation()} </div> ); // other cases... } };🧰 Tools
🪛 Biome (1.9.4)
[error] 211-257: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/mail/components/create/editor.tsx (1)
95-135: Remove unnecessary comments in the MenuBar component.There are leftover development comments that don't add value to the code and should be removed for clarity.
- // Replace the old setLink function with this new implementation const handleLinkDialogOpen = () => { // If a link is already active, pre-fill the input with the current URL if (editor.isActive("link")) { const attrs = editor.getAttributes("link"); setLinkUrl(attrs.href || ""); } else { setLinkUrl(""); } setLinkDialogOpen(true); }; const handleSaveLink = () => { - // empty if (linkUrl === "") { editor.chain().focus().unsetLink().run(); } else { // Format the URL with proper protocol if missing let formattedUrl = linkUrl; if (formattedUrl && !/^https?:\/\//i.test(formattedUrl)) { formattedUrl = `https://${formattedUrl}`; } // set link editor.chain().focus().setLink({ href: formattedUrl }).run(); } setLinkDialogOpen(false); };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
apps/mail/app/(routes)/mail/layout.tsx(1 hunks)apps/mail/app/(routes)/settings/connections/page.tsx(2 hunks)apps/mail/app/(routes)/settings/layout.tsx(0 hunks)apps/mail/app/api/v1/mail/auth/[providerId]/callback/route.ts(1 hunks)apps/mail/app/globals.css(1 hunks)apps/mail/app/onboarding/page.tsx(1 hunks)apps/mail/components/connection/add.tsx(2 hunks)apps/mail/components/create/editor-buttons.tsx(1 hunks)apps/mail/components/create/editor.css(0 hunks)apps/mail/components/create/editor.tsx(5 hunks)apps/mail/components/create/prosemirror.css(2 hunks)apps/mail/components/create/selectors/text-buttons.tsx(1 hunks)apps/mail/components/onboarding/oboarding-flow.tsx(1 hunks)apps/mail/components/ui/dialog.tsx(2 hunks)apps/mail/components/ui/spinner.tsx(1 hunks)apps/mail/package.json(2 hunks)package.json(1 hunks)
💤 Files with no reviewable changes (2)
- apps/mail/components/create/editor.css
- apps/mail/app/(routes)/settings/layout.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
apps/mail/components/onboarding/oboarding-flow.tsx
[error] 211-257: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (21)
apps/mail/components/create/selectors/text-buttons.tsx (1)
17-26: AI functionality implementation is incomplete.The
handleChatWithAIfunction currently only logs the selected text without implementing the actual AI functionality. Since this is a core feature being introduced, it should either be fully implemented or have a more descriptive TODO comment indicating next steps.Consider enhancing this implementation with actual API calls to your AI service or adding more detailed TODOs about how this will be connected.
apps/mail/app/onboarding/page.tsx (1)
5-7: Component implementation is minimal but correct.The component structure is simple and follows React best practices. It properly exports a default function that returns the OnboardingFlow component.
apps/mail/package.json (1)
59-82:Details
✅ Verification successful
Verify that the new dependencies are being used in the codebase.
Two new dependencies (framer-motion, react-use-measure) have been added to package.json. Ensure they're being used in the codebase to avoid unnecessary dependencies.
🏁 Script executed:
#!/bin/bash # Search for usage of framer-motion and react-use-measure in the codebase echo "=== Searching for framer-motion usage ===" rg -l "from ['\"]framer-motion['\"]" --type tsx --type ts echo "=== Searching for react-use-measure usage ===" rg -l "from ['\"]react-use-measure['\"]" --type tsx --type tsLength of output: 381
Below is an updated script to verify the dependency usage. The previous search failed due to file-type issues with ripgrep; this new script uses the Unix
findcommand to look through all TypeScript files (both *.ts and *.tsx):Next Steps:
Please re-run this script manually to confirm whether these dependencies are actually imported anywhere in the TypeScript code. Once you confirm the output, we can update or resolve the review comment accordingly.
🏁 Script executed:
#!/bin/bash echo "=== Searching for framer-motion usage in .ts/.tsx files ===" find . -type f \( -iname "*.ts" -o -iname "*.tsx" \) -exec grep -H "from ['\"]framer-motion['\"]" {} \; echo "=== Searching for react-use-measure usage in .ts/.tsx files ===" find . -type f \( -iname "*.ts" -o -iname "*.tsx" \) -exec grep -H "from ['\"]react-use-measure['\"]" {} \;Length of output: 987
Dependency usage verified: The search confirms that the new dependencies are actively used in the codebase:
framer-motion is imported in:
apps/mail/components/connection/add.tsxapps/mail/components/onboarding/oboarding-flow.tsxapps/mail/components/ui/spinner.tsxreact-use-measure is imported in:
apps/mail/components/onboarding/oboarding-flow.tsxNo further action is needed for these dependency changes.
apps/mail/app/api/v1/mail/auth/[providerId]/callback/route.ts (1)
62-62: Redirect flow changed from settings to onboarding.The redirect URL has been changed from a settings page with success feedback to an onboarding page. This changes the user flow after authentication.
Ensure that:
- The onboarding page is prepared to handle users coming from an authentication flow
- Any functionality previously available on the settings page post-authentication is now available in the onboarding flow
- Users have a clear path to navigate back to settings if needed
You might want to consider adding a query parameter like
?auth_success=trueto inform the onboarding page about the successful authentication.apps/mail/app/(routes)/mail/layout.tsx (1)
9-9: Padding adjustments in the layout wrapperThe padding has been changed from having uniform padding on all sides (
md:p-3) to only having padding on the top, bottom, and right sides (md:py-3 md:pr-3). This removes the left padding, which could affect how content aligns with the sidebar in medium and larger screens.apps/mail/app/(routes)/settings/connections/page.tsx (2)
21-21: New icon import addedThe
Plusicon has been imported from lucide-react to support the new Add Connection button design.
153-165: Great UI enhancement for Add Connection buttonThe new button design with expand-on-hover effect creates a cleaner interface by default while still providing clear labeling when users interact with it. The implementation using group hover states and transitions is well-crafted.
The transition animation is smooth and intuitive. The overflow handling and absolute positioning ensure the layout doesn't shift during the animation.
apps/mail/components/ui/dialog.tsx (2)
23-23: Enhanced dialog overlay with blur effectAdding
backdrop-blur-smto the dialog overlay creates a more modern, depth-enhancing visual effect that helps focus attention on the dialog content.
40-40: Updated dialog styling for better theming and rounded cornersThe changes to the dialog content include:
- Replacing
bg-backgroundwithbg-offsetLight dark:bg-offsetDarkfor better theme support- Changing from
sm:rounded-2xltorounded-lgfor a more consistent border radiusThese updates improve the dialog's appearance across different themes and screen sizes.
package.json (2)
45-45:Details
❌ Incorrect review comment
Missing animation dependencies in package.json
According to the AI summary, the PR should also include
framer-motionandreact-use-measuredependencies, but they don't appear in this diff section. Make sure these dependencies are properly added since they appear to be needed for animations implemented in the code.
🏁 Script executed:
#!/bin/bash # Check if the dependencies are defined elsewhere or in another package.json grep -r "framer-motion\|react-use-measure" --include="package.json" .Length of output: 187
Animation dependencies already integrated
The
framer-motionandreact-use-measuredependencies are correctly added in theapps/mail/package.jsonfile. The diff in the rootpackage.jsononly showing the update for"@vercel/analytics": "1.5.0"is expected, as these animation libraries are intentionally managed in the mail app’s package configuration. Please disregard the request for adding these dependencies to the rootpackage.json.Likely an incorrect or invalid review comment.
41-44:Details
❓ Verification inconclusive
Added Tiptap rich text editor dependencies
The addition of Tiptap packages suggests implementation of rich text editing features. The chosen versions are aligned, which is good practice.
🌐 Web query:
Are there any known issues with Tiptap 2.11.5 that should be considered?💡 Result:
Tiptap 2.11.5 has several known issues that developers should consider, particularly around specific extensions and behavioral inconsistencies. While generally stable, these issues may impact implementation decisions:
1. Table Extension Validator Conflicts
Recent reports indicate problems with table rendering in strict validation environments, where basic tables get rejected by the validator despite correct syntax[3]. This appears environment-specific but could affect projects using strict content validation rules.2. toggleMark Whitespace Behavior
The core package diverges from ProseMirror's expected behavior by applying marks to leading/trailing whitespace in text selections. This causes inconsistencies when toggling formatting (bold/italic/etc.) compared to native ProseMirror implementations[11].3. Dependency Management Challenges
The React implementation (@tiptap/react 2.11.5) shows:
- 2 outdated dependencies
- 11 total dependencies
While no critical vulnerabilities are reported[12][13], outdated dependencies could lead to compatibility issues in complex projects[1][6].4. Frequent Versioning Considerations
Though not exclusive to 2.11.5, historical patterns show rapid updates sometimes cause peer dependency warnings during upgrades[6]. Developers should implement strict version pinning for critical production environments.For most implementations, these issues are manageable through workarounds like custom validation rules or mark handling logic. The active development status (28k+ GitHub stars, recent issues) suggests ongoing maintenance and responsiveness to reported problems[1][4].
Citations:
- 1: https://cloudsmith.com/navigator/npm/@tiptap/react
- 2: https://community.wappler.io/t/call-for-help-building-tiptap-custom-app-connect-extension/58383
- 3: ueberdosis/tiptap#6103
- 4: https://www.ashbyhq.com/blog/engineering/tiptap-part-1
- 5: https://codesandbox.io/examples/package/@tiptap/starter-kit
- 6: ueberdosis/tiptap#5379
- 7: https://codesandbox.io/examples/package/@tiptap/extension-blockquote
- 8: https://forum.bubble.io/t/rich-text-editor-with-real-time-collaboration-tiptap/238504?page=5
- 9: https://classic.yarnpkg.com/en/package/@tiptap/extension-collaboration-cursor
- 10: https://www.npmjs.com/package/@tiptap/extension-task-item
- 11: ueberdosis/tiptap#6130
- 12: https://security.snyk.io/package/npm/@tiptap%2Fextension-document/2.11.5
- 13: https://security.snyk.io/package/npm/@tiptap%2Fextension-ordered-list/2.11.2
Attention: Tiptap 2.11.5 Known Issues & Testing Advisory
The addition of Tiptap rich text editor dependencies in
package.json(lines 41–44) is noted, and aligning the versions is good practice. However, please be aware of a few known concerns with version 2.11.5:
- Table Extension Validator: In environments with strict validation, there have been reports of valid tables being rejected.
- toggleMark Whitespace Behavior: The handling of leading/trailing whitespace when toggling marks (e.g., bold/italic) may behave unexpectedly compared to ProseMirror’s native behavior.
- Dependency Management: The
@tiptap/reactpackage includes a few outdated dependencies that might result in versioning warnings, even though no critical vulnerabilities are reported at this time.It would be prudent to test these cases in your implementation and consider any necessary workarounds (such as custom table validators or mark handling adjustments) if your project relies on strict content validation or precise text formatting behavior.
apps/mail/components/ui/spinner.tsx (1)
1-41: Well-implemented spinner component with framer-motion animations!The Spinner component is cleanly implemented with proper TypeScript types and default values for props. The animation configuration creates a smooth loading indicator with continuous rotation and path length/opacity transitions.
apps/mail/components/connection/add.tsx (2)
8-16: Good addition of onOpenChange prop for better dialog controlThe onOpenChange prop enables parent components to control the dialog state, enhancing component reusability.
33-75: Excellent use of framer-motion for enhanced UI feedbackThe implementation of animated transitions using framer-motion improves the user experience with smooth, staggered animations. The delay calculation based on index creates a pleasing visual effect.
apps/mail/app/globals.css (1)
192-202: Well-defined gradient animation keyframesThe gradient-flow keyframes create a smooth background animation effect with proper timing.
apps/mail/components/create/editor.tsx (3)
280-284: Good implementation of focusEditor function.The focusEditor function is well-implemented, providing a clean way to focus the editor when needed.
286-296: Clarify the purpose of preventing Enter key propagation.The event handler prevents Enter key propagation even without Shift key. Consider adding a comment explaining why this behavior is needed, or modify it to only prevent default for specific scenarios.
onKeyDown={(e) => { // Prevent form submission on Enter key if (e.key === "Enter" && !e.shiftKey) { e.stopPropagation(); + // Note: This prevents form submission but allows the editor to handle the Enter key } }}Could you verify if this approach correctly prevents form submission while still allowing the editor to create new lines with Enter?
323-324: Good integration of MenuBar component.The MenuBar component is well-integrated into the Editor through the slotBefore prop, providing a clean separation of concerns.
apps/mail/components/create/prosemirror.css (3)
2-6: Consistent styling updates to ProseMirror.The padding and line-height changes help maintain a consistent appearance throughout the editor.
188-207: Good fix for list placeholder issues.The newly added CSS rules effectively address the placeholder display issues in list items, ensuring a better user experience.
209-229: Well-considered spacing adjustments.The spacing and line-height adjustments for list items and paragraphs create a more compact and readable layout while maintaining consistent indentation.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
apps/mail/components/create/editor.tsx (2)
93-134: Well-implemented MenuBar with link handling functionality.The MenuBar component properly uses the Tiptap editor context and implements link management functionality. The pre-filling of URLs and URL formatting logic are well thought out.
However, the
handleSaveLinkfunction has an empty comment that could be removed.const handleSaveLink = () => { - // empty if (linkUrl === "") { editor.chain().focus().unsetLink().run(); } else {
224-256: Well-implemented link dialog with good UX.The link dialog provides a clear interface for adding and managing links. The dialog includes a descriptive header, input field with proper labeling, and action buttons.
Consider adding keyboard handling to allow users to submit the form by pressing Enter.
<Input id="url" value={linkUrl} onChange={(e) => setLinkUrl(e.target.value)} placeholder="https://example.com" + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleSaveLink(); + } + }} />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
apps/mail/components/create/editor.tsx(5 hunks)apps/mail/package.json(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/mail/package.json
🔇 Additional comments (16)
apps/mail/components/create/editor.tsx (16)
3-15: Good addition of relevant icons for the editor toolbar.The import of various icons from
lucide-reactprovides necessary UI elements for the rich text editing features. The chosen icons appropriately represent their respective formatting actions.
25-32: Appropriate use of dialog components for the link functionality.The import of Dialog components from the UI library provides a solid foundation for implementing the link addition feature.
36-36: Good update to the Tiptap import.Adding the
useCurrentEditorimport from@tiptap/reactis essential for accessing the editor instance within the MenuBar component.
41-43: Appropriate imports for the enhanced UI components.The Button and Input components are correctly imported for use in the link dialog, and the Markdown import enables proper markdown support.
45-45: Required useState import added.Adding the useState import is necessary for managing local state in the new MenuBar component.
47-47: Good setup of extensions with Markdown support.The extensions array includes Markdown support, enhancing the editor's capabilities.
136-222: Well-structured formatting toolbar with appropriate UI feedback.The toolbar is well-organized into logical groups (headings, text formatting, lists) with appropriate spacing and visual feedback for active states. The implementation correctly uses the editor API to apply formatting.
259-263: Clean function signature with proper defaults.The Editor component has a clean function signature with appropriate defaults for the placeholder text.
274-274: Good addition of editor reference.Adding a reference to the editor instance allows for programmatic control of the editor outside of Tiptap's internal mechanisms.
278-284: Well-implemented focus handling.The focusEditor function properly checks for the existence of the editor reference before attempting to focus, preventing potential errors.
286-289: Good UX improvement with click-to-focus behavior.Adding the click handler to focus the editor improves user experience by allowing clicks anywhere in the editor container to focus the editor.
291-291: Improved key handling for form submission prevention.The updated condition properly prevents form submission only when Enter is pressed without the Shift key, allowing for line breaks with Shift+Enter.
318-320: Good editor instance storage for external access.Storing the editor instance in the ref allows the focusEditor function and potentially other external functions to access and control the editor.
322-322: Appropriate placement of the MenuBar component.Using the slotBefore prop to insert the MenuBar ensures it appears in the correct position above the editor content.
326-334: Improved key handling in EditorCommand.The updated key handling prevents form submission when pressing Enter, Space, or Spacebar, ensuring that these keys work properly within the command context.
364-365: Good comment update reflecting the UI changes.The comment accurately reflects that only the TextButtons component is being used, which clarifies the intention of the EditorMenu.
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (13)
apps/mail/components/ui/input.tsx (1)
6-9: Fix for controlled/uncontrolled input warningGood improvement to prevent the React warning about switching between controlled and uncontrolled inputs. Consider also handling null values to make the solution more robust.
- const inputValue = value === undefined ? "" : value; + const inputValue = value === undefined || value === null ? "" : value;Also applies to: 17-17
apps/mail/app/(auth)/zero/signup/page.tsx (3)
12-16: Schema validation mismatch with UI labelsThe validation schema refers to the email field as "Username" in the error message, but the UI labels it as "Email". This inconsistency could confuse users.
- email: z.string().min(1, { message: "Username must be at least 1 character" }), + email: z.string().min(1, { message: "Email username must be at least 1 character" }),
112-116: Incorrect login prompt textSince this is a signup page, the text should say "Already have an account?" instead of "Don't have an account?".
- Don't have an account?{" "} + Already have an account?{" "}
91-94: Empty container in password field sectionThere's an empty div with flex layout that doesn't contain any content. This was likely intended for a "Forgot password" link or similar UI element.
Either remove the empty container or add the intended content:
- <div className="flex items-center justify-between"> - <FormLabel className="text-muted-foreground">Password</FormLabel> - - </div> + <FormLabel className="text-muted-foreground">Password</FormLabel>apps/mail/app/(auth)/zero/login/page.tsx (1)
62-86: Add password strength requirements and visual feedback.The password field could benefit from additional feedback to users about password requirements.
Consider adding:
- Visual password strength indicator
- Clear requirements text
- Show/hide password toggle
<FormItem> <div className="flex items-center justify-between"> <FormLabel className="text-muted-foreground">Password</FormLabel> <Link href="/forgot-password" className="text-muted-foreground text-xs hover:text-white" > Forgot your password? </Link> </div> <FormControl> <div className="relative"> <Input type="password" placeholder="••••••••" {...field} className="bg-black text-white" /> + <button + type="button" + onClick={() => { + const input = document.querySelector('input[name="password"]'); + if (input) { + const newType = input.type === 'password' ? 'text' : 'password'; + input.type = newType; + } + }} + className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground" + > + {field.value ? "Show" : "Hide"} + </button> </div> </FormControl> + <p className="text-xs text-muted-foreground mt-1"> + Password must be at least 6 characters + </p> </FormItem>apps/mail/app/(auth)/login/early-access/page.tsx (4)
19-24: Enhance form validation.The current schema validation is minimal. Consider enhancing it to improve user experience and security.
const formSchema = z.object({ - name: z.string().min(1, { message: "Name must be at least 1 character" }), - email: z.string().min(1, { message: "Invalid email address" }), - earlyAccessEmail: z.string().min(1, { message: "Invalid early access email address" }), - password: z.string().min(6, { message: "Password must be at least 6 characters" }), + name: z.string().min(1, { message: "Name must be at least 1 character" }) + .max(50, { message: "Name cannot exceed 50 characters" }), + email: z.string() + .min(1, { message: "Email cannot be empty" }) + .max(30, { message: "Email cannot exceed 30 characters" }) + .regex(/^[a-zA-Z0-9_.-]+$/, { message: "Email can only contain letters, numbers, periods, underscores, and hyphens" }), + earlyAccessEmail: z.string() + .email({ message: "Please enter a valid email address" }), + password: z.string() + .min(6, { message: "Password must be at least 6 characters" }) + .regex(/[A-Z]/, { message: "Password must contain at least one uppercase letter" }) + .regex(/[0-9]/, { message: "Password must contain at least one number" }), });
149-161: Add explanation for "Early access email".It's not immediately clear what the "Early access email" field is for. Add a description or tooltip to explain this field to users.
<FormItem> <FormLabel className="text-muted-foreground">Early access email</FormLabel> + <p className="text-xs text-muted-foreground mb-1"> + The email address where you received your early access invitation. + </p> <FormControl> <Input placeholder="luke@example.com" {...field} className="bg-black text-sm text-white placeholder:text-sm" /> </FormControl> </FormItem>
238-246: Add email copying functionality.In the success screen, it would be helpful to add a "Copy email" button to allow users to easily copy their new email address.
<div className="mb-8"> <h1 className="mb-4 text-4xl font-bold text-white"> Congratulations 🎉 Your email is now: </h1> - <p className="text-primary mb-2 text-2xl font-bold">{userEmail}</p> + <div className="flex items-center justify-center gap-2 mb-2"> + <p className="text-primary text-2xl font-bold">{userEmail}</p> + <button + onClick={() => { + navigator.clipboard.writeText(userEmail); + toast.success("Email copied to clipboard!"); + }} + className="text-muted-foreground hover:text-white" + > + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> + <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /> + </svg> + </button> + </div> <p className="text-muted-foreground text-sm">Stay tuned for our beta release!</p> </div>
63-95: Consider limiting confetti animation.The current confetti animation implementation could potentially cause performance issues on low-end devices. Consider adding a check to limit or disable animations based on device performance.
// Trigger confetti when verified changes to true useEffect(() => { if (verified) { + // Check if the device is potentially low-end + const isLowEndDevice = () => { + // Check if device is mobile + const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); + // Check if browser supports the hardwareConcurrency API + const lowCPUCount = navigator.hardwareConcurrency && navigator.hardwareConcurrency < 4; + return isMobile || lowCPUCount; + }; + + // Reduce particles or skip animation for low-end devices + if (isLowEndDevice()) { + toast.success("Email verified successfully!"); + return; + } + const duration = 3 * 1000; const animationEnd = Date.now() + duration; const randomInRange = (min: number, max: number) => { return Math.random() * (max - min) + min; }; const interval = setInterval(() => { const timeLeft = animationEnd - Date.now(); if (timeLeft <= 0) { return clearInterval(interval); } const particleCount = 50 * (timeLeft / duration); // since particles fall down, start a bit higher than random confetti({ particleCount, startVelocity: 30, spread: 360, origin: { x: randomInRange(0.1, 0.9), y: randomInRange(0, 0.2), }, }); }, 250); return () => clearInterval(interval); } }, [verified]);apps/mail/components/ui/input-otp.tsx (4)
33-59: Consider adding error state handling to InputOTPSlot.The current implementation handles active state, but it might be beneficial to also support error states for validation feedback. This would make the component more robust for form validation scenarios.
const InputOTPSlot = React.forwardRef< React.ElementRef<"div">, - React.ComponentPropsWithoutRef<"div"> & { index: number } + React.ComponentPropsWithoutRef<"div"> & { index: number; hasError?: boolean } >(({ index, className, ...props }, ref) => { const inputOTPContext = React.useContext(OTPInputContext) const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index] + const { hasError } = props; return ( <div ref={ref} className={cn( "relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md", isActive && "z-10 ring-1 ring-ring", + hasError && "border-destructive ring-1 ring-destructive", className )} {...props} >
37-38: Add a safety check for OTPInputContext.It's a good practice to add a safety check when using React context to handle cases where the component might be used outside of its intended context provider.
const InputOTPSlot = React.forwardRef< React.ElementRef<"div">, React.ComponentPropsWithoutRef<"div"> & { index: number } >(({ index, className, ...props }, ref) => { const inputOTPContext = React.useContext(OTPInputContext) + if (!inputOTPContext) { + throw new Error("InputOTPSlot must be used within an InputOTP component") + } const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
61-68: Enhance accessibility for InputOTPSeparator.Adding more detailed ARIA attributes would improve the accessibility of the separator for screen readers.
const InputOTPSeparator = React.forwardRef< React.ElementRef<"div">, React.ComponentPropsWithoutRef<"div"> >(({ ...props }, ref) => ( - <div ref={ref} role="separator" {...props}> + <div ref={ref} role="separator" aria-hidden="true" {...props}> <Minus /> </div> ))
9-23: Add an example JSDoc comment for component usage.Documentation would help other developers understand how to use this component correctly.
+/** + * InputOTP - A component for One-Time Password input fields + * + * @example + * <InputOTP maxLength={6}> + * <InputOTPGroup> + * <InputOTPSlot index={0} /> + * <InputOTPSlot index={1} /> + * <InputOTPSeparator /> + * <InputOTPSlot index={2} /> + * <InputOTPSlot index={3} /> + * </InputOTPGroup> + * </InputOTP> + */ const InputOTP = React.forwardRef< React.ElementRef<typeof OTPInput>, React.ComponentPropsWithoutRef<typeof OTPInput>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
apps/mail/app/(auth)/login/early-access/page.tsx(1 hunks)apps/mail/app/(auth)/login/page.tsx(2 hunks)apps/mail/app/(auth)/signup/page.tsx(0 hunks)apps/mail/app/(auth)/signup/verify/page.tsx(0 hunks)apps/mail/app/(auth)/zero/login/page.tsx(1 hunks)apps/mail/app/(auth)/zero/signup/page.tsx(1 hunks)apps/mail/components/home/navbar.tsx(4 hunks)apps/mail/components/ui/input-otp.tsx(1 hunks)apps/mail/components/ui/input.tsx(1 hunks)apps/mail/tailwind.config.ts(2 hunks)package.json(1 hunks)
💤 Files with no reviewable changes (2)
- apps/mail/app/(auth)/signup/page.tsx
- apps/mail/app/(auth)/signup/verify/page.tsx
🔇 Additional comments (11)
apps/mail/components/home/navbar.tsx (3)
25-34: UI adjustments look good - more compact layoutThe navbar layout has been updated with reduced padding (from px-7/lg:px-20 to px-3/lg:px-4) and smaller logo size (from h-9/w-9 to h-6/w-6), creating a more compact and modern design.
39-44: Class reorganization preserves functionalityThe reorganization of classes in both the Menu component and SheetContent maintain the same behavior while improving code readability.
64-69: Improved Button formattingThe Button component has been formatted with better readability by putting the asChild prop on a separate line, which is a good practice for maintaining clean code.
apps/mail/tailwind.config.ts (1)
94-97: Well-implemented caret blinking animationThe new "caret-blink" animation is properly defined with appropriate opacity transitions and timing. This will create a natural blinking effect that improves user experience when used with input elements.
Also applies to: 131-131
apps/mail/components/ui/input.tsx (1)
14-14: Smooth transition effect addedAdding transition-shadow with duration and easing improves the user experience by making focus state changes appear smoother.
apps/mail/app/(auth)/zero/signup/page.tsx (1)
73-80: Well-implemented email input with domain suffixThe input field with the "@0.email" suffix is well-implemented, providing clear visual feedback to users about the domain they're signing up with.
package.json (1)
41-46:Details
✅ Verification successful
Ensure Tiptap and OTP dependencies are compatible with your project.
The added dependencies suggest the implementation of rich text editing (Tiptap) and OTP input functionality in the application. The version constraints are mixed between exact versions (2.11.5) and compatible versions (^).
🏁 Script executed:
#!/bin/bash # Check npm for compatibility issues and recent vulnerabilities in the added packages echo "Checking for latest versions of added packages:" npm view @tiptap/extension-link version npm view @tiptap/pm version npm view @tiptap/react version npm view @tiptap/starter-kit version npm view input-otp version echo -e "\nChecking for any known vulnerabilities:" npm audit --json @tiptap/extension-link@^2.11.5 @tiptap/pm@2.11.5 @tiptap/react@2.11.5 @tiptap/starter-kit@^2.11.5 input-otp@^1.4.2 2>/dev/null | jq '.vulnerabilities'Length of output: 573
Dependencies and Vulnerability Check Confirmed
The executed verification confirms that the Tiptap and OTP dependencies are correctly set to version 2.11.5 and 1.4.2 respectively, with no reported vulnerabilities. The mix of exact and caret version specifiers does not cause any compatibility issues as the resolved versions are consistent.
apps/mail/app/(auth)/zero/login/page.tsx (2)
43-60: LGTM: Form structure and validation well implemented.The form structure is well implemented with proper validation and field control using react-hook-form and zod. The form layout is clean and accessible with appropriate labels and controls.
92-98: LGTM: Clean signup link implementation.The signup navigation link is well-implemented and properly styled.
apps/mail/app/(auth)/login/page.tsx (1)
6-6:Details
✅ Verification successful
Ensure Navbar component is properly exported from its module.
You've added the Navbar import, but make sure the component is being exported correctly from its module.
🏁 Script executed:
#!/bin/bash # Check if Navbar is properly exported from the module echo "Checking Navbar component exports:" cat $(fd --type file --full-path "components/home/navbar.tsx")Length of output: 4192
Navbar export verified – no changes necessary.
The verification confirms that the
Navbarcomponent is correctly exported as a default export fromapps/mail/components/home/navbar.tsx, matching its import in the login page.apps/mail/components/ui/input-otp.tsx (1)
1-71: Well-structured OTP input components with good TypeScript type definitions.This looks like a well-implemented set of OTP input components that follow React best practices. The components are properly typed and use ref forwarding correctly. Good job on using Context from the input-otp package and adding proper displayNames for better debugging.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (7)
apps/mail/app/(auth)/zero/signup/page.tsx (2)
12-16: Mismatch between field name and validation message.
Your form schema usesemail: z.string().min(1, ...)but the error message states "Username must be at least 1 character." Consider updating the label or leveraging a more precise email validation approach if you truly want an email field.- email: z.string().min(1, { message: "Username must be at least 1 character" }), + email: z.string().min(1, { message: "Email must be at least 1 character" }),
123-139: Review absolute footer positioning.
Usingposition: absolutemay cause overlap issues on smaller viewports and cause the footer to appear above the bottom of the screen. Consider a relative or sticky footer approach instead.apps/mail/app/(auth)/login/login-client.tsx (3)
59-98: Use optional chaining to improve code readabilityThe session check on line 99 could be simplified using optional chaining.
- if (isPending || (session && session.connectionId)) return null; + if (isPending || session?.connectionId) return null;
111-127: Consider using a more specific type thananyIn the
handleProviderClickfunction, you're usingprovider.id as anywhen callingsignIn.social(). Consider defining a proper type for this instead of usinganyto maintain type safety.
315-330: Consider adding version information to the footerThe footer currently includes links to Terms of Service and Privacy Policy. Consider adding version information or a link to the project repository to help with support and transparency.
apps/mail/lib/auth-providers.ts (2)
1-16: Consider using a more specific type for the config propertyThe
configproperty in theProviderConfiginterface is typed asany. Consider defining a more specific interface for each provider's configuration to improve type safety.export interface ProviderConfig { id: string; name: string; requiredEnvVars: string[]; envVarInfo?: EnvVarInfo[]; - config: any; + config: { + clientId?: string; + clientSecret?: string; + prompt?: string; + accessType?: string; + scope?: string[]; + [key: string]: any; + }; required?: boolean; isCustom?: boolean; customRedirectPath?: string; }
75-77: Inconsistent null handling between providersThe GitHub configuration doesn't use non-null assertions, unlike the Google configuration. Consider standardizing the approach for all providers.
config: { - clientId: process.env.GITHUB_CLIENT_ID, - clientSecret: process.env.GITHUB_CLIENT_SECRET, + clientId: process.env.GITHUB_CLIENT_ID || '', + clientSecret: process.env.GITHUB_CLIENT_SECRET || '', },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/mail/app/(auth)/login/login-client.tsx(1 hunks)apps/mail/app/(auth)/login/page.tsx(1 hunks)apps/mail/app/(auth)/zero/login/page.tsx(1 hunks)apps/mail/app/(auth)/zero/signup/page.tsx(1 hunks)apps/mail/lib/auth-providers.ts(1 hunks)apps/mail/lib/auth.ts(2 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
apps/mail/app/(auth)/login/login-client.tsx
[error] 99-99: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (17)
apps/mail/app/(auth)/zero/signup/page.tsx (3)
1-2: Good usage of client directive.
No issues found; everything looks standard for a Next.js Client Component.
27-37: No actual signup logic implemented.
TheonSubmitfunction only displays a toast message and doesn't perform real account creation or authentication. This is a known issue from previous reviews.
39-120: Form structure looks solid.
The usage ofreact-hook-formandzodis consistent and well-structured. Labeling and placeholders are intuitive. Good job on providing descriptive placeholders.apps/mail/lib/auth.ts (1)
9-9: Modular approach for social providers.
Extracting social provider configurations intogetSocialProviders()improves maintainability and reduces clutter in this file. Ensure thatgetSocialProviders()gracefully handles missing or invalid provider configurations.Also applies to: 30-30
apps/mail/app/(auth)/zero/login/page.tsx (3)
1-16: Well-structured imports and schema definition.
Everything looks neat and consistent with the usage ofreact-hook-formandzod.
26-33: Authentication logic is missing.
Similar toSignupZero, the code only shows a toast message instead of actually performing the login. Please integrate the real authentication flow or clarify if it's still a work in progress.
35-121: UI design is clear.
The form fields, placeholders, and styling are coherent with the rest of the app. Good use ofLinkfor password resets and sign-up navigation.apps/mail/app/(auth)/login/page.tsx (1)
1-46: Dynamic provider setup is well-structured.
Combining built-in providers and custom providers intoallProvidersyields a flexible approach. The environment variable checks are thorough.apps/mail/app/(auth)/login/login-client.tsx (5)
36-57: Good implementation of the provider icon mapping functionThe
getProviderIconfunction is well-structured with a clear switch statement and proper fallback handling for unknown providers.
129-136: Well-implemented sorting logic for providersThe sorting logic effectively prioritizes the "Zero" provider first, followed by required providers before non-required ones. This provides a good user experience by highlighting the most important options.
156-270: Good user experience for configuration assistanceThe detailed configuration UI for development environments is well-implemented, with:
- Clear visual indicators for missing configuration
- Collapsible sections for each provider
- Animated transitions for better UX
- Sample environment variable values
- Link to documentation
This will significantly help developers during setup.
272-294: Clear error handling for production environmentsThe simplified error message for production environments appropriately hides implementation details while still informing users about the authentication service unavailability.
296-311:Details
✅ Verification successful
Verify the callbackURL for authentication
The
callbackURLis hardcoded to "/mail" in thehandleProviderClickfunction. Ensure this is the correct redirect path after authentication for all providers.
🏁 Script executed:
#!/bin/bash # Search for other callbackURL references in the codebase rg "callbackURL" --type ts --type tsxLength of output: 65
Attention: Verify Hardcoded callbackURL Usage
The previous search failed due to the TSX file type not being recognized. Please re-run the above script to ensure that the hardcodedcallbackURL(set to"/mail"in thehandleProviderClickfunction) is the intended redirect path across all providers.
🏁 Script executed:
#!/bin/bash # Re-run the search for "callbackURL" in TS and TSX files rg --type-add 'tsx:*.tsx' --type tsx "callbackURL"Length of output: 126
Callback URL Verification
The search confirmed that the only usage ofcallbackURLis inapps/mail/app/(auth)/login/login-client.tsx, where it is hardcoded to"/mail". If this is indeed the intended redirect path for all providers post-authentication, then the implementation is consistent. However, if different providers require unique callback paths, consider parameterizing this value.apps/mail/lib/auth-providers.ts (4)
18-27: Good implementation of custom provider for ZeroThe custom provider for Zero is well-structured with appropriate properties. The empty arrays and objects for
requiredEnvVarsandconfigmake sense as this is handled by a custom redirect.
81-92: Well-implemented provider validation logicThe
isProviderEnabledfunction correctly checks for required environment variables and logs appropriate error messages. The special handling for custom providers is also a good addition.
94-106: Good error handling for required providersThe
getSocialProvidersfunction properly throws an error when required providers are not configured, which will help catch configuration issues early.
69-72:Details
❓ Verification inconclusive
Inconsistent redirect URI paths between providers
The default redirect URI for GitHub points to
/api/auth/callback/github, while Google uses/api/v1/mail/auth/google/callback. Ensure this inconsistency is intentional and properly documented.
🏁 Script executed:
#!/bin/bash # Check for callback URI patterns in the codebase rg "callback" --type ts --type tsx | grep -i "uri\|url"Length of output: 83
Verify Inconsistent Redirect URI Paths for Providers
The GitHub provider’s default redirect URI in
apps/mail/lib/auth-providers.ts(line 69-72) is set to
http://localhost:3000/api/auth/callback/github, while the Google provider (configured elsewhere) appears to use
/api/v1/mail/auth/google/callback. Please confirm whether this discrepancy is intentional. If it is, ensure the rationale is clearly documented.Note: The initial automated search using
rg "callback" --type ts --type tsx | grep -i "uri\|url"resulted in an error regarding an unrecognized file type ("tsx"). Consider re-running the search with a corrected command such as:
#!/bin/bash # Search for callback URI patterns in both .ts and .tsx files using glob filters rg "callback" -g "*.ts" -g "*.tsx" | grep -i "uri\|url"or perform a manual verification to ensure no unintended mismatches exist.
- Confirm specifically whether the different callback URI paths are by design.
- Update documentation or code comments accordingly if the divergence is intentional.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
apps/mail/app/(auth)/login/early-access/page.tsx (3)
111-122:⚠️ Potential issueImplement actual registration logic.
The
onSubmitfunction currently only shows a toast and updates the UI state without actually registering the user. Implement the actual API call to register the user.function onSubmit(values: z.infer<typeof formSchema>) { // Append the @0.email suffix to the username const fullEmail = `${values.email}@0.email`; setUserEmail(fullEmail); + // Show loading toast + const toastId = toast.loading("Creating your account..."); + + // Implement actual registration API call + try { + // Replace with actual API call + // await registerUser({ + // name: values.name, + // email: fullEmail, + // earlyAccessEmail: values.earlyAccessEmail, + // password: values.password + // }); + + toast.success("Signup successful, please verify your email", { id: toastId }); + + // Show verification screen + setShowVerification(true); + } catch (error) { + toast.error("Signup failed", { + id: toastId, + description: error instanceof Error ? error.message : "Please try again" + }); + } - // Use the correct sonner toast API - toast.success("Signup successful, please verify your email"); - - // Show verification screen - setShowVerification(true); // URL will be updated in the useEffect }
399-404:⚠️ Potential issueImplement actual "Resend" functionality.
The "Resend" button currently only shows a toast message but doesn't actually resend the verification code. Implement the actual resend functionality.
<button - onClick={() => toast.info("New code sent!")} + onClick={() => { + const toastId = toast.loading("Sending new code..."); + + // Implement actual resend API call + try { + // Replace with actual API call + // await resendVerificationCode({ + // email: userEmail + // }); + + toast.success("New verification code sent!", { id: toastId }); + } catch (error) { + toast.error("Failed to send new code", { + id: toastId, + description: error instanceof Error ? error.message : "Please try again" + }); + } + }} className="text-primary hover:underline" > Resend </button>
193-205:⚠️ Potential issueImplement actual verification logic and handle the redirect properly.
The
handleVerifyfunction currently doesn't actually verify the code against any backend. Also, the immediate redirect tofunction handleVerify() { if (verificationCode.length === 6) { - setVerified(true); - setVerificationError(false); - toast.success("Email verified successfully!"); - // Redirect to /mail after verification - router.push("/mail"); + // Show loading toast + const toastId = toast.loading("Verifying email..."); + + // Implement actual verification API call + try { + // Replace with actual API call + // await verifyEmail({ + // email: userEmail, + // code: verificationCode + // }); + + toast.success("Email verified successfully!", { id: toastId }); + setVerified(true); + setVerificationError(false); + + // Redirect after a delay to show the success animation + setTimeout(() => { + router.push("/mail"); + }, 3000); // 3 seconds should be enough to see the confetti + } catch (error) { + setVerificationError(true); + toast.error("Verification failed", { + id: toastId, + description: error instanceof Error ? error.message : "Please try again" + }); + } // URL will be updated in the useEffect } else { setVerificationError(true); toast.error("Please enter a valid 6-digit code"); } }
🧹 Nitpick comments (6)
apps/mail/components/ui/input.tsx (1)
17-19: Consider adding accessibility attributes for error states.The visual error state with transition effects is a good UX improvement, but it would be even better with proper accessibility support.
Consider adding the
aria-invalidattribute when in error state to improve screen reader support:<input type={type} className={cn( "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-[#454545] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm transition-shadow duration-300 ease-in-out", error && "ring-2 ring-red-500 ring-offset-1", className, )} value={inputValue} + aria-invalid={error} ref={ref} {...props} />apps/mail/app/(auth)/login/early-access/page.tsx (5)
20-28: Good validation schema, but password requirements should be stronger.The form validation schema is well-structured with clear error messages. However, the password validation only requires 6 characters minimum, which is relatively weak by modern security standards.
Consider strengthening password requirements:
password: z.string().min(6, { message: "Password must be at least 6 characters" }), + // Add more password requirements + password: z + .string() + .min(8, { message: "Password must be at least 8 characters" }) + .refine( + (password) => /[A-Z]/.test(password) && /[a-z]/.test(password) && /[0-9]/.test(password), + { message: "Password must include uppercase, lowercase, and numbers" } + ),
125-191: Refactor error handling for better maintainability.The current error handling approach with a large error message mapping array is verbose and could be difficult to maintain. Consider refactoring to a more concise approach.
- // Handle form errors with toast notifications - const onError = (errors: any) => { - // Define error messages mapping - const errorMessageMap = [ - // Email errors - { - field: "email", - pattern: "@ symbol", - message: "Zero email has to have only letters (a-z), numbers (0-9), and periods (.).", - }, - { - field: "email", - pattern: "required", - message: "Username is required", - }, - // ... many more mappings - ]; - - // Find the first matching error and show toast - for (const [field, fieldError] of Object.entries(errors)) { - const errorMessage = (fieldError as { message?: string })?.message || ""; - - // Find matching error pattern - const matchedError = errorMessageMap.find( - (mapping) => - mapping.field === field && - (mapping.pattern === "" || errorMessage.includes(mapping.pattern)), - ); - - if (matchedError) { - toast.error(matchedError.message); - return; - } - } - - // Fallback for any other errors - toast.error("Please fix the form errors"); - }; + // Handle form errors with toast notifications + const onError = (errors: any) => { + // Get the first error message and display it + const firstError = Object.values(errors)[0] as { message?: string } | undefined; + if (firstError?.message) { + toast.error(firstError.message); + } else { + toast.error("Please fix the form errors"); + } + };
330-387: Improve code modularity and reduce duplication in OTP input slots.The OTP input section has a lot of repeated code for the InputOTPSlot components. Consider extracting this to a helper function or component to reduce duplication.
+ // Create a helper component for OTP slots + const OTPSlot = ({ index, hasError }: { index: number; hasError: boolean }) => ( + <InputOTPSlot + index={index} + className={cn( + "border-input h-12 w-12 bg-black text-lg text-white", + hasError && "ring-2 ring-red-500 ring-offset-1", + )} + /> + ); <InputOTP maxLength={6} value={verificationCode} onChange={(value) => { setVerificationCode(value); // Clear error when user starts typing again if (verificationError) { setVerificationError(false); } }} className="justify-center gap-2" > <InputOTPGroup> - <InputOTPSlot - index={0} - className={cn( - "border-input h-12 w-12 bg-black text-lg text-white", - verificationError && "ring-2 ring-red-500 ring-offset-1", - )} - /> - <InputOTPSlot - index={1} - className={cn( - "border-input h-12 w-12 bg-black text-lg text-white", - verificationError && "ring-2 ring-red-500 ring-offset-1", - )} - /> - ... repeat for other slots + {[0, 1, 2, 3, 4, 5].map((index) => ( + <OTPSlot key={index} index={index} hasError={verificationError} /> + ))} </InputOTPGroup> </InputOTP>
273-276: Improve field change handling to include validation.The current field change handler for email bypasses validation. Consider updating it to properly validate input while typing.
onChange={(e) => { // Just update the field value without showing toast errors const value = e.target.value; - field.onChange(value); + // Prevent @ symbol in username + if (!value.includes('@')) { + field.onChange(value); + } }}
416-426: Improve loading state feedback.The current loading fallback only shows "Loading..." text. Consider implementing a more user-friendly loading state with a spinner or progress indicator.
<Suspense fallback={ <div className="flex h-full min-h-screen w-full items-center justify-center bg-black"> - <div className="text-white">Loading...</div> + <div className="flex flex-col items-center gap-4"> + <div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent"></div> + <div className="text-white">Loading...</div> + </div> </div> } > <EarlyAccessContent /> </Suspense>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/mail/app/(auth)/login/early-access/page.tsx(1 hunks)apps/mail/components/ui/input.tsx(1 hunks)
🔇 Additional comments (5)
apps/mail/components/ui/input.tsx (3)
5-7: Well-structured type definition with error handling support.Adding a dedicated interface for input props with error handling capability is a good TypeScript practice. This makes the component API more explicit and enables proper type checking.
9-13: Good solution for controlled component consistency.The implementation to prevent switching between controlled and uncontrolled states is excellent. By ensuring the value is always defined, you avoid the common React warning about components switching between these states.
22-22: Properly implemented controlled component pattern.Using the derived
inputValueinstead of directly usingvalueensures the component remains consistently controlled, which is the recommended React pattern.apps/mail/app/(auth)/login/early-access/page.tsx (2)
69-101: Good use of useEffect for confetti animation and cleanup.The confetti animation implementation with proper interval cleanup in the effect return function is well done. This prevents memory leaks when the component unmounts.
47-66: Good URL management through URL parameters.The use of URLSearchParams to manage application state in the URL is excellent. It provides a shareable URL and maintains state across page reloads.
This PR includes both an update to creating emails as well as the onboarding page (WIP)
Summary by CodeRabbit
New Features
LoginZeroandSignupZerocomponent for a streamlined user experience.LoginClientfor improved authentication provider management.Style
Refactor