@faststore/core 3.97.0-dev.1 → 3.97.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +24 -24
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/config.json +3 -3
  5. package/.next/cache/webpack/client-production/0.pack +0 -0
  6. package/.next/cache/webpack/client-production/index.pack +0 -0
  7. package/.next/cache/webpack/server-production/0.pack +0 -0
  8. package/.next/cache/webpack/server-production/index.pack +0 -0
  9. package/.next/prerender-manifest.js +1 -1
  10. package/.next/prerender-manifest.json +1 -1
  11. package/.next/react-loadable-manifest.json +7 -7
  12. package/.next/routes-manifest.json +1 -1
  13. package/.next/server/chunks/9630.js +1 -1
  14. package/.next/server/functions-config-manifest.json +1 -1
  15. package/.next/server/middleware-build-manifest.js +1 -1
  16. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  17. package/.next/server/pages/en-US/404.html +1 -1
  18. package/.next/server/pages/en-US/500.html +1 -1
  19. package/.next/server/pages/en-US/checkout.html +1 -1
  20. package/.next/server/pages/en-US/login.html +1 -1
  21. package/.next/server/pages/en-US/s.html +1 -1
  22. package/.next/server/pages/en-US.html +1 -1
  23. package/.next/server/pages/pvt/account/orders/[id].js +1 -1
  24. package/.next/server/pages-manifest.json +1 -1
  25. package/.next/static/chunks/{2927.5a79877943a6bf7c.js → 2927.23bae2c79f0ac0f3.js} +1 -1
  26. package/.next/static/chunks/CartSidebar.f0c16e2bc6f96e9e.js +1 -0
  27. package/.next/static/chunks/{UIToast.19a8664c01a00d3a.js → UIToast.de15325248043ce5.js} +1 -1
  28. package/.next/static/chunks/pages/{_app-dbee0add24c249fe.js → _app-5875d79041a9064f.js} +1 -1
  29. package/.next/static/chunks/pages/pvt/account/orders/[id]-ef8aad8a6be9fb80.js +1 -0
  30. package/.next/static/chunks/{webpack-c6f7dbc72e738310.js → webpack-5269d37fda85c9f2.js} +1 -1
  31. package/.next/static/css/{5eecefd2c6deeee4.css → edb7b00b99fe13ed.css} +1 -1
  32. package/.next/static/{TfWAwIRiLLmgPy8iyBQtG → hjIUsireAvfvMDagHWk9A}/_buildManifest.js +1 -1
  33. package/.next/trace +140 -139
  34. package/.turbo/turbo-build.log +12 -12
  35. package/.turbo/turbo-test.log +6 -5
  36. package/CHANGELOG.md +6 -0
  37. package/package.json +7 -7
  38. package/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderActions/MyAccountOrderActions.tsx +19 -6
  39. package/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderActions/styles.scss +10 -0
  40. package/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderDetails.tsx +10 -5
  41. package/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/MyAccountReorderButton.tsx +37 -0
  42. package/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/index.ts +2 -0
  43. package/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/styles.scss +10 -0
  44. package/src/components/account/orders/MyAccountOrderDetails/section.module.scss +41 -17
  45. package/src/sdk/account/useReorder.ts +148 -0
  46. package/src/sdk/cart/redirectToCheckout.ts +15 -0
  47. package/src/sdk/cart/useCheckoutButton.ts +2 -9
  48. package/src/sdk/error/ReorderError/ReorderError.ts +6 -0
  49. package/.next/static/chunks/CartSidebar.3342e22b115732a3.js +0 -1
  50. package/.next/static/chunks/pages/pvt/account/orders/[id]-dc662a778c5b8876.js +0 -1
  51. /package/.next/static/{TfWAwIRiLLmgPy8iyBQtG → hjIUsireAvfvMDagHWk9A}/_ssgManifest.js +0 -0
@@ -1,23 +1,23 @@
1
1
 
2
- > @faststore/core@3.97.0-dev.0 prebuild /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@3.97.0-dev.1 prebuild /home/runner/work/faststore/faststore/packages/core
3
3
  > na run partytown && na run generate
4
4
 
5
5
 
6
- > @faststore/core@3.97.0-dev.0 partytown /home/runner/work/faststore/faststore/packages/core
6
+ > @faststore/core@3.97.0-dev.1 partytown /home/runner/work/faststore/faststore/packages/core
7
7
  > partytown copylib ./public/~partytown
8
8
 
9
9
  Partytown lib copied to: /home/runner/work/faststore/faststore/packages/core/public/~partytown
10
10
 
11
- > @faststore/core@3.97.0-dev.0 generate /home/runner/work/faststore/faststore/packages/core
11
+ > @faststore/core@3.97.0-dev.1 generate /home/runner/work/faststore/faststore/packages/core
12
12
  > na run generate:schema && na run generate:codegen && na run format:generated
13
13
 
14
14
 
15
- > @faststore/core@3.97.0-dev.0 generate:schema /home/runner/work/faststore/faststore/packages/core
15
+ > @faststore/core@3.97.0-dev.1 generate:schema /home/runner/work/faststore/faststore/packages/core
16
16
  > tsx src/server/generator/generateGraphQLSchemaFile.ts
17
17
 
18
18
  Schema GraphQL file generated successfully
19
19
 
20
- > @faststore/core@3.97.0-dev.0 generate:codegen /home/runner/work/faststore/faststore/packages/core
20
+ > @faststore/core@3.97.0-dev.1 generate:codegen /home/runner/work/faststore/faststore/packages/core
21
21
  > graphql-codegen
22
22
 
23
23
  [STARTED] Parse Configuration
@@ -37,11 +37,11 @@ Running lifecycle hook "afterStart" scripts...
37
37
  [CLI] Loading Documents
38
38
  [CLI] Generating output
39
39
 
40
- > @faststore/core@3.97.0-dev.0 format:generated /home/runner/work/faststore/faststore/packages/core
40
+ > @faststore/core@3.97.0-dev.1 format:generated /home/runner/work/faststore/faststore/packages/core
41
41
  > prettier --write "@generated/**/*.{ts,js,tsx,jsx,json}" --loglevel error
42
42
 
43
43
 
44
- > @faststore/core@3.97.0-dev.0 build /home/runner/work/faststore/faststore/packages/core
44
+ > @faststore/core@3.97.0-dev.1 build /home/runner/work/faststore/faststore/packages/core
45
45
  > next build
46
46
 
47
47
  ⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache
@@ -80,8 +80,8 @@ Import trace for requested module:
80
80
  Collecting page data ...
81
81
  Generating static pages (0/6) ...
82
82
 
83
83
  Generating static pages (1/6)
84
- Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Content documentation at https://developers.vtex.com/docs/guides/faststore/dynamic-content-overview for mapping the page and the corresponding data-fetching function.
85
84
 
86
85
  Generating static pages (2/6)
86
+ Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Content documentation at https://developers.vtex.com/docs/guides/faststore/dynamic-content-overview for mapping the page and the corresponding data-fetching function.
87
87
 
88
88
  Generating static pages (4/6)
89
89
 
90
90
  ✓ Generating static pages (6/6)
91
91
  Finalizing page optimization ...
@@ -111,8 +111,8 @@ Route (pages) Size First Load JS
111
111
  ├ └ css/0fc6b2ff69142c6a.css 4.74 kB
112
112
  ├ λ /pvt/account/orders 9.78 kB 150 kB
113
113
  ├ └ css/40a294d0a24ad01d.css 14.1 kB
114
- ├ λ /pvt/account/orders/[id] 12.1 kB 152 kB
115
- ├ └ css/5eecefd2c6deeee4.css 13.3 kB
114
+ ├ λ /pvt/account/orders/[id] 13.2 kB 153 kB
115
+ ├ └ css/edb7b00b99fe13ed.css 13.4 kB
116
116
  ├ λ /pvt/account/profile 1.98 kB 142 kB
117
117
  ├ └ css/47f1b4e8de15d314.css 4.42 kB
118
118
  ├ λ /pvt/account/security 3.96 kB 144 kB
@@ -123,8 +123,8 @@ Route (pages) Size First Load JS
123
123
  + First Load JS shared by all 112 kB
124
124
  ├ chunks/framework-d514426edf885c68.js 45.4 kB
125
125
  ├ chunks/main-ec03882c4375091d.js 33.2 kB
126
- ├ chunks/pages/_app-dbee0add24c249fe.js 25.8 kB
127
- ├ chunks/webpack-c6f7dbc72e738310.js 3.85 kB
126
+ ├ chunks/pages/_app-5875d79041a9064f.js 25.9 kB
127
+ ├ chunks/webpack-5269d37fda85c9f2.js 3.85 kB
128
128
  └ css/0f070d03aacd9cc5.css 3.57 kB
129
129
 
130
130
  λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
@@ -1,16 +1,17 @@
1
1
 
2
- > @faststore/core@3.97.0-dev.0 test /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@3.97.0-dev.1 test /home/runner/work/faststore/faststore/packages/core
3
3
  > jest
4
4
 
5
- PASS test/utils/multipleTemplates.test.ts (28.944 s)
6
- PASS test/utils/clearCookies.test.ts (28.834 s)
5
+ PASS test/utils/multipleTemplates.test.ts (27.725 s)
6
+ PASS test/utils/clearCookies.test.ts (27.116 s)
7
7
  PASS test/utils/cookieCacheBusting.test.ts
8
8
  PASS test/server/cms/global.test.ts
9
9
  PASS test/server/cms/index.test.ts
10
- PASS test/server/index.test.ts (33.061 s)
10
+ PASS test/server/index.test.ts (32.42 s)
11
+ A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.
11
12
 
12
13
  Test Suites: 6 passed, 6 total
13
14
  Tests: 47 passed, 47 total
14
15
  Snapshots: 0 total
15
- Time: 34.431 s
16
+ Time: 33.84 s
16
17
  Ran all test suites.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.97.0-dev.2 (2026-02-06)
7
+
8
+ ### Features
9
+
10
+ - reorder feature ([#3153](https://github.com/vtex/faststore/issues/3153)) ([d0fdeec](https://github.com/vtex/faststore/commit/d0fdeec77cd94e16f1b79dcc927487320983ba0e))
11
+
6
12
  # [3.97.0-dev.1](https://github.com/vtex/faststore/compare/v3.96.5...v3.97.0-dev.1) (2026-02-03)
7
13
 
8
14
  # 3.97.0-dev.0 (2026-01-27)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "3.97.0-dev.1",
3
+ "version": "3.97.0-dev.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -51,11 +51,11 @@
51
51
  "@envelop/graphql-jit": "^8.0.3",
52
52
  "@envelop/parser-cache": "^6.0.2",
53
53
  "@envelop/validation-cache": "^6.0.2",
54
- "@faststore/api": "3.96.4-dev.0",
55
- "@faststore/graphql-utils": "^3.96.4-dev.0",
56
- "@faststore/lighthouse": "3.96.4-dev.0",
57
- "@faststore/sdk": "3.96.4-dev.0",
58
- "@faststore/ui": "3.96.4-dev.0",
54
+ "@faststore/api": "3.97.0-dev.2",
55
+ "@faststore/graphql-utils": "^3.97.0-dev.2",
56
+ "@faststore/lighthouse": "3.97.0-dev.2",
57
+ "@faststore/sdk": "3.97.0-dev.2",
58
+ "@faststore/ui": "3.97.0-dev.2",
59
59
  "@graphql-codegen/cli": "5.0.2",
60
60
  "@graphql-codegen/client-preset": "4.2.6",
61
61
  "@graphql-codegen/typescript": "4.0.7",
@@ -123,5 +123,5 @@
123
123
  "ts-jest": "29.1.1",
124
124
  "typescript": "5.3.2"
125
125
  },
126
- "gitHead": "03c4793a9a9e2ffcf22cf5eb2820b8d17c5f1387"
126
+ "gitHead": "301d4a4aa7651b1cc4cdf6e480e0242476aa00b0"
127
127
  }
@@ -9,22 +9,29 @@ import {
9
9
  import { useState } from 'react'
10
10
  import MyAccountOrderActionModal from 'src/components/account/orders/MyAccountOrderDetails/MyAccountOrderActionModal'
11
11
  import { useCancelOrder } from 'src/sdk/account/useCancelOrder'
12
+ import { useReorder } from 'src/sdk/account/useReorder'
13
+ import type { ServerOrderDetailsQueryQuery } from '@generated/graphql'
14
+
15
+ type Order = ServerOrderDetailsQueryQuery['userOrder']
12
16
 
13
17
  interface MyAccountOrderActionsProps {
14
18
  allowCancellation: boolean
15
19
  orderId: string
16
20
  customerEmail?: string
21
+ order: Order
17
22
  }
18
23
 
19
24
  export default function MyAccountOrderActions({
20
25
  allowCancellation,
21
26
  orderId,
22
27
  customerEmail,
28
+ order,
23
29
  }: MyAccountOrderActionsProps) {
24
30
  const [isCancelOpen, setIsCancelOpen] = useState<boolean>(false)
25
31
  const { pushToast } = useUI()
26
32
 
27
33
  const { cancelOrder, loading } = useCancelOrder()
34
+ const { reorder } = useReorder()
28
35
 
29
36
  const handleCancel = async () => {
30
37
  const data = {
@@ -54,9 +61,8 @@ export default function MyAccountOrderActions({
54
61
  }
55
62
  }
56
63
 
57
- // Don't render if no actions are available
58
- if (!allowCancellation) {
59
- return null
64
+ const handleReorder = () => {
65
+ reorder(order)
60
66
  }
61
67
 
62
68
  return (
@@ -67,13 +73,20 @@ export default function MyAccountOrderActions({
67
73
  <UIIcon name="DotsThree" data-fs-dropdown-icon />
68
74
  </DropdownButton>
69
75
  <DropdownMenu align="right">
76
+ <DropdownItem
77
+ type="button"
78
+ onClick={handleReorder}
79
+ data-fs-order-actions-item
80
+ data-fs-order-actions-item-reorder
81
+ >
82
+ Reorder
83
+ </DropdownItem>
70
84
  {allowCancellation && (
71
85
  <DropdownItem
72
86
  type="button"
73
87
  onClick={() => setIsCancelOpen(true)}
74
- style={{
75
- color: 'var(--fs-color-text)',
76
- }}
88
+ data-fs-order-actions-item
89
+ data-fs-order-actions-item-cancel
77
90
  >
78
91
  Cancel order
79
92
  </DropdownItem>
@@ -7,4 +7,14 @@
7
7
  [data-fs-dropdown-button] {
8
8
  width: var(--fs-spacing-7);
9
9
  }
10
+
11
+ [data-fs-order-actions-item] {
12
+ color: var(--fs-color-text);
13
+ }
14
+
15
+ [data-fs-order-actions-item-reorder] {
16
+ @include media(">=tablet") {
17
+ display: none;
18
+ }
19
+ }
10
20
  }
@@ -6,6 +6,7 @@ import { MyAccountDeliveryOptionAccordion } from './MyAccountDeliveryOptionAccor
6
6
  import MyAccountOrderActions from './MyAccountOrderActions'
7
7
  import MyAccountOrderedByCard from './MyAccountOrderedByCard'
8
8
  import MyAccountPaymentCard from './MyAccountPaymentCard'
9
+ import MyAccountReorderButton from './MyAccountReorderButton'
9
10
  import MyAccountSummaryCard from './MyAccountSummaryCard'
10
11
 
11
12
  import type {
@@ -55,11 +56,15 @@ export default function MyAccountOrderDetails({
55
56
  </div>
56
57
  </div>
57
58
 
58
- <MyAccountOrderActions
59
- allowCancellation={order.allowCancellation}
60
- orderId={order.orderId}
61
- customerEmail={order.clientProfileData?.email}
62
- />
59
+ <div data-fs-order-details-header-actions>
60
+ <MyAccountReorderButton order={order} />
61
+ <MyAccountOrderActions
62
+ allowCancellation={order.allowCancellation}
63
+ orderId={order.orderId}
64
+ customerEmail={order.clientProfileData?.email}
65
+ order={order}
66
+ />
67
+ </div>
63
68
  </header>
64
69
 
65
70
  <main data-fs-order-details-content>
@@ -0,0 +1,37 @@
1
+ import { Button } from '@faststore/ui'
2
+ import { useReorder } from 'src/sdk/account/useReorder'
3
+ import type { ServerOrderDetailsQueryQuery } from '@generated/graphql'
4
+
5
+ type Order = ServerOrderDetailsQueryQuery['userOrder']
6
+
7
+ export interface MyAccountReorderButtonProps {
8
+ order: Order
9
+ onClick?: () => void
10
+ }
11
+
12
+ export default function MyAccountReorderButton({
13
+ order,
14
+ onClick,
15
+ }: MyAccountReorderButtonProps) {
16
+ const { reorder, loading } = useReorder()
17
+
18
+ const handleClick = async () => {
19
+ try {
20
+ await reorder(order)
21
+ onClick?.()
22
+ } catch (error) {
23
+ console.error(error)
24
+ }
25
+ }
26
+
27
+ return (
28
+ <Button
29
+ variant="secondary"
30
+ data-fs-reorder-button
31
+ onClick={handleClick}
32
+ disabled={loading}
33
+ >
34
+ Reorder
35
+ </Button>
36
+ )
37
+ }
@@ -0,0 +1,2 @@
1
+ export { default } from './MyAccountReorderButton'
2
+ export type { MyAccountReorderButtonProps } from './MyAccountReorderButton'
@@ -0,0 +1,10 @@
1
+ [data-fs-reorder-button] {
2
+ flex-shrink: 0;
3
+
4
+ &:hover:not(:disabled) {
5
+ --fs-button-secondary-bkg-color: var(--fs-button-primary-bkg-color);
6
+ --fs-button-secondary-text-color: var(--fs-button-primary-text-color);
7
+ --fs-button-secondary-bkg-color-hover: var(--fs-button-primary-bkg-color-hover);
8
+ --fs-button-secondary-bkg-color-active: var(--fs-button-primary-bkg-color-active);
9
+ }
10
+ }
@@ -15,6 +15,7 @@
15
15
  @import "./MyAccountPaymentCard/styles.scss";
16
16
  @import "./MyAccountDeliveryOptionAccordion/styles.scss";
17
17
  @import "./MyAccountOrderActions/styles.scss";
18
+ @import "./MyAccountReorderButton/styles.scss";
18
19
  @import "./MyAccountStatusCard/styles.scss";
19
20
  @import "./MyAccountMoreInformationCard/styles.scss";
20
21
  @import "./MyAccountBuyingPolicyAlert/styles.scss";
@@ -24,24 +25,24 @@
24
25
  // --------------------------------------------------------
25
26
 
26
27
  // Default properties
27
- --fs-order-details-padding : 0 20px;
28
+ --fs-order-details-padding: 0 20px;
28
29
 
29
30
  // Header
30
- --fs-order-details-header-gap : var(--fs-spacing-3);
31
- --fs-order-details-header-padding : var(--fs-spacing-5) 0 var(--fs-spacing-4);
32
- --fs-order-details-header-weight : var(--fs-text-weight-semibold);
33
- --fs-order-details-header-size : var(--fs-text-size-4);
34
- --fs-order-details-header-line-height : 1.33;
31
+ --fs-order-details-header-gap: var(--fs-spacing-3);
32
+ --fs-order-details-header-padding: var(--fs-spacing-5) 0 var(--fs-spacing-4);
33
+ --fs-order-details-header-weight: var(--fs-text-weight-semibold);
34
+ --fs-order-details-header-size: var(--fs-text-size-4);
35
+ --fs-order-details-header-line-height: 1.33;
35
36
 
36
37
  // Content
37
- --fs-order-details-content-gap : var(--fs-spacing-4);
38
+ --fs-order-details-content-gap: var(--fs-spacing-4);
38
39
 
39
40
  // --------------------------------------------------------
40
41
  // Structural Styles
41
42
  // --------------------------------------------------------
42
43
 
43
- @include media (">=notebook") {
44
- --fs-order-details-padding : 0;
44
+ @include media(">=notebook") {
45
+ --fs-order-details-padding: 0;
45
46
  }
46
47
 
47
48
  [data-fs-order-details-header] {
@@ -52,14 +53,14 @@
52
53
  justify-content: space-between;
53
54
  padding: var(--fs-order-details-header-padding);
54
55
 
55
- @include media (">=tablet") {
56
- --fs-order-details-header-gap : var(--fs-spacing-2);
56
+ @include media(">=tablet") {
57
+ --fs-order-details-header-gap: var(--fs-spacing-2);
57
58
 
58
59
  align-items: center;
59
60
  }
60
61
 
61
- @include media (">=notebook") {
62
- --fs-order-details-header-padding : var(--fs-spacing-6) 0;
62
+ @include media(">=notebook") {
63
+ --fs-order-details-header-padding: var(--fs-spacing-6) 0;
63
64
  }
64
65
 
65
66
  [data-fs-order-details-header-title] {
@@ -70,11 +71,21 @@
70
71
 
71
72
  [data-fs-order-details-header-back-button] {
72
73
  flex-shrink: 0;
73
- margin-top: calc(var(--fs-spacing-2) * -1); // Align the back button with the title
74
- margin-left: calc(var(--fs-spacing-2) * -1); // Align the back button with the content
74
+ margin-top:
75
+ calc(
76
+ var(--fs-spacing-2) * -1
77
+ ); // Align the back button with the title
78
+
79
+ margin-left:
80
+ calc(
81
+ var(--fs-spacing-2) * -1
82
+ ); // Align the back button with the content
75
83
 
76
84
  @include media(">=notebook") {
77
- margin-top: calc(var(--fs-spacing-1) * -1); // Align the back button with the title
85
+ margin-top:
86
+ calc(
87
+ var(--fs-spacing-1) * -1
88
+ ); // Align the back button with the title
78
89
  }
79
90
  }
80
91
 
@@ -98,6 +109,19 @@
98
109
  @include truncate-title(2);
99
110
  }
100
111
  }
112
+
113
+ [data-fs-order-details-header-actions] {
114
+ display: flex;
115
+ flex-direction: row;
116
+ gap: var(--fs-spacing-2);
117
+ align-items: center;
118
+
119
+ [data-fs-reorder-button] {
120
+ @include media("<tablet") {
121
+ display: none;
122
+ }
123
+ }
124
+ }
101
125
  }
102
126
 
103
127
  [data-fs-order-details-content] {
@@ -105,7 +129,7 @@
105
129
  flex-direction: column;
106
130
  gap: var(--fs-order-details-content-gap);
107
131
 
108
- @include media (">=notebook") {
132
+ @include media(">=notebook") {
109
133
  display: grid;
110
134
  grid-template-columns: repeat(2, 1fr);
111
135
  }
@@ -0,0 +1,148 @@
1
+ import { useState } from 'react'
2
+ import type { ServerOrderDetailsQueryQuery } from '@generated/graphql'
3
+ import { cartStore, ValidateCartMutation } from '../cart'
4
+ import type {
5
+ IStoreOffer,
6
+ ValidateCartMutationMutation,
7
+ ValidateCartMutationMutationVariables,
8
+ CartItemFragment,
9
+ IStoreCart,
10
+ } from '@generated/graphql'
11
+ import { request } from '../graphql/request'
12
+ import { sessionStore } from '../session'
13
+ import { redirectToCheckout } from '../cart/redirectToCheckout'
14
+ import ReorderError from '../error/ReorderError/ReorderError'
15
+
16
+ type Order = ServerOrderDetailsQueryQuery['userOrder']
17
+ type AdditionalProperties =
18
+ CartItemFragment['itemOffered']['additionalProperty']
19
+
20
+ const getItemId = (item: CartItemFragment) => {
21
+ const propertyIds =
22
+ item.itemOffered.additionalProperty
23
+ ?.map((prop) => prop.propertyID)
24
+ .join('-') ?? ''
25
+
26
+ const sellerId = item.seller?.identifier ?? ''
27
+
28
+ return [item.itemOffered.sku, sellerId, propertyIds]
29
+ .filter(Boolean)
30
+ .join('::')
31
+ }
32
+
33
+ export const useReorder = () => {
34
+ const [loading, setLoading] = useState(false)
35
+ const [error, setError] = useState<Error | null>(null)
36
+
37
+ const reorder = async (order: Order | null | undefined) => {
38
+ if (!order) {
39
+ const err = new ReorderError('Order not found')
40
+ setError(err)
41
+ return
42
+ }
43
+
44
+ const deliveryOptions = order.deliveryOptionsData?.deliveryOptions ?? []
45
+ const orderItemsWithSeller =
46
+ deliveryOptions.flatMap((option) =>
47
+ (option?.items ?? []).map((item) => ({
48
+ ...item,
49
+ seller: option?.seller,
50
+ }))
51
+ ) ?? []
52
+
53
+ if (!orderItemsWithSeller || orderItemsWithSeller.length === 0) {
54
+ const err = new ReorderError('No items found in order')
55
+ setError(err)
56
+ return
57
+ }
58
+
59
+ setLoading(true)
60
+ setError(null)
61
+
62
+ try {
63
+ const currentCart = cartStore.read()
64
+
65
+ const acceptedOffer: IStoreOffer[] = orderItemsWithSeller
66
+ .filter(
67
+ (item) =>
68
+ item && item.id && item.quantity && item.seller && item.quantity > 0
69
+ )
70
+ .map((item) => ({
71
+ quantity: item.quantity,
72
+ seller: {
73
+ identifier: item.seller,
74
+ },
75
+ price: item.price ?? 0,
76
+ listPrice: item.price ?? 0,
77
+ itemOffered: {
78
+ sku: item.id ?? '',
79
+ image: item.imageUrl
80
+ ? [
81
+ {
82
+ url: item.imageUrl,
83
+ alternateName: item.name ?? '',
84
+ },
85
+ ]
86
+ : [],
87
+ name: item.name ?? '',
88
+ additionalProperty: [] as AdditionalProperties,
89
+ },
90
+ }))
91
+
92
+ if (acceptedOffer.length === 0) {
93
+ throw new ReorderError('No valid items to reorder')
94
+ }
95
+
96
+ const orderPayload: Partial<IStoreCart['order']> & {
97
+ acceptedOffer: IStoreCart['order']['acceptedOffer']
98
+ shouldSplitItem?: IStoreCart['order']['shouldSplitItem']
99
+ } = {
100
+ acceptedOffer,
101
+ shouldSplitItem: false,
102
+ }
103
+
104
+ if (currentCart.id) {
105
+ orderPayload.orderNumber = currentCart.id
106
+ }
107
+
108
+ const { validateCart: validated } = await request<
109
+ ValidateCartMutationMutation,
110
+ ValidateCartMutationMutationVariables
111
+ >(ValidateCartMutation, {
112
+ session: sessionStore.read(),
113
+ cart: {
114
+ order: orderPayload as IStoreCart['order'],
115
+ },
116
+ })
117
+
118
+ if (!validated) {
119
+ throw new ReorderError('Failed to add items to cart')
120
+ }
121
+
122
+ const updatedCart = {
123
+ id: validated.order.orderNumber,
124
+ items: validated.order.acceptedOffer.map((item) => ({
125
+ ...item,
126
+ id: getItemId(item),
127
+ })),
128
+ messages: validated.messages,
129
+ shouldSplitItem: validated.order.shouldSplitItem,
130
+ }
131
+
132
+ cartStore.set(updatedCart)
133
+
134
+ redirectToCheckout(validated.order.orderNumber)
135
+ } catch (err) {
136
+ setError(err instanceof Error ? err : new ReorderError('Unknown error'))
137
+ console.error('Error reordering:', err)
138
+ } finally {
139
+ setLoading(false)
140
+ }
141
+ }
142
+
143
+ return {
144
+ reorder,
145
+ loading,
146
+ error,
147
+ }
148
+ }
@@ -0,0 +1,15 @@
1
+ import storeConfig from '../../../discovery.config'
2
+
3
+ export const redirectToCheckout = (orderFormId?: string) => {
4
+ const isDevEnv =
5
+ window.location.host.includes('.vtex.app') ||
6
+ window.location.host.includes('localhost')
7
+
8
+ if (!isDevEnv) {
9
+ window.location.href = `${storeConfig.checkoutUrl}`
10
+ } else if (orderFormId) {
11
+ window.location.href = `${storeConfig.checkoutUrl}?orderFormId=${orderFormId}`
12
+ } else {
13
+ window.location.href = `${storeConfig.checkoutUrl}`
14
+ }
15
+ }
@@ -1,21 +1,14 @@
1
- import storeConfig from '../../../discovery.config'
2
1
  import { useCart } from './index'
2
+ import { redirectToCheckout } from './redirectToCheckout'
3
3
 
4
4
  export const useCheckoutButton = () => {
5
5
  const { isValidating, id } = useCart()
6
6
 
7
7
  const onClick = (e: React.MouseEvent<HTMLButtonElement>) => {
8
8
  e.preventDefault()
9
- const isDevEnv =
10
- window.location.host.includes('.vtex.app') ||
11
- window.location.host.includes('localhost')
12
9
 
13
10
  if (!isValidating) {
14
- if (!isDevEnv) {
15
- window.location.href = `${storeConfig.checkoutUrl}`
16
- } else if (id) {
17
- window.location.href = `${storeConfig.checkoutUrl}?orderFormId=${id}`
18
- }
11
+ redirectToCheckout(id)
19
12
  }
20
13
  }
21
14
 
@@ -0,0 +1,6 @@
1
+ export default class ReorderError extends Error {
2
+ constructor(message: string) {
3
+ super(message)
4
+ this.name = 'ReorderError'
5
+ }
6
+ }
@@ -1 +0,0 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1781],{76:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return CartSidebar_CartSidebar}});var r=n(33067),i=n(73888),a=n.n(i),o=n(16652),l=n(13666),c=n(2614),s=n(44194),u=n(71041),d=n(43412),b=n.n(d),useCheckoutButton=()=>{var{isValidating:e,id:t}=(0,u.jD)();return{onClick:n=>{n.preventDefault();var r=window.location.host.includes(".vtex.app")||window.location.host.includes("localhost");!e&&(r?t&&(window.location.href="".concat(b().checkoutUrl,"?orderFormId=").concat(t)):window.location.href="".concat(b().checkoutUrl))},disabled:e,"data-testid":"checkout-button"}},h=n(97358),p=n(94588),m=n.n(p),f=n(31549);function ownKeys(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function _objectSpread(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?ownKeys(Object(n),!0).forEach(function(t){(0,r.Z)(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):ownKeys(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}var j=a()(()=>Promise.all([n.e(9237),n.e(7522),n.e(9465),n.e(9701),n.e(5906)]).then(n.bind(n,49465)).then(e=>e.Button),{ssr:!1,loadableGenerated:{webpack:()=>[null]}}),w=a()(()=>Promise.all([n.e(9237),n.e(7522),n.e(9465),n.e(9701),n.e(5906)]).then(n.bind(n,49465)).then(e=>e.CartSidebarFooter),{ssr:!1,loadableGenerated:{webpack:()=>[null]}}),O=a()(()=>Promise.all([n.e(9237),n.e(7522),n.e(9465),n.e(9701),n.e(5906)]).then(n.bind(n,49465)).then(e=>e.CartSidebarList),{ssr:!1,loadableGenerated:{webpack:()=>[null]}}),x=a()(()=>Promise.all([n.e(9237),n.e(7522),n.e(9465),n.e(9701),n.e(5906)]).then(n.bind(n,49465)).then(e=>e.CartSidebar),{ssr:!1,loadableGenerated:{webpack:()=>[null]}}),v=a()(()=>n.e(1724).then(n.bind(n,96348)),{ssr:!1,loadableGenerated:{webpack:()=>[96348]}}),k=a()(()=>n.e(2985).then(n.bind(n,36683)),{ssr:!1,loadableGenerated:{webpack:()=>[36683]}}),y=a()(()=>n.e(549).then(n.bind(n,39550)),{ssr:!1,loadableGenerated:{webpack:()=>[39550]}}),_=a()(()=>n.e(2553).then(n.bind(n,56768)),{ssr:!1,loadableGenerated:{webpack:()=>[56768]}}),CartSidebar_CartSidebar=function(e){var{title:t,alert:{icon:{icon:r,alt:i},text:a},checkoutButton:{label:d,loadingLabel:b,icon:{icon:p,alt:g}},quantitySelector:P,taxesConfiguration:C}=e,S=useCheckoutButton(),{items:D,gifts:G,totalItems:T,isValidating:F,subTotal:M,total:U,subTotalWithTaxes:B,totalWithTaxes:E}=(0,u.jD)({useUnitMultiplier:null==P?void 0:P.useUnitMultiplier}),{cart:I,closeCart:N}=(0,o.l8)(),{fadeOut:L}=(0,l.b)(),{sendViewCartEvent:K}=function(){var{currency:{code:e}}=(0,h.kP)(),{items:t,gifts:r,total:i}=(0,u.jD)(),a=JSON.stringify(r),o=JSON.stringify(t),l=(0,s.useCallback)(()=>{n.e(9399).then(n.bind(n,66393)).then(n=>{var{sendAnalyticsEvent:a}=n;return a({name:"view_cart",params:{currency:e,value:i,items:t.concat(r).map(t=>({item_id:t.itemOffered.isVariantOf.productGroupID,item_name:t.itemOffered.isVariantOf.name,item_brand:t.itemOffered.brand.name,item_variant:t.itemOffered.sku,quantity:t.quantity,price:t.price,discount:t.listPrice-t.price,currency:e,item_variant_name:t.itemOffered.name,product_reference_id:t.itemOffered.gtin}))}})})},[e,a,o,i]);return(0,s.useMemo)(()=>({sendViewCartEvent:l}),[l])}(),W=(0,s.useMemo)(()=>0===D.length,[D]);return(0,s.useEffect)(()=>{I&&K()},[I,K]),(0,f.jsx)(f.Fragment,{children:I&&(0,f.jsx)(x,{overlayProps:{className:"section ".concat(m().section," section-cart-sidebar")},title:t,totalItems:T,alertIcon:(0,f.jsx)(c.Z,{name:r,"aria-label":i}),alertText:a,onClose:L,children:W?(0,f.jsx)(v,{onDismiss:N}):(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(O,{children:[D.map(e=>{var t;return(0,f.jsx)("li",{children:(0,f.jsx)(y,{item:e,taxesConfiguration:C,useUnitMultiplier:null!==(t=null==P?void 0:P.useUnitMultiplier)&&void 0!==t&&t})},e.id)}),G.length>0&&(0,f.jsx)(f.Fragment,{children:G.map(e=>(0,f.jsx)("li",{children:(0,f.jsx)(k,{item:e})},e.id))})]}),(0,f.jsx)(w,{children:(0,f.jsx)(_,{subTotal:null!=C&&C.usePriceWithTaxes?B:M,total:null!=C&&C.usePriceWithTaxes?E:U,includeTaxes:null==C?void 0:C.usePriceWithTaxes,includeTaxesLabel:null==C?void 0:C.taxesLabel,numberOfItems:T,checkoutButton:(0,f.jsx)(j,_objectSpread(_objectSpread({variant:"primary",icon:!F&&(0,f.jsx)(c.Z,{name:p,"aria-label":g,width:18,height:18}),iconPosition:"right"},S),{},{children:F?b:d}))})})]})})})}},94588:function(e){e.exports={section:"section_section__yzDFp"}}}]);