Skip to content

Resending verificatio nemail done - #54

Merged
reijjo merged 4 commits into
mainfrom
front
Apr 4, 2026
Merged

Resending verificatio nemail done#54
reijjo merged 4 commits into
mainfrom
front

Conversation

@reijjo

@reijjo reijjo commented Apr 4, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added a dedicated resend button for users to request verification emails again
    • Display clear confirmation when an account is already verified
  • Bug Fixes

    • Improved error handling for invalid or missing verification tokens
    • Prevent double-verification of already-verified accounts with appropriate feedback

@coderabbitai

coderabbitai Bot commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@reijjo has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 58 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 14 minutes and 58 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f11b7d59-425d-40ee-9a8a-5ab1e3716b5a

📥 Commits

Reviewing files that changed from the base of the PR and between 3698686 and 7a22e80.

📒 Files selected for processing (3)
  • client/src/app/(auth)/verify/_components/ResendButton.tsx
  • client/src/app/(auth)/verify/page.tsx
  • client/src/lib/actions/auth.ts

Walkthrough

This PR adds a resend verification email feature to the application. New ResendButton component is introduced client-side with styling, the verification page is refactored to use a component directory structure, and corresponding server actions and API helpers are added. The token database query is enhanced to fetch user verification status, and the verification handler gains stronger error handling and an additional check for already-verified accounts.

Changes

Cohort / File(s) Summary
Resend Email Button Component
client/src/app/(auth)/verify/_components/ResendButton.tsx, ResendButton.css
New React component with form handling via useActionState, conditional success/error message display, and loading states. Stylesheet configures centered flex column layout with proper spacing and child element alignment.
Verification Page Restructuring
client/src/app/(auth)/verify/_components/VerifyContent.tsx, client/src/app/(auth)/verify/page.tsx
Integrated ResendButton component, reorganized file imports to reference _components directory. Updated token extraction to parse searchParams instead of direct params access. Enhanced conditional rendering for success (409) and failure states.
Resend Email Server-Side Handler
client/src/lib/actions/auth.ts, client/src/lib/api/auth.ts
Added resendVerificationEmailAction server action that wraps form submission and calls new resendVerificationEmailRequest API helper. New helper issues POST request to /verify endpoint with token in JSON body and returns standardized ApiResponse.
Token Verification Enhancement
rust-server/src/db/queries.rs, rust-server/src/features/auth/handlers.rs
Updated find_token_by_value query to fetch users.verified status via table join. Enhanced verify_account handler with explicit Result error handling for query parsing, stricter token validation, and new early-return check for already-verified accounts. Standardized error messages across handlers.
Layout Spacing
client/src/app/(auth)/layout.css
Reduced .container gap from 2rem to 1rem for tighter vertical/horizontal spacing between child elements.

Sequence Diagram

sequenceDiagram
    actor User
    participant ResendButton as ResendButton Component
    participant Action as resendVerificationEmailAction
    participant API as resendVerificationEmailRequest
    participant AuthServer as Auth Server

    User->>ResendButton: Submit resend form with token
    ResendButton->>Action: Dispatch server action via useActionState
    Action->>API: Call API helper with extracted token
    API->>AuthServer: POST /verify with {token}
    AuthServer-->>API: Return success or error response
    API-->>Action: Return ApiResponse object
    Action-->>ResendButton: Update formState and isPending flag
    ResendButton->>ResendButton: Render FormSuccessMessage or FormErrorMessage
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • SOme frontend and couple of sql queries in the backend #52 — Modifies both auth UI (client/(auth)/layout.css) and server-side token verification logic (rust-server/src/db/queries.rs), directly intersecting with the verification flow changes.
  • Backend stuff done for the verification #53 — Updates the same server verification pipeline (rust-server/src/db/queries.rs and rust-server/src/features/auth/handlers.rs), including token lookup and resend handler logic.
  • pretty email #24 — Handles account verification flow and token/verified column management, providing context for the verification state checks now being enforced.

A Word from Your Mentor

You've just built something important here: a complete request–response cycle for a security-sensitive feature. Let me highlight a few professional touches I'm seeing:

The Good:

  • You're using useActionState correctly—managing form state and pending flags prevents the double-submit race condition that kills UX on flaky networks.
  • The database query now joins users.verified instead of requiring a separate lookup. That's thinking like a backend engineer: one query, complete data.
  • Adding explicit error handling to the handler (Result<Query<...>, QueryRejection>) is defensive programming—you're not assuming the extraction will succeed.

A teaching moment:
Notice how the token verification handler now checks if verified is already true and returns 409 Conflict? That's semantically correct HTTP. Don't use 400 Bad Request for state conflicts—use 409. It tells clients "your request is valid, but can't proceed due to current state." The UI can then show "Account already verified!" instead of "Something went wrong."

One thing to watch:
In your new resendVerificationEmailRequest, make sure the backend /verify endpoint truly supports POST. If it was built for GET with query params (which is common for verification links), a POST endpoint might not exist. Double-check your backend matches your client assumptions—that's where silent failures hide.

You're building thoughtfully. Keep it up! 🚀

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title contains a typo ('verificatio nemail') making it unclear, though it attempts to reference the main feature of resending verification emails. Correct the typo to 'Resending verification email done' for clarity and professionalism.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch front

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (1)
rust-server/src/features/auth/handlers.rs (1)

170-201: 🧹 Nitpick | 🔵 Trivial

Resend token handler looks solid.

Good implementation of the resend flow. A few observations for your learning:

The Json(body) destructuring directly (line 172) works because you're not using Result<Json<_>, JsonRejection> here like you do in register_user. This means malformed JSON will return Axum's default rejection error. Consider whether you want consistency:

// Option: Match the register_user pattern for consistent error messages
pub async fn resend_token(
    State(state): State<AppState>,
    payload: Result<Json<ResendTokenData>, JsonRejection>,
) -> Result<ApiResponse<()>, AppError> {
    let Json(body) = match payload {
        Ok(json) => json,
        Err(rejection) => return Err(AppError::Json(rejection)),
    };
    // ...
}

However, for a simple single-field payload, the current approach is arguably fine since the error scenario is less likely.

The shortened success message "Check your inbox." (line 200) is cleaner than verbose alternatives. Concise is good!

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust-server/src/features/auth/handlers.rs` around lines 170 - 201, Change the
handler to mirror the register_user pattern so malformed JSON yields your
AppError: update resend_token to accept payload: Result<Json<ResendTokenData>,
JsonRejection> (instead of Json(body)), destructure with let Json(body) = match
payload { Ok(j) => j, Err(rej) => return Err(AppError::Json(rej)) }, and keep
the rest of the logic (use ResendTokenData, State(AppState),
update_verification_token, and state.email.send_verification_email as before) so
errors from invalid JSON are converted to your AppError::Json rather than Axum’s
default rejection.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/src/app/`(auth)/layout.css:
- Line 37: The .container spacing change from 2rem to 1rem is global; revert
.container back to its original 2rem and instead create a modifier class (e.g.,
.container--compact) with gap: 1rem to target only the verification page; update
the verification page component (where ResendButton is rendered) to use both
classes (container container--compact) so other auth pages keep the original
spacing while the verify page gets the tighter layout.

In `@client/src/app/`(auth)/verify/_components/ResendButton.css:
- Around line 9-18: The CSS has a redundant broad rule "& div" that overlaps
with the direct-child rule "& > *" and can unintentionally style deeply nested
markup; either remove the "& div" rule if the target divs are direct children of
the ResendButton container, or replace it with a more specific selector (e.g.,
"& > .form-messages" or a class tied to FormErrorMessage/FormSuccessMessage) and
add that class to the appropriate components so only the intended nested
container(s) receive width: 100%.

In `@client/src/app/`(auth)/verify/_components/ResendButton.tsx:
- Around line 22-34: The conditional for the error message uses a truthy check
(formState.error && ...) which makes the ?? fallback unreachable; change the
error rendering to explicitly check for undefined (e.g., formState.error !==
undefined) and keep message={formState.error ?? "Failed to resend verification
email. Please try again."} so an empty string or nullish value still falls back;
keep the success branch as-is (formState.success with FormSuccessMessage) and
update references to formState, FormErrorMessage, and FormSuccessMessage
accordingly.

In `@client/src/app/`(auth)/verify/page.tsx:
- Around line 12-13: The code incorrectly constructs new URLSearchParams(params)
where params is the already-parsed searchParams; instead, read the token
directly from the parsed object (use params.token or the searchParams variable)
and call .trim() on that value (e.g., token = params.token?.trim()) to avoid
serializing the object; update the usage in page.tsx replacing the
URLSearchParams construction with direct property access of params/token.

In `@client/src/lib/actions/auth.ts`:
- Around line 176-196: The resendVerificationEmailAction function lacks a
try/catch and does unsafe casting of data.get("token"); update
resendVerificationEmailAction to validate the token (check that
data.get("token") is not null and is a string) and return a standardized error
object if missing, then wrap the call to resendVerificationEmailRequest(token)
in a try/catch that returns a consistent { success: false, error: ... } on
exceptions and preserves the existing success response shape on success.

---

Outside diff comments:
In `@rust-server/src/features/auth/handlers.rs`:
- Around line 170-201: Change the handler to mirror the register_user pattern so
malformed JSON yields your AppError: update resend_token to accept payload:
Result<Json<ResendTokenData>, JsonRejection> (instead of Json(body)),
destructure with let Json(body) = match payload { Ok(j) => j, Err(rej) => return
Err(AppError::Json(rej)) }, and keep the rest of the logic (use ResendTokenData,
State(AppState), update_verification_token, and
state.email.send_verification_email as before) so errors from invalid JSON are
converted to your AppError::Json rather than Axum’s default rejection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fcec0159-1948-4305-8dd3-604e8c17ac2b

📥 Commits

Reviewing files that changed from the base of the PR and between 7f5ed1e and 3698686.

📒 Files selected for processing (9)
  • client/src/app/(auth)/layout.css
  • client/src/app/(auth)/verify/_components/ResendButton.css
  • client/src/app/(auth)/verify/_components/ResendButton.tsx
  • client/src/app/(auth)/verify/_components/VerifyContent.tsx
  • client/src/app/(auth)/verify/page.tsx
  • client/src/lib/actions/auth.ts
  • client/src/lib/api/auth.ts
  • rust-server/src/db/queries.rs
  • rust-server/src/features/auth/handlers.rs

Comment thread client/src/app/(auth)/layout.css
Comment thread client/src/app/(auth)/verify/_components/ResendButton.css
Comment thread client/src/app/(auth)/verify/_components/ResendButton.tsx
Comment thread client/src/app/(auth)/verify/page.tsx Outdated
Comment thread client/src/lib/actions/auth.ts
@reijjo
reijjo merged commit d29d48e into main Apr 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant