Skip to content

feat: reorder feature#3153

Merged
eduardoformiga merged 7 commits intodevfrom
feat/reorder
Feb 6, 2026
Merged

feat: reorder feature#3153
eduardoformiga merged 7 commits intodevfrom
feat/reorder

Conversation

@ArthurTriis1
Copy link
Copy Markdown
Contributor

@ArthurTriis1 ArthurTriis1 commented Dec 11, 2025

What's the purpose of this pull request?

This PR implements the "Reorder" button feature in the My Account order details page, allowing customers to quickly add all items from a previous order back to their cart with a single click. This improves the shopping experience by reducing friction when customers want to repurchase items they've bought before.

How it works?

The feature consists of:

  1. Reorder Button Component (MyAccountReorderButton): A dedicated button component displayed in the order details header that triggers the reorder action. The button is styled as outlined by default and filled on hover, and is hidden on mobile devices.

  2. Reorder Hook (useReorder): A custom hook that handles the reorder logic:

    • Extracts all items from the order's delivery options
    • Converts order items to the format required by the checkout API (IStoreOffer[])
    • Uses the validateCart GraphQL mutation to add items to the cart
    • The mutation automatically handles cart synchronization (replacing existing items with the reordered items)
    • Updates the local cart store with the validated cart response
    • Redirects the user to the checkout page after successfully adding items
  3. Integration Points:

    • The reorder button is displayed in the order details header alongside other order actions
    • A "Reorder" option is also available in the MyAccountOrderActions dropdown menu
    • Both trigger the same useReorder hook
  4. Cart Synchronization: When the user already has items in their cart, the validateCart mutation handles the synchronization by replacing all existing cart items with the reordered items from the order.

  5. Redirect to Checkout: After successfully adding items to the cart, users are automatically redirected to the checkout page using the redirectToCheckout utility function, which handles both development and production environments.

How to test it?

  1. Navigate to My Account > Orders
  2. Open any completed order details page
  3. Verify that the "Reorder" button is visible in the order header (desktop/tablet only)
  4. Click the "Reorder" button
  5. Verify that:
    • All items from the order are added to the cart
    • If there were existing items in the cart, they are replaced by the reordered items
    • The user is redirected to the checkout page
    • The cart displays the correct items and quantities
  6. Test the "Reorder" option in the dropdown menu (three dots icon) - it should work the same way
  7. Test on mobile - the reorder button should be hidden, but the dropdown option should still be available
  8. Test with an empty cart and with a cart that already has items

Starters Deploy Preview

References

Screenshots

Screenshot 2025-12-11 at 17 55 48

Checklist

PR Title and Commit Messages

  • PR title and commit messages follow the Conventional Commits specification
    • Available prefixes: feat, fix, chore, docs, style, refactor, ci and test

PR Description

  • Added a label according to the PR goal - breaking change, bug, contributing, performance, documentation..

Dependencies

  • Committed the pnpm-lock.yaml file when there were changes to the packages

Documentation

  • PR description
  • For documentation changes, ping @Mariana-Caetano to review and update (Or submit a doc request)

Summary by CodeRabbit

  • New Features

    • Added reorder flow: a Reorder button in order details and a Reorder item in the actions dropdown to quickly recreate previous orders and proceed to checkout.
    • Reorder button shows loading/disabled state while processing.
  • Bug Fixes / Behavior

    • Order actions now render consistently; cancellation remains available only when allowed.
  • Style

    • Updated styles and responsive behavior for order header actions and the reorder button (hidden on smaller viewports).

@ArthurTriis1 ArthurTriis1 requested a review from a team as a code owner December 11, 2025 20:58
@ArthurTriis1 ArthurTriis1 requested review from eduardoformiga and emersonlaurentino and removed request for a team December 11, 2025 20:59
@ArthurTriis1 ArthurTriis1 self-assigned this Dec 11, 2025
@codesandbox-ci
Copy link
Copy Markdown

codesandbox-ci Bot commented Dec 11, 2025

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@ArthurTriis1 ArthurTriis1 changed the title Feat/reorder Feat: reorder feature Dec 16, 2025
@ArthurTriis1 ArthurTriis1 changed the title Feat: reorder feature feat: reorder feature Dec 16, 2025
Copy link
Copy Markdown
Member

@eduardoformiga eduardoformiga left a comment

Choose a reason for hiding this comment

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

Good Job! I left some comments in the review :)

Comment thread packages/core/src/sdk/account/useReorder.ts Outdated
Comment thread packages/core/src/sdk/account/useReorder.ts Outdated
Comment thread packages/core/src/sdk/account/useReorder.ts Outdated
Comment thread packages/core/src/sdk/account/useReorder.ts Outdated
Comment thread packages/core/src/sdk/account/useReorder.ts
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 4, 2026

Warning

Rate limit exceeded

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

⌛ 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.

📝 Walkthrough

Walkthrough

Adds a reorder flow: new useReorder hook, a MyAccountReorderButton and Reorder dropdown item wired to the hook, a redirectToCheckout helper, a ReorderError class, and accompanying style/layout updates; MyAccountOrderActions now accepts a full order prop.

Changes

Cohort / File(s) Summary
Reorder hook & error
packages/core/src/sdk/account/useReorder.ts, packages/core/src/sdk/error/ReorderError/ReorderError.ts
Adds useReorder hook that extracts items from an order, validates via GraphQL, updates cartStore, and redirects to checkout; adds ReorderError.
Checkout redirect & checkout button
packages/core/src/sdk/cart/redirectToCheckout.ts, packages/core/src/sdk/cart/useCheckoutButton.ts
Adds redirectToCheckout(orderFormId?); useCheckoutButton now calls this helper instead of inlined navigation.
Reorder UI component
packages/core/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/MyAccountReorderButton.tsx, .../MyAccountReorderButton/index.ts, .../MyAccountReorderButton/styles.scss
New MyAccountReorderButton component using useReorder, with loading state and styles; exports added.
Order details integration
packages/core/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderDetails.tsx, .../MyAccountOrderActions/MyAccountOrderActions.tsx
Passes full order into MyAccountOrderActions; adds Reorder dropdown item wired to reorder flow; removes early-return so actions render regardless of allowCancellation; cancel action attributes adjusted.
Styling & layout
packages/core/src/components/account/orders/MyAccountOrderDetails/section.module.scss, .../MyAccountOrderActions/styles.scss
Adds header actions container, responsive rules to hide reorder on small viewports, color rule for action items, and media-query/spacing normalization.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as Reorder Button / Dropdown
    participant Hook as useReorder
    participant API as Cart GraphQL
    participant Store as cartStore
    participant Browser as Browser/Checkout

    User->>UI: Click "Reorder"
    UI->>Hook: reorder(order)
    Hook->>Hook: Extract & validate items
    alt no valid items
        Hook-->>UI: Throw ReorderError
    else valid items
        Hook->>API: ValidateCartMutation(acceptedOffers)
        API-->>Hook: Cart data
        Hook->>Store: update cartStore
        Hook->>Browser: redirectToCheckout(orderFormId?)
        Browser->>Browser: Navigate to checkout
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

enhancement

Suggested reviewers

  • lemagnetic
  • raabelo

Poem

🐰 A tiny hop, a tidy cart,

I fetch old items, play my part.
Click Reorder — I twirl and spin,
Pack your goods and send you in;
Off you dash to checkout's start! 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
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.
Title check ❓ Inconclusive The title 'feat: reorder feature' is vague and generic, using non-descriptive language that doesn't convey the specific functionality being implemented despite the PR clearly adding a reorder feature to the My Account order details page. Consider a more descriptive title such as 'feat: add reorder button and dropdown action to order details' or 'feat: implement one-click reorder functionality for My Account orders' to better communicate the scope and impact of the change.
✅ 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
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/reorder

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

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
packages/core/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderActions/MyAccountOrderActions.tsx (1)

33-66: ⚠️ Potential issue | 🟡 Minor

Guard against repeated reorder calls.

handleReorder doesn’t check loading, so repeated clicks can trigger overlapping mutations. Use the hook’s loading state to prevent reentry.

🔧 Suggested change
-  const { reorder } = useReorder()
+  const { reorder, loading: reorderLoading } = useReorder()
...
-  const handleReorder = () => {
-    reorder(order)
-  }
+  const handleReorder = () => {
+    if (reorderLoading) return
+    reorder(order)
+  }
🤖 Fix all issues with AI agents
In
`@packages/core/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/MyAccountReorderButton.tsx`:
- Around line 18-23: handleClick currently calls reorder(order) without awaiting
it, so onClick may run before the async reorder completes; make handleClick
async, await the call to reorder(order) (and optionally wrap in try/catch to
surface errors), and only invoke the optional onClick callback after the await
completes (i.e., after reorder resolves) so any dependent logic runs after the
reorder finishes; refer to handleClick, reorder, onClick and order when updating
the implementation.

In `@packages/core/src/sdk/account/useReorder.ts`:
- Around line 61-108: The code sets orderFormId = currentCart.id || '' and
always passes orderNumber into the ValidateCartMutation, which breaks schema
validation when no cart id exists; change the request payload construction in
the function (around currentCart, orderFormId and the ValidateCartMutation
request call) to omit orderNumber when currentCart.id is falsy (or set it to
undefined) so that the order object is only sent with orderNumber when
currentCart.id is present; update any related typing handling for the cart
payload accordingly.
🧹 Nitpick comments (3)
packages/core/src/sdk/error/ReorderError/ReorderError.ts (1)

1-6: Consider adding Object.setPrototypeOf for robust Error subclassing.

When extending built-in classes like Error in TypeScript, the prototype chain can break in some transpilation targets (ES5), causing instanceof ReorderError to return false. Adding Object.setPrototypeOf ensures correct behavior across all environments.

♻️ Proposed fix
 export default class ReorderError extends Error {
   constructor(message: string) {
     super(message)
     this.name = 'ReorderError'
+    Object.setPrototypeOf(this, ReorderError.prototype)
   }
 }
packages/core/src/sdk/cart/redirectToCheckout.ts (1)

3-15: Simplify redundant conditional branches and encode the query parameter.

Lines 9 and 13 are identical. The logic can be simplified. Additionally, orderFormId should be URL-encoded for safety, even though it's typically a UUID.

♻️ Proposed simplification
 export const redirectToCheckout = (orderFormId?: string) => {
   const isDevEnv =
     window.location.host.includes('.vtex.app') ||
     window.location.host.includes('localhost')
 
-  if (!isDevEnv) {
-    window.location.href = `${storeConfig.checkoutUrl}`
-  } else if (orderFormId) {
-    window.location.href = `${storeConfig.checkoutUrl}?orderFormId=${orderFormId}`
-  } else {
-    window.location.href = `${storeConfig.checkoutUrl}`
-  }
+  const baseUrl = storeConfig.checkoutUrl
+  const url = isDevEnv && orderFormId
+    ? `${baseUrl}?orderFormId=${encodeURIComponent(orderFormId)}`
+    : baseUrl
+
+  window.location.href = url
 }
packages/core/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/MyAccountReorderButton.tsx (1)

32-32: Consider externalizing the button label for internationalization.

The "Reorder" text is hardcoded. If the application supports multiple languages, this string should be externalized using an i18n solution for consistency with the rest of the UI.

Comment thread packages/core/src/sdk/account/useReorder.ts
Copy link
Copy Markdown
Contributor

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

🤖 Fix all issues with AI agents
In
`@packages/core/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/MyAccountReorderButton.tsx`:
- Around line 18-22: handleClick currently calls onClick regardless because
useReorder's reorder(order) never rejects; update the contract and call site so
onClick only runs on real success: modify useReorder's reorder to either return
a boolean success flag or rethrow errors (pick one), then in
MyAccountReorderButton.handleClick await the reorder result and only call
onClick when the result indicates success (true) or when no error was thrown;
keep the existing try/catch for logging/UX but gate onClick behind the success
check and ensure the unique symbols referenced are useReorder and handleClick
(and the reorder(order) call).

Comment on lines +18 to +22
const handleClick = async () => {
try {
await reorder(order)
onClick?.()
} catch (error) {
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Feb 4, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

onClick executes even when reorder fails.
useReorder catches errors internally, so await reorder(order) always resolves and onClick runs even on failure or missing order. Consider returning a success boolean (or rethrowing) and gating the callback on success.

🔧 Suggested adjustment (paired with useReorder returning a boolean)
-      await reorder(order)
-      onClick?.()
+      const ok = await reorder(order)
+      if (ok) onClick?.()
🤖 Prompt for AI Agents
In
`@packages/core/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/MyAccountReorderButton.tsx`
around lines 18 - 22, handleClick currently calls onClick regardless because
useReorder's reorder(order) never rejects; update the contract and call site so
onClick only runs on real success: modify useReorder's reorder to either return
a boolean success flag or rethrow errors (pick one), then in
MyAccountReorderButton.handleClick await the reorder result and only call
onClick when the result indicates success (true) or when no error was thrown;
keep the existing try/catch for logging/UX but gate onClick behind the success
check and ensure the unique symbols referenced are useReorder and handleClick
(and the reorder(order) call).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@ArthurTriis1, this suggestion makes sense to me. WDYT?

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.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
Contributor

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

🤖 Fix all issues with AI agents
In
`@packages/core/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderActions/styles.scss`:
- Around line 15-19: The reorder action is being hidden on mobile because the
standalone MyAccountReorderButton and the dropdown item selector
[data-fs-order-actions-item-reorder] are both set to display:none below the
tablet breakpoint; either restore mobile access by removing or altering the
media("<tablet") rule that hides [data-fs-order-actions-item-reorder] so the
dropdown item remains visible as a fallback when MyAccountReorderButton is
hidden, or if the hide is intentional add an inline code comment next to the
MyAccountReorderButton and [data-fs-order-actions-item-reorder] rules
documenting the rationale and any plan to re-enable on mobile.

@eduardoformiga eduardoformiga merged commit d0fdeec into dev Feb 6, 2026
5 of 6 checks passed
@eduardoformiga eduardoformiga deleted the feat/reorder branch February 6, 2026 19:40
@coderabbitai coderabbitai Bot mentioned this pull request Feb 6, 2026
5 tasks
thiagopereira-vtex pushed a commit that referenced this pull request Mar 10, 2026
## What's the purpose of this pull request?

This PR implements the "Reorder" button feature in the My Account order
details page, allowing customers to quickly add all items from a
previous order back to their cart with a single click. This improves the
shopping experience by reducing friction when customers want to
repurchase items they've bought before.

## How it works?

The feature consists of:

1. **Reorder Button Component** (`MyAccountReorderButton`): A dedicated
button component displayed in the order details header that triggers the
reorder action. The button is styled as outlined by default and filled
on hover, and is hidden on mobile devices.

2. **Reorder Hook** (`useReorder`): A custom hook that handles the
reorder logic:
   - Extracts all items from the order's delivery options
- Converts order items to the format required by the checkout API
(`IStoreOffer[]`)
   - Uses the `validateCart` GraphQL mutation to add items to the cart
- The mutation automatically handles cart synchronization (replacing
existing items with the reordered items)
   - Updates the local cart store with the validated cart response
- Redirects the user to the checkout page after successfully adding
items

3. **Integration Points**:
- The reorder button is displayed in the order details header alongside
other order actions
- A "Reorder" option is also available in the `MyAccountOrderActions`
dropdown menu
   - Both trigger the same `useReorder` hook

4. **Cart Synchronization**: When the user already has items in their
cart, the `validateCart` mutation handles the synchronization by
replacing all existing cart items with the reordered items from the
order.

5. **Redirect to Checkout**: After successfully adding items to the
cart, users are automatically redirected to the checkout page using the
`redirectToCheckout` utility function, which handles both development
and production environments.

## How to test it?

1. Navigate to My Account > Orders
2. Open any completed order details page
3. Verify that the "Reorder" button is visible in the order header
(desktop/tablet only)
4. Click the "Reorder" button
5. Verify that:
   - All items from the order are added to the cart
- If there were existing items in the cart, they are replaced by the
reordered items
   - The user is redirected to the checkout page
   - The cart displays the correct items and quantities
6. Test the "Reorder" option in the dropdown menu (three dots icon) - it
should work the same way
7. Test on mobile - the reorder button should be hidden, but the
dropdown option should still be available
8. Test with an empty cart and with a cart that already has items

### Starters Deploy Preview

<!--- Add a link to a deploy preview from `starter.store` with this
branch being used. --->

<!--- Tip: You can get an installable version of this branch from the
CodeSandbox generated when this PR is created. --->

## References

- **Figma Design**:
https://www.figma.com/design/Jyt5kWamjkdPC8xMfeuWfR/My-Account?node-id=5005-80468&p=f&t=lJwhSHXsKzeNhdUS-0
- **Task**: B2BTEAM-2988
- **Checkout API Documentation**: Used `validateCart` mutation to add
items to the cart
- Related components:
  - `MyAccountOrderDetails` - Main order details page
  - `MyAccountReorderButton` - Reorder button component
  - `MyAccountOrderActions` - Order actions dropdown
  - `useReorder` - Reorder functionality hook
  - `redirectToCheckout` - Checkout redirection utility

## Screenshots

<img width="993" height="324" alt="Screenshot 2025-12-11 at 17 55 48"
src="https://github.com/user-attachments/assets/033842ed-4769-4de1-8dbe-b8335d25bfc8"
/>

## Checklist

**PR Title and Commit Messages**

- [x] PR title and commit messages follow the [Conventional
Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification
- Available prefixes: `feat`, `fix`, `chore`, `docs`, `style`,
`refactor`, `ci` and `test`

**PR Description**

- [x] Added a label according to the PR goal - `breaking change`, `bug`,
`contributing`, `performance`, `documentation`..

**Dependencies**

- [ ] Committed the `pnpm-lock.yaml` file when there were changes to the
packages

**Documentation**

- [x] PR description
- [ ] For documentation changes, ping `@Mariana-Caetano` to review and
update (Or submit a doc request)



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added reorder flow: a Reorder button in order details and a Reorder
item in the actions dropdown to quickly recreate previous orders and
proceed to checkout.
  * Reorder button shows loading/disabled state while processing.

* **Bug Fixes / Behavior**
* Order actions now render consistently; cancellation remains available
only when allowed.

* **Style**
* Updated styles and responsive behavior for order header actions and
the reorder button (hidden on smaller viewports).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants