@faststore/core 3.0.130 → 3.0.132
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 +29 -29
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/config.json +3 -3
- package/.next/cache/eslint/.cache_1gneedd +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-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.js +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/react-loadable-manifest.json +2 -2
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/158.js +1 -1
- package/.next/server/chunks/350.js +1 -1
- package/.next/server/chunks/371.js +1 -1
- package/.next/server/chunks/430.js +1 -1
- package/.next/server/chunks/646.js +2 -2
- package/.next/server/chunks/671.js +1 -1
- package/.next/server/chunks/96.js +1 -1
- package/.next/server/functions-config-manifest.json +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/api/graphql.js +1 -1
- package/.next/server/pages/en-US/404.html +1 -1
- package/.next/server/pages/en-US/404.json +1 -1
- package/.next/server/pages/en-US/500.html +1 -1
- package/.next/server/pages/en-US/500.json +1 -1
- package/.next/server/pages/en-US/account.html +1 -1
- package/.next/server/pages/en-US/account.json +1 -1
- package/.next/server/pages/en-US/checkout.html +1 -1
- package/.next/server/pages/en-US/checkout.json +1 -1
- package/.next/server/pages/en-US/login.html +1 -1
- package/.next/server/pages/en-US/login.json +1 -1
- package/.next/server/pages/en-US/s.html +1 -1
- package/.next/server/pages/en-US/s.json +1 -1
- package/.next/server/pages/en-US.html +2 -2
- package/.next/server/pages/en-US.json +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/static/{8vzjQghRcsjOlyIq8UHyC → QumIIgsiZ1UZUHbqVzzNR}/_buildManifest.js +1 -1
- package/.next/static/chunks/{235-a7d9d6cf81ae08ef.js → 235-973ebc8cf442e7f2.js} +1 -1
- package/.next/static/chunks/798.f16a775f53df6766.js +1 -0
- package/.next/static/chunks/87-a5c39fc100e83f67.js +1 -0
- package/.next/static/chunks/968-1e18abc7032f157c.js +1 -0
- package/.next/static/chunks/pages/{_app-ed807a0c1aebeb38.js → _app-cb1c3a94f987c5c8.js} +1 -1
- package/.next/static/chunks/{webpack-904b033805de64d4.js → webpack-ca5fe5a8d57b1bda.js} +1 -1
- package/.next/trace +94 -94
- package/.turbo/turbo-build.log +6 -6
- package/.turbo/turbo-test.log +4 -4
- package/discovery.config.default.js +1 -0
- package/next.config.js +10 -0
- package/package.json +9 -9
- package/src/components/cms/ViewportObserver.tsx +88 -0
- package/src/components/common/Footer/FooterLinks.tsx +6 -4
- package/src/components/navigation/Navbar/Navbar.tsx +4 -1
- package/src/components/product/ProductGrid/ProductGrid.tsx +82 -21
- package/src/components/search/Filter/Filter.tsx +4 -2
- package/src/components/sections/RegionBar/RegionBar.tsx +9 -7
- package/src/components/ui/Carousel/Carousel.tsx +6 -2
- package/src/components/ui/ProductGallery/ProductGallery.tsx +4 -3
- package/src/components/ui/ProductGallery/ProductGalleryPage.tsx +10 -2
- package/src/sdk/ui/useScreenResize.ts +43 -0
- package/.next/static/chunks/758.829db9862d9c4add.js +0 -1
- package/.next/static/chunks/87-5709356a398fea13.js +0 -1
- package/.next/static/chunks/968-dffabcd6f064d487.js +0 -1
- /package/.next/static/{8vzjQghRcsjOlyIq8UHyC → QumIIgsiZ1UZUHbqVzzNR}/_ssgManifest.js +0 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -45,12 +45,12 @@ Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Cont
|
|
|
45
45
|
Collecting build traces ...
|
|
46
46
|
|
|
47
47
|
Route (pages) Size First Load JS
|
|
48
|
-
┌ ● / 1.23 kB
|
|
48
|
+
┌ ● / 1.23 kB 143 kB
|
|
49
49
|
├ └ css/197e314c5a03eabd.css 740 B
|
|
50
50
|
├ /_app 0 B 90.7 kB
|
|
51
|
-
├ ● /[...slug] 2.79 kB
|
|
51
|
+
├ ● /[...slug] 2.79 kB 156 kB
|
|
52
52
|
├ └ css/e47f1a002bdcf76f.css 2.38 kB
|
|
53
|
-
├ ● /[slug]/p 11.2 kB
|
|
53
|
+
├ ● /[slug]/p 11.2 kB 153 kB
|
|
54
54
|
├ └ css/9b6bba2472d272ec.css 10.5 kB
|
|
55
55
|
├ ○ /404 1.28 kB 126 kB
|
|
56
56
|
├ ● /500 1.29 kB 126 kB
|
|
@@ -60,13 +60,13 @@ Route (pages) Size First Load JS
|
|
|
60
60
|
├ λ /api/health/ready 0 B 90.7 kB
|
|
61
61
|
├ λ /api/preview 0 B 90.7 kB
|
|
62
62
|
├ ● /checkout 661 B 126 kB
|
|
63
|
-
├ ● /login 1.4 kB
|
|
63
|
+
├ ● /login 1.4 kB 127 kB
|
|
64
64
|
└ ● /s 2.22 kB 155 kB
|
|
65
65
|
+ First Load JS shared by all 93.8 kB
|
|
66
66
|
├ chunks/framework-8e279965036b6169.js 45.4 kB
|
|
67
67
|
├ chunks/main-029f1328cfee9686.js 33.1 kB
|
|
68
|
-
├ chunks/pages/_app-
|
|
69
|
-
├ chunks/webpack-
|
|
68
|
+
├ chunks/pages/_app-cb1c3a94f987c5c8.js 9.87 kB
|
|
69
|
+
├ chunks/webpack-ca5fe5a8d57b1bda.js 2.45 kB
|
|
70
70
|
└ css/ee0556daedda6306.css 3.07 kB
|
|
71
71
|
|
|
72
72
|
λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
$ jest
|
|
2
|
-
PASS test/
|
|
3
|
-
PASS test/
|
|
4
|
-
PASS test/server/index.test.ts (
|
|
2
|
+
PASS test/utils/multipleTemplates.test.ts (35.769 s)
|
|
3
|
+
PASS test/server/cms/index.test.ts (36.47 s)
|
|
4
|
+
PASS test/server/index.test.ts (39.897 s)
|
|
5
5
|
|
|
6
6
|
Test Suites: 3 passed, 3 total
|
|
7
7
|
Tests: 19 passed, 19 total
|
|
8
8
|
Snapshots: 0 total
|
|
9
|
-
Time:
|
|
9
|
+
Time: 41.135 s
|
|
10
10
|
Ran all test suites.
|
package/next.config.js
CHANGED
|
@@ -46,6 +46,16 @@ const nextConfig = {
|
|
|
46
46
|
config.optimization.splitChunks.maxInitialRequests = 1
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
if (storeConfig.experimental.preact && !isServer && !dev) {
|
|
50
|
+
Object.assign(config.resolve.alias, {
|
|
51
|
+
react: 'preact/compat',
|
|
52
|
+
|
|
53
|
+
'react-dom/test-utils': 'preact/test-utils',
|
|
54
|
+
|
|
55
|
+
'react-dom': 'preact/compat',
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
49
59
|
return config
|
|
50
60
|
},
|
|
51
61
|
redirects: storeConfig.redirects,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.132",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": "vtex/faststore",
|
|
6
6
|
"browserslist": "supports es6-module and not dead",
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"@envelop/graphql-jit": "^8.0.3",
|
|
44
44
|
"@envelop/parser-cache": "^6.0.2",
|
|
45
45
|
"@envelop/validation-cache": "^6.0.2",
|
|
46
|
-
"@faststore/api": "^3.0.
|
|
47
|
-
"@faststore/components": "^3.0.
|
|
48
|
-
"@faststore/graphql-utils": "^3.0.
|
|
49
|
-
"@faststore/lighthouse": "^3.0.
|
|
50
|
-
"@faststore/sdk": "^3.0.
|
|
51
|
-
"@faststore/ui": "^3.0.
|
|
46
|
+
"@faststore/api": "^3.0.131",
|
|
47
|
+
"@faststore/components": "^3.0.131",
|
|
48
|
+
"@faststore/graphql-utils": "^3.0.131",
|
|
49
|
+
"@faststore/lighthouse": "^3.0.131",
|
|
50
|
+
"@faststore/sdk": "^3.0.131",
|
|
51
|
+
"@faststore/ui": "^3.0.131",
|
|
52
52
|
"@graphql-codegen/cli": "5.0.2",
|
|
53
53
|
"@graphql-codegen/client-preset": "4.2.6",
|
|
54
54
|
"@graphql-codegen/typescript": "4.0.7",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"devDependencies": {
|
|
88
88
|
"@cypress/code-coverage": "^3.12.1",
|
|
89
89
|
"@envelop/testing": "^6.0.0",
|
|
90
|
-
"@faststore/eslint-config": "^3.0.
|
|
90
|
+
"@faststore/eslint-config": "^3.0.131",
|
|
91
91
|
"@lhci/cli": "^0.9.0",
|
|
92
92
|
"@testing-library/cypress": "^10.0.1",
|
|
93
93
|
"@types/cypress": "^1.1.3",
|
|
@@ -128,5 +128,5 @@
|
|
|
128
128
|
"node": "18.19.0",
|
|
129
129
|
"yarn": "1.19.1"
|
|
130
130
|
},
|
|
131
|
-
"gitHead": "
|
|
131
|
+
"gitHead": "a99b6bc07181fbaa67077b5c12df219fa9975505"
|
|
132
132
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { PropsWithChildren } from 'react'
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
3
|
+
|
|
4
|
+
// Mobile height to prevent sections outside the viewport from being rendered initially.
|
|
5
|
+
// We are using the Moto G Power device measurement as a reference, as used by PageSpeed Insights.
|
|
6
|
+
const VIEWPORT_SIZE = 823
|
|
7
|
+
|
|
8
|
+
type ViewportObserverProps = {
|
|
9
|
+
/**
|
|
10
|
+
* Identify the store section
|
|
11
|
+
*/
|
|
12
|
+
sectionName?: string
|
|
13
|
+
/**
|
|
14
|
+
* Debug/test purposes: enables visual debugging to identify the visibility of the section.
|
|
15
|
+
*/
|
|
16
|
+
debug?: boolean
|
|
17
|
+
} & IntersectionObserverInit
|
|
18
|
+
|
|
19
|
+
function ViewportObserver({
|
|
20
|
+
sectionName = '',
|
|
21
|
+
threshold = 0,
|
|
22
|
+
root = null,
|
|
23
|
+
rootMargin,
|
|
24
|
+
children,
|
|
25
|
+
debug = false,
|
|
26
|
+
}: PropsWithChildren<ViewportObserverProps>) {
|
|
27
|
+
const [isVisible, setVisible] = useState(false)
|
|
28
|
+
const ref = useRef<HTMLDivElement | null>(null)
|
|
29
|
+
|
|
30
|
+
const observerCallback = useCallback(
|
|
31
|
+
([entry]: IntersectionObserverEntry[], obs: IntersectionObserver) => {
|
|
32
|
+
if (entry.isIntersecting) {
|
|
33
|
+
if (debug) {
|
|
34
|
+
console.log(`section '${sectionName}' VISIBLE`)
|
|
35
|
+
document.body.style.border = '2px solid green'
|
|
36
|
+
}
|
|
37
|
+
setVisible(true)
|
|
38
|
+
if (ref.current) {
|
|
39
|
+
obs.unobserve(ref.current)
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
setVisible(false)
|
|
43
|
+
if (debug) {
|
|
44
|
+
console.log(`section '${sectionName}' NOT VISIBLE`)
|
|
45
|
+
document.body.style.border = '2px solid red'
|
|
46
|
+
document.body.style.height = `${VIEWPORT_SIZE}px`
|
|
47
|
+
document.body.style.boxSizing = 'border-box'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
[debug, sectionName]
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
const observer = new IntersectionObserver(observerCallback, {
|
|
56
|
+
root,
|
|
57
|
+
rootMargin,
|
|
58
|
+
threshold,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
if (ref.current) {
|
|
62
|
+
observer.observe(ref.current)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return () => observer.disconnect()
|
|
66
|
+
}, [observerCallback, root, rootMargin, threshold])
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<>
|
|
70
|
+
{!isVisible && (
|
|
71
|
+
<div
|
|
72
|
+
data-store-section-name={sectionName}
|
|
73
|
+
ref={ref}
|
|
74
|
+
style={{
|
|
75
|
+
border: debug ? '2px solid red' : undefined,
|
|
76
|
+
backgroundColor: debug ? 'red' : undefined,
|
|
77
|
+
height: VIEWPORT_SIZE, // required to make sections out of the viewport to be rendered on demand
|
|
78
|
+
width: '100%',
|
|
79
|
+
}}
|
|
80
|
+
></div>
|
|
81
|
+
)}
|
|
82
|
+
|
|
83
|
+
{isVisible && children}
|
|
84
|
+
</>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default ViewportObserver
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { useState } from 'react'
|
|
9
9
|
|
|
10
10
|
import Link from 'src/components/ui/Link'
|
|
11
|
+
import useScreenResize from 'src/sdk/ui/useScreenResize'
|
|
11
12
|
|
|
12
13
|
type Item = {
|
|
13
14
|
url: string
|
|
@@ -38,6 +39,7 @@ export interface FooterLinksProps {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
function FooterLinks({ links }: FooterLinksProps) {
|
|
42
|
+
const { isDesktop } = useScreenResize()
|
|
41
43
|
const [indicesExpanded, setIndicesExpanded] = useState<Set<number>>(
|
|
42
44
|
new Set([])
|
|
43
45
|
)
|
|
@@ -53,7 +55,7 @@ function FooterLinks({ links }: FooterLinksProps) {
|
|
|
53
55
|
|
|
54
56
|
return (
|
|
55
57
|
<section data-fs-footer data-fs-footer-links>
|
|
56
|
-
|
|
58
|
+
{!isDesktop && (
|
|
57
59
|
<UIAccordion indices={indicesExpanded} onChange={onChange}>
|
|
58
60
|
{links.map(({ sectionTitle, items }) => (
|
|
59
61
|
<UIAccordionItem key={sectionTitle}>
|
|
@@ -64,9 +66,9 @@ function FooterLinks({ links }: FooterLinksProps) {
|
|
|
64
66
|
</UIAccordionItem>
|
|
65
67
|
))}
|
|
66
68
|
</UIAccordion>
|
|
67
|
-
|
|
69
|
+
)}
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
{isDesktop && (
|
|
70
72
|
<nav data-fs-footer-links-columns aria-label="Footer Links Navigation">
|
|
71
73
|
{links.map(({ sectionTitle, items }) => (
|
|
72
74
|
<div key={sectionTitle}>
|
|
@@ -75,7 +77,7 @@ function FooterLinks({ links }: FooterLinksProps) {
|
|
|
75
77
|
</div>
|
|
76
78
|
))}
|
|
77
79
|
</nav>
|
|
78
|
-
|
|
80
|
+
)}
|
|
79
81
|
</section>
|
|
80
82
|
)
|
|
81
83
|
}
|
|
@@ -12,6 +12,7 @@ import Link from 'src/components/ui/Link'
|
|
|
12
12
|
import { useOverrideComponents } from 'src/sdk/overrides/OverrideContext'
|
|
13
13
|
|
|
14
14
|
import type { NavbarProps as SectionNavbarProps } from '../../sections/Navbar'
|
|
15
|
+
import useScreenResize from 'src/sdk/ui/useScreenResize'
|
|
15
16
|
|
|
16
17
|
export interface NavbarProps {
|
|
17
18
|
/**
|
|
@@ -78,6 +79,8 @@ function Navbar({
|
|
|
78
79
|
} = useOverrideComponents<'Navbar'>()
|
|
79
80
|
const scrollDirection = useScrollDirection()
|
|
80
81
|
const { openNavbar, navbar: displayNavbar } = useUI()
|
|
82
|
+
const { isDesktop } = useScreenResize()
|
|
83
|
+
|
|
81
84
|
const searchMobileRef = useRef<SearchInputRef>(null)
|
|
82
85
|
const [searchExpanded, setSearchExpanded] = useState(false)
|
|
83
86
|
|
|
@@ -157,7 +160,7 @@ function Navbar({
|
|
|
157
160
|
</NavbarRow.Component>
|
|
158
161
|
</NavbarHeader.Component>
|
|
159
162
|
|
|
160
|
-
<NavbarLinks links={links} region={region}
|
|
163
|
+
{isDesktop && <NavbarLinks links={links} region={region} />}
|
|
161
164
|
|
|
162
165
|
{displayNavbar && (
|
|
163
166
|
<NavbarSlider
|
|
@@ -7,6 +7,7 @@ import ProductGridSkeleton from 'src/components/skeletons/ProductGridSkeleton'
|
|
|
7
7
|
import { ProductCardProps } from '../ProductCard'
|
|
8
8
|
|
|
9
9
|
import { memo } from 'react'
|
|
10
|
+
import ViewportObserver from 'src/components/cms/ViewportObserver'
|
|
10
11
|
import { useOverrideComponents } from 'src/sdk/overrides/OverrideContext'
|
|
11
12
|
|
|
12
13
|
interface Props {
|
|
@@ -26,6 +27,10 @@ interface Props {
|
|
|
26
27
|
ProductCardProps,
|
|
27
28
|
'showDiscountBadge' | 'bordered' | 'taxesConfiguration'
|
|
28
29
|
>
|
|
30
|
+
/**
|
|
31
|
+
* Identify the number of firstPage
|
|
32
|
+
*/
|
|
33
|
+
firstPage?: number
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
function ProductGrid({
|
|
@@ -33,38 +38,94 @@ function ProductGrid({
|
|
|
33
38
|
page,
|
|
34
39
|
pageSize,
|
|
35
40
|
productCard: { showDiscountBadge, bordered, taxesConfiguration } = {},
|
|
41
|
+
firstPage,
|
|
36
42
|
}: Props) {
|
|
37
43
|
const { __experimentalProductCard: ProductCard } =
|
|
38
44
|
useOverrideComponents<'ProductGallery'>()
|
|
39
45
|
const aspectRatio = 1
|
|
40
46
|
|
|
47
|
+
// TODO: Check if is also isMobile
|
|
48
|
+
const isFirstPage = firstPage === page
|
|
49
|
+
|
|
41
50
|
return (
|
|
42
51
|
<ProductGridSkeleton
|
|
43
52
|
aspectRatio={aspectRatio}
|
|
44
53
|
loading={products.length === 0}
|
|
45
54
|
>
|
|
46
55
|
<UIProductGrid>
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
{isFirstPage ? (
|
|
57
|
+
<>
|
|
58
|
+
{products.slice(0, 2).map(({ node: product }, idx) => (
|
|
59
|
+
<UIProductGridItem key={`${product.id}`}>
|
|
60
|
+
<ProductCard.Component
|
|
61
|
+
aspectRatio={aspectRatio}
|
|
62
|
+
imgProps={{
|
|
63
|
+
width: 150,
|
|
64
|
+
height: 150,
|
|
65
|
+
sizes: '30vw',
|
|
66
|
+
loading: 'eager',
|
|
67
|
+
}}
|
|
68
|
+
{...ProductCard.props}
|
|
69
|
+
bordered={bordered ?? ProductCard.props.bordered}
|
|
70
|
+
showDiscountBadge={
|
|
71
|
+
showDiscountBadge ?? ProductCard.props.showDiscountBadge
|
|
72
|
+
}
|
|
73
|
+
product={product}
|
|
74
|
+
index={pageSize * page + idx + 1}
|
|
75
|
+
taxesConfiguration={taxesConfiguration}
|
|
76
|
+
/>
|
|
77
|
+
</UIProductGridItem>
|
|
78
|
+
))}
|
|
79
|
+
<></>
|
|
80
|
+
<ViewportObserver sectionName="UIProductGrid-out-viewport">
|
|
81
|
+
{products.slice(2).map(({ node: product }, idx) => (
|
|
82
|
+
<UIProductGridItem key={`${product.id}`}>
|
|
83
|
+
<ProductCard.Component
|
|
84
|
+
aspectRatio={aspectRatio}
|
|
85
|
+
imgProps={{
|
|
86
|
+
width: 150,
|
|
87
|
+
height: 150,
|
|
88
|
+
sizes: '30vw',
|
|
89
|
+
loading: 'lazy',
|
|
90
|
+
}}
|
|
91
|
+
{...ProductCard.props}
|
|
92
|
+
bordered={bordered ?? ProductCard.props.bordered}
|
|
93
|
+
showDiscountBadge={
|
|
94
|
+
showDiscountBadge ?? ProductCard.props.showDiscountBadge
|
|
95
|
+
}
|
|
96
|
+
product={product}
|
|
97
|
+
index={pageSize * page + idx + 1}
|
|
98
|
+
taxesConfiguration={taxesConfiguration}
|
|
99
|
+
/>
|
|
100
|
+
</UIProductGridItem>
|
|
101
|
+
))}
|
|
102
|
+
</ViewportObserver>
|
|
103
|
+
</>
|
|
104
|
+
) : (
|
|
105
|
+
<>
|
|
106
|
+
{products.map(({ node: product }, idx) => (
|
|
107
|
+
<UIProductGridItem key={`${product.id}`}>
|
|
108
|
+
<ProductCard.Component
|
|
109
|
+
aspectRatio={aspectRatio}
|
|
110
|
+
imgProps={{
|
|
111
|
+
width: 150,
|
|
112
|
+
height: 150,
|
|
113
|
+
sizes: '30vw',
|
|
114
|
+
loading: idx === 0 ? 'eager' : 'lazy',
|
|
115
|
+
}}
|
|
116
|
+
{...ProductCard.props}
|
|
117
|
+
bordered={bordered ?? ProductCard.props.bordered}
|
|
118
|
+
showDiscountBadge={
|
|
119
|
+
showDiscountBadge ?? ProductCard.props.showDiscountBadge
|
|
120
|
+
}
|
|
121
|
+
product={product}
|
|
122
|
+
index={pageSize * page + idx + 1}
|
|
123
|
+
taxesConfiguration={taxesConfiguration}
|
|
124
|
+
/>
|
|
125
|
+
</UIProductGridItem>
|
|
126
|
+
))}
|
|
127
|
+
</>
|
|
128
|
+
)}
|
|
68
129
|
</UIProductGrid>
|
|
69
130
|
</ProductGridSkeleton>
|
|
70
131
|
)
|
|
@@ -6,6 +6,7 @@ import { gql } from '@generated'
|
|
|
6
6
|
import { ProductGalleryProps } from 'src/components/ui/ProductGallery/ProductGallery'
|
|
7
7
|
import { useOverrideComponents } from 'src/sdk/overrides/OverrideContext'
|
|
8
8
|
import { useFilter } from 'src/sdk/search/useFilter'
|
|
9
|
+
import useScreenResize from 'src/sdk/ui/useScreenResize'
|
|
9
10
|
|
|
10
11
|
interface Props {
|
|
11
12
|
/**
|
|
@@ -35,17 +36,18 @@ function Filter({
|
|
|
35
36
|
|
|
36
37
|
const filter = useFilter(allFacets)
|
|
37
38
|
const { filter: displayFilter } = useUI()
|
|
39
|
+
const { isDesktop } = useScreenResize()
|
|
38
40
|
|
|
39
41
|
return (
|
|
40
42
|
<>
|
|
41
|
-
|
|
43
|
+
{isDesktop && (
|
|
42
44
|
<FilterDesktop.Component
|
|
43
45
|
{...FilterDesktop.props}
|
|
44
46
|
{...filter}
|
|
45
47
|
testId={testId}
|
|
46
48
|
title={filterCmsData?.title}
|
|
47
49
|
/>
|
|
48
|
-
|
|
50
|
+
)}
|
|
49
51
|
|
|
50
52
|
{displayFilter && (
|
|
51
53
|
<Suspense fallback={null}>
|
|
@@ -3,6 +3,7 @@ import Section from '../Section/Section'
|
|
|
3
3
|
import styles from './section.module.scss'
|
|
4
4
|
import { RegionBarDefaultComponents } from './DefaultComponents'
|
|
5
5
|
import { getOverridableSection } from '../../..//sdk/overrides/getOverriddenSection'
|
|
6
|
+
import useScreenResize from 'src/sdk/ui/useScreenResize'
|
|
6
7
|
|
|
7
8
|
type RegionBarSectionProps = {
|
|
8
9
|
/**
|
|
@@ -27,14 +28,15 @@ type RegionBarSectionProps = {
|
|
|
27
28
|
buttonIcon?: RegionBarProps['buttonIcon']
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
function RegionBarSection({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}: RegionBarSectionProps) {
|
|
31
|
+
function RegionBarSection({ ...otherProps }: RegionBarSectionProps) {
|
|
32
|
+
const { isMobile } = useScreenResize()
|
|
33
|
+
|
|
34
34
|
return (
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
|
|
35
|
+
isMobile && (
|
|
36
|
+
<Section className={`${styles.section} section-region-bar`}>
|
|
37
|
+
<RegionBar {...otherProps} />
|
|
38
|
+
</Section>
|
|
39
|
+
)
|
|
38
40
|
)
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -2,6 +2,8 @@ import type { PropsWithChildren } from 'react'
|
|
|
2
2
|
import { Carousel as UICarousel } from '@faststore/ui'
|
|
3
3
|
import type { CarouselProps as UICarouselProps } from '@faststore/ui'
|
|
4
4
|
|
|
5
|
+
import useScreenResize from 'src/sdk/ui/useScreenResize'
|
|
6
|
+
|
|
5
7
|
export type CarouselProps = {
|
|
6
8
|
id?: string
|
|
7
9
|
testId?: string
|
|
@@ -21,7 +23,9 @@ function Carousel({
|
|
|
21
23
|
variant = 'scroll',
|
|
22
24
|
infiniteMode = false,
|
|
23
25
|
}: PropsWithChildren<CarouselProps>) {
|
|
24
|
-
const isMobile =
|
|
26
|
+
const { loading, isTablet, isMobile } = useScreenResize()
|
|
27
|
+
|
|
28
|
+
if (loading) return null
|
|
25
29
|
|
|
26
30
|
return (
|
|
27
31
|
<UICarousel
|
|
@@ -29,7 +33,7 @@ function Carousel({
|
|
|
29
33
|
testId={testId}
|
|
30
34
|
variant={variant}
|
|
31
35
|
infiniteMode={infiniteMode}
|
|
32
|
-
itemsPerPage={isMobile ? 1.6 : itemsPerPage}
|
|
36
|
+
itemsPerPage={isTablet || isMobile ? 1.6 : itemsPerPage}
|
|
33
37
|
>
|
|
34
38
|
{children}
|
|
35
39
|
</UICarousel>
|
|
@@ -12,15 +12,15 @@ import ProductGridSkeleton from 'src/components/skeletons/ProductGridSkeleton'
|
|
|
12
12
|
import { ProductCardProps } from 'src/components/product/ProductCard'
|
|
13
13
|
import { FilterSliderProps } from 'src/components/search/Filter/FilterSlider'
|
|
14
14
|
import { SortProps } from 'src/components/search/Sort/Sort'
|
|
15
|
-
import {
|
|
16
|
-
import { useDelayedPagination } from 'src/sdk/search/useDelayedPagination'
|
|
15
|
+
import { useOverrideComponents } from 'src/sdk/overrides/OverrideContext'
|
|
17
16
|
import {
|
|
18
17
|
PLPContext,
|
|
19
18
|
SearchPageContext,
|
|
20
19
|
usePage,
|
|
21
20
|
} from 'src/sdk/overrides/PageProvider'
|
|
22
21
|
import { useProductsPrefetch } from 'src/sdk/product/useProductsPrefetch'
|
|
23
|
-
import {
|
|
22
|
+
import { useDelayedFacets } from 'src/sdk/search/useDelayedFacets'
|
|
23
|
+
import { useDelayedPagination } from 'src/sdk/search/useDelayedPagination'
|
|
24
24
|
|
|
25
25
|
const ProductGalleryPage = lazy(() => import('./ProductGalleryPage'))
|
|
26
26
|
const GalleryPageSkeleton = <ProductGridSkeleton loading />
|
|
@@ -237,6 +237,7 @@ function ProductGallery({
|
|
|
237
237
|
title={title}
|
|
238
238
|
productCard={productCard}
|
|
239
239
|
itemsPerPage={itemsPerPage}
|
|
240
|
+
firstPage={pages[0]}
|
|
240
241
|
/>
|
|
241
242
|
))}
|
|
242
243
|
</Suspense>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import ProductGrid from 'src/components/product/ProductGrid'
|
|
2
2
|
import Sentinel from 'src/sdk/search/Sentinel'
|
|
3
3
|
|
|
4
|
-
import { ProductCardProps } from 'src/components/product/ProductCard'
|
|
5
4
|
import { memo } from 'react'
|
|
5
|
+
import { ProductCardProps } from 'src/components/product/ProductCard'
|
|
6
6
|
import { useGalleryPage } from 'src/sdk/product/usePageProductsQuery'
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
@@ -13,9 +13,16 @@ interface Props {
|
|
|
13
13
|
'showDiscountBadge' | 'bordered' | 'taxesConfiguration'
|
|
14
14
|
>
|
|
15
15
|
itemsPerPage: number
|
|
16
|
+
firstPage: number
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
function ProductGalleryPage({
|
|
19
|
+
function ProductGalleryPage({
|
|
20
|
+
page,
|
|
21
|
+
title,
|
|
22
|
+
productCard,
|
|
23
|
+
itemsPerPage,
|
|
24
|
+
firstPage,
|
|
25
|
+
}: Props) {
|
|
19
26
|
const { data } = useGalleryPage(page)
|
|
20
27
|
|
|
21
28
|
const products = data?.search?.products?.edges ?? []
|
|
@@ -33,6 +40,7 @@ function ProductGalleryPage({ page, title, productCard, itemsPerPage }: Props) {
|
|
|
33
40
|
page={page}
|
|
34
41
|
pageSize={itemsPerPage}
|
|
35
42
|
productCard={productCard}
|
|
43
|
+
firstPage={firstPage}
|
|
36
44
|
/>
|
|
37
45
|
</>
|
|
38
46
|
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
// We are using the Moto G Power device measurement as a reference (mobile), as used by PageSpeed Insights.
|
|
4
|
+
const MAX_MOBILE_WIDTH = 420
|
|
5
|
+
const MAX_TABLET_WIDTH = 768
|
|
6
|
+
const MIN_NOTEBOOK_WIDTH = 1280
|
|
7
|
+
|
|
8
|
+
function useScreenResize() {
|
|
9
|
+
const [isMobile, setIsMobile] = useState(undefined)
|
|
10
|
+
const [isTablet, setIsTablet] = useState(undefined)
|
|
11
|
+
const [isDesktop, setIsDesktop] = useState(undefined)
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const handleResize = () => {
|
|
15
|
+
setIsMobile(window.innerWidth <= MAX_MOBILE_WIDTH)
|
|
16
|
+
setIsTablet(
|
|
17
|
+
window.innerWidth > MAX_MOBILE_WIDTH &&
|
|
18
|
+
window.innerWidth <= MAX_TABLET_WIDTH
|
|
19
|
+
)
|
|
20
|
+
setIsDesktop(window.innerWidth >= MIN_NOTEBOOK_WIDTH)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
handleResize()
|
|
24
|
+
|
|
25
|
+
window.addEventListener('resize', handleResize)
|
|
26
|
+
|
|
27
|
+
return () => {
|
|
28
|
+
window.removeEventListener('resize', handleResize)
|
|
29
|
+
}
|
|
30
|
+
}, [])
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
isMobile,
|
|
34
|
+
isTablet,
|
|
35
|
+
isDesktop,
|
|
36
|
+
loading:
|
|
37
|
+
isMobile === undefined ||
|
|
38
|
+
isTablet === undefined ||
|
|
39
|
+
isDesktop === undefined,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default useScreenResize
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[758],{5758:function(e,r,t){t.r(r),t.d(r,{default:function(){return j}});var n=t(9499),o=t(2784);let a=(0,o.forwardRef)(function({testId:e="fs-product-grid",children:r,...t},n){return o.createElement("ul",{ref:n,"data-fs-product-grid":!0,...t},r)}),c=(0,o.forwardRef)(function({testId:e="fs-product-grid-item",children:r,...t},n){return o.createElement("li",{ref:n,"data-fs-product-grid-item":!0,...t},r)});var i=t(4548),s=t(4329),u=t(2322);function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable})),t.push.apply(t,n)}return t}function _objectSpread(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?ownKeys(Object(t),!0).forEach(function(r){(0,n.Z)(e,r,t[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):ownKeys(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))})}return e}var d=(0,o.memo)(function(e){var{products:r,page:t,pageSize:n,productCard:{showDiscountBadge:o,bordered:d,taxesConfiguration:l}={}}=e,{__experimentalProductCard:p}=(0,s.r3)();return(0,u.jsx)(i.Z,{aspectRatio:1,loading:0===r.length,children:(0,u.jsx)(a,{children:r.map((e,r)=>{var{node:a}=e;return(0,u.jsx)(c,{children:(0,u.jsx)(p.Component,_objectSpread(_objectSpread({aspectRatio:1,imgProps:{width:150,height:150,sizes:"30vw",loading:0===r?"eager":"lazy"}},p.props),{},{bordered:null!=d?d:p.props.bordered,showDiscountBadge:null!=o?o:p.props.showDiscountBadge,product:a,index:n*t+r+1,taxesConfiguration:l}))},"".concat(a.id))})})})}),l=t(9029),p=t(7704),f=t(1163),g=t(6414),replacePagination=(e,r)=>{var t=new URL(window.location.href);t.searchParams.get("page")!==e&&(t.searchParams.set("page",e),r.replace(t,void 0,{shallow:!0,scroll:!1}))},search_Sentinel=function(e){var{page:r,pageSize:t,products:n,title:a}=e,c=(0,o.useRef)(!1),{ref:i,inView:s}=(0,p.YD)(),{pages:d}=(0,l.R)(),h=(0,f.useRouter)(),{sendViewItemListEvent:j}=(0,g.m)({products:n,title:a,page:r,pageSize:t});return(0,o.useEffect)(()=>{s&&d.length>1&&replacePagination(r.toString(),h),s&&!c.current&&n.length&&(j(),c.current=!0)},[d.length,s,r,h,j,n.length]),(0,u.jsx)("div",{ref:i})},h=t(7171),j=(0,o.memo)(function(e){var r,t,n,{page:o,title:a,productCard:c,itemsPerPage:i}=e,{data:s}=(0,h.__)(o),l=null!==(r=null==s?void 0:null===(t=s.search)||void 0===t?void 0:null===(n=t.products)||void 0===n?void 0:n.edges)&&void 0!==r?r:[];return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(search_Sentinel,{products:l,page:o,pageSize:i,title:a}),(0,u.jsx)(d,{products:l,page:o,pageSize:i,productCard:c})]})})}}]);
|