@faststore/core 3.97.0 → 3.97.1

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 (125) 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 +1 -1
  12. package/.next/routes-manifest.json +1 -1
  13. package/.next/server/chunks/2445.js +12 -1
  14. package/.next/server/chunks/3890.js +492 -0
  15. package/.next/server/chunks/3951.js +7 -0
  16. package/.next/server/chunks/4365.js +1 -1
  17. package/.next/server/chunks/870.js +1 -1
  18. package/.next/server/chunks/9563.js +2 -2
  19. package/.next/server/middleware-build-manifest.js +1 -1
  20. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  21. package/.next/server/pages/404.js +1 -1
  22. package/.next/server/pages/404.js.nft.json +1 -1
  23. package/.next/server/pages/500.js +1 -1
  24. package/.next/server/pages/500.js.nft.json +1 -1
  25. package/.next/server/pages/[...slug].js +1 -1
  26. package/.next/server/pages/[...slug].js.nft.json +1 -1
  27. package/.next/server/pages/[slug]/p.js +1 -1
  28. package/.next/server/pages/[slug]/p.js.nft.json +1 -1
  29. package/.next/server/pages/_app.js +1 -1
  30. package/.next/server/pages/_app.js.nft.json +1 -1
  31. package/.next/server/pages/_document.js +1 -1
  32. package/.next/server/pages/_document.js.nft.json +1 -1
  33. package/.next/server/pages/_error.js +1 -1
  34. package/.next/server/pages/_error.js.nft.json +1 -1
  35. package/.next/server/pages/api/fs/logout.js.nft.json +1 -1
  36. package/.next/server/pages/api/graphql.js +3 -3
  37. package/.next/server/pages/api/graphql.js.nft.json +1 -1
  38. package/.next/server/pages/api/health/live.js.nft.json +1 -1
  39. package/.next/server/pages/api/health/ready.js.nft.json +1 -1
  40. package/.next/server/pages/api/preview.js +1 -1
  41. package/.next/server/pages/api/preview.js.nft.json +1 -1
  42. package/.next/server/pages/checkout.js +1 -1
  43. package/.next/server/pages/checkout.js.nft.json +1 -1
  44. package/.next/server/pages/en-US/404.html +28 -13
  45. package/.next/server/pages/en-US/500.html +28 -13
  46. package/.next/server/pages/en-US/checkout.html +28 -13
  47. package/.next/server/pages/en-US/login.html +28 -13
  48. package/.next/server/pages/en-US/s.html +28 -13
  49. package/.next/server/pages/en-US.html +28 -13
  50. package/.next/server/pages/index.js +1 -1
  51. package/.next/server/pages/index.js.nft.json +1 -1
  52. package/.next/server/pages/login.js +1 -1
  53. package/.next/server/pages/login.js.nft.json +1 -1
  54. package/.next/server/pages/pvt/account/403.js +1 -1
  55. package/.next/server/pages/pvt/account/403.js.nft.json +1 -1
  56. package/.next/server/pages/pvt/account/404.js +1 -1
  57. package/.next/server/pages/pvt/account/404.js.nft.json +1 -1
  58. package/.next/server/pages/pvt/account/[...unknown].js +1 -1
  59. package/.next/server/pages/pvt/account/[...unknown].js.nft.json +1 -1
  60. package/.next/server/pages/pvt/account/orders/[id].js +1 -1
  61. package/.next/server/pages/pvt/account/orders/[id].js.nft.json +1 -1
  62. package/.next/server/pages/pvt/account/orders.js +1 -1
  63. package/.next/server/pages/pvt/account/orders.js.nft.json +1 -1
  64. package/.next/server/pages/pvt/account/profile.js +1 -1
  65. package/.next/server/pages/pvt/account/profile.js.nft.json +1 -1
  66. package/.next/server/pages/pvt/account/security.js +1 -1
  67. package/.next/server/pages/pvt/account/security.js.nft.json +1 -1
  68. package/.next/server/pages/pvt/account/user-details.js +1 -1
  69. package/.next/server/pages/pvt/account/user-details.js.nft.json +1 -1
  70. package/.next/server/pages/pvt/account.js +1 -1
  71. package/.next/server/pages/pvt/account.js.nft.json +1 -1
  72. package/.next/server/pages/s.js +1 -1
  73. package/.next/server/pages/s.js.nft.json +1 -1
  74. package/.next/server/pages-manifest.json +1 -1
  75. package/.next/static/{wEDc4gCW_Kv0gEGlYKana → DAJIfXczlTKGDp0c66INm}/_buildManifest.js +1 -1
  76. package/.next/static/chunks/7692.8d5bf4560341a2f6.js +1 -0
  77. package/.next/static/chunks/941.3e2782ab9c490eb0.js +1 -0
  78. package/.next/static/chunks/CartSidebar.f0c16e2bc6f96e9e.js +1 -0
  79. package/.next/static/chunks/pages/_app-1595678557980d65.js +1 -0
  80. package/.next/static/chunks/pages/pvt/account/orders/[id]-e03ebb0393ac92a2.js +1 -0
  81. package/.next/static/chunks/webpack-f3fde0e8298ce999.js +1 -0
  82. package/.next/static/css/{5eecefd2c6deeee4.css → 08d03445f1797608.css} +1 -1
  83. package/.next/trace +140 -139
  84. package/.turbo/turbo-build.log +26 -26
  85. package/.turbo/turbo-test.log +6 -7
  86. package/@generated/gql.ts +2 -2
  87. package/@generated/graphql.ts +54 -1
  88. package/@generated/persisted-documents.json +1 -1
  89. package/@generated/schema.graphql +41 -0
  90. package/CHANGELOG.md +32 -0
  91. package/discovery.config.default.js +1 -0
  92. package/package.json +4 -4
  93. package/src/Layout.tsx +2 -2
  94. package/src/components/ThirdPartyScripts/GoogleTagManager.tsx +19 -10
  95. package/src/components/ThirdPartyScripts/ThirdPartyScripts.tsx +1 -22
  96. package/src/components/ThirdPartyScripts/vtex.tsx +6 -1
  97. package/src/components/account/orders/MyAccountOrderDetails/MyAccountBudgetsCard/MyAccountBudgetsCard.tsx +119 -0
  98. package/src/components/account/orders/MyAccountOrderDetails/MyAccountBudgetsCard/index.ts +1 -0
  99. package/src/components/account/orders/MyAccountOrderDetails/MyAccountBudgetsCard/styles.scss +129 -0
  100. package/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderActions/MyAccountOrderActions.tsx +19 -6
  101. package/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderActions/styles.scss +10 -0
  102. package/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderDetails.tsx +18 -5
  103. package/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/MyAccountReorderButton.tsx +37 -0
  104. package/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/index.ts +2 -0
  105. package/src/components/account/orders/MyAccountOrderDetails/MyAccountReorderButton/styles.scss +10 -0
  106. package/src/components/account/orders/MyAccountOrderDetails/section.module.scss +46 -17
  107. package/src/constants.ts +2 -0
  108. package/src/pages/_document.tsx +40 -0
  109. package/src/pages/api/preview.ts +4 -4
  110. package/src/pages/pvt/account/orders/[id].tsx +19 -1
  111. package/src/sdk/account/useReorder.ts +148 -0
  112. package/src/sdk/analytics/hooks/usePageViewEvent.ts +7 -2
  113. package/src/sdk/analytics/platform/vtex/search.ts +22 -8
  114. package/src/sdk/cart/redirectToCheckout.ts +15 -0
  115. package/src/sdk/cart/useCheckoutButton.ts +2 -9
  116. package/src/sdk/error/ReorderError/ReorderError.ts +6 -0
  117. package/.next/server/chunks/4168.js +0 -1
  118. package/.next/server/chunks/9630.js +0 -495
  119. package/.next/static/chunks/7692.a352cce6d744fa8b.js +0 -1
  120. package/.next/static/chunks/941.417f354fd61bae91.js +0 -1
  121. package/.next/static/chunks/CartSidebar.3342e22b115732a3.js +0 -1
  122. package/.next/static/chunks/pages/_app-dbee0add24c249fe.js +0 -1
  123. package/.next/static/chunks/pages/pvt/account/orders/[id]-dc662a778c5b8876.js +0 -1
  124. package/.next/static/chunks/webpack-c6f7dbc72e738310.js +0 -1
  125. /package/.next/static/{wEDc4gCW_Kv0gEGlYKana → DAJIfXczlTKGDp0c66INm}/_ssgManifest.js +0 -0
@@ -0,0 +1,119 @@
1
+ import type { ServerOrderDetailsQueryQuery } from '@generated/graphql'
2
+ import MyAccountCard from 'src/components/account/components/MyAccountCard'
3
+ import { useFormatPrice } from 'src/components/account/utils/useFormatPrice'
4
+
5
+ interface MyAccountBudgetsCardProps {
6
+ budgetData: ServerOrderDetailsQueryQuery['userOrder']['budgetData']
7
+ currencyCode: string
8
+ }
9
+
10
+ function MyAccountBudgetsCard({
11
+ budgetData,
12
+ currencyCode,
13
+ }: MyAccountBudgetsCardProps) {
14
+ const formatPrice = useFormatPrice()
15
+
16
+ if (!budgetData?.budgets || budgetData.budgets.length === 0) {
17
+ return null
18
+ }
19
+
20
+ // Process each budget to display correctly
21
+ const budgetRows = budgetData.budgets
22
+ .filter(
23
+ (budget) => budget && budget.allocations && budget.allocations.length > 0
24
+ )
25
+ .map((budget) => {
26
+ const allocations = budget.allocations.filter(Boolean)
27
+
28
+ // Calculate toBeSpent: sum all reservation values from all allocations
29
+ // reservations is an object (key: value), so we need to sum all values
30
+ const toBeSpent = allocations.reduce((total, allocation) => {
31
+ if (!allocation?.reservations) return total
32
+
33
+ const reservations = allocation.reservations
34
+ // If reservations is an object, sum all its values
35
+ if (typeof reservations === 'object' && reservations !== null) {
36
+ const reservationValues = Object.values(reservations).filter(
37
+ (val): val is number => typeof val === 'number'
38
+ )
39
+ return total + reservationValues.reduce((sum, val) => sum + val, 0)
40
+ }
41
+
42
+ return total
43
+ }, 0)
44
+
45
+ // Get remaining from budget.balance.remaining
46
+ const remaining = budget.balance?.remaining || 0
47
+
48
+ // Calculate available: toBeSpent + remaining
49
+ const available = toBeSpent + remaining
50
+
51
+ // Get list of allocation linkedEntity IDs
52
+ const allocationIds = allocations
53
+ .map((allocation) => allocation?.linkedEntity?.id)
54
+ .filter(Boolean)
55
+ .join(', ')
56
+
57
+ return {
58
+ budget,
59
+ allocationIds,
60
+ toBeSpent,
61
+ remaining,
62
+ available,
63
+ }
64
+ })
65
+
66
+ if (budgetRows.length === 0) {
67
+ return null
68
+ }
69
+
70
+ return (
71
+ <MyAccountCard title="Budgets" data-fs-order-budgets-card>
72
+ <div data-fs-budgets-table>
73
+ <div data-fs-budgets-table-header>
74
+ <div data-fs-budgets-header-name>Name</div>
75
+ <div data-fs-budgets-header-available>Available</div>
76
+ <div data-fs-budgets-header-to-be-spent>To be spent</div>
77
+ <div data-fs-budgets-header-remaining>Remaining</div>
78
+ </div>
79
+ <div data-fs-budgets-table-body>
80
+ {budgetRows.map(
81
+ (
82
+ { budget, allocationIds, toBeSpent, remaining, available },
83
+ index
84
+ ) => {
85
+ const budgetName = budget.name || ''
86
+ const allocationsList = allocationIds || ''
87
+
88
+ return (
89
+ <div data-fs-budgets-row key={budget.id || index}>
90
+ <div data-fs-budgets-name>
91
+ <div data-fs-budgets-name-primary>{budgetName}</div>
92
+ <div data-fs-budgets-name-secondary title={allocationsList}>
93
+ {allocationsList}
94
+ </div>
95
+ </div>
96
+ <div data-fs-budgets-available>
97
+ {Number.isFinite(available)
98
+ ? formatPrice(available, currencyCode)
99
+ : '—'}
100
+ </div>
101
+ <div data-fs-budgets-to-be-spent>
102
+ {toBeSpent !== 0
103
+ ? formatPrice(toBeSpent, currencyCode)
104
+ : formatPrice(0, currencyCode)}
105
+ </div>
106
+ <div data-fs-budgets-remaining>
107
+ <strong>{formatPrice(remaining, currencyCode)}</strong>
108
+ </div>
109
+ </div>
110
+ )
111
+ }
112
+ )}
113
+ </div>
114
+ </div>
115
+ </MyAccountCard>
116
+ )
117
+ }
118
+
119
+ export default MyAccountBudgetsCard
@@ -0,0 +1 @@
1
+ export { default } from './MyAccountBudgetsCard'
@@ -0,0 +1,129 @@
1
+ [data-fs-order-budgets-card] {
2
+ --fs-budgets-gap: var(--fs-spacing-3);
3
+ --fs-budgets-padding-y: var(--fs-spacing-2);
4
+ --fs-budgets-row-padding: var(--fs-spacing-3) 0;
5
+ --fs-budgets-font-size: var(--fs-text-size-2);
6
+ --fs-budgets-font-size-sm: var(--fs-text-size-1);
7
+ --fs-budgets-weight-regular: var(--fs-text-weight-regular);
8
+ --fs-budgets-weight-semibold: var(--fs-text-weight-semibold);
9
+ --fs-budgets-text: var(--fs-color-text);
10
+ --fs-budgets-text-secondary: var(--fs-color-text-secondary);
11
+ --fs-budgets-border-color: var(--fs-border-color-light);
12
+ --fs-budgets-cols-mobile: 2fr 1fr 1fr;
13
+ --fs-budgets-cols-desktop: 2fr 1fr 1fr 1fr;
14
+
15
+ [data-fs-budgets-table] {
16
+ display: flex;
17
+ flex-direction: column;
18
+ width: 100%;
19
+ }
20
+
21
+ [data-fs-budgets-table-header] {
22
+ display: grid;
23
+ grid-template-columns: var(--fs-budgets-cols-mobile);
24
+ gap: var(--fs-budgets-gap);
25
+ padding: var(--fs-budgets-padding-y) 0;
26
+ font-size: var(--fs-budgets-font-size);
27
+ font-weight: var(--fs-budgets-weight-regular);
28
+ color: var(--fs-budgets-text-secondary);
29
+ border-bottom: 1px solid var(--fs-budgets-border-color);
30
+
31
+ [data-fs-budgets-header-name] {
32
+ text-align: left;
33
+ }
34
+
35
+ [data-fs-budgets-header-available],
36
+ [data-fs-budgets-header-to-be-spent],
37
+ [data-fs-budgets-header-remaining] {
38
+ text-align: right;
39
+ white-space: nowrap;
40
+ }
41
+
42
+ @include media('>=tablet') {
43
+ grid-template-columns: var(--fs-budgets-cols-desktop);
44
+ }
45
+
46
+ [data-fs-budgets-header-available] {
47
+ @include media('<tablet') {
48
+ display: none;
49
+ }
50
+ }
51
+ }
52
+
53
+ [data-fs-budgets-table-body] {
54
+ display: flex;
55
+ flex-direction: column;
56
+
57
+ [data-fs-budgets-row] {
58
+ display: grid;
59
+ grid-template-columns: var(--fs-budgets-cols-mobile);
60
+ gap: var(--fs-budgets-gap);
61
+ padding: var(--fs-budgets-row-padding);
62
+ border-bottom: 1px solid var(--fs-budgets-border-color);
63
+
64
+ // Prevent long content from forcing the grid to overflow
65
+ > * {
66
+ min-width: 0;
67
+ }
68
+
69
+ &:last-child {
70
+ border-bottom: none;
71
+ }
72
+
73
+ @include media('>=tablet') {
74
+ grid-template-columns: var(--fs-budgets-cols-desktop);
75
+ }
76
+ }
77
+
78
+ [data-fs-budgets-available] {
79
+ @include media('<tablet') {
80
+ display: none;
81
+ }
82
+ }
83
+ }
84
+
85
+ [data-fs-budgets-name] {
86
+ display: flex;
87
+ flex-direction: column;
88
+ gap: var(--fs-spacing-0);
89
+ }
90
+
91
+ [data-fs-budgets-name-primary] {
92
+ overflow: hidden;
93
+ font-size: var(--fs-budgets-font-size);
94
+ font-weight: var(--fs-budgets-weight-semibold);
95
+ line-height: 1.4;
96
+ color: var(--fs-budgets-text);
97
+ text-overflow: ellipsis;
98
+ white-space: nowrap;
99
+ }
100
+
101
+ [data-fs-budgets-name-secondary] {
102
+ overflow: hidden;
103
+ font-size: var(--fs-budgets-font-size-sm);
104
+ font-weight: var(--fs-budgets-weight-regular);
105
+ line-height: 1.4;
106
+ color: var(--fs-budgets-text-secondary);
107
+ text-overflow: ellipsis;
108
+ white-space: nowrap;
109
+ }
110
+
111
+ [data-fs-budgets-available],
112
+ [data-fs-budgets-to-be-spent],
113
+ [data-fs-budgets-remaining] {
114
+ font-size: var(--fs-budgets-font-size);
115
+ font-weight: var(--fs-budgets-weight-regular);
116
+ color: var(--fs-budgets-text);
117
+ text-align: right;
118
+ }
119
+
120
+ [data-fs-budgets-remaining] {
121
+ strong {
122
+ font-weight: var(--fs-budgets-weight-semibold);
123
+ }
124
+ }
125
+
126
+ [data-fs-budgets-to-be-spent] {
127
+ color: var(--fs-budgets-text-secondary);
128
+ }
129
+ }
@@ -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,7 +6,9 @@ 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'
11
+ import MyAccountBudgetsCard from './MyAccountBudgetsCard'
10
12
 
11
13
  import type {
12
14
  ServerOrderDetailsQueryQuery,
@@ -55,11 +57,15 @@ export default function MyAccountOrderDetails({
55
57
  </div>
56
58
  </div>
57
59
 
58
- <MyAccountOrderActions
59
- allowCancellation={order.allowCancellation}
60
- orderId={order.orderId}
61
- customerEmail={order.clientProfileData?.email}
62
- />
60
+ <div data-fs-order-details-header-actions>
61
+ <MyAccountReorderButton order={order} />
62
+ <MyAccountOrderActions
63
+ allowCancellation={order.allowCancellation}
64
+ orderId={order.orderId}
65
+ customerEmail={order.clientProfileData?.email}
66
+ order={order}
67
+ />
68
+ </div>
63
69
  </header>
64
70
 
65
71
  <main data-fs-order-details-content>
@@ -117,6 +123,13 @@ export default function MyAccountOrderDetails({
117
123
  {moreInformationCustomFields?.length > 0 && (
118
124
  <MyAccountMoreInformationCard fields={moreInformationCustomFields} />
119
125
  )}
126
+
127
+ {order.budgetData && (
128
+ <MyAccountBudgetsCard
129
+ budgetData={order.budgetData}
130
+ currencyCode={order.storePreferencesData.currencyCode}
131
+ />
132
+ )}
120
133
  </main>
121
134
  </div>
122
135
  )
@@ -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,33 +15,35 @@
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";
22
+ @import "./MyAccountBudgetsCard/styles.scss";
21
23
 
22
24
  // --------------------------------------------------------
23
25
  // Design Tokens
24
26
  // --------------------------------------------------------
25
27
 
26
28
  // Default properties
27
- --fs-order-details-padding : 0 20px;
29
+ --fs-order-details-padding: 0 20px;
28
30
 
29
31
  // 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;
32
+ --fs-order-details-header-gap: var(--fs-spacing-3);
33
+ --fs-order-details-header-padding: var(--fs-spacing-5) 0 var(--fs-spacing-4);
34
+ --fs-order-details-header-weight: var(--fs-text-weight-semibold);
35
+ --fs-order-details-header-size: var(--fs-text-size-4);
36
+ --fs-order-details-header-line-height: 1.33;
35
37
 
36
38
  // Content
37
- --fs-order-details-content-gap : var(--fs-spacing-4);
39
+ --fs-order-details-content-gap: var(--fs-spacing-4);
38
40
 
39
41
  // --------------------------------------------------------
40
42
  // Structural Styles
41
43
  // --------------------------------------------------------
42
44
 
43
- @include media (">=notebook") {
44
- --fs-order-details-padding : 0;
45
+ @include media(">=notebook") {
46
+ --fs-order-details-padding: 0;
45
47
  }
46
48
 
47
49
  [data-fs-order-details-header] {
@@ -52,14 +54,14 @@
52
54
  justify-content: space-between;
53
55
  padding: var(--fs-order-details-header-padding);
54
56
 
55
- @include media (">=tablet") {
56
- --fs-order-details-header-gap : var(--fs-spacing-2);
57
+ @include media(">=tablet") {
58
+ --fs-order-details-header-gap: var(--fs-spacing-2);
57
59
 
58
60
  align-items: center;
59
61
  }
60
62
 
61
- @include media (">=notebook") {
62
- --fs-order-details-header-padding : var(--fs-spacing-6) 0;
63
+ @include media(">=notebook") {
64
+ --fs-order-details-header-padding: var(--fs-spacing-6) 0;
63
65
  }
64
66
 
65
67
  [data-fs-order-details-header-title] {
@@ -70,11 +72,21 @@
70
72
 
71
73
  [data-fs-order-details-header-back-button] {
72
74
  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
75
+ margin-top:
76
+ calc(
77
+ var(--fs-spacing-2) * -1
78
+ ); // Align the back button with the title
79
+
80
+ margin-left:
81
+ calc(
82
+ var(--fs-spacing-2) * -1
83
+ ); // Align the back button with the content
75
84
 
76
85
  @include media(">=notebook") {
77
- margin-top: calc(var(--fs-spacing-1) * -1); // Align the back button with the title
86
+ margin-top:
87
+ calc(
88
+ var(--fs-spacing-1) * -1
89
+ ); // Align the back button with the title
78
90
  }
79
91
  }
80
92
 
@@ -98,6 +110,19 @@
98
110
  @include truncate-title(2);
99
111
  }
100
112
  }
113
+
114
+ [data-fs-order-details-header-actions] {
115
+ display: flex;
116
+ flex-direction: row;
117
+ gap: var(--fs-spacing-2);
118
+ align-items: center;
119
+
120
+ [data-fs-reorder-button] {
121
+ @include media("<tablet") {
122
+ display: none;
123
+ }
124
+ }
125
+ }
101
126
  }
102
127
 
103
128
  [data-fs-order-details-content] {
@@ -105,7 +130,7 @@
105
130
  flex-direction: column;
106
131
  gap: var(--fs-order-details-content-gap);
107
132
 
108
- @include media (">=notebook") {
133
+ @include media(">=notebook") {
109
134
  display: grid;
110
135
  grid-template-columns: repeat(2, 1fr);
111
136
  }
@@ -125,5 +150,9 @@
125
150
  [data-fs-delivery-option-accordion] {
126
151
  grid-column: span 2;
127
152
  }
153
+
154
+ [data-fs-order-budgets-card] {
155
+ grid-column: span 2;
156
+ }
128
157
  }
129
158
  }
package/src/constants.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export const ITEMS_PER_PAGE = 12
2
2
  export const ITEMS_PER_SECTION = 5
3
3
  export const TIME_TO_VALIDATE_SESSION = 3000
4
+ export const LOG_LABEL_STYLE =
5
+ 'background:#C4144F;color:#fff;padding:2px 4px;border-radius:2px'
@@ -1,10 +1,17 @@
1
1
  import { Head, Html, Main, NextScript } from 'next/document'
2
2
  import storeConfig from '../../discovery.config'
3
3
 
4
+ import { GTM_DEBUG_QUERY_STRING } from 'src/components/ThirdPartyScripts/GoogleTagManager'
4
5
  import { WebFonts } from 'src/customizations/src/GlobalOverrides'
5
6
 
6
7
  function Document() {
7
8
  const direction = storeConfig.direction || 'ltr'
9
+ const gtmContainerId = storeConfig.analytics?.gtmContainerId
10
+ const includeGTM = typeof gtmContainerId === 'string'
11
+ const includeVTEX = storeConfig.platform === 'vtex'
12
+ const enableScriptsLogs = storeConfig.experimental?.enableScriptsLogs === true
13
+ const forwards = []
14
+ if (includeVTEX) forwards.push('sendrc')
8
15
 
9
16
  return (
10
17
  <Html dir={direction}>
@@ -19,6 +26,39 @@ function Document() {
19
26
  />
20
27
  <meta name="storefront" content="fast_store" />
21
28
  <WebFonts />
29
+ {/* Partytown config must be set before loading the library.
30
+ * We're setting the partytown config (forward property) dynamically based on the gtm_debug query string
31
+ * This helps users see the GTM events properly when using GTM preview. All it does is NOT forward dataLayer.push
32
+ * calls to partytown when the gtm_debug query string is present.
33
+ *
34
+ * This is not done in the component because the window var is not available yet.
35
+ */}
36
+ <script
37
+ dangerouslySetInnerHTML={{
38
+ __html: `var partytown={
39
+ debug:${enableScriptsLogs},
40
+ logCalls:${enableScriptsLogs},
41
+ forward:[...${JSON.stringify(
42
+ forwards
43
+ )},!window.location.search.includes('${GTM_DEBUG_QUERY_STRING}=')&&${includeGTM}?'dataLayer.push':null].filter(Boolean)
44
+ }`,
45
+ }}
46
+ />
47
+ {/* Only load Partytown when not in an iframe to prevent cross-origin errors.
48
+ * https://github.com/vtex/faststore/pull/3155
49
+ */}
50
+ <script
51
+ dangerouslySetInnerHTML={{
52
+ __html: `
53
+ if (window.self === window.top) {
54
+ var partytownScript = document.createElement('script');
55
+ partytownScript.async = true;
56
+ partytownScript.src = '/~partytown/partytown.js';
57
+ document.head.appendChild(partytownScript);
58
+ }
59
+ `,
60
+ }}
61
+ />
22
62
  </Head>
23
63
  <body className="theme">
24
64
  <Main />
@@ -1,13 +1,13 @@
1
1
  import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
2
2
 
3
- import { previewRedirects } from '../../../discovery.config'
4
- import { contentService } from 'src/server/content/service'
5
3
  import { isLocator } from 'src/server/cms'
4
+ import { contentService } from 'src/server/content/service'
5
+ import type { PreviewData } from 'src/server/content/types'
6
6
  import {
7
7
  isBranchPreview,
8
8
  isContentPlatformSource,
9
9
  } from 'src/server/content/utils'
10
- import type { PreviewData } from 'src/server/content/types'
10
+ import { previewRedirects } from '../../../discovery.config'
11
11
 
12
12
  type Settings = {
13
13
  seo: {
@@ -40,7 +40,7 @@ const setPreviewAndRedirect = (
40
40
  }
41
41
 
42
42
  if (!isBranchPreview(previewData as PreviewData)) {
43
- options.path = redirectPath
43
+ options.path = redirectPath.split('?')[0]
44
44
  }
45
45
 
46
46
  res.setPreviewData(previewData, options)
@@ -257,6 +257,22 @@ const query = gql(`
257
257
  email
258
258
  phone
259
259
  }
260
+ budgetData {
261
+ budgets {
262
+ id
263
+ name
264
+ balance {
265
+ remaining
266
+ }
267
+ allocations {
268
+ id
269
+ linkedEntity {
270
+ id
271
+ }
272
+ reservations
273
+ }
274
+ }
275
+ }
260
276
  }
261
277
  accountProfile {
262
278
  name
@@ -339,10 +355,12 @@ export const getServerSideProps: GetServerSideProps<
339
355
  globalSectionsFooter,
340
356
  })
341
357
 
358
+ const order = orderDetails.data.userOrder
359
+
342
360
  return {
343
361
  props: {
344
362
  globalSections: globalSectionsResult,
345
- order: orderDetails.data.userOrder,
363
+ order,
346
364
  accountName: orderDetails.data.accountProfile.name,
347
365
  isRepresentative,
348
366
  },