Skip to content

Conversation

@PunGrumpy
Copy link
Owner

@PunGrumpy PunGrumpy commented Apr 8, 2025

This pull request includes significant updates to the authentication and password management features, as well as some UI adjustments. The most important changes include the addition of forgot password and reset password functionalities, integration of email services for password reset and email verification, and minor layout improvements.

Authentication and Password Management:

  • Added forgot password functionality with a new component ForgotPassword and its associated schema (apps/web/app/(unauthenticated)/forgot-password/forgot-password.tsx, apps/web/app/(unauthenticated)/forgot-password/schema.ts). [1] [2]
  • Implemented reset password functionality with a new component ResetPassword and its associated schema (apps/web/app/(unauthenticated)/reset-password/reset-password.tsx, apps/web/app/(unauthenticated)/reset-password/schema.ts). [1] [2]
  • Updated the signup schema to include password confirmation (apps/web/app/(unauthenticated)/signup/schema.ts, apps/web/app/(unauthenticated)/signup/signup.tsx). [1] [2]

Email Integration:

  • Integrated email services for sending password reset and verification emails using the resend library (packages/email/index.ts, packages/auth/server.ts). [1] [2]

UI Adjustments:

  • Modified the header and various layout components to improve the user interface (apps/web/app/(unauthenticated)/components/header.tsx, apps/web/app/(unauthenticated)/layout.tsx). [1] [2]
  • Added a "Forgot password?" link to the login page (apps/web/app/(unauthenticated)/login/email/login-email.tsx).

Environment Configuration:

  • Updated environment configuration to include new email-related keys (apps/web/.env.example, apps/web/lib/env.ts). [1] [2]

These changes enhance the user experience by providing essential password management features and improving the overall layout and usability of the application.

Summary by CodeRabbit

  • New Features

    • Introduced "Forgot Password" and "Reset Password" flows with robust form handling and validation.
    • Added new email templates for password reset, verification, and contact notifications.
    • Enhanced the sign-up experience by incorporating a confirm password field.
  • Style

    • Streamlined header and login layouts for a more consistent and polished user interface.
    • Enabled a disabled state for password input fields for improved usability.
  • Chores

    • Configured additional environment settings to support enhanced email functionality.

…rification templates

- Added email package with templates for password reset and email verification.
- Integrated email sending functionality in the auth module for password reset and verification emails.
- Updated environment configuration to include email-related keys.
- Created new Forgot Password and Reset Password pages in the web app with corresponding forms and validation.
- Enhanced existing signup and login forms to include password confirmation validation.
@PunGrumpy PunGrumpy added the enhancement New feature or request label Apr 8, 2025
@PunGrumpy PunGrumpy self-assigned this Apr 8, 2025
@vercel
Copy link

vercel bot commented Apr 8, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
blackhead-api ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 8, 2025 7:40pm
blackhead-web ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 8, 2025 7:40pm

@coderabbitai
Copy link

coderabbitai bot commented Apr 8, 2025

Walkthrough

The changes add new email-related environment variables and update various authentication components. New forgot password and reset password components are introduced with form validation via react-hook-form and zod. The UI components are adjusted to streamline button properties and layout structures. The authentication client now exposes additional password management methods. A new email package is established offering templates for contact, password reset, and verification emails, while the auth server’s configuration gains email functionality improvements. Minor adjustments to the signup process and UI components (e.g., password input disable prop) complete the update.

Changes

File(s) Change Summary
apps/web/.env.example Added new environment variables (RESEND_FROM, RESEND_TOKEN) initialized as empty strings.
apps/web/app/(unauthenticated)/components/header.tsx Removed size="sm" prop from two Button components, simplifying their declarations.
apps/web/app/(unauthenticated)/forgot-password/* Introduced new ForgotPassword component with form handling, added page for dynamic import, and defined zod schema for email validation.
apps/web/app/(unauthenticated)/reset-password/* Added new ResetPassword component with form validation and token handling, new page for dynamic import, and a zod schema for password and confirmPassword validation.
apps/web/app/(unauthenticated)/login/email/login-email.tsx
apps/web/app/(unauthenticated)/login/login.tsx
Updated JSX layout in login components; restructured container elements and changed navigation link text from "Other Login Options" to "Forgot password?" and adjusted CSS classes.
apps/web/app/(unauthenticated)/signup/* Modified signup form and schema by adding a confirmPassword field with a refinement to ensure password matching, and updated default form values.
apps/web/app/(unauthenticated)/layout.tsx Wrapped children prop in a new <main> element with updated styling for layout organization.
apps/web/lib/env.ts
apps/web/package.json
Updated environment configuration to include email keys and added dependency "@repo/email": "*" to the project.
packages/auth/* (client.ts, keys.ts, package.json, server.ts) Expanded the authentication client to include forgetPassword and resetPassword, updated keys import to use @repo/email/keys, added dependency "@repo/email": "*", and enhanced email handling in the server with email verification and password reset functionalities.
packages/email/** (index.ts, keys.ts, package.json, templates/*, tsconfig.json) Introduced a new email package with a Resend instance, defined environment keys for email, created package configuration, and added multiple email templates (contact, password-reset, verification) along with a tsconfig file.
packages/ui/components/password-input.tsx Added an optional disabled property to the PasswordInput component, enabling the input and toggle button to be rendered in a non-interactive state.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant F as ForgotPassword Component
    participant A as AuthClient (forgetPassword)
    
    U->>F: Enter email & submit form
    F->>A: Call forgetPassword(email, redirectURL)
    alt Success
      A-->>F: Return success
      F->>U: Display success message
    else Error
      A-->>F: Return error
      F->>U: Display error alert
    end
Loading
sequenceDiagram
    participant U as User
    participant R as ResetPassword Component
    participant A as AuthClient (resetPassword)
    
    U->>R: Submit new password & confirm password
    R->>A: Call resetPassword(token, newPassword)
    alt Success
      A-->>R: Return success
      R->>U: Show success message and redirect to login
    else Error
      A-->>R: Return error
      R->>U: Display error message
    end
Loading

Poem

I'm a rabbit hopping through new code trails,
With buttons and forms now light as sails.
Passwords reset and emails sent anew,
Each change a hop in a world so true.
My whiskers twitch in joyful, coding delight,
In CodeRabbit land, everything feels just right! 🐰✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88c1186 and 23ead0a.

📒 Files selected for processing (1)
  • .github/labeler.yml (2 hunks)
🔇 Additional comments (2)
.github/labeler.yml (2)

5-8: Analytics Section Addition
The new analytics section is correctly added. The changed-files pattern 'packages/analytics/**' is consistent with the existing label configuration and will efficiently capture any changes within the analytics package.


17-20: Email Section Addition
The email section is properly defined with the changed-files pattern 'packages/email/**'. This addition enhances the labeler's coverage by tracking changes in the email package, aligning well with the PR’s objectives regarding email functionality improvements.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added app Changes in the main application auth Changes in the authentication system ui Changes in the user interface labels Apr 8, 2025
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: 4

🧹 Nitpick comments (4)
apps/web/.env.example (1)

6-7: Good addition of email environment variables

The environment variables for Resend have been properly added. Consider adding brief comments to explain the expected format for these variables (especially that RESEND_FROM should be a valid email address).

 # Server
 BETTER_AUTH_SECRET=""
 DATABASE_URL=""
 GOOGLE_CLIENT_ID=""
 GOOGLE_CLIENT_SECRET=""
-RESEND_FROM=""
-RESEND_TOKEN=""
+# Email address that will appear as the sender (e.g., "no-reply@yourdomain.com")
+RESEND_FROM=""
+# API token from Resend dashboard
+RESEND_TOKEN=""
 BETTERSTACK_API_KEY=""
packages/auth/client.ts (1)

5-12: Enhanced authentication API with password management

Good addition of forgetPassword and resetPassword functions to support the new password management features.

Minor naming suggestion: Consider renaming forgetPassword to forgotPassword as it's more commonly used in authentication flows and would improve developer experience.

apps/web/app/(unauthenticated)/reset-password/reset-password.tsx (1)

23-42: Well-implemented token validation and redirection.

The component correctly validates the presence of a token and redirects users when no token is found. However, users might be confused by the sudden redirection.

Consider adding a brief explanatory message before redirecting, or using a toast notification to inform users why they're being redirected.

  // Redirect if no token is present
  if (!token) {
+   // Show a message briefly before redirecting
+   setGeneralError('No reset token found. Redirecting to login page...');
+   setTimeout(() => {
      router.push('/login')
+   }, 1500);
    return null
  }
packages/email/templates/password-reset.tsx (1)

95-100: Fix typo in example email address.

There's a typo in the example email address used in the demo component.

-    email="exmaple@blackhead.com"
+    email="example@blackhead.com"
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58ae999 and 88c1186.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (27)
  • apps/web/.env.example (1 hunks)
  • apps/web/app/(unauthenticated)/components/header.tsx (1 hunks)
  • apps/web/app/(unauthenticated)/forgot-password/forgot-password.tsx (1 hunks)
  • apps/web/app/(unauthenticated)/forgot-password/page.tsx (1 hunks)
  • apps/web/app/(unauthenticated)/forgot-password/schema.ts (1 hunks)
  • apps/web/app/(unauthenticated)/layout.tsx (1 hunks)
  • apps/web/app/(unauthenticated)/login/email/login-email.tsx (1 hunks)
  • apps/web/app/(unauthenticated)/login/login.tsx (1 hunks)
  • apps/web/app/(unauthenticated)/reset-password/page.tsx (1 hunks)
  • apps/web/app/(unauthenticated)/reset-password/reset-password.tsx (1 hunks)
  • apps/web/app/(unauthenticated)/reset-password/schema.ts (1 hunks)
  • apps/web/app/(unauthenticated)/signup/schema.ts (1 hunks)
  • apps/web/app/(unauthenticated)/signup/signup.tsx (3 hunks)
  • apps/web/lib/env.ts (1 hunks)
  • apps/web/package.json (1 hunks)
  • packages/auth/client.ts (1 hunks)
  • packages/auth/keys.ts (1 hunks)
  • packages/auth/package.json (1 hunks)
  • packages/auth/server.ts (2 hunks)
  • packages/email/index.ts (1 hunks)
  • packages/email/keys.ts (1 hunks)
  • packages/email/package.json (1 hunks)
  • packages/email/templates/contact.tsx (1 hunks)
  • packages/email/templates/password-reset.tsx (1 hunks)
  • packages/email/templates/verification.tsx (1 hunks)
  • packages/email/tsconfig.json (1 hunks)
  • packages/ui/components/password-input.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (16)
apps/web/app/(unauthenticated)/forgot-password/page.tsx (1)
apps/web/app/(unauthenticated)/forgot-password/forgot-password.tsx (1)
  • ForgotPassword (22-102)
packages/email/keys.ts (1)
packages/auth/keys.ts (1)
  • keys (5-29)
apps/web/app/(unauthenticated)/reset-password/schema.ts (2)
apps/web/app/(unauthenticated)/signup/schema.ts (1)
  • formSchema (6-19)
packages/ui/lib/password-validation.ts (1)
  • passwordSchema (14-22)
apps/web/app/(unauthenticated)/reset-password/page.tsx (1)
apps/web/app/(unauthenticated)/reset-password/reset-password.tsx (1)
  • ResetPassword (23-136)
apps/web/app/(unauthenticated)/forgot-password/schema.ts (2)
apps/web/app/(unauthenticated)/reset-password/schema.ts (1)
  • formSchema (4-14)
apps/web/app/(unauthenticated)/signup/schema.ts (1)
  • formSchema (6-19)
packages/auth/keys.ts (1)
packages/email/keys.ts (1)
  • keys (4-14)
apps/web/lib/env.ts (4)
apps/api/lib/env.ts (1)
  • env (7-12)
packages/analytics/posthog/server.ts (1)
  • analytics (6-12)
packages/auth/server.ts (1)
  • auth (10-73)
packages/database/index.ts (1)
  • database (11-11)
apps/web/app/(unauthenticated)/signup/signup.tsx (2)
packages/ui/components/ui/form.tsx (5)
  • FormField (166-166)
  • FormItem (161-161)
  • FormLabel (162-162)
  • FormControl (163-163)
  • FormMessage (165-165)
packages/ui/components/password-input.tsx (1)
  • PasswordInput (17-194)
apps/web/app/(unauthenticated)/login/email/login-email.tsx (5)
packages/ui/components/ui/alert.tsx (1)
  • Alert (66-66)
packages/ui/components/ui/form.tsx (6)
  • Form (160-160)
  • FormField (166-166)
  • FormItem (161-161)
  • FormLabel (162-162)
  • FormControl (163-163)
  • FormMessage (165-165)
packages/ui/components/ui/input.tsx (1)
  • Input (21-21)
packages/ui/components/password-input.tsx (1)
  • PasswordInput (17-194)
packages/ui/components/ui/button.tsx (1)
  • Button (59-59)
apps/web/app/(unauthenticated)/signup/schema.ts (2)
apps/web/app/(unauthenticated)/reset-password/schema.ts (1)
  • formSchema (4-14)
packages/ui/lib/password-validation.ts (1)
  • passwordSchema (14-22)
apps/web/app/(unauthenticated)/reset-password/reset-password.tsx (4)
apps/web/app/(unauthenticated)/reset-password/schema.ts (1)
  • formSchema (4-14)
packages/ui/components/ui/alert.tsx (1)
  • Alert (66-66)
packages/ui/components/ui/form.tsx (6)
  • Form (160-160)
  • FormField (166-166)
  • FormItem (161-161)
  • FormLabel (162-162)
  • FormControl (163-163)
  • FormMessage (165-165)
packages/ui/components/ui/button.tsx (1)
  • Button (59-59)
apps/web/app/(unauthenticated)/forgot-password/forgot-password.tsx (5)
apps/web/app/(unauthenticated)/forgot-password/schema.ts (1)
  • formSchema (3-5)
packages/ui/components/ui/alert.tsx (1)
  • Alert (66-66)
packages/ui/components/ui/form.tsx (5)
  • Form (160-160)
  • FormItem (161-161)
  • FormLabel (162-162)
  • FormControl (163-163)
  • FormMessage (165-165)
packages/ui/components/ui/input.tsx (1)
  • Input (21-21)
packages/ui/components/ui/button.tsx (1)
  • Button (59-59)
packages/email/templates/password-reset.tsx (2)
apps/web/components/section.tsx (1)
  • Section (19-37)
packages/ui/components/ui/button.tsx (1)
  • Button (59-59)
packages/email/templates/verification.tsx (2)
apps/web/components/section.tsx (1)
  • Section (19-37)
packages/ui/components/ui/button.tsx (1)
  • Button (59-59)
packages/email/templates/contact.tsx (1)
apps/web/components/section.tsx (1)
  • Section (19-37)
packages/auth/server.ts (4)
packages/email/index.ts (1)
  • resend (4-4)
packages/email/keys.ts (1)
  • keys (4-14)
packages/email/templates/password-reset.tsx (1)
  • PasswordResetEmail (20-93)
packages/email/templates/verification.tsx (1)
  • VerificationEmail (20-89)
🔇 Additional comments (57)
packages/auth/package.json (1)

18-18: New dependency added for email functionality

Adding @repo/email as a dependency aligns with the PR's objective to implement email services for password reset and verification. This is an appropriate change as the auth package will now use email functionality.

packages/email/keys.ts (1)

1-14: Well-structured environment validation for Resend email service

The environment variables required for the Resend email service are properly defined and validated:

  • RESEND_FROM is validated as a non-empty email string
  • RESEND_TOKEN is validated as a non-empty string starting with 're_' (Resend's token format)

This implementation is consistent with the pattern used in other parts of the application, like packages/auth/keys.ts.

packages/email/tsconfig.json (1)

1-8: Standard TypeScript configuration for the new email package

This TypeScript configuration appropriately extends the base configuration and sets up the compiler options needed for the new email package. The includes and excludes are properly configured to handle all TypeScript files in the directory.

apps/web/lib/env.ts (2)

4-4: Import added for email environment keys

The new import for email keys from @repo/email/keys is correctly added to support the email functionality being implemented in this PR.


9-9: Extension order changed while adding email environment

While adding the email environment extension is necessary, note that the ordering of extensions has been changed from the original. The new order places analytics() before auth() (previously it was after), with email() added at the end.

This reordering could potentially affect how environment variables are merged or overridden if there are any conflicts between these different configurations.

Please verify that no environment variables in these different configurations would conflict in a way that the new ordering would change the expected behavior.

packages/email/index.ts (1)

1-4: Clean implementation of the email client

Good job setting up the Resend client with proper separation of concerns. The implementation correctly retrieves the token from a separate configuration module and exports the initialized client for use throughout the application.

apps/web/package.json (1)

17-17: Correctly added email package dependency

The addition of the @repo/email package dependency is appropriate for implementing the email functionality in the web application.

apps/web/app/(unauthenticated)/forgot-password/schema.ts (1)

1-5: Well-defined schema for forgot password

The schema correctly validates the email field using Zod, following the same pattern as other form schemas in the application. The implementation is appropriately minimal for the forgot password functionality, requiring only a valid email address.

apps/web/app/(unauthenticated)/forgot-password/page.tsx (1)

1-9: Clean implementation of the ForgotPassword page with dynamic import.

The implementation follows Next.js best practices by using dynamic imports for code splitting, which improves initial page load performance by only loading the component when needed. The structure is clean and follows a proper separation of concerns by keeping the page component separate from the implementation.

apps/web/app/(unauthenticated)/reset-password/page.tsx (1)

1-9: Well-structured ResetPassword page with consistent pattern.

The implementation maintains consistency with the ForgotPassword page pattern, using dynamic imports correctly for code splitting. This approach ensures better performance and maintainability across the authentication-related pages.

apps/web/app/(unauthenticated)/layout.tsx (1)

25-27: Good improvement to layout structure with semantic HTML.

Adding the <main> element improves semantic HTML structure while providing consistent layout styling for all unauthenticated pages. The flexbox styling ensures that content properly fills the available space and maintains consistent vertical alignment across different authentication-related pages.

apps/web/app/(unauthenticated)/login/login.tsx (1)

10-10: Good refactoring of layout responsibilities.

The className changes appropriately remove positioning and height constraints that are now handled by the parent layout component. This refactoring creates better separation of concerns where the layout component manages the overall container constraints while this component focuses on its specific layout needs.

packages/ui/components/password-input.tsx (4)

13-14: Good addition of the disabled prop to PasswordInputProps

Adding this prop enhances the component's flexibility and makes it more consistent with standard form input behavior.


18-19: Appropriate default value for the disabled prop

Setting disabled = false as default ensures backward compatibility with existing usage of the component.


98-99: Correctly applying disabled state to the Input component

This ensures the input field respects the disabled state passed from parent components.


107-108: Well-implemented disabled state for the visibility toggle button

Good implementation that ensures both the input field and its associated visibility toggle button are disabled together, maintaining proper accessibility and user experience.

apps/web/app/(unauthenticated)/reset-password/schema.ts (3)

1-3: Good imports for form schema validation

Properly importing the reusable passwordSchema promotes code reuse across the application.


4-10: Well-structured password reset form schema

The schema properly validates both the password and confirmation fields. Using the existing passwordSchema ensures consistent password requirements across the application.


11-14: Excellent password matching validation with targeted error

The refinement correctly ensures passwords match and provides a clear error message. The path: ['confirmPassword'] properly targets the error to the confirmPassword field, which improves user experience by showing the error in the right location.

packages/email/package.json (5)

1-5: Good package configuration for the new email module

The package is properly named following the repo's naming convention, and marked as private to prevent accidental publishing.


5-9: Well-organized exports structure

The exports configuration clearly defines the module's public API, making it easy for other packages to import and use the email functionality.


10-15: Comprehensive scripts for email development

The scripts provide all necessary commands for development, building, and type checking of the email templates.


24-30: Well-configured development dependencies

The devDependencies include all necessary tools for TypeScript development and email template creation.


16-23:

Details

✅ Verification successful

Verify React version compatibility

The package uses React 19.1.0, which is a very recent version. Ensure this is compatible with other packages in the monorepo.


🏁 Script executed:

#!/bin/bash
# Check React versions across the monorepo
echo "Checking React versions across packages:"
find . -name "package.json" -not -path "*/node_modules/*" -exec grep -l "\"react\":" {} \; | xargs grep -A 1 "\"react\":"

Length of output: 896


React Version Compatibility Confirmed

After verifying the React versions across the monorepo, all packages—including packages/email/package.json—consistently use React ^19.1.0. No further action is required.

apps/web/app/(unauthenticated)/signup/schema.ts (2)

6-15: Enhanced signup schema with password confirmation

The updated schema now properly validates password confirmation, improving user security and reducing user errors during signup.


16-19: Consistent implementation of password matching validation

This refinement uses the same pattern as in the reset-password schema, ensuring consistent behavior across similar forms. The targeted error path improves the user experience by showing errors in the right location.

apps/web/app/(unauthenticated)/signup/signup.tsx (3)

34-35: Password confirmation field added

Good addition of the confirmPassword field to the form's default values. This follows security best practices by requiring users to enter their password twice to prevent typos.


63-63: UI layout adjustment looks good

The flex container's class adjustments create a more consistent layout that centers the signup form appropriately.


131-143:

Details

✅ Verification successful

Password confirmation field implementation is complete

The implementation of the confirmPassword field follows the same pattern as other form fields, maintaining consistency in the UI. The PasswordInput component is appropriately reused without the strength indicator for the confirmation field.

However, verify that the schema validation (not shown here) properly ensures the confirmation matches the original password:


🏁 Script executed:

#!/bin/bash
# Check if the schema properly validates password matching
grep -A 10 "confirmPassword" apps/web/app/\(unauthenticated\)/signup/schema.ts

Length of output: 310


Schema validation and field implementation verified

  • The confirmPassword field in apps/web/app/(unauthenticated)/signup/signup.tsx is implemented consistently with other form fields.
  • The validation schema in apps/web/app/(unauthenticated)/signup/schema.ts correctly enforces matching passwords using a .refine check with the appropriate error message.

No further changes are required.

packages/auth/keys.ts (1)

1-1:

Details

✅ Verification successful

Email configuration integration

The change from core keys to email keys properly integrates the email functionality into the authentication system. This enables password reset and verification emails.

The imported email configuration correctly validates essential fields:

  • RESEND_FROM: Validates it's a proper email
  • RESEND_TOKEN: Validates the token format starts with 're_'

Verify that these environment variables are properly documented in the project's README or .env.example files:

Also applies to: 7-7


🏁 Script executed:

#!/bin/bash
# Check if the email environment variables are documented
grep -r "RESEND_" --include="*.md" --include="*.env*" .

Length of output: 134


Email configuration integration approved

The change from core keys to email keys successfully integrates the email functionality (supporting password reset and verification emails) into the authentication system. The validations for both RESEND_FROM (ensuring it's a valid email) and RESEND_TOKEN (ensuring it starts with 're_') are correctly implemented. Additionally, the environment variables are properly documented in the project, as confirmed by their presence in apps/web/.env.example.

apps/web/app/(unauthenticated)/components/header.tsx (1)

48-48: Button size standardization

Removing the size="sm" prop simplifies the button implementation and allows it to use the default sizing from the design system, improving consistency across the UI.

apps/web/app/(unauthenticated)/login/email/login-email.tsx (2)

58-132: Layout restructuring improves component organization.

The refactored layout with React fragments improves the component structure by eliminating unnecessary wrapper divs and organizing the content into logical sections.


123-130: Good addition of "Forgot password?" link.

Adding the forgot password link improves user experience by providing a direct path for users who need to reset their password.

apps/web/app/(unauthenticated)/reset-password/reset-password.tsx (4)

44-68: Comprehensive error handling in form submission.

The implementation properly handles potential errors during password reset, providing clear feedback to users in various scenarios.


82-87: Well-designed success feedback with redirection.

Good implementation of success feedback with automatic redirection. The use of the PartyPopper icon is a nice touch for positive reinforcement.


97-102: Password strength indicator enhances security awareness.

Using the PasswordInput with showStrengthIndicator provides valuable feedback to users about password security, encouraging stronger passwords.


125-127: Comprehensive button disabled state.

The button is properly disabled based on form submission state, validity, and success status, preventing multiple submissions and improving user experience.

packages/email/templates/contact.tsx (3)

13-17: Well-typed props interface.

The ContactTemplateProps type clearly defines the required properties with appropriate types, making the component API clear and type-safe.


19-46: Clean and accessible email template structure.

The email template uses proper semantic structure with preview text and clear content organization. The template renders well for contact emails.

However, consider adding alt text for better accessibility in email clients that may not fully render the styling:

  <Text className="mt-0 mb-4 font-semibold text-2xl text-zinc-950">
-   New email from {name}
+   New email from {name} {/* #contact-email-heading */}
  </Text>

48-56: Helpful example component.

Including an example component with sample data makes it easier for developers to understand how to use the template and visualize the output.

apps/web/app/(unauthenticated)/forgot-password/forgot-password.tsx (4)

32-51: Comprehensive error handling in forgot password flow.

The implementation correctly handles API errors and connection issues, providing clear feedback to users. The use of the redirectTo parameter ensures users will be properly directed to the reset password page.


65-70: Clear success messaging.

The success message clearly informs users to check their email, and the use of the PartyPopper icon adds a positive visual cue.


80-80: Appropriate form field disabling.

Good practice to disable the email input when the form has been successfully submitted, preventing users from making additional submissions.


86-96: Well-implemented submit button with proper state management.

The button correctly displays different text based on the submission state and is properly disabled when appropriate.

packages/email/templates/verification.tsx (6)

1-13: Good use of React Email components.

The imports are properly structured and include all necessary components for building the email template.


15-18: LGTM! Well-defined interface.

The interface for VerificationEmailProps is appropriately defined with readonly properties to ensure immutability.


20-22: Good implementation of dynamic year calculation.

The current year is correctly calculated for use in the copyright notice.


23-49: Well-structured email template with clear user instructions.

The template has a logical flow with informative heading, clear instructions, and both button and URL options for verification.


50-55: Good security practice including expiration information.

Including the link expiration time and advice for unrequested emails is a security best practice.


91-96: Good example implementation for testing and documentation.

The ExampleVerificationEmail component provides a clear demonstration of how to use the VerificationEmail component.

packages/email/templates/password-reset.tsx (5)

1-13: Good use of React Email components.

The imports are properly structured and include all necessary components for building the email template.


15-18: LGTM! Well-defined interface.

The interface for PasswordResetEmailProps is appropriately defined with readonly properties to ensure immutability.


20-22: Good implementation of dynamic year calculation.

The current year is correctly calculated for use in the copyright notice.


23-50: Well-structured password reset email with clear instructions.

The template has a logical flow with informative heading, clear instructions, and both button and URL options for password reset.


51-58: Excellent security practices in the email template.

The template includes important security information: link expiration time, advice for unrequested emails, and a warning against forwarding the email.

packages/auth/server.ts (2)

2-4: Good imports for email functionality.

The necessary imports for email functionality have been correctly added, including the Resend client and email templates.


16-17: Verify sign-up configuration for email verification flow.

The code includes disableSignUp: true with a comment "Disable sign up for now", which might conflict with the new email verification flow. If sign-up is disabled, users won't be able to register and receive verification emails. Ensure this is the intended behavior or consider enabling sign-up to utilize the new verification flow.

form.formState.isSubmitting || !form.formState.isValid
}
>
{form.formState.isSubmitting ? 'Signing up...' : 'Continue'}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Incorrect loading text for login form.

The button displays "Signing up..." during submission, but this is a login form, not a signup form.

-                {form.formState.isSubmitting ? 'Signing up...' : 'Continue'}
+                {form.formState.isSubmitting ? 'Logging in...' : 'Continue'}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{form.formState.isSubmitting ? 'Signing up...' : 'Continue'}
{form.formState.isSubmitting ? 'Logging in...' : 'Continue'}

Comment on lines +63 to +83
<a
href="https://yourapp.com/unsubscribe"
className="text-zinc-500 underline"
>
Unsubscribe
</a>{' '}
·{' '}
<a
href="https://yourapp.com/terms"
className="text-zinc-500 underline"
>
Terms
</a>{' '}
·{' '}
<a
href="https://yourapp.com/privacy"
className="text-zinc-500 underline"
>
Privacy
</a>
</Text>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update placeholder URLs with actual application URLs.

The unsubscribe, terms, and privacy links currently point to placeholder URLs (yourapp.com), which should be updated to the actual application URLs before deployment.

-                href="https://yourapp.com/unsubscribe"
+                href="https://blackhead-web.vercel.app/unsubscribe"

-                href="https://yourapp.com/terms"
+                href="https://blackhead-web.vercel.app/terms"

-                href="https://yourapp.com/privacy"
+                href="https://blackhead-web.vercel.app/privacy"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a
href="https://yourapp.com/unsubscribe"
className="text-zinc-500 underline"
>
Unsubscribe
</a>{' '}
·{' '}
<a
href="https://yourapp.com/terms"
className="text-zinc-500 underline"
>
Terms
</a>{' '}
·{' '}
<a
href="https://yourapp.com/privacy"
className="text-zinc-500 underline"
>
Privacy
</a>
</Text>
<a
href="https://blackhead-web.vercel.app/unsubscribe"
className="text-zinc-500 underline"
>
Unsubscribe
</a>{' '}
·{' '}
<a
href="https://blackhead-web.vercel.app/terms"
className="text-zinc-500 underline"
>
Terms
</a>{' '}
·{' '}
<a
href="https://blackhead-web.vercel.app/privacy"
className="text-zinc-500 underline"
>
Privacy
</a>
</Text>

Comment on lines +16 to +34
disableSignUp: true, // Disable sign up for now
requireEmailVerification: true,
sendResetPassword: async ({ user, url }) => {
await resend.emails.send({
from: keys().RESEND_FROM,
to: user.email,
tags: [
{
name: 'password',
value: 'reset'
}
],
subject: 'Reset your password',
react: PasswordResetEmail({
email: user.email,
url: url
})
})
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Well-implemented password reset functionality.

The password reset email implementation is well-structured with appropriate tags and uses the imported email template correctly.

However, consider adding error handling to the sendResetPassword function to gracefully handle email sending failures.

    sendResetPassword: async ({ user, url }) => {
-      await resend.emails.send({
-        from: keys().RESEND_FROM,
-        to: user.email,
-        tags: [
-          {
-            name: 'password',
-            value: 'reset'
-          }
-        ],
-        subject: 'Reset your password',
-        react: PasswordResetEmail({
-          email: user.email,
-          url: url
-        })
-      })
+      try {
+        await resend.emails.send({
+          from: keys().RESEND_FROM,
+          to: user.email,
+          tags: [
+            {
+              name: 'password',
+              value: 'reset'
+            }
+          ],
+          subject: 'Reset your password',
+          react: PasswordResetEmail({
+            email: user.email,
+            url: url
+          })
+        })
+      } catch (error) {
+        console.error('Failed to send reset password email:', error)
+        // Consider how to handle this failure (retry, notify admin, etc.)
+      }
    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
disableSignUp: true, // Disable sign up for now
requireEmailVerification: true,
sendResetPassword: async ({ user, url }) => {
await resend.emails.send({
from: keys().RESEND_FROM,
to: user.email,
tags: [
{
name: 'password',
value: 'reset'
}
],
subject: 'Reset your password',
react: PasswordResetEmail({
email: user.email,
url: url
})
})
}
disableSignUp: true, // Disable sign up for now
requireEmailVerification: true,
sendResetPassword: async ({ user, url }) => {
try {
await resend.emails.send({
from: keys().RESEND_FROM,
to: user.email,
tags: [
{
name: 'password',
value: 'reset'
}
],
subject: 'Reset your password',
react: PasswordResetEmail({
email: user.email,
url: url
})
})
} catch (error) {
console.error('Failed to send reset password email:', error)
// Consider how to handle this failure (retry, notify admin, etc.)
}
}

Comment on lines +36 to +56
emailVerification: {
sendOnSignUp: true,
requireEmailVerification: true,
expiresIn: 60 * 60 * 24, // 1 day
sendVerificationEmail: async ({ user, url }) => {
await resend.emails.send({
from: keys().RESEND_FROM,
to: user.email,
tags: [
{
name: 'verification',
value: 'email'
}
],
subject: 'Verify your email',
react: VerificationEmail({
email: user.email,
url: url
})
})
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Comprehensive email verification configuration.

The email verification configuration is thorough with appropriate settings:

  • Sending on signup
  • Requiring verification
  • Setting reasonable expiration time (1 day)
  • Well-implemented verification email sending

Similar to the password reset functionality, consider adding error handling to the sendVerificationEmail function.

    sendVerificationEmail: async ({ user, url }) => {
-      await resend.emails.send({
-        from: keys().RESEND_FROM,
-        to: user.email,
-        tags: [
-          {
-            name: 'verification',
-            value: 'email'
-          }
-        ],
-        subject: 'Verify your email',
-        react: VerificationEmail({
-          email: user.email,
-          url: url
-        })
-      })
+      try {
+        await resend.emails.send({
+          from: keys().RESEND_FROM,
+          to: user.email,
+          tags: [
+            {
+              name: 'verification',
+              value: 'email'
+            }
+          ],
+          subject: 'Verify your email',
+          react: VerificationEmail({
+            email: user.email,
+            url: url
+          })
+        })
+      } catch (error) {
+        console.error('Failed to send verification email:', error)
+        // Consider how to handle this failure
+      }
    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
emailVerification: {
sendOnSignUp: true,
requireEmailVerification: true,
expiresIn: 60 * 60 * 24, // 1 day
sendVerificationEmail: async ({ user, url }) => {
await resend.emails.send({
from: keys().RESEND_FROM,
to: user.email,
tags: [
{
name: 'verification',
value: 'email'
}
],
subject: 'Verify your email',
react: VerificationEmail({
email: user.email,
url: url
})
})
}
emailVerification: {
sendOnSignUp: true,
requireEmailVerification: true,
expiresIn: 60 * 60 * 24, // 1 day
sendVerificationEmail: async ({ user, url }) => {
try {
await resend.emails.send({
from: keys().RESEND_FROM,
to: user.email,
tags: [
{
name: 'verification',
value: 'email'
}
],
subject: 'Verify your email',
react: VerificationEmail({
email: user.email,
url: url
})
})
} catch (error) {
console.error('Failed to send verification email:', error)
// Consider how to handle this failure
}
}
}

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

Labels

app Changes in the main application auth Changes in the authentication system enhancement New feature or request ui Changes in the user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants