@akinon/projectzero 2.0.0-beta.20 → 2.0.0-beta.21
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/CHANGELOG.md +8 -0
- package/app-template/CHANGELOG.md +138 -0
- package/app-template/next.config.mjs +0 -1
- package/app-template/package.json +31 -30
- package/app-template/src/app/[pz]/[...prettyurl]/page.tsx +2 -2
- package/app-template/src/app/[pz]/account/layout.tsx +2 -1
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/blog/[slug]/page.tsx +4 -2
- package/app-template/src/app/[pz]/category/[pk]/page.tsx +11 -1
- package/app-template/src/app/[pz]/group-product/[pk]/page.tsx +2 -2
- package/app-template/src/app/[pz]/layout.tsx +3 -1
- package/app-template/src/app/[pz]/list/page.tsx +11 -1
- package/app-template/src/app/[pz]/page.tsx +13 -35
- package/app-template/src/app/[pz]/pages/[slug]/page.tsx +19 -0
- package/app-template/src/app/[pz]/product/[pk]/page.tsx +2 -2
- package/app-template/src/app/api/barcode-search/route.ts +1 -1
- package/app-template/src/app/api/cache/route.ts +1 -1
- package/app-template/src/app/api/image-proxy/route.ts +1 -1
- package/app-template/src/app/api/logout/route.ts +1 -1
- package/app-template/src/app/api/product-categories/route.ts +1 -1
- package/app-template/src/app/api/similar-product-list/route.ts +1 -1
- package/app-template/src/app/api/similar-products/route.ts +1 -1
- package/app-template/src/app/api/virtual-try-on/route.ts +1 -1
- package/app-template/src/app/api/web-vitals/route.ts +1 -1
- package/app-template/src/components/quantity-selector.tsx +16 -4
- package/app-template/src/components/widget-content.tsx +3 -3
- package/app-template/src/routes/index.ts +6 -6
- package/app-template/src/utils/__tests__/theme-page-context.test.ts +145 -0
- package/app-template/src/utils/theme-page-context.ts +309 -0
- package/app-template/src/views/basket/basket-item.tsx +107 -691
- package/app-template/src/views/basket/index.ts +0 -2
- package/app-template/src/views/basket/summary.tsx +75 -496
- package/app-template/src/views/breadcrumb.tsx +38 -13
- package/app-template/src/views/category/category-header.tsx +66 -289
- package/app-template/src/views/category/category-info.tsx +24 -173
- package/app-template/src/views/category/filters/index.tsx +48 -208
- package/app-template/src/views/category/layout.tsx +5 -7
- package/app-template/src/views/checkout/index.tsx +0 -5
- package/app-template/src/views/checkout/steps/payment/index.tsx +2 -5
- package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +1 -72
- package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +40 -171
- package/app-template/src/views/checkout/steps/shipping/address-box.tsx +12 -74
- package/app-template/src/views/checkout/steps/shipping/addresses.tsx +45 -128
- package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +27 -232
- package/app-template/src/views/checkout/summary.tsx +29 -303
- package/app-template/src/views/footer.tsx +13 -415
- package/app-template/src/views/guest-login/index.tsx +1 -1
- package/app-template/src/views/header/action-menu.tsx +45 -277
- package/app-template/src/views/header/band.tsx +21 -6
- package/app-template/src/views/header/index.tsx +47 -109
- package/app-template/src/views/header/mini-basket.tsx +45 -820
- package/app-template/src/views/header/navbar.tsx +111 -178
- package/app-template/src/views/header/search/index.tsx +32 -71
- package/app-template/src/views/header/search/results.tsx +65 -127
- package/app-template/src/views/product/accordion-wrapper.tsx +43 -135
- package/app-template/src/views/product/index.ts +1 -1
- package/app-template/src/views/product/layout.tsx +7 -2
- package/app-template/src/views/product/misc-buttons.tsx +25 -339
- package/app-template/src/views/product/product-actions.tsx +8 -137
- package/app-template/src/views/product/product-info.tsx +31 -69
- package/app-template/src/views/product/product-share.tsx +8 -11
- package/app-template/src/views/product/slider.tsx +79 -117
- package/app-template/src/views/product-item/index.tsx +46 -119
- package/app-template/src/widgets/footer-social.tsx +16 -47
- package/app-template/src/widgets/footer-subscription/index.tsx +17 -183
- package/dist/commands/plugins.js +23 -2
- package/package.json +1 -1
- package/app-template/src/app/[commerce]/[locale]/[currency]/pages/[slug]/page.tsx +0 -15
- package/app-template/src/views/basket/basket-summary-context.tsx +0 -560
- package/app-template/src/views/basket/designer-context.tsx +0 -617
- package/app-template/src/views/breadcrumb/breadcrumb-client.tsx +0 -190
- package/app-template/src/views/breadcrumb/breadcrumb-registrar.tsx +0 -286
- package/app-template/src/views/breadcrumb/constants.ts +0 -15
- package/app-template/src/views/breadcrumb/index.tsx +0 -127
- package/app-template/src/views/category/native-widget-context.tsx +0 -257
- package/app-template/src/views/category/product-list-registrar.tsx +0 -665
- package/app-template/src/views/checkout/checkout-address-registrar.tsx +0 -254
- package/app-template/src/views/checkout/checkout-buttons-registrar.tsx +0 -183
- package/app-template/src/views/checkout/checkout-delivery-method-registrar.tsx +0 -259
- package/app-template/src/views/checkout/checkout-payment-options-registrar.tsx +0 -253
- package/app-template/src/views/checkout/checkout-summary-registrar.tsx +0 -183
- package/app-template/src/views/checkout/constants.ts +0 -5
- package/app-template/src/views/checkout/steps/payment/options/masterpass-rest.tsx +0 -15
- package/app-template/src/views/checkout/steps/payment/options/saved-card.tsx +0 -18
- package/app-template/src/views/footer/footer-app-banner-context.tsx +0 -326
- package/app-template/src/views/footer/footer-bottom-context.tsx +0 -215
- package/app-template/src/views/footer/footer-bottom-wrapper.tsx +0 -74
- package/app-template/src/views/footer/footer-layout-constants.ts +0 -35
- package/app-template/src/views/footer/footer-layout-registrar.tsx +0 -342
- package/app-template/src/views/footer/footer-layout-switcher.tsx +0 -110
- package/app-template/src/views/footer/footer-menu-context.tsx +0 -211
- package/app-template/src/views/footer/footer-native-widgets.tsx +0 -60
- package/app-template/src/views/footer/footer-social-context.tsx +0 -254
- package/app-template/src/views/footer/footer-subscription-context.tsx +0 -210
- package/app-template/src/views/footer/footer-utils.ts +0 -43
- package/app-template/src/views/footer/footer-value-props-context.tsx +0 -326
- package/app-template/src/views/footer/logo-settings.ts +0 -183
- package/app-template/src/views/footer/native-widget-config.ts +0 -262
- package/app-template/src/views/footer/subscription-settings.ts +0 -122
- package/app-template/src/views/footer/use-footer-logo.ts +0 -162
- package/app-template/src/views/header/designer-context.tsx +0 -261
- package/app-template/src/views/header/header-announcement-registrar.tsx +0 -267
- package/app-template/src/views/header/header-client-wrapper.tsx +0 -496
- package/app-template/src/views/header/header-content.tsx +0 -1026
- package/app-template/src/views/header/header-currency-registrar.tsx +0 -348
- package/app-template/src/views/header/header-icons-context.tsx +0 -262
- package/app-template/src/views/header/header-language-registrar.tsx +0 -348
- package/app-template/src/views/header/header-layout-context.tsx +0 -143
- package/app-template/src/views/header/header-layout-registrar.tsx +0 -658
- package/app-template/src/views/header/header-logo-context.tsx +0 -228
- package/app-template/src/views/header/header-logo.tsx +0 -118
- package/app-template/src/views/header/header-mini-basket-context.tsx +0 -524
- package/app-template/src/views/header/header-search-registrar.tsx +0 -511
- package/app-template/src/views/header/header-text-slider-registrar.tsx +0 -382
- package/app-template/src/views/header/inline-search.tsx +0 -262
- package/app-template/src/views/header/navbar-menu-context.tsx +0 -219
- package/app-template/src/views/header/search/search-input.tsx +0 -61
- package/app-template/src/views/header/server-settings-parser.ts +0 -1105
- package/app-template/src/views/header/use-header-icons.ts +0 -241
- package/app-template/src/views/header/use-header-logo.ts +0 -213
- package/app-template/src/views/header/use-navbar-menu.ts +0 -179
- package/app-template/src/views/product/accordion-section.tsx +0 -61
- package/app-template/src/views/product/custom-button-group.tsx +0 -69
- package/app-template/src/views/product/favorites-button-section.tsx +0 -69
- package/app-template/src/views/product/find-in-store-section.tsx +0 -60
- package/app-template/src/views/product/product-info-section.tsx +0 -140
- package/app-template/src/views/product/quantity-section.tsx +0 -73
- package/app-template/src/views/product/sale-tag.tsx +0 -10
- package/app-template/src/views/product/share-section.tsx +0 -357
- package/app-template/src/views/product/variants-section.tsx +0 -126
- package/app-template/src/views/product-detail/constants.ts +0 -272
- package/app-template/src/views/product-detail/index.ts +0 -10
- package/app-template/src/views/product-detail/product-detail-registrar.tsx +0 -616
- package/app-template/src/widgets/footer-app-banner.tsx +0 -444
- package/app-template/src/widgets/footer-bottom.tsx +0 -127
- package/app-template/src/widgets/footer-menu-compact.tsx +0 -238
- package/app-template/src/widgets/footer-menu-two.tsx +0 -298
- package/app-template/src/widgets/footer-social-client.tsx +0 -251
- package/app-template/src/widgets/footer-value-props.tsx +0 -201
|
@@ -16,8 +16,6 @@ import { Link, LoaderSpinner } from '@akinon/next/components';
|
|
|
16
16
|
import { ROUTES } from '@theme/routes';
|
|
17
17
|
import { useRouter } from '@akinon/next/hooks';
|
|
18
18
|
import { RootState } from '@theme/redux/store';
|
|
19
|
-
import { NativeWidgetProvider, useNativeWidget } from './native-widget-context';
|
|
20
|
-
import { useProductList } from './product-list-registrar';
|
|
21
19
|
|
|
22
20
|
interface ListPageProps {
|
|
23
21
|
data: GetCategoryResponse;
|
|
@@ -34,7 +32,7 @@ export default function ListPage(props: ListPageProps) {
|
|
|
34
32
|
const router = useRouter();
|
|
35
33
|
|
|
36
34
|
const layoutSize = useMemo(
|
|
37
|
-
() => searchParams.get('layout') ??
|
|
35
|
+
() => Number(searchParams.get('layout') ?? 3),
|
|
38
36
|
[searchParams]
|
|
39
37
|
);
|
|
40
38
|
|
|
@@ -45,9 +43,9 @@ export default function ListPage(props: ListPageProps) {
|
|
|
45
43
|
|
|
46
44
|
const itemDimensions = useMemo(() => {
|
|
47
45
|
switch (layoutSize) {
|
|
48
|
-
case
|
|
46
|
+
case 2:
|
|
49
47
|
return { width: 510, height: 765 };
|
|
50
|
-
case
|
|
48
|
+
case 3:
|
|
51
49
|
default:
|
|
52
50
|
return { width: 340, height: 510 };
|
|
53
51
|
}
|
|
@@ -60,7 +58,7 @@ export default function ListPage(props: ListPageProps) {
|
|
|
60
58
|
router.push(newUrl.pathname + newUrl.search, undefined);
|
|
61
59
|
}
|
|
62
60
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
63
|
-
}, [searchParams, data
|
|
61
|
+
}, [searchParams, data.products, page]);
|
|
64
62
|
|
|
65
63
|
const { t } = useLocalization();
|
|
66
64
|
|
|
@@ -69,109 +67,32 @@ export default function ListPage(props: ListPageProps) {
|
|
|
69
67
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70
68
|
}, [data.facets]);
|
|
71
69
|
|
|
72
|
-
return (
|
|
73
|
-
<NativeWidgetProvider>
|
|
74
|
-
<ListPageContent data={data} />
|
|
75
|
-
</NativeWidgetProvider>
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function ListPageContent({ data }: ListPageProps) {
|
|
80
|
-
const dispatch = useAppDispatch();
|
|
81
|
-
const isMenuOpen = useAppSelector(
|
|
82
|
-
(state: RootState) => state.category.isMenuOpen
|
|
83
|
-
);
|
|
84
|
-
const {
|
|
85
|
-
isDesigner,
|
|
86
|
-
filterProperties: registrarProps,
|
|
87
|
-
productsStyles: registrarProductsStyles,
|
|
88
|
-
paginationProperties: registrarPaginationProps,
|
|
89
|
-
paginationStyles: registrarPaginationStyles
|
|
90
|
-
} = useProductList();
|
|
91
|
-
const {
|
|
92
|
-
filterProperties: widgetProps,
|
|
93
|
-
productsStyles: widgetProductsStyles,
|
|
94
|
-
paginationProperties: widgetPaginationProps,
|
|
95
|
-
paginationStyles: widgetPaginationStyles
|
|
96
|
-
} = useNativeWidget();
|
|
97
|
-
|
|
98
|
-
// Use registrar properties in designer mode, widget properties otherwise
|
|
99
|
-
const filterProperties = isDesigner ? registrarProps : widgetProps;
|
|
100
|
-
const productsStyles = isDesigner
|
|
101
|
-
? registrarProductsStyles
|
|
102
|
-
: widgetProductsStyles;
|
|
103
|
-
const paginationProperties = isDesigner
|
|
104
|
-
? { ...widgetPaginationProps, ...registrarPaginationProps }
|
|
105
|
-
: widgetPaginationProps;
|
|
106
|
-
const paginationStyles = isDesigner
|
|
107
|
-
? { ...widgetPaginationStyles, ...registrarPaginationStyles }
|
|
108
|
-
: widgetPaginationStyles;
|
|
109
|
-
const { t } = useLocalization();
|
|
110
|
-
|
|
111
|
-
const searchParams = useSearchParams();
|
|
112
|
-
|
|
113
|
-
const layoutSize = useMemo(
|
|
114
|
-
() => searchParams.get('layout') ?? '4',
|
|
115
|
-
[searchParams]
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
const page = useMemo(
|
|
119
|
-
() => Number(searchParams.get('page') ?? 1),
|
|
120
|
-
[searchParams]
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
const itemDimensions = useMemo(() => {
|
|
124
|
-
switch (layoutSize) {
|
|
125
|
-
case '2':
|
|
126
|
-
return { width: 510, height: 765 };
|
|
127
|
-
case '3':
|
|
128
|
-
default:
|
|
129
|
-
return { width: 340, height: 510 };
|
|
130
|
-
}
|
|
131
|
-
}, [layoutSize]);
|
|
132
|
-
|
|
133
|
-
// Get layout from widget properties
|
|
134
|
-
const layout = (filterProperties.layout as string) || 'top';
|
|
135
|
-
|
|
136
70
|
return (
|
|
137
71
|
<>
|
|
138
|
-
<div className="container px-4 mx-auto lg:px-0">
|
|
139
|
-
<div
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
>
|
|
145
|
-
{layout === 'sidebar' && (
|
|
146
|
-
<>
|
|
147
|
-
<Filters
|
|
148
|
-
isMenuOpen={isMenuOpen}
|
|
149
|
-
totalCount={data.pagination?.total_count}
|
|
150
|
-
setIsMenuOpen={(open) => dispatch(setMenuOpen(open))}
|
|
151
|
-
sortOptions={data.sorters}
|
|
152
|
-
/>
|
|
153
|
-
<div
|
|
154
|
-
onClick={() => dispatch(setMenuOpen(false))}
|
|
155
|
-
className={clsx(
|
|
156
|
-
'transition-opacity duration-300 ease-linear lg:hidden',
|
|
157
|
-
isMenuOpen
|
|
158
|
-
? 'fixed bg-black bg-opacity-60 top-16 inset-x-0 bottom-0 z-10 opacity-100 pointer-events-auto'
|
|
159
|
-
: 'opacity-0 pointer-events-none'
|
|
160
|
-
)}
|
|
161
|
-
></div>
|
|
162
|
-
</>
|
|
163
|
-
)}
|
|
72
|
+
<div className="container px-4 mx-auto lg:px-0 lg:my-4">
|
|
73
|
+
<div className="grid grid-cols-[19rem_1fr]">
|
|
74
|
+
<Filters
|
|
75
|
+
isMenuOpen={isMenuOpen}
|
|
76
|
+
setIsMenuOpen={(open) => dispatch(setMenuOpen(open))}
|
|
77
|
+
/>
|
|
164
78
|
<div
|
|
79
|
+
onClick={() => dispatch(setMenuOpen(false))}
|
|
165
80
|
className={clsx(
|
|
166
|
-
'
|
|
167
|
-
|
|
81
|
+
'transition-opacity duration-300 ease-linear lg:hidden',
|
|
82
|
+
isMenuOpen
|
|
83
|
+
? 'fixed bg-black bg-opacity-60 inset-0 z-10 opacity-100'
|
|
84
|
+
: 'opacity-0'
|
|
168
85
|
)}
|
|
169
|
-
>
|
|
86
|
+
></div>
|
|
87
|
+
<div className="flex flex-col items-center lg:items-stretch col-span-2 lg:col-span-1">
|
|
170
88
|
<CategoryHeader
|
|
171
89
|
totalCount={data.pagination?.total_count}
|
|
172
90
|
setMenuStatus={() => dispatch(setMenuOpen(true))}
|
|
173
91
|
sortOptions={data.sorters}
|
|
174
92
|
/>
|
|
93
|
+
<div className="hidden lg:block">
|
|
94
|
+
<CategoryActiveFilters />
|
|
95
|
+
</div>
|
|
175
96
|
|
|
176
97
|
{data.products?.length === 0 && page === 1 && (
|
|
177
98
|
<div className="text-center bg-gray-200 px-5 py-20">
|
|
@@ -185,25 +106,11 @@ function ListPageContent({ data }: ListPageProps) {
|
|
|
185
106
|
{data.products?.length === 0 && page > 1 && <LoaderSpinner />}
|
|
186
107
|
|
|
187
108
|
<div
|
|
188
|
-
className={clsx('grid
|
|
189
|
-
'
|
|
190
|
-
'lg:grid-cols-
|
|
191
|
-
'lg:grid-cols-
|
|
192
|
-
'lg:grid-cols-6': layoutSize === '6'
|
|
109
|
+
className={clsx('grid gap-x-4 gap-y-12 grid-cols-2', {
|
|
110
|
+
'md:grid-cols-3': layoutSize === 3,
|
|
111
|
+
'lg:grid-cols-2': layoutSize === 2,
|
|
112
|
+
'lg:grid-cols-3': layoutSize === 3
|
|
193
113
|
})}
|
|
194
|
-
style={{
|
|
195
|
-
gap: `${(productsStyles['gap-y'] as string) || '48px'} ${
|
|
196
|
-
(productsStyles['gap-x'] as string) || '16px'
|
|
197
|
-
}`,
|
|
198
|
-
paddingTop: (productsStyles['padding-top'] as string) || '0px',
|
|
199
|
-
paddingBottom:
|
|
200
|
-
(productsStyles['padding-bottom'] as string) || '0px',
|
|
201
|
-
paddingLeft:
|
|
202
|
-
(productsStyles['padding-left'] as string) || '0px',
|
|
203
|
-
paddingRight:
|
|
204
|
-
(productsStyles['padding-right'] as string) || '0px'
|
|
205
|
-
}}
|
|
206
|
-
data-section-id="products-section"
|
|
207
114
|
>
|
|
208
115
|
{data?.products?.map((product, index) => (
|
|
209
116
|
<ProductItem
|
|
@@ -221,62 +128,6 @@ function ListPageContent({ data }: ListPageProps) {
|
|
|
221
128
|
limit={data.pagination.page_size}
|
|
222
129
|
currentPage={data.pagination.current_page}
|
|
223
130
|
numberOfPages={data.pagination.num_pages}
|
|
224
|
-
type={
|
|
225
|
-
(paginationProperties.type as 'list' | 'more' | 'infinite') ||
|
|
226
|
-
'list'
|
|
227
|
-
}
|
|
228
|
-
customStyles={{
|
|
229
|
-
marginTop:
|
|
230
|
-
(paginationStyles['margin-top'] as string) || '32px',
|
|
231
|
-
marginBottom:
|
|
232
|
-
(paginationStyles['margin-bottom'] as string) || '16px',
|
|
233
|
-
pageFontSize:
|
|
234
|
-
(paginationStyles['page-font-size'] as string) || '14px',
|
|
235
|
-
pageColor:
|
|
236
|
-
(paginationStyles['page-color'] as string) || '#9ca3af',
|
|
237
|
-
pageActiveColor:
|
|
238
|
-
(paginationStyles['page-active-color'] as string) ||
|
|
239
|
-
'#1a1a1a',
|
|
240
|
-
pageActiveFontWeight:
|
|
241
|
-
(paginationStyles['page-active-font-weight'] as string) ||
|
|
242
|
-
'600',
|
|
243
|
-
pageGap: (paginationStyles['page-gap'] as string) || '8px',
|
|
244
|
-
pageBgColor:
|
|
245
|
-
(paginationStyles['page-bg-color'] as string) ||
|
|
246
|
-
'transparent',
|
|
247
|
-
pageActiveBgColor:
|
|
248
|
-
(paginationStyles['page-active-bg-color'] as string) ||
|
|
249
|
-
'transparent',
|
|
250
|
-
pagePaddingX:
|
|
251
|
-
(paginationStyles['page-padding-x'] as string) || '8px',
|
|
252
|
-
pagePaddingY:
|
|
253
|
-
(paginationStyles['page-padding-y'] as string) || '4px',
|
|
254
|
-
pageBorderRadius:
|
|
255
|
-
(paginationStyles['page-border-radius'] as string) || '0px',
|
|
256
|
-
pageBorderWidth:
|
|
257
|
-
(paginationStyles['page-border-width'] as string) || '0px',
|
|
258
|
-
pageBorderColor:
|
|
259
|
-
(paginationStyles['page-border-color'] as string) ||
|
|
260
|
-
'#e5e7eb',
|
|
261
|
-
pageActiveBorderColor:
|
|
262
|
-
(paginationStyles['page-active-border-color'] as string) ||
|
|
263
|
-
'#1a1a1a',
|
|
264
|
-
arrowColor:
|
|
265
|
-
(paginationStyles['arrow-color'] as string) || '#1a1a1a',
|
|
266
|
-
buttonBgColor:
|
|
267
|
-
(paginationStyles['button-bg-color'] as string) ||
|
|
268
|
-
'#000000',
|
|
269
|
-
buttonTextColor:
|
|
270
|
-
(paginationStyles['button-text-color'] as string) ||
|
|
271
|
-
'#ffffff',
|
|
272
|
-
buttonBorderRadius:
|
|
273
|
-
(paginationStyles['button-border-radius'] as string) ||
|
|
274
|
-
'4px',
|
|
275
|
-
buttonPaddingX:
|
|
276
|
-
(paginationStyles['button-padding-x'] as string) || '20px',
|
|
277
|
-
buttonPaddingY:
|
|
278
|
-
(paginationStyles['button-padding-y'] as string) || '12px'
|
|
279
|
-
}}
|
|
280
131
|
/>
|
|
281
132
|
)}
|
|
282
133
|
</div>
|
|
@@ -1,56 +1,27 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import clsx from 'clsx';
|
|
4
|
-
import { Button, Icon
|
|
5
|
-
import {
|
|
4
|
+
import { Button, Icon } from '@theme/components';
|
|
5
|
+
import { useLocalization } from '@akinon/next/hooks';
|
|
6
6
|
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
|
|
7
7
|
import { resetSelectedFacets } from '@theme/redux/reducers/category';
|
|
8
8
|
import CategoryActiveFilters from '@theme/views/category/category-active-filters';
|
|
9
|
-
import { useMemo, useTransition
|
|
9
|
+
import { useMemo, useTransition } from 'react';
|
|
10
10
|
import { FilterItem } from './filter-item';
|
|
11
|
-
import { SortOption } from '@akinon/next/types';
|
|
12
|
-
import { usePathname, useSearchParams } from 'next/navigation';
|
|
13
|
-
import { useProductList } from '../product-list-registrar';
|
|
14
|
-
import { useNativeWidget } from '../native-widget-context';
|
|
15
11
|
|
|
16
12
|
interface Props {
|
|
17
13
|
isMenuOpen: boolean;
|
|
18
14
|
setIsMenuOpen: (isMenuOpen: boolean) => void;
|
|
19
|
-
totalCount?: number;
|
|
20
|
-
sortOptions: SortOption[];
|
|
21
15
|
}
|
|
22
16
|
|
|
23
17
|
export const Filters = (props: Props) => {
|
|
24
18
|
const facets = useAppSelector((state) => state.category.facets);
|
|
25
19
|
const dispatch = useAppDispatch();
|
|
26
20
|
const { t } = useLocalization();
|
|
27
|
-
const { isMenuOpen, setIsMenuOpen
|
|
28
|
-
const [openDropdown, setOpenDropdown] = useState<string | null>(null);
|
|
21
|
+
const { isMenuOpen, setIsMenuOpen } = props;
|
|
29
22
|
|
|
30
23
|
const [isPending, startTransition] = useTransition();
|
|
31
24
|
|
|
32
|
-
const router = useRouter();
|
|
33
|
-
const searchParams = useSearchParams();
|
|
34
|
-
const pathname = usePathname();
|
|
35
|
-
|
|
36
|
-
// Get styles and properties from both contexts
|
|
37
|
-
const {
|
|
38
|
-
isDesigner,
|
|
39
|
-
filterStyles: registrarStyles,
|
|
40
|
-
filterProperties: registrarProps
|
|
41
|
-
} = useProductList();
|
|
42
|
-
const { filterStyles: widgetStyles, filterProperties: widgetProps } =
|
|
43
|
-
useNativeWidget();
|
|
44
|
-
|
|
45
|
-
// Use registrar data in designer mode, widget data otherwise
|
|
46
|
-
const filterStyles = isDesigner ? registrarStyles : widgetStyles;
|
|
47
|
-
|
|
48
|
-
// Merge properties - registrar props override widget props for live updates
|
|
49
|
-
const filterProperties = {
|
|
50
|
-
...widgetProps,
|
|
51
|
-
...registrarProps
|
|
52
|
-
};
|
|
53
|
-
|
|
54
25
|
const haveFilter = useMemo(() => {
|
|
55
26
|
return facets?.some((facet) =>
|
|
56
27
|
facet?.data?.choices?.some((choice) => choice.is_selected)
|
|
@@ -61,181 +32,50 @@ export const Filters = (props: Props) => {
|
|
|
61
32
|
dispatch(resetSelectedFacets());
|
|
62
33
|
};
|
|
63
34
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const itemPaddingX =
|
|
90
|
-
typeof filterProperties['item-padding-x'] === 'number'
|
|
91
|
-
? filterProperties['item-padding-x']
|
|
92
|
-
: typeof filterProperties['item-padding-x'] === 'string'
|
|
93
|
-
? parseInt(filterProperties['item-padding-x'], 10)
|
|
94
|
-
: 0;
|
|
95
|
-
const itemMarginBottom =
|
|
96
|
-
typeof filterProperties['item-margin-bottom'] === 'number'
|
|
97
|
-
? filterProperties['item-margin-bottom']
|
|
98
|
-
: typeof filterProperties['item-margin-bottom'] === 'string'
|
|
99
|
-
? parseInt(filterProperties['item-margin-bottom'], 10)
|
|
100
|
-
: 0;
|
|
101
|
-
|
|
102
|
-
// Sidebar layout (desktop + mobile)
|
|
103
|
-
if (layout === 'sidebar') {
|
|
104
|
-
return (
|
|
105
|
-
<>
|
|
106
|
-
{/* Mobile overlay backdrop */}
|
|
107
|
-
{isMenuOpen && (
|
|
108
|
-
<div
|
|
109
|
-
className="fixed inset-0 bg-black/80 z-40 lg:hidden transition-opacity duration-300"
|
|
110
|
-
onClick={() => setIsMenuOpen(false)}
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
className={clsx(
|
|
38
|
+
'w-9/10 fixed left-0 top-0 bottom-0 bg-white z-20 p-6 transition-all ease-in duration-300 lg:static lg:block lg:mr-16 lg:text-sm lg:p-0 lg:pt-4',
|
|
39
|
+
isMenuOpen
|
|
40
|
+
? 'flex flex-col opacity-100 overflow-auto'
|
|
41
|
+
: 'opacity-0 invisible absolute -translate-x-full lg:opacity-100 lg:visible lg:translate-x-0'
|
|
42
|
+
)}
|
|
43
|
+
>
|
|
44
|
+
<div className="flex justify-between mb-6 lg:hidden">
|
|
45
|
+
<h3 className="text-2xl">{t('category.filters.title')}</h3>
|
|
46
|
+
<Icon name="close" size={22} onClick={() => setIsMenuOpen(false)} />
|
|
47
|
+
</div>
|
|
48
|
+
<div className="flex justify-between items-center mb-6 lg:hidden">
|
|
49
|
+
<span className="text-sm">1 {t('category.filters.results')}</span>
|
|
50
|
+
<span>{t('category.filters.ready_to_wear')}</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
{facets?.map((facet) => {
|
|
54
|
+
return (
|
|
55
|
+
<FilterItem
|
|
56
|
+
key={facet.key}
|
|
57
|
+
facet={facet}
|
|
58
|
+
isPending={isPending}
|
|
59
|
+
startTransition={startTransition}
|
|
111
60
|
/>
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
<span className="text-[10px]">
|
|
129
|
-
{totalCount} {t('category.header.results')}
|
|
130
|
-
</span>
|
|
131
|
-
</div>
|
|
132
|
-
<Button
|
|
133
|
-
type="button"
|
|
134
|
-
appearance="ghost"
|
|
135
|
-
aria-label="Close Filter Menu"
|
|
136
|
-
onClick={() => setIsMenuOpen(false)}
|
|
137
|
-
className="absolute right-4 p-0 text-black bg-transparent hover:bg-transparent hover:text-black"
|
|
138
|
-
>
|
|
139
|
-
<Icon name="close" size={16} />
|
|
140
|
-
</Button>
|
|
141
|
-
</div>
|
|
142
|
-
|
|
143
|
-
<div className="px-4">
|
|
144
|
-
{facets?.map((facet) => {
|
|
145
|
-
return (
|
|
146
|
-
<FilterItem
|
|
147
|
-
key={facet.key}
|
|
148
|
-
facet={facet}
|
|
149
|
-
isPending={isPending}
|
|
150
|
-
startTransition={startTransition}
|
|
151
|
-
itemPaddingY={itemPaddingY}
|
|
152
|
-
itemPaddingX={itemPaddingX}
|
|
153
|
-
itemMarginBottom={itemMarginBottom}
|
|
154
|
-
/>
|
|
155
|
-
);
|
|
156
|
-
})}
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
<div className="px-4 flex items-center justify-between text-black-750 text-sm">
|
|
160
|
-
{t('category.header.sort_by')}:
|
|
161
|
-
<Select
|
|
162
|
-
options={sortOptions}
|
|
163
|
-
value={sortOptions?.find(({ is_selected }) => is_selected)?.value}
|
|
164
|
-
data-testid="list-sorter"
|
|
165
|
-
className="border-0 text-black-750 text-sm"
|
|
166
|
-
onChange={(e) => {
|
|
167
|
-
handleSelectFilter({
|
|
168
|
-
key: 'sorter',
|
|
169
|
-
value: e.currentTarget.value
|
|
170
|
-
});
|
|
171
|
-
}}
|
|
172
|
-
borderless={false}
|
|
173
|
-
/>
|
|
174
|
-
</div>
|
|
175
|
-
|
|
176
|
-
<div className="p-8">
|
|
177
|
-
<CategoryActiveFilters />
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
{haveFilter && (
|
|
181
|
-
<div className="px-4">
|
|
182
|
-
<Button
|
|
183
|
-
onClick={handleResetFilter}
|
|
184
|
-
appearance="filled"
|
|
185
|
-
className="w-full mt-4"
|
|
186
|
-
data-section-id="filters-section"
|
|
187
|
-
>
|
|
188
|
-
{t('category.filters.clear_all')}
|
|
189
|
-
</Button>
|
|
190
|
-
</div>
|
|
191
|
-
)}
|
|
61
|
+
);
|
|
62
|
+
})}
|
|
63
|
+
|
|
64
|
+
<div className="lg:hidden">
|
|
65
|
+
<CategoryActiveFilters />
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
{haveFilter && (
|
|
69
|
+
<div className="lg:hidden">
|
|
70
|
+
<Button
|
|
71
|
+
onClick={handleResetFilter}
|
|
72
|
+
appearance="outlined"
|
|
73
|
+
className="w-full mt-4 lg:hidden"
|
|
74
|
+
>
|
|
75
|
+
{t('category.filters.clear_all')}
|
|
76
|
+
</Button>
|
|
192
77
|
</div>
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
className="hidden lg:block lg:col-span-1"
|
|
197
|
-
style={containerStyles}
|
|
198
|
-
data-section-id="filters-section"
|
|
199
|
-
>
|
|
200
|
-
<div className="sticky top-24">
|
|
201
|
-
<h3 className="text-lg font-medium mb-4">
|
|
202
|
-
{t('category.filters.title')}
|
|
203
|
-
</h3>
|
|
204
|
-
|
|
205
|
-
<div>
|
|
206
|
-
{facets?.map((facet) => {
|
|
207
|
-
return (
|
|
208
|
-
<FilterItem
|
|
209
|
-
key={facet.key}
|
|
210
|
-
facet={facet}
|
|
211
|
-
isPending={isPending}
|
|
212
|
-
startTransition={startTransition}
|
|
213
|
-
itemPaddingY={itemPaddingY}
|
|
214
|
-
itemPaddingX={itemPaddingX}
|
|
215
|
-
itemMarginBottom={itemMarginBottom}
|
|
216
|
-
/>
|
|
217
|
-
);
|
|
218
|
-
})}
|
|
219
|
-
</div>
|
|
220
|
-
|
|
221
|
-
{haveFilter && (
|
|
222
|
-
<div className="mt-6">
|
|
223
|
-
<Button
|
|
224
|
-
onClick={handleResetFilter}
|
|
225
|
-
appearance="outlined"
|
|
226
|
-
className="w-full"
|
|
227
|
-
data-section-id="filters-section"
|
|
228
|
-
>
|
|
229
|
-
{t('category.filters.clear_all')}
|
|
230
|
-
</Button>
|
|
231
|
-
</div>
|
|
232
|
-
)}
|
|
233
|
-
</div>
|
|
234
|
-
</aside>
|
|
235
|
-
</>
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Top layout - return null, handled in category-header
|
|
240
|
-
return null;
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
241
81
|
};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import { BreadcrumbResultType, GetCategoryResponse } from '@akinon/next/types';
|
|
3
|
-
import ThemePlaceholder from '@akinon/next/components/theme-editor/theme-placeholder';
|
|
4
3
|
import Breadcrumb from '@theme/views/breadcrumb';
|
|
5
4
|
import { CategoryBanner } from '@theme/views/category/category-banner';
|
|
6
5
|
import ListPage from '@theme/views/category/category-info';
|
|
7
|
-
import ProductListRegistrar from '@theme/views/category/product-list-registrar';
|
|
8
6
|
|
|
9
7
|
export default async function Layout({
|
|
10
8
|
data,
|
|
@@ -14,10 +12,10 @@ export default async function Layout({
|
|
|
14
12
|
data: GetCategoryResponse;
|
|
15
13
|
children?: React.ReactNode;
|
|
16
14
|
breadcrumbData?: BreadcrumbResultType[];
|
|
15
|
+
pageContext?: Record<string, unknown>;
|
|
17
16
|
}) {
|
|
18
17
|
return (
|
|
19
|
-
|
|
20
|
-
<ThemePlaceholder slug="list-page-body-new" />
|
|
18
|
+
<>
|
|
21
19
|
<div
|
|
22
20
|
className={clsx(
|
|
23
21
|
data?.category?.attributes?.category_banner
|
|
@@ -28,16 +26,16 @@ export default async function Layout({
|
|
|
28
26
|
{children}
|
|
29
27
|
<div
|
|
30
28
|
className={clsx(
|
|
31
|
-
'my-
|
|
29
|
+
'my-4 lg:mt-7',
|
|
32
30
|
data?.category?.attributes?.category_banner &&
|
|
33
31
|
'lg:absolute lg:inset-x-0 z-10 container lg:my-4 mx-auto'
|
|
34
32
|
)}
|
|
35
33
|
>
|
|
36
34
|
<Breadcrumb breadcrumbList={breadcrumbData} />
|
|
37
35
|
</div>
|
|
38
|
-
<CategoryBanner {...data?.category?.attributes?.
|
|
36
|
+
<CategoryBanner {...data?.category?.attributes?.category_banner} />
|
|
39
37
|
</div>
|
|
40
38
|
<ListPage data={data} />
|
|
41
|
-
|
|
39
|
+
</>
|
|
42
40
|
);
|
|
43
41
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
1
|
export * from './step-button';
|
|
2
2
|
export * from './step-list';
|
|
3
3
|
export * from './summary';
|
|
4
|
-
export * from './checkout-address-registrar';
|
|
5
|
-
export * from './checkout-delivery-method-registrar';
|
|
6
|
-
export * from './checkout-payment-options-registrar';
|
|
7
|
-
export * from './checkout-summary-registrar';
|
|
8
|
-
export * from './checkout-buttons-registrar';
|
|
@@ -4,7 +4,6 @@ import { CheckoutPaymentOption } from '@akinon/next/types';
|
|
|
4
4
|
import clsx from 'clsx';
|
|
5
5
|
import { RootState } from '@theme/redux/store';
|
|
6
6
|
import PaymentOptionButtons from './payment-option-buttons';
|
|
7
|
-
import { CheckoutPaymentOptionsRegistrar } from '@theme/views/checkout/checkout-payment-options-registrar';
|
|
8
7
|
|
|
9
8
|
export const PaymentOptionViews: Array<CheckoutPaymentOption> = [];
|
|
10
9
|
|
|
@@ -19,10 +18,8 @@ const PaymentStep = () => {
|
|
|
19
18
|
'pointer-events-none opacity-30': isPaymentStepBusy
|
|
20
19
|
})}
|
|
21
20
|
>
|
|
22
|
-
<div className="w-full mt-4
|
|
23
|
-
<
|
|
24
|
-
<PaymentOptionButtons />
|
|
25
|
-
</CheckoutPaymentOptionsRegistrar>
|
|
21
|
+
<div className="w-full mt-4 flex justify-start border border-gray-400 -mb-px z-10 md:mt-0 md:border-r-0 md:border-b-0 md:w-auto order-2 md:order-none overflow-x-auto">
|
|
22
|
+
<PaymentOptionButtons />
|
|
26
23
|
</div>
|
|
27
24
|
<div className="w-full border border-solid border-gray-400 bg-white">
|
|
28
25
|
<SelectedPaymentOptionView />
|