Skip to content

Implement reset password - #63

Merged
damianlegawiec merged 2 commits into
mainfrom
feature/password-reset
Mar 16, 2026
Merged

Implement reset password#63
damianlegawiec merged 2 commits into
mainfrom
feature/password-reset

Conversation

@damianlegawiec

@damianlegawiec damianlegawiec commented Mar 15, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added client-side password recovery flow: Forgot Password and Reset Password pages with token-based reset and confirmation views.
  • Style

    • Redesigned account and registration pages with a cohesive card-based layout, side-by-side name fields, and improved password visibility controls.
  • Chores

    • Updated dependency versions for two packages.

@coderabbitai

coderabbitai Bot commented Mar 15, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20dc704d-224e-491e-a499-81ef54d025c4

📥 Commits

Reviewing files that changed from the base of the PR and between 22a19e1 and f0e12ba.

📒 Files selected for processing (2)
  • src/app/[country]/[locale]/(storefront)/account/forgot-password/page.tsx
  • src/app/[country]/[locale]/(storefront)/account/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/[country]/[locale]/(storefront)/account/forgot-password/page.tsx

Walkthrough

This PR adds a Card UI component, implements a client-side password reset flow (forgot + reset pages), refactors account and register pages to use Card components, exposes password-reset wrappers in the data layer, and bumps two Spree-related package versions.

Changes

Cohort / File(s) Summary
Package Dependencies
package.json
Bumped @spree/next ^0.10.4 → ^0.10.5 and @spree/sdk ^0.10.0 → ^0.10.1.
Password Reset Pages
src/app/[country]/[locale]/(storefront)/account/forgot-password/page.tsx, src/app/[country]/[locale]/(storefront)/account/reset-password/page.tsx
Added client-side forgot-password and reset-password pages: email collection, token validation, password inputs with visibility toggles, submit flows calling data-layer wrappers, and success/error UIs.
Account Layout / Auth Gate
src/app/[country]/[locale]/(storefront)/account/layout.tsx
Replaced substring auth check with an explicit Set of auth page paths (register, forgot-password, reset-password) for exact-match detection.
Account + Register Pages (UI refactor)
src/app/[country]/[locale]/(storefront)/account/page.tsx, src/app/[country]/[locale]/(storefront)/account/register/page.tsx
Refactored login, register, and authenticated dashboard UIs to use new Card components; added password visibility toggles and moved links (e.g., forgot-password) into card layouts.
UI Component
src/components/ui/card.tsx
New Card component module exporting Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter with data-slot attributes and composed classNames for consistent card layouts.
Data Layer Wrappers
src/lib/data/customer.ts
Added exported wrapper functions requestPasswordReset(email, redirectUrl?) and resetPassword(token, password, passwordConfirmation) delegating to @spree/next SDK functions.

Sequence Diagram

sequenceDiagram
    participant User
    participant Browser
    participant ForgotPage as "ForgotPassword Page"
    participant ResetPage as "ResetPassword Page"
    participant SDK as "@spree/next SDK"
    participant Backend

    User->>Browser: Open forgot-password
    Browser->>ForgotPage: render
    User->>ForgotPage: submit email
    ForgotPage->>SDK: requestPasswordReset(email, redirectUrl)
    SDK->>Backend: send reset request
    Backend-->>SDK: success
    SDK-->>ForgotPage: success
    ForgotPage->>Browser: show confirmation

    User->>Browser: click email link (token)
    Browser->>ResetPage: load with token
    ResetPage->>ResetPage: validate token present
    User->>ResetPage: submit new password
    ResetPage->>SDK: resetPassword(token, password, confirmation)
    SDK->>Backend: perform reset
    Backend-->>SDK: success
    SDK-->>ResetPage: success
    ResetPage->>Browser: show success / sign-in link
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped in with a brand-new Card,
Tucked reset links into a yard,
Emails sent, tokens checked,
Passwords swapped, no step neglected,
Hooray — the account's back on guard! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Implement reset password' is partially related to the changeset. While password reset functionality is a significant component, the PR also implements a forgot password flow and refactors account pages with new Card-based UI components.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/password-reset
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@damianlegawiec
damianlegawiec marked this pull request as ready for review March 15, 2026 19:29

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/app/`[country]/[locale]/(storefront)/account/forgot-password/page.tsx:
- Around line 39-40: The call to requestPasswordReset currently sets
setSubmitted(true) unconditionally; instead, capture the returned result (from
requestPasswordReset(email, redirectUrl)), check result.success and only call
setSubmitted(true) on success, otherwise call setError(result.error ||
"Something went wrong. Please try again."); mirror the resetPassword handling so
failures surface to the user rather than showing the success confirmation.

In `@src/app/`[country]/[locale]/(storefront)/account/layout.tsx:
- Around line 152-155: The current isAuthPage uses substring checks
(pathname.includes) which can false-match; change it to exact-route matching by
normalizing pathname (strip query string and trailing slashes) and then compare
against an explicit list of auth routes (e.g., "/register", "/forgot-password",
"/reset-password") using exact equality (or matching the final path segment)
instead of includes; update the isAuthPage assignment to call this normalization
and equality check (replace uses of pathname.includes in isAuthPage) so only
exact auth routes are considered.
🪄 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: CHILL

Plan: Pro

Run ID: 348e02d2-420e-4b81-8f8d-5e575b59daa5

📥 Commits

Reviewing files that changed from the base of the PR and between 8455681 and 22a19e1.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • package.json
  • src/app/[country]/[locale]/(storefront)/account/forgot-password/page.tsx
  • src/app/[country]/[locale]/(storefront)/account/layout.tsx
  • src/app/[country]/[locale]/(storefront)/account/page.tsx
  • src/app/[country]/[locale]/(storefront)/account/register/page.tsx
  • src/app/[country]/[locale]/(storefront)/account/reset-password/page.tsx
  • src/components/ui/card.tsx
  • src/lib/data/customer.ts

Comment on lines +39 to +40
await requestPasswordReset(email, redirectUrl);
setSubmitted(true);

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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

For @spree/next v0.10.5, what is the exact failure behavior of requestPasswordReset(email, redirectUrl): does it throw, or return an object like { success: false, error }?

💡 Result:

I couldn’t verify the exact v0.10.5 behavior from public docs/source via web search (the Spree docs page for @spree/next doesn’t document requestPasswordReset, and I couldn’t retrieve the v0.10.5 package source itself from an authoritative public location in this environment). (spreecommerce.org)

What I can say confidently is:

  • The older Spree JS SDK (@spree/storefront-api-v2-sdk) explicitly does not throw and instead returns a “result object” you must inspect (isSuccess()/isFail(), fail()), but that statement is about that SDK, not @spree/next. (app.unpkg.com)

So for @spree/next@0.10.5 specifically, you’ll need to confirm by checking the installed package’s typings/implementation locally:

  • node_modules/@spree/next/dist/**/*.d.ts (or equivalent) — see whether requestPasswordReset(...) returns Promise<void> / Promise<...> and whether it documents throwing.
  • node_modules/@spree/next/dist/**/*.js — search for function requestPasswordReset and see if it does if (!res.ok) throw ... vs return { success: false, error }.

If you paste the requestPasswordReset function (or its .d.ts signature) from @spree/next@0.10.5, I can tell you precisely whether it throws or returns a { success: false, error }-style object.

Citations:


🏁 Script executed:

find . -type f -name "page.tsx" | grep "forgot-password" | head -5

Repository: spree/storefront

Length of output: 134


🏁 Script executed:

cat -n src/app/[country]/[locale]/\(storefront\)/account/forgot-password/page.tsx 2>/dev/null || find . -type f -path "*forgot-password/page.tsx" -exec cat -n {} \;

Repository: spree/storefront

Length of output: 5935


🏁 Script executed:

rg "requestPasswordReset" -t ts -t tsx -A 3 -B 3

Repository: spree/storefront

Length of output: 87


🏁 Script executed:

find . -path "*/node_modules/@spree/next*" -name "*.d.ts" -o -path "*/node_modules/@spree/next*" -name "package.json" | head -10

Repository: spree/storefront

Length of output: 42


🏁 Script executed:

find . -path "*/lib/data/customer*" -type f

Repository: spree/storefront

Length of output: 86


🏁 Script executed:

cat -n src/lib/data/customer.ts 2>/dev/null || cat -n src/lib/data/customer.js 2>/dev/null || find . -path "*/lib/data/customer*" -type f -exec cat -n {} \;

Repository: spree/storefront

Length of output: 1767


🏁 Script executed:

find . -type d -name "@spree" | head -5

Repository: spree/storefront

Length of output: 42


🏁 Script executed:

find . -path "*/node_modules/@spree/next*" -type f \( -name "*.d.ts" -o -name "index.js" -o -name "index.ts" \) | head -20

Repository: spree/storefront

Length of output: 42


🏁 Script executed:

grep -r "requestPasswordReset" node_modules/@spree/next --include="*.d.ts" --include="*.ts" --include="*.js" 2>/dev/null | head -20

Repository: spree/storefront

Length of output: 42


🏁 Script executed:

cat package.json | grep -A 2 -B 2 "@spree/next"

Repository: spree/storefront

Length of output: 231


🏁 Script executed:

find . -type f \( -name "package.json" -o -name "package-lock.json" -o -name "pnpm-lock.yaml" \) -exec grep -l "@spree/next" {} \;

Repository: spree/storefront

Length of output: 94


🏁 Script executed:

grep -r "requestPasswordReset" src/ --include="*.ts" --include="*.tsx" -B 5 -A 10

Repository: spree/storefront

Length of output: 5109


🏁 Script executed:

find . -type f -name "*.ts" -o -name "*.tsx" | xargs grep -l "login\|register" | grep -E "(page|component)" | head -5

Repository: spree/storefront

Length of output: 186


🏁 Script executed:

grep -A 10 "handleSubmit\|await _login\|await _register" src/app/**/*.tsx 2>/dev/null | head -40

Repository: spree/storefront

Length of output: 42


🏁 Script executed:

find . -type f -name "*.tsx" -path "*/account/*" -exec grep -l "login\|register" {} \; | head -5

Repository: spree/storefront

Length of output: 247


🏁 Script executed:

cat -n src/app/[country]/[locale]/\(storefront\)/account/page.tsx | head -100

Repository: spree/storefront

Length of output: 3823


🏁 Script executed:

cat -n src/app/[country]/[locale]/\(storefront\)/account/register/page.tsx | head -100

Repository: spree/storefront

Length of output: 3937


🏁 Script executed:

cat -n src/contexts/AuthContext.tsx | head -150

Repository: spree/storefront

Length of output: 4239


🏁 Script executed:

cat -n src/lib/data/customer.ts

Repository: spree/storefront

Length of output: 1767


🏁 Script executed:

grep -r "login as _login" src/ --include="*.ts" --include="*.tsx" -A 5 -B 5 | head -50

Repository: spree/storefront

Length of output: 550


🏁 Script executed:

cat -n src/lib/data/utils.ts 2>/dev/null || find . -path "*/lib/data/utils*" -type f -exec cat -n {} \;

Repository: spree/storefront

Length of output: 1142


🏁 Script executed:

find . -type f \( -name "*.ts" -o -name "*.tsx" \) -exec grep -l "resetPassword\|requestPasswordReset" {} \;

Repository: spree/storefront

Length of output: 235


🏁 Script executed:

cat -n src/app/[country]/[locale]/\(storefront\)/account/reset-password/page.tsx 2>/dev/null | head -100

Repository: spree/storefront

Length of output: 3764


Check the requestPasswordReset result for success before showing confirmation.

At lines 39-40, setSubmitted(true) is called unconditionally after await requestPasswordReset(...). The reset-password page (lines 80-88) treats resetPassword as returning a result object with { success, error } and checks if (result.success). Since requestPasswordReset is wrapped identically to resetPassword in the customer module, it likely returns the same result object. If requestPasswordReset returns { success: false }, the try-catch will not catch it, and users will see a false "Check your email" success message.

Align the error handling with the reset-password page pattern:

const result = await requestPasswordReset(email, redirectUrl);
if (result.success) {
  setSubmitted(true);
} else {
  setError(result.error || "Something went wrong. Please try again.");
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/`[country]/[locale]/(storefront)/account/forgot-password/page.tsx
around lines 39 - 40, The call to requestPasswordReset currently sets
setSubmitted(true) unconditionally; instead, capture the returned result (from
requestPasswordReset(email, redirectUrl)), check result.success and only call
setSubmitted(true) on success, otherwise call setError(result.error ||
"Something went wrong. Please try again."); mirror the resetPassword handling so
failures surface to the user rather than showing the success confirmation.

Comment thread src/app/[country]/[locale]/(storefront)/account/layout.tsx Outdated
@damianlegawiec
damianlegawiec merged commit 7589c66 into main Mar 16, 2026
4 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Mar 16, 2026
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