@faststore/core 2.2.0-alpha.5 → 2.2.0-alpha.6
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.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +63 -64
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/config.json +3 -3
- package/.next/cache/eslint/.cache_1gneedd +1 -1
- package/.next/cache/next-server.js.nft.json +1 -1
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/react-loadable-manifest.json +11 -8
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/{647.js → 117.js} +25 -32
- package/.next/server/chunks/183.js +1 -0
- package/.next/server/chunks/289.js +25 -27
- package/.next/server/chunks/312.js +46 -66
- package/.next/server/chunks/350.js +7 -7
- package/.next/server/chunks/{483.js → 37.js} +121 -162
- package/.next/server/chunks/386.js +200 -0
- package/.next/server/chunks/{753.js → 387.js} +8 -12
- package/.next/server/chunks/576.js +1 -0
- package/.next/server/chunks/{530.js → 585.js} +65 -51
- package/.next/server/chunks/{186.js → 692.js} +6 -8
- package/.next/server/chunks/{112.js → 732.js} +136 -369
- package/.next/server/chunks/74.js +214 -335
- package/.next/server/chunks/{71.js → 897.js} +173 -177
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.js +13 -13
- package/.next/server/pages/404.js.nft.json +1 -1
- package/.next/server/pages/500.js +14 -14
- package/.next/server/pages/500.js.nft.json +1 -1
- package/.next/server/pages/[...slug].js +131 -183
- package/.next/server/pages/[...slug].js.nft.json +1 -1
- package/.next/server/pages/[slug]/p.js +145 -145
- package/.next/server/pages/[slug]/p.js.nft.json +1 -1
- package/.next/server/pages/_app.js +2 -4
- package/.next/server/pages/_app.js.nft.json +1 -1
- package/.next/server/pages/_document.js +17 -33
- package/.next/server/pages/account.js +12 -12
- package/.next/server/pages/account.js.nft.json +1 -1
- package/.next/server/pages/api/graphql.js +7 -7
- package/.next/server/pages/api/preview.js +2 -20
- package/.next/server/pages/checkout.js +12 -12
- package/.next/server/pages/checkout.js.nft.json +1 -1
- package/.next/server/pages/en-US/404.html +2 -2
- package/.next/server/pages/en-US/500.html +2 -2
- package/.next/server/pages/en-US/account.html +2 -2
- package/.next/server/pages/en-US/checkout.html +2 -2
- package/.next/server/pages/en-US/login.html +2 -2
- package/.next/server/pages/en-US/s.html +2 -2
- package/.next/server/pages/en-US.html +11 -2
- package/.next/server/pages/index.js +41 -48
- package/.next/server/pages/index.js.nft.json +1 -1
- package/.next/server/pages/login.js +15 -15
- package/.next/server/pages/login.js.nft.json +1 -1
- package/.next/server/pages/s.js +52 -52
- package/.next/server/pages/s.js.nft.json +1 -1
- package/.next/server/pages-manifest.json +4 -4
- package/.next/static/chunks/251.47f06fb688ea42d1.js +1 -0
- package/.next/static/chunks/383-f5039943ae2a4372.js +1 -0
- package/.next/static/chunks/386.d01e0db26c523f0f.js +1 -0
- package/.next/static/chunks/585.3350efefe61c9461.js +1 -0
- package/.next/static/chunks/635-666ee2cad2925bb7.js +1 -0
- package/.next/static/chunks/721-717d8a2486b7d30e.js +1 -0
- package/.next/static/chunks/722-686f01490d4d2176.js +1 -0
- package/.next/static/chunks/783-ded9d8cda0d5c8d9.js +1 -0
- package/.next/static/chunks/{709.daf1eddebf1e7952.js → 800.851af48fe2ab4a4c.js} +1 -1
- package/.next/static/chunks/988.afda042dd9ba11d1.js +1 -0
- package/.next/static/chunks/pages/{404-af78f7cd1d3c1f60.js → 404-6c674028b2f80cbb.js} +1 -1
- package/.next/static/chunks/pages/{500-f6346ca5f9dc4fef.js → 500-ff55de77265a7e43.js} +1 -1
- package/.next/static/chunks/pages/[...slug]-7f8dc13cc9542463.js +1 -0
- package/.next/static/chunks/pages/[slug]/p-1cec94f3f7583058.js +1 -0
- package/.next/static/chunks/pages/{_app-6d0e6ab9a4dd8106.js → _app-7db7de3d205714be.js} +1 -1
- package/.next/static/chunks/pages/{account-05bd79fb78365e88.js → account-b06035cba2c99604.js} +1 -1
- package/.next/static/chunks/pages/{checkout-c973786e68f25a39.js → checkout-f0c3e8d691cb8a54.js} +1 -1
- package/.next/static/chunks/pages/index-a141c747fcc197a1.js +1 -0
- package/.next/static/chunks/pages/{login-8deb9243376b6aa1.js → login-4e0e6cab7a07f1f3.js} +1 -1
- package/.next/static/chunks/pages/s-823f8e1cabbf63b3.js +1 -0
- package/.next/static/chunks/webpack-bed5a9784a3af4e8.js +1 -0
- package/.next/static/css/1b48021b9c503e72.css +1 -0
- package/.next/static/css/6a7fdc5a21fbead5.css +1 -0
- package/.next/static/css/723835bce380750d.css +1 -0
- package/.next/static/css/8f93a4630936c20b.css +1 -0
- package/.next/static/css/fd27ecc37832aa54.css +1 -0
- package/.next/static/h5IF1CNB8dJwLG9OAuMOX/_buildManifest.js +1 -0
- package/.next/trace +77 -80
- package/.turbo/turbo-build.log +13 -13
- package/.turbo/turbo-test.log +9 -9
- package/README.md +3 -3
- package/cms/faststore/sections.json +12 -0
- package/cypress/global.js +8 -0
- package/cypress/integration/a11y.test.js +7 -24
- package/cypress/integration/analytics.test.js +78 -87
- package/cypress/integration/cart.test.js +4 -4
- package/cypress/integration/plp.test.js +6 -6
- package/cypress/integration/search.test.js +1 -1
- package/cypress/integration/seo.test.js +14 -14
- package/cypress.config.ts +19 -0
- package/faststore.config.js +1 -0
- package/package.json +13 -12
- package/src/components/cart/CartSidebar/CartSidebar.tsx +41 -27
- package/src/components/product/NotAvailableButton/NotAvailableButton.tsx +13 -0
- package/src/components/product/NotAvailableButton/index.ts +1 -0
- package/src/components/sections/Newsletter/Overrides.tsx +4 -0
- package/src/components/sections/ProductDetails/Overrides.tsx +4 -0
- package/src/components/sections/ProductDetails/ProductDetails.tsx +21 -15
- package/src/components/ui/Newsletter/Newsletter.tsx +6 -44
- package/src/components/ui/Newsletter/NewsletterAddendum.tsx +86 -0
- package/src/components/ui/Newsletter/index.ts +1 -1
- package/src/components/ui/ProductDetails/ProductDetailsSettings.tsx +88 -68
- package/src/experimental/index.ts +0 -2
- package/src/pages/[...slug].tsx +1 -0
- package/src/pages/[slug]/p.tsx +1 -0
- package/src/typings/overrides.ts +3 -0
- package/.next/static/63Mec0cKi1kSycIPG6y8Z/_buildManifest.js +0 -1
- package/.next/static/chunks/148.3bb7e05cc5d1c1c4.js +0 -1
- package/.next/static/chunks/238-0ea98e053285c8dd.js +0 -1
- package/.next/static/chunks/243-4d96f27ed60bcbe7.js +0 -1
- package/.next/static/chunks/530.848b014622932b93.js +0 -1
- package/.next/static/chunks/548-ab84e9e8b49413ab.js +0 -1
- package/.next/static/chunks/721-42caacad18f27d0c.js +0 -1
- package/.next/static/chunks/738-67a288ca3569cdbb.js +0 -1
- package/.next/static/chunks/988.d10040040cdfebbb.js +0 -1
- package/.next/static/chunks/pages/[...slug]-97d48d75131c2a0e.js +0 -1
- package/.next/static/chunks/pages/[slug]/p-37a30953f761128f.js +0 -1
- package/.next/static/chunks/pages/index-79b05b0071c02fff.js +0 -1
- package/.next/static/chunks/pages/s-45d23ec628d8832f.js +0 -1
- package/.next/static/chunks/webpack-00c7bb6e48f23dff.js +0 -1
- package/.next/static/css/7ca374e5534a3f68.css +0 -1
- package/.next/static/css/d5a515091be5db82.css +0 -1
- package/.next/static/css/e3b039e8f5daf95f.css +0 -1
- package/.next/static/css/f0e2d1b8832e935d.css +0 -1
- package/cypress.json +0 -9
- /package/.next/static/{63Mec0cKi1kSycIPG6y8Z → h5IF1CNB8dJwLG9OAuMOX}/_ssgManifest.js +0 -0
|
@@ -16,7 +16,7 @@ describe('Home Page Seo', () => {
|
|
|
16
16
|
cy.clearIDB()
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
it
|
|
19
|
+
it('has meta/canonical/link tags', () => {
|
|
20
20
|
cy.visit(pages.home, options)
|
|
21
21
|
cy.waitForHydration()
|
|
22
22
|
|
|
@@ -34,7 +34,7 @@ describe('Home Page Seo', () => {
|
|
|
34
34
|
})
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
it
|
|
37
|
+
it('has structured data', () => {
|
|
38
38
|
cy.visit(pages.home, options)
|
|
39
39
|
cy.waitForHydration()
|
|
40
40
|
|
|
@@ -48,7 +48,7 @@ describe('Home Page Seo', () => {
|
|
|
48
48
|
})
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
it
|
|
51
|
+
it('has OpenGraph tags', () => {
|
|
52
52
|
cy.visit(pages.home, options)
|
|
53
53
|
cy.waitForHydration()
|
|
54
54
|
|
|
@@ -77,7 +77,7 @@ describe('Product Page Seo', () => {
|
|
|
77
77
|
cy.clearIDB()
|
|
78
78
|
})
|
|
79
79
|
|
|
80
|
-
it
|
|
80
|
+
it('has meta/canonical/link tags', () => {
|
|
81
81
|
cy.visit(pages.pdp, options)
|
|
82
82
|
cy.waitForHydration()
|
|
83
83
|
|
|
@@ -95,7 +95,7 @@ describe('Product Page Seo', () => {
|
|
|
95
95
|
})
|
|
96
96
|
})
|
|
97
97
|
|
|
98
|
-
it
|
|
98
|
+
it('has structured data', () => {
|
|
99
99
|
cy.visit(pages.pdp, options)
|
|
100
100
|
cy.waitForHydration()
|
|
101
101
|
|
|
@@ -115,7 +115,7 @@ describe('Product Page Seo', () => {
|
|
|
115
115
|
})
|
|
116
116
|
})
|
|
117
117
|
|
|
118
|
-
it
|
|
118
|
+
it('has OpenGraph tags', () => {
|
|
119
119
|
cy.visit(pages.pdp, options)
|
|
120
120
|
cy.waitForHydration()
|
|
121
121
|
|
|
@@ -162,7 +162,7 @@ describe('Collection Page Seo', () => {
|
|
|
162
162
|
cy.clearIDB()
|
|
163
163
|
})
|
|
164
164
|
|
|
165
|
-
it
|
|
165
|
+
it('has meta/canonical/link tags', () => {
|
|
166
166
|
cy.visit(pages.collection, options)
|
|
167
167
|
cy.waitForHydration()
|
|
168
168
|
|
|
@@ -182,7 +182,7 @@ describe('Collection Page Seo', () => {
|
|
|
182
182
|
})
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
-
it
|
|
185
|
+
it('has structured data', () => {
|
|
186
186
|
cy.visit(pages.collection, options)
|
|
187
187
|
cy.waitForHydration()
|
|
188
188
|
|
|
@@ -201,7 +201,7 @@ describe('Collection Page Seo', () => {
|
|
|
201
201
|
})
|
|
202
202
|
})
|
|
203
203
|
|
|
204
|
-
it
|
|
204
|
+
it('has OpenGraph tags', () => {
|
|
205
205
|
cy.visit(pages.collection, options)
|
|
206
206
|
cy.waitForHydration()
|
|
207
207
|
|
|
@@ -226,7 +226,7 @@ describe('Collection Page Seo', () => {
|
|
|
226
226
|
})
|
|
227
227
|
|
|
228
228
|
describe('Filtered Collection Page Seo', () => {
|
|
229
|
-
it
|
|
229
|
+
it('has canonical pointing to parent url', () => {
|
|
230
230
|
cy.visit(pages.collection_filtered, options)
|
|
231
231
|
cy.waitForHydration()
|
|
232
232
|
|
|
@@ -239,7 +239,7 @@ describe('Filtered Collection Page Seo', () => {
|
|
|
239
239
|
})
|
|
240
240
|
})
|
|
241
241
|
|
|
242
|
-
it
|
|
242
|
+
it('has structured data', () => {
|
|
243
243
|
cy.visit(pages.collection_filtered, options)
|
|
244
244
|
cy.waitForHydration()
|
|
245
245
|
|
|
@@ -258,7 +258,7 @@ describe('Filtered Collection Page Seo', () => {
|
|
|
258
258
|
})
|
|
259
259
|
})
|
|
260
260
|
|
|
261
|
-
it
|
|
261
|
+
it('has OpenGraph tags', () => {
|
|
262
262
|
cy.visit(pages.collection_filtered, options)
|
|
263
263
|
cy.waitForHydration()
|
|
264
264
|
|
|
@@ -283,7 +283,7 @@ describe('Filtered Collection Page Seo', () => {
|
|
|
283
283
|
})
|
|
284
284
|
|
|
285
285
|
describe('Search Page Seo', () => {
|
|
286
|
-
it
|
|
286
|
+
it('has meta/canonical/link tags', () => {
|
|
287
287
|
cy.visit(pages.search, options)
|
|
288
288
|
cy.waitForHydration()
|
|
289
289
|
|
|
@@ -297,7 +297,7 @@ describe('Search Page Seo', () => {
|
|
|
297
297
|
cy.get('link[rel="canonical"]').should('not.exist')
|
|
298
298
|
})
|
|
299
299
|
|
|
300
|
-
it
|
|
300
|
+
it('has OpenGraph tags', () => {
|
|
301
301
|
cy.visit(pages.search, options)
|
|
302
302
|
cy.waitForHydration()
|
|
303
303
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig } from 'cypress'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
retries: 0,
|
|
5
|
+
video: true,
|
|
6
|
+
trashAssetsBeforeRuns: true,
|
|
7
|
+
screenshotOnRunFailure: true,
|
|
8
|
+
viewportWidth: 1000,
|
|
9
|
+
viewportHeight: 600,
|
|
10
|
+
e2e: {
|
|
11
|
+
supportFile: 'cypress/support/index.js',
|
|
12
|
+
specPattern: 'cypress/integration/**/*.test.{js,jsx,ts,tsx}',
|
|
13
|
+
setupNodeEvents(on, config) {
|
|
14
|
+
return require('cypress/plugins/index.js')(on, config)
|
|
15
|
+
},
|
|
16
|
+
baseUrl: 'http://localhost:3000/',
|
|
17
|
+
experimentalRunAllSpecs: true,
|
|
18
|
+
},
|
|
19
|
+
})
|
package/faststore.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "2.2.0-alpha.
|
|
3
|
+
"version": "2.2.0-alpha.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"browserslist": "supports es6-module and not dead",
|
|
6
6
|
"exports": {
|
|
@@ -31,13 +31,14 @@
|
|
|
31
31
|
"engines": {
|
|
32
32
|
"node": ">=14"
|
|
33
33
|
},
|
|
34
|
+
"sideEffects": false,
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"@builder.io/partytown": "^0.6.1",
|
|
36
37
|
"@envelop/core": "^1.2.0",
|
|
37
38
|
"@envelop/graphql-jit": "^1.1.1",
|
|
38
39
|
"@envelop/parser-cache": "^2.2.0",
|
|
39
40
|
"@envelop/validation-cache": "^2.2.0",
|
|
40
|
-
"@faststore/api": "^2.2.0-alpha.
|
|
41
|
+
"@faststore/api": "^2.2.0-alpha.6",
|
|
41
42
|
"@faststore/components": "^2.2.0-alpha.4",
|
|
42
43
|
"@faststore/graphql-utils": "^2.2.0-alpha.1",
|
|
43
44
|
"@faststore/sdk": "^2.2.0-alpha.1",
|
|
@@ -55,8 +56,7 @@
|
|
|
55
56
|
"chalk": "^5.2.0",
|
|
56
57
|
"css-loader": "^6.7.1",
|
|
57
58
|
"deepmerge": "^4.3.1",
|
|
58
|
-
"
|
|
59
|
-
"draft-js-export-html": "^1.4.1",
|
|
59
|
+
"draftjs-to-html": "^0.9.1",
|
|
60
60
|
"graphql": "^15.0.0",
|
|
61
61
|
"include-media": "^1.4.10",
|
|
62
62
|
"msw": "^0.43.1",
|
|
@@ -78,9 +78,9 @@
|
|
|
78
78
|
"typescript": "4.7.3"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@cypress/code-coverage": "^3.
|
|
81
|
+
"@cypress/code-coverage": "^3.12.1",
|
|
82
82
|
"@envelop/testing": "^6.0.0",
|
|
83
|
-
"@faststore/cli": "^2.2.0-alpha.
|
|
83
|
+
"@faststore/cli": "^2.2.0-alpha.6",
|
|
84
84
|
"@faststore/eslint-config": "^2.2.0-alpha.1",
|
|
85
85
|
"@faststore/lighthouse": "^1.12.32",
|
|
86
86
|
"@lhci/cli": "^0.9.0",
|
|
@@ -91,13 +91,14 @@
|
|
|
91
91
|
"@storybook/builder-webpack5": "^6.5.9",
|
|
92
92
|
"@storybook/manager-webpack5": "^6.5.9",
|
|
93
93
|
"@storybook/react": "^6.5.9",
|
|
94
|
-
"@testing-library/cypress": "^
|
|
94
|
+
"@testing-library/cypress": "^10.0.1",
|
|
95
95
|
"@types/cypress": "^1.1.3",
|
|
96
96
|
"@types/jest": "29.1.0",
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"cypress
|
|
100
|
-
"cypress-
|
|
97
|
+
"@vtex/prettier-config": "1.0.0",
|
|
98
|
+
"axe-core": "^4.8.1",
|
|
99
|
+
"cypress": "12.17.4",
|
|
100
|
+
"cypress-axe": "^1.5.0",
|
|
101
|
+
"cypress-wait-until": "^2.0.1",
|
|
101
102
|
"dotenv": "^8.2.0",
|
|
102
103
|
"eslint": "^7.32.0",
|
|
103
104
|
"husky": "^5.2.0",
|
|
@@ -128,5 +129,5 @@
|
|
|
128
129
|
"msw": {
|
|
129
130
|
"workerDirectory": "public"
|
|
130
131
|
},
|
|
131
|
-
"gitHead": "
|
|
132
|
+
"gitHead": "1d01644a9c6f9e6fbb2df4e05523aaa85b5d2b1b"
|
|
132
133
|
}
|
|
@@ -10,7 +10,7 @@ import type { CartSidebarProps as UICartSidebarProps } from '@faststore/ui'
|
|
|
10
10
|
|
|
11
11
|
import type { CurrencyCode, ViewCartEvent } from '@faststore/sdk'
|
|
12
12
|
import { Icon, useFadeEffect, useUI } from '@faststore/ui'
|
|
13
|
-
import { Suspense, useEffect } from 'react'
|
|
13
|
+
import { Suspense, useCallback, useEffect, useMemo } from 'react'
|
|
14
14
|
import { useCart } from 'src/sdk/cart'
|
|
15
15
|
import { useCheckoutButton } from 'src/sdk/cart/useCheckoutButton'
|
|
16
16
|
import { useSession } from 'src/sdk/session'
|
|
@@ -21,6 +21,37 @@ import EmptyCart from '../EmptyCart'
|
|
|
21
21
|
import OrderSummary from '../OrderSummary'
|
|
22
22
|
import styles from './section.module.scss'
|
|
23
23
|
|
|
24
|
+
function useViewCartEvent() {
|
|
25
|
+
const {
|
|
26
|
+
currency: { code },
|
|
27
|
+
} = useSession()
|
|
28
|
+
const { items, gifts, total } = useCart()
|
|
29
|
+
|
|
30
|
+
const sendViewCartEvent = useCallback(() => {
|
|
31
|
+
return sendAnalyticsEvent<ViewCartEvent>({
|
|
32
|
+
name: 'view_cart',
|
|
33
|
+
params: {
|
|
34
|
+
currency: code as CurrencyCode,
|
|
35
|
+
value: total,
|
|
36
|
+
items: items.concat(gifts).map((item) => ({
|
|
37
|
+
item_id: item.itemOffered.isVariantOf.productGroupID,
|
|
38
|
+
item_name: item.itemOffered.isVariantOf.name,
|
|
39
|
+
item_brand: item.itemOffered.brand.name,
|
|
40
|
+
item_variant: item.itemOffered.sku,
|
|
41
|
+
quantity: item.quantity,
|
|
42
|
+
price: item.price,
|
|
43
|
+
discount: item.listPrice - item.price,
|
|
44
|
+
currency: code as CurrencyCode,
|
|
45
|
+
item_variant_name: item.itemOffered.name,
|
|
46
|
+
product_reference_id: item.itemOffered.gtin,
|
|
47
|
+
})),
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
}, [code, gifts, items, total])
|
|
51
|
+
|
|
52
|
+
return useMemo(() => ({ sendViewCartEvent }), [sendViewCartEvent])
|
|
53
|
+
}
|
|
54
|
+
|
|
24
55
|
export interface CartSidebarProps {
|
|
25
56
|
title: UICartSidebarProps['title']
|
|
26
57
|
alert?: {
|
|
@@ -52,38 +83,21 @@ function CartSidebar({
|
|
|
52
83
|
icon: { icon: checkoutButtonIcon, alt: checkoutButtonIconAlt },
|
|
53
84
|
},
|
|
54
85
|
}: CartSidebarProps) {
|
|
55
|
-
const { currency } = useSession()
|
|
56
86
|
const btnProps = useCheckoutButton()
|
|
57
|
-
const
|
|
87
|
+
const { items, gifts, totalItems, isValidating, subTotal, total } = useCart()
|
|
58
88
|
const { cart: displayCart, closeCart } = useUI()
|
|
59
89
|
const { fadeOut } = useFadeEffect()
|
|
90
|
+
const { sendViewCartEvent } = useViewCartEvent()
|
|
60
91
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
const isEmpty = items.length === 0
|
|
92
|
+
const isEmpty = useMemo(() => items.length === 0, [items])
|
|
64
93
|
|
|
65
94
|
useEffect(() => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
item_id: item.itemOffered.isVariantOf.productGroupID,
|
|
73
|
-
item_name: item.itemOffered.isVariantOf.name,
|
|
74
|
-
item_brand: item.itemOffered.brand.name,
|
|
75
|
-
item_variant: item.itemOffered.sku,
|
|
76
|
-
quantity: item.quantity,
|
|
77
|
-
price: item.price,
|
|
78
|
-
discount: item.listPrice - item.price,
|
|
79
|
-
currency: currency.code as CurrencyCode,
|
|
80
|
-
item_variant_name: item.itemOffered.name,
|
|
81
|
-
product_reference_id: item.itemOffered.gtin,
|
|
82
|
-
})),
|
|
83
|
-
},
|
|
84
|
-
})
|
|
85
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
86
|
-
}, [])
|
|
95
|
+
if (!displayCart) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
sendViewCartEvent()
|
|
100
|
+
}, [displayCart, sendViewCartEvent])
|
|
87
101
|
|
|
88
102
|
return (
|
|
89
103
|
<>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react'
|
|
2
|
+
import { Button } from '@faststore/ui'
|
|
3
|
+
|
|
4
|
+
// TODO: Remove this component when <OutOfStock /> is ready to use
|
|
5
|
+
function NotAvailableButton({ children }: PropsWithChildren) {
|
|
6
|
+
return (
|
|
7
|
+
<Button variant="primary" disabled data-fs-buy-button>
|
|
8
|
+
{children}
|
|
9
|
+
</Button>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default NotAvailableButton
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './NotAvailableButton'
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
InputField as UIInputField,
|
|
4
4
|
Icon as UIIcon,
|
|
5
5
|
} from '@faststore/ui'
|
|
6
|
+
import { NewsletterAddendum } from 'src/components/ui/Newsletter/NewsletterAddendum'
|
|
6
7
|
|
|
7
8
|
import { getSectionOverrides } from 'src/utils/overrides'
|
|
8
9
|
import { override } from 'src/customizations/components/overrides/Newsletter'
|
|
@@ -15,6 +16,7 @@ const {
|
|
|
15
16
|
InputFieldName,
|
|
16
17
|
InputFieldEmail,
|
|
17
18
|
Button,
|
|
19
|
+
__experimentalNewsletterAddendum,
|
|
18
20
|
} = getSectionOverrides(
|
|
19
21
|
{
|
|
20
22
|
ToastIconSuccess: UIIcon,
|
|
@@ -23,6 +25,7 @@ const {
|
|
|
23
25
|
InputFieldName: UIInputField,
|
|
24
26
|
InputFieldEmail: UIInputField,
|
|
25
27
|
Button: UIButton,
|
|
28
|
+
__experimentalNewsletterAddendum: NewsletterAddendum,
|
|
26
29
|
},
|
|
27
30
|
override as NewsletterOverrideDefinition
|
|
28
31
|
)
|
|
@@ -34,4 +37,5 @@ export {
|
|
|
34
37
|
InputFieldName,
|
|
35
38
|
InputFieldEmail,
|
|
36
39
|
Button,
|
|
40
|
+
__experimentalNewsletterAddendum,
|
|
37
41
|
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import LocalImageGallery from 'src/components/ui/ImageGallery'
|
|
15
15
|
import LocalShippingSimulation from 'src/components/ui/ShippingSimulation/ShippingSimulation'
|
|
16
16
|
import { Image } from 'src/components/ui/Image'
|
|
17
|
+
import LocalNotAvailableButton from 'src/components/product/NotAvailableButton'
|
|
17
18
|
|
|
18
19
|
import { getSectionOverrides } from 'src/utils/overrides'
|
|
19
20
|
import { override } from 'src/customizations/components/overrides/ProductDetails'
|
|
@@ -33,6 +34,7 @@ const {
|
|
|
33
34
|
__experimentalImageGalleryImage,
|
|
34
35
|
__experimentalImageGallery,
|
|
35
36
|
__experimentalShippingSimulation,
|
|
37
|
+
__experimentalNotAvailableButton,
|
|
36
38
|
} = getSectionOverrides(
|
|
37
39
|
{
|
|
38
40
|
ProductTitle: UIProductTitle,
|
|
@@ -48,6 +50,7 @@ const {
|
|
|
48
50
|
__experimentalImageGalleryImage: Image,
|
|
49
51
|
__experimentalImageGallery: LocalImageGallery,
|
|
50
52
|
__experimentalShippingSimulation: LocalShippingSimulation,
|
|
53
|
+
__experimentalNotAvailableButton: LocalNotAvailableButton,
|
|
51
54
|
},
|
|
52
55
|
override as ProductDetailsOverrideDefinition
|
|
53
56
|
)
|
|
@@ -66,4 +69,5 @@ export {
|
|
|
66
69
|
__experimentalImageGalleryImage,
|
|
67
70
|
__experimentalImageGallery,
|
|
68
71
|
__experimentalShippingSimulation,
|
|
72
|
+
__experimentalNotAvailableButton,
|
|
69
73
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
1
|
+
import { useEffect, useState, useMemo } from 'react'
|
|
2
2
|
|
|
3
3
|
import { gql } from '@faststore/graphql-utils'
|
|
4
4
|
import type { CurrencyCode, ViewItemEvent } from '@faststore/sdk'
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
ProductTitle,
|
|
20
20
|
__experimentalImageGallery as ImageGallery,
|
|
21
21
|
__experimentalShippingSimulation as ShippingSimulation,
|
|
22
|
+
__experimentalNotAvailableButton as NotAvailableButton,
|
|
22
23
|
} from 'src/components/sections/ProductDetails/Overrides'
|
|
23
24
|
|
|
24
25
|
import { usePDP } from 'src/sdk/overrides/PageProvider'
|
|
@@ -55,6 +56,9 @@ export interface ProductDetailsProps {
|
|
|
55
56
|
imageGallery: {
|
|
56
57
|
imagePosition: 'top' | 'center' | 'bottom'
|
|
57
58
|
}
|
|
59
|
+
notAvailableButton: {
|
|
60
|
+
title: string
|
|
61
|
+
}
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
function ProductDetails({
|
|
@@ -86,6 +90,9 @@ function ProductDetails({
|
|
|
86
90
|
displayDescription: shouldDisplayProductDescription,
|
|
87
91
|
},
|
|
88
92
|
imageGallery: { imagePosition = ImageGallery.props.imagePosition },
|
|
93
|
+
notAvailableButton: {
|
|
94
|
+
title: notAvailableButtonTitle = NotAvailableButton.props.title,
|
|
95
|
+
},
|
|
89
96
|
}: ProductDetailsProps) {
|
|
90
97
|
const { currency } = useSession()
|
|
91
98
|
const [quantity, setQuantity] = useState(1)
|
|
@@ -145,7 +152,10 @@ function ProductDetails({
|
|
|
145
152
|
gtin,
|
|
146
153
|
])
|
|
147
154
|
|
|
148
|
-
const outOfStock =
|
|
155
|
+
const outOfStock = useMemo(
|
|
156
|
+
() => availability === 'https://schema.org/OutOfStock',
|
|
157
|
+
[availability]
|
|
158
|
+
)
|
|
149
159
|
|
|
150
160
|
return (
|
|
151
161
|
<Section className={`${styles.section} section-product-details`}>
|
|
@@ -184,19 +194,15 @@ function ProductDetails({
|
|
|
184
194
|
data-fs-product-details-settings
|
|
185
195
|
data-fs-product-details-section
|
|
186
196
|
>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
) : (
|
|
197
|
-
// TODO: Adds <OutOfStock /> when component is ready to use
|
|
198
|
-
<p>Not Available</p>
|
|
199
|
-
)}
|
|
197
|
+
<ProductDetailsSettings
|
|
198
|
+
product={product}
|
|
199
|
+
isValidating={isValidating}
|
|
200
|
+
buyButtonTitle={buyButtonTitle}
|
|
201
|
+
quantity={quantity}
|
|
202
|
+
setQuantity={setQuantity}
|
|
203
|
+
buyButtonIcon={buyButtonIcon}
|
|
204
|
+
notAvailableButtonTitle={notAvailableButtonTitle}
|
|
205
|
+
/>
|
|
200
206
|
</section>
|
|
201
207
|
|
|
202
208
|
{!outOfStock && (
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { ComponentPropsWithRef, FormEvent
|
|
1
|
+
import { ComponentPropsWithRef, FormEvent } from 'react'
|
|
2
2
|
import { forwardRef, useRef } from 'react'
|
|
3
|
-
import { convertFromRaw } from 'draft-js'
|
|
4
|
-
import { stateToHTML } from 'draft-js-export-html'
|
|
5
3
|
import { useUI } from '@faststore/ui'
|
|
6
4
|
import type { InputFieldProps } from '@faststore/ui'
|
|
7
5
|
|
|
@@ -13,39 +11,9 @@ import {
|
|
|
13
11
|
InputFieldName,
|
|
14
12
|
InputFieldEmail,
|
|
15
13
|
Button,
|
|
14
|
+
__experimentalNewsletterAddendum as NewsletterAddendum,
|
|
16
15
|
} from 'src/components/sections/Newsletter/Overrides'
|
|
17
16
|
|
|
18
|
-
export const cmsToHtml = (content) => {
|
|
19
|
-
if (!content) {
|
|
20
|
-
return ''
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const rawDraftContentState = JSON.parse(content)
|
|
24
|
-
const html = stateToHTML(convertFromRaw(rawDraftContentState), {
|
|
25
|
-
entityStyleFn: (entity) => {
|
|
26
|
-
const entityType = entity.get('type').toLowerCase()
|
|
27
|
-
|
|
28
|
-
if (entityType === 'link') {
|
|
29
|
-
const data = entity.getData()
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
element: 'a',
|
|
33
|
-
attributes: {
|
|
34
|
-
'data-fs-link': 'true',
|
|
35
|
-
'data-fs-link-variant': 'inline',
|
|
36
|
-
'data-fs-link-inverse': 'true',
|
|
37
|
-
'data-fs-link-size': 'regular',
|
|
38
|
-
'data-testid': 'fs-link',
|
|
39
|
-
href: data.url,
|
|
40
|
-
},
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
return html
|
|
47
|
-
}
|
|
48
|
-
|
|
49
17
|
export type SubscribeMessage = {
|
|
50
18
|
title: string
|
|
51
19
|
message: string
|
|
@@ -124,10 +92,6 @@ const Newsletter = forwardRef<HTMLFormElement, NewsletterProps>(
|
|
|
124
92
|
const { subscribeUser, loading, data } = useNewsletter()
|
|
125
93
|
const nameInputRef = useRef<HTMLInputElement>(null)
|
|
126
94
|
const emailInputRef = useRef<HTMLInputElement>(null)
|
|
127
|
-
const subscriptionButtonLabel = useMemo(
|
|
128
|
-
() => (loading ? subscribeButtonLoadingLabel : subscribeButtonLabel),
|
|
129
|
-
[loading, subscribeButtonLabel, subscribeButtonLoadingLabel]
|
|
130
|
-
)
|
|
131
95
|
|
|
132
96
|
const { pushToast } = useUI()
|
|
133
97
|
|
|
@@ -217,12 +181,10 @@ const Newsletter = forwardRef<HTMLFormElement, NewsletterProps>(
|
|
|
217
181
|
// This decision can be reviewed later if needed
|
|
218
182
|
inputRef={emailInputRef}
|
|
219
183
|
/>
|
|
220
|
-
<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}}
|
|
225
|
-
></span>
|
|
184
|
+
<NewsletterAddendum.Component
|
|
185
|
+
addendum={privacyPolicy}
|
|
186
|
+
{...NewsletterAddendum.props}
|
|
187
|
+
/>
|
|
226
188
|
<Button.Component
|
|
227
189
|
variant="secondary"
|
|
228
190
|
inverse
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TODO:
|
|
3
|
+
*
|
|
4
|
+
* This library hasn't been updated in 4 years at the time of writing.
|
|
5
|
+
*
|
|
6
|
+
* We're using it as a patch, and it is expected that some Rich Text use cases of draftjs are not supported by it.
|
|
7
|
+
* We have the dependency on draftjs because of the way the headless CMS send us the data.
|
|
8
|
+
*
|
|
9
|
+
* This library should be removed as soon as possible, which will probably be possible through one of two cases:
|
|
10
|
+
* 1. We support React Server Components and go back to using the official draftjs library for doing this, only on the server.
|
|
11
|
+
* This is still not the ideal solution, since it still relies on a unsupported, deprecated and archived library (draftjs).
|
|
12
|
+
* 2. CMS uses a new library or changes how it sends the data to not depend on draftjs.
|
|
13
|
+
*
|
|
14
|
+
* This is a limitation not only for this component, but for every native & custom component that makes use of Rich Text.
|
|
15
|
+
*/
|
|
16
|
+
import draftToHtml from 'draftjs-to-html'
|
|
17
|
+
|
|
18
|
+
export interface NewsletterAddendumProps {
|
|
19
|
+
/**
|
|
20
|
+
* Expects a string of a JSON object in the form of draftjs's raw content state.
|
|
21
|
+
*/
|
|
22
|
+
addendum: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getLinkElementAsString(url: string, text: string) {
|
|
26
|
+
return `
|
|
27
|
+
<a
|
|
28
|
+
data-fs-link="true"
|
|
29
|
+
data-fs-link-variant="inline"
|
|
30
|
+
data-fs-link-inverse="true"
|
|
31
|
+
data-fs-link-size="regular"
|
|
32
|
+
data-testid="fs-link"
|
|
33
|
+
href="${url}"
|
|
34
|
+
>${text}</a>`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function cmsToHtml(addendum: string) {
|
|
38
|
+
if (!addendum) {
|
|
39
|
+
return ''
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let rawDraftContentState = null
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
rawDraftContentState = JSON.parse(addendum)
|
|
46
|
+
} catch (e) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
'Newsletter\'s prop "addendum" is not a JSON string. This is happening because the overridden prop is malformed or the CMS is providing malformed content for that prop.',
|
|
49
|
+
{
|
|
50
|
+
cause: e,
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!rawDraftContentState) {
|
|
56
|
+
return ''
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return draftToHtml(
|
|
60
|
+
rawDraftContentState,
|
|
61
|
+
undefined,
|
|
62
|
+
undefined,
|
|
63
|
+
(entity: { type: string; data: { url: string } }, text: string) => {
|
|
64
|
+
if (entity.type !== 'LINK') {
|
|
65
|
+
return null
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return getLinkElementAsString(entity.data.url, text)
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function NewsletterAddendum({
|
|
74
|
+
addendum,
|
|
75
|
+
...otherProps
|
|
76
|
+
}: NewsletterAddendumProps) {
|
|
77
|
+
return (
|
|
78
|
+
<span
|
|
79
|
+
data-fs-newsletter-addendum
|
|
80
|
+
dangerouslySetInnerHTML={{
|
|
81
|
+
__html: cmsToHtml(addendum),
|
|
82
|
+
}}
|
|
83
|
+
{...otherProps}
|
|
84
|
+
></span>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default
|
|
1
|
+
export { default } from './Newsletter'
|
|
2
2
|
export type { NewsletterProps } from './Newsletter'
|