@akinon/projectzero 2.0.0-beta.19 → 2.0.0-beta.20

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 (223) hide show
  1. package/CHANGELOG.md +9 -7
  2. package/app-template/CHANGELOG.md +251 -204
  3. package/app-template/akinon.json +1 -1
  4. package/app-template/package.json +28 -28
  5. package/app-template/public/amex.svg +12 -0
  6. package/app-template/public/apple-pay.svg +16 -0
  7. package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
  8. package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
  9. package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
  10. package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
  11. package/app-template/public/google-pay.svg +16 -0
  12. package/app-template/public/locales/en/account.json +6 -3
  13. package/app-template/public/locales/en/auth.json +6 -7
  14. package/app-template/public/locales/en/basket.json +6 -6
  15. package/app-template/public/locales/en/blog.json +7 -0
  16. package/app-template/public/locales/en/category.json +3 -1
  17. package/app-template/public/locales/en/checkout.json +5 -4
  18. package/app-template/public/locales/en/common.json +11 -2
  19. package/app-template/public/locales/en/forgot_password.json +6 -7
  20. package/app-template/public/locales/en/product.json +4 -3
  21. package/app-template/public/locales/tr/account.json +6 -3
  22. package/app-template/public/locales/tr/auth.json +16 -17
  23. package/app-template/public/locales/tr/basket.json +4 -4
  24. package/app-template/public/locales/tr/blog.json +7 -0
  25. package/app-template/public/locales/tr/category.json +3 -1
  26. package/app-template/public/locales/tr/checkout.json +39 -38
  27. package/app-template/public/locales/tr/common.json +10 -1
  28. package/app-template/public/locales/tr/forgot_password.json +12 -13
  29. package/app-template/public/locales/tr/product.json +1 -0
  30. package/app-template/public/logo.svg +3 -27
  31. package/app-template/public/mastercard.svg +14 -0
  32. package/app-template/public/promotion-banner.jpg +0 -0
  33. package/app-template/public/shop-pay.svg +12 -0
  34. package/app-template/public/visa.svg +12 -0
  35. package/app-template/src/app/[commerce]/[locale]/[currency]/blog/[slug]/page.tsx +118 -0
  36. package/app-template/src/app/[commerce]/[locale]/[currency]/pages/[slug]/page.tsx +15 -0
  37. package/app-template/src/app/api/theme-settings/route.ts +12 -0
  38. package/app-template/src/assets/fonts/pz-icon.css +211 -49
  39. package/app-template/src/assets/fonts/pz-icon.eot +0 -0
  40. package/app-template/src/assets/fonts/pz-icon.html +486 -0
  41. package/app-template/src/assets/fonts/pz-icon.scss +373 -49
  42. package/app-template/src/assets/fonts/pz-icon.svg +215 -53
  43. package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
  44. package/app-template/src/assets/fonts/pz-icon.woff +0 -0
  45. package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
  46. package/app-template/src/assets/globals.scss +4 -0
  47. package/app-template/src/assets/icons/arrow-right.svg +3 -0
  48. package/app-template/src/assets/icons/cart.svg +4 -12
  49. package/app-template/src/assets/icons/check.svg +2 -18
  50. package/app-template/src/assets/icons/chevron-down.svg +2 -7
  51. package/app-template/src/assets/icons/delete.svg +3 -0
  52. package/app-template/src/assets/icons/facebook.svg +2 -8
  53. package/app-template/src/assets/icons/fav-off.svg +5 -0
  54. package/app-template/src/assets/icons/fav-on.svg +5 -0
  55. package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
  56. package/app-template/src/assets/icons/heart.svg +3 -0
  57. package/app-template/src/assets/icons/instagram.svg +2 -13
  58. package/app-template/src/assets/icons/materials.svg +3 -0
  59. package/app-template/src/assets/icons/person.svg +4 -0
  60. package/app-template/src/assets/icons/pinterest.svg +5 -11
  61. package/app-template/src/assets/icons/ruler.svg +3 -0
  62. package/app-template/src/assets/icons/search.svg +8 -11
  63. package/app-template/src/assets/icons/share.svg +2 -9
  64. package/app-template/src/assets/icons/snapchat.svg +3 -0
  65. package/app-template/src/assets/icons/tiktok.svg +3 -0
  66. package/app-template/src/assets/icons/tumblr.svg +6 -0
  67. package/app-template/src/assets/icons/twitter.svg +2 -10
  68. package/app-template/src/assets/icons/vimeo.svg +3 -0
  69. package/app-template/src/assets/icons/youtube.svg +3 -0
  70. package/app-template/src/assets/icons/zoom.svg +8 -0
  71. package/app-template/src/components/accordion.tsx +33 -11
  72. package/app-template/src/components/action-tooltip.tsx +160 -0
  73. package/app-template/src/components/currency-select.tsx +149 -4
  74. package/app-template/src/components/icon.tsx +5 -6
  75. package/app-template/src/components/index.ts +4 -1
  76. package/app-template/src/components/language-select.tsx +88 -2
  77. package/app-template/src/components/pagination.tsx +132 -20
  78. package/app-template/src/components/quantity-input.tsx +63 -0
  79. package/app-template/src/components/quantity-selector.tsx +203 -0
  80. package/app-template/src/components/route-handler.tsx +50 -0
  81. package/app-template/src/components/select.tsx +89 -69
  82. package/app-template/src/components/types/index.ts +26 -0
  83. package/app-template/src/components/widget-content.tsx +323 -0
  84. package/app-template/src/data/server/theme.ts +70 -0
  85. package/app-template/src/hooks/use-fav-button.tsx +5 -2
  86. package/app-template/src/hooks/use-product-cart.ts +11 -8
  87. package/app-template/src/hooks/use-theme-settings.ts +42 -0
  88. package/app-template/src/lib/fonts.ts +149 -0
  89. package/app-template/src/settings.js +2 -2
  90. package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
  91. package/app-template/src/types/widget.ts +169 -0
  92. package/app-template/src/utils/formatDate.ts +48 -0
  93. package/app-template/src/utils/styles.ts +71 -0
  94. package/app-template/src/views/account/contact-form.tsx +147 -130
  95. package/app-template/src/views/basket/basket-item.tsx +691 -107
  96. package/app-template/src/views/basket/basket-summary-context.tsx +560 -0
  97. package/app-template/src/views/basket/designer-context.tsx +617 -0
  98. package/app-template/src/views/basket/index.ts +2 -0
  99. package/app-template/src/views/basket/summary.tsx +496 -75
  100. package/app-template/src/views/breadcrumb/breadcrumb-client.tsx +190 -0
  101. package/app-template/src/views/breadcrumb/breadcrumb-registrar.tsx +286 -0
  102. package/app-template/src/views/breadcrumb/constants.ts +15 -0
  103. package/app-template/src/views/breadcrumb/index.tsx +127 -0
  104. package/app-template/src/views/breadcrumb.tsx +13 -38
  105. package/app-template/src/views/category/category-banner.tsx +4 -23
  106. package/app-template/src/views/category/category-header.tsx +289 -66
  107. package/app-template/src/views/category/category-info.tsx +173 -24
  108. package/app-template/src/views/category/filters/filter-item.tsx +138 -42
  109. package/app-template/src/views/category/filters/index.tsx +208 -48
  110. package/app-template/src/views/category/layout.tsx +7 -4
  111. package/app-template/src/views/category/native-widget-context.tsx +257 -0
  112. package/app-template/src/views/category/product-list-registrar.tsx +665 -0
  113. package/app-template/src/views/checkout/auth.tsx +64 -40
  114. package/app-template/src/views/checkout/checkout-address-registrar.tsx +254 -0
  115. package/app-template/src/views/checkout/checkout-buttons-registrar.tsx +183 -0
  116. package/app-template/src/views/checkout/checkout-delivery-method-registrar.tsx +259 -0
  117. package/app-template/src/views/checkout/checkout-payment-options-registrar.tsx +253 -0
  118. package/app-template/src/views/checkout/checkout-summary-registrar.tsx +183 -0
  119. package/app-template/src/views/checkout/constants.ts +5 -0
  120. package/app-template/src/views/checkout/index.tsx +5 -0
  121. package/app-template/src/views/checkout/layout/header.tsx +9 -5
  122. package/app-template/src/views/checkout/steps/payment/index.tsx +5 -2
  123. package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +72 -1
  124. package/app-template/src/views/checkout/steps/payment/options/masterpass-rest.tsx +15 -0
  125. package/app-template/src/views/checkout/steps/payment/options/saved-card.tsx +18 -0
  126. package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +171 -40
  127. package/app-template/src/views/checkout/steps/shipping/address-box.tsx +74 -12
  128. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +128 -45
  129. package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +232 -27
  130. package/app-template/src/views/checkout/summary.tsx +303 -29
  131. package/app-template/src/views/footer/footer-app-banner-context.tsx +326 -0
  132. package/app-template/src/views/footer/footer-bottom-context.tsx +215 -0
  133. package/app-template/src/views/footer/footer-bottom-wrapper.tsx +74 -0
  134. package/app-template/src/views/footer/footer-layout-constants.ts +35 -0
  135. package/app-template/src/views/footer/footer-layout-registrar.tsx +342 -0
  136. package/app-template/src/views/footer/footer-layout-switcher.tsx +110 -0
  137. package/app-template/src/views/footer/footer-menu-context.tsx +211 -0
  138. package/app-template/src/views/footer/footer-native-widgets.tsx +60 -0
  139. package/app-template/src/views/footer/footer-social-context.tsx +254 -0
  140. package/app-template/src/views/footer/footer-subscription-context.tsx +210 -0
  141. package/app-template/src/views/footer/footer-utils.ts +43 -0
  142. package/app-template/src/views/footer/footer-value-props-context.tsx +326 -0
  143. package/app-template/src/views/footer/logo-settings.ts +183 -0
  144. package/app-template/src/views/footer/native-widget-config.ts +262 -0
  145. package/app-template/src/views/footer/subscription-settings.ts +122 -0
  146. package/app-template/src/views/footer/use-footer-logo.ts +162 -0
  147. package/app-template/src/views/footer.tsx +415 -13
  148. package/app-template/src/views/guest-login/index.tsx +62 -58
  149. package/app-template/src/views/header/action-menu.tsx +277 -45
  150. package/app-template/src/views/header/band.tsx +6 -21
  151. package/app-template/src/views/header/designer-context.tsx +261 -0
  152. package/app-template/src/views/header/header-announcement-registrar.tsx +267 -0
  153. package/app-template/src/views/header/header-client-wrapper.tsx +496 -0
  154. package/app-template/src/views/header/header-content.tsx +1026 -0
  155. package/app-template/src/views/header/header-currency-registrar.tsx +348 -0
  156. package/app-template/src/views/header/header-icons-context.tsx +262 -0
  157. package/app-template/src/views/header/header-language-registrar.tsx +348 -0
  158. package/app-template/src/views/header/header-layout-context.tsx +143 -0
  159. package/app-template/src/views/header/header-layout-registrar.tsx +658 -0
  160. package/app-template/src/views/header/header-logo-context.tsx +228 -0
  161. package/app-template/src/views/header/header-logo.tsx +118 -0
  162. package/app-template/src/views/header/header-mini-basket-context.tsx +524 -0
  163. package/app-template/src/views/header/header-search-registrar.tsx +511 -0
  164. package/app-template/src/views/header/header-text-slider-registrar.tsx +382 -0
  165. package/app-template/src/views/header/index.tsx +109 -47
  166. package/app-template/src/views/header/inline-search.tsx +262 -0
  167. package/app-template/src/views/header/mini-basket.tsx +819 -44
  168. package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
  169. package/app-template/src/views/header/mobile-menu.tsx +12 -0
  170. package/app-template/src/views/header/navbar-menu-context.tsx +219 -0
  171. package/app-template/src/views/header/navbar.tsx +178 -111
  172. package/app-template/src/views/header/search/index.tsx +71 -32
  173. package/app-template/src/views/header/search/results.tsx +127 -65
  174. package/app-template/src/views/header/search/search-input.tsx +61 -0
  175. package/app-template/src/views/header/server-settings-parser.ts +1105 -0
  176. package/app-template/src/views/header/use-header-icons.ts +241 -0
  177. package/app-template/src/views/header/use-header-logo.ts +213 -0
  178. package/app-template/src/views/header/use-navbar-menu.ts +179 -0
  179. package/app-template/src/views/login/index.tsx +54 -46
  180. package/app-template/src/views/product/accordion-section.tsx +61 -0
  181. package/app-template/src/views/product/accordion-wrapper.tsx +135 -43
  182. package/app-template/src/views/product/custom-button-group.tsx +69 -0
  183. package/app-template/src/views/product/favorites-button-section.tsx +69 -0
  184. package/app-template/src/views/product/find-in-store-section.tsx +60 -0
  185. package/app-template/src/views/product/index.ts +1 -0
  186. package/app-template/src/views/product/layout.tsx +6 -5
  187. package/app-template/src/views/product/misc-buttons.tsx +339 -25
  188. package/app-template/src/views/product/price-wrapper.tsx +3 -29
  189. package/app-template/src/views/product/product-actions.tsx +137 -8
  190. package/app-template/src/views/product/product-info-section.tsx +140 -0
  191. package/app-template/src/views/product/product-info.tsx +69 -31
  192. package/app-template/src/views/product/product-share.tsx +13 -8
  193. package/app-template/src/views/product/product-variants.tsx +2 -2
  194. package/app-template/src/views/product/quantity-section.tsx +73 -0
  195. package/app-template/src/views/product/sale-tag.tsx +10 -0
  196. package/app-template/src/views/product/share-section.tsx +357 -0
  197. package/app-template/src/views/product/slider.tsx +117 -79
  198. package/app-template/src/views/product/variant.tsx +69 -41
  199. package/app-template/src/views/product/variants-section.tsx +126 -0
  200. package/app-template/src/views/product-detail/constants.ts +272 -0
  201. package/app-template/src/views/product-detail/index.ts +10 -0
  202. package/app-template/src/views/product-detail/product-detail-registrar.tsx +616 -0
  203. package/app-template/src/views/product-item/index.tsx +119 -46
  204. package/app-template/src/views/register/index.tsx +14 -25
  205. package/app-template/src/views/share/index.tsx +9 -6
  206. package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
  207. package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
  208. package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
  209. package/app-template/src/widgets/footer-app-banner.tsx +444 -0
  210. package/app-template/src/widgets/footer-bottom.tsx +127 -0
  211. package/app-template/src/widgets/footer-menu-compact.tsx +238 -0
  212. package/app-template/src/widgets/footer-menu-two.tsx +298 -0
  213. package/app-template/src/widgets/footer-social-client.tsx +251 -0
  214. package/app-template/src/widgets/footer-social.tsx +47 -16
  215. package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
  216. package/app-template/src/widgets/footer-subscription/index.tsx +183 -17
  217. package/app-template/src/widgets/footer-value-props.tsx +201 -0
  218. package/app-template/src/widgets/index.ts +7 -0
  219. package/app-template/src/widgets/schemas/about-us.json +46 -0
  220. package/app-template/src/widgets/schemas/blog-list.json +37 -0
  221. package/app-template/src/widgets/schemas/blog.json +29 -0
  222. package/app-template/tailwind.config.js +18 -2
  223. package/package.json +1 -1
@@ -16,6 +16,8 @@ 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';
19
21
 
20
22
  interface ListPageProps {
21
23
  data: GetCategoryResponse;
@@ -32,7 +34,7 @@ export default function ListPage(props: ListPageProps) {
32
34
  const router = useRouter();
33
35
 
34
36
  const layoutSize = useMemo(
35
- () => Number(searchParams.get('layout') ?? 3),
37
+ () => searchParams.get('layout') ?? '4',
36
38
  [searchParams]
37
39
  );
38
40
 
@@ -43,9 +45,9 @@ export default function ListPage(props: ListPageProps) {
43
45
 
44
46
  const itemDimensions = useMemo(() => {
45
47
  switch (layoutSize) {
46
- case 2:
48
+ case '2':
47
49
  return { width: 510, height: 765 };
48
- case 3:
50
+ case '3':
49
51
  default:
50
52
  return { width: 340, height: 510 };
51
53
  }
@@ -58,7 +60,7 @@ export default function ListPage(props: ListPageProps) {
58
60
  router.push(newUrl.pathname + newUrl.search, undefined);
59
61
  }
60
62
  // eslint-disable-next-line react-hooks/exhaustive-deps
61
- }, [searchParams, data.products, page]);
63
+ }, [searchParams, data?.products, page]);
62
64
 
63
65
  const { t } = useLocalization();
64
66
 
@@ -67,32 +69,109 @@ export default function ListPage(props: ListPageProps) {
67
69
  // eslint-disable-next-line react-hooks/exhaustive-deps
68
70
  }, [data.facets]);
69
71
 
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
+
70
136
  return (
71
137
  <>
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
- />
138
+ <div className="container px-4 mx-auto lg:px-0">
139
+ <div
140
+ className={clsx(
141
+ 'grid',
142
+ layout === 'sidebar' && 'lg:grid-cols-[280px_1fr] lg:gap-8'
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
+ )}
78
164
  <div
79
- onClick={() => dispatch(setMenuOpen(false))}
80
165
  className={clsx(
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'
166
+ 'flex flex-col items-center lg:items-stretch',
167
+ layout !== 'sidebar' && 'col-span-2 lg:col-span-1'
85
168
  )}
86
- ></div>
87
- <div className="flex flex-col items-center lg:items-stretch col-span-2 lg:col-span-1">
169
+ >
88
170
  <CategoryHeader
89
171
  totalCount={data.pagination?.total_count}
90
172
  setMenuStatus={() => dispatch(setMenuOpen(true))}
91
173
  sortOptions={data.sorters}
92
174
  />
93
- <div className="hidden lg:block">
94
- <CategoryActiveFilters />
95
- </div>
96
175
 
97
176
  {data.products?.length === 0 && page === 1 && (
98
177
  <div className="text-center bg-gray-200 px-5 py-20">
@@ -106,11 +185,25 @@ export default function ListPage(props: ListPageProps) {
106
185
  {data.products?.length === 0 && page > 1 && <LoaderSpinner />}
107
186
 
108
187
  <div
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
188
+ className={clsx('grid grid-cols-2 md:grid-cols-3', {
189
+ 'lg:grid-cols-2': layoutSize === '2',
190
+ 'lg:grid-cols-3': layoutSize === '3',
191
+ 'lg:grid-cols-4': layoutSize === '4',
192
+ 'lg:grid-cols-6': layoutSize === '6'
113
193
  })}
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"
114
207
  >
115
208
  {data?.products?.map((product, index) => (
116
209
  <ProductItem
@@ -128,6 +221,62 @@ export default function ListPage(props: ListPageProps) {
128
221
  limit={data.pagination.page_size}
129
222
  currentPage={data.pagination.current_page}
130
223
  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
+ }}
131
280
  />
132
281
  )}
133
282
  </div>
@@ -1,7 +1,14 @@
1
1
  import clsx from 'clsx';
2
2
  import { useAppDispatch } from '@akinon/next/redux/hooks';
3
3
  import { Facet, FacetChoice } from '@akinon/next/types';
4
- import { Accordion, Radio, Checkbox, LoaderSpinner } from '../../../components';
4
+ import {
5
+ Accordion,
6
+ Radio,
7
+ Checkbox,
8
+ LoaderSpinner,
9
+ Button,
10
+ Icon
11
+ } from '../../../components';
5
12
  import { WIDGET_TYPE } from '../../../types';
6
13
  import { SizeFilter } from './size-filter';
7
14
  import { toggleFacet } from '@theme/redux/reducers/category';
@@ -25,6 +32,16 @@ interface Props {
25
32
  startTransition: (callback: () => void) => void;
26
33
  }
27
34
 
35
+ interface FilterItemProps {
36
+ facet: any;
37
+ isPending: boolean;
38
+ startTransition: (callback: () => void) => void;
39
+ isDropdown?: boolean;
40
+ itemPaddingY?: number;
41
+ itemPaddingX?: number;
42
+ itemMarginBottom?: number;
43
+ }
44
+
28
45
  const sortByPredefinedOrder = (
29
46
  aLabel: string,
30
47
  bLabel: string,
@@ -82,12 +99,21 @@ const getComponentByWidgetType = (widgetType: string, facetKey: string) => {
82
99
  return COMPONENT_TYPES[widgetType] || COMPONENT_TYPES[WIDGET_TYPE.category];
83
100
  };
84
101
 
85
- export const FilterItem = ({ facet, isPending, startTransition }: Props) => {
102
+ export const FilterItem = ({
103
+ facet,
104
+ isPending,
105
+ startTransition,
106
+ isDropdown = false,
107
+ itemPaddingY = 6,
108
+ itemPaddingX = 0,
109
+ itemMarginBottom = 0
110
+ }: FilterItemProps) => {
86
111
  const dispatch = useAppDispatch();
87
112
  const router = useRouter();
88
113
  const pathname = usePathname();
89
114
 
90
115
  const [pendingChoice, setPendingChoice] = useState<string | null>(null);
116
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
91
117
 
92
118
  const handleSelectFilter = ({
93
119
  facet,
@@ -96,6 +122,7 @@ export const FilterItem = ({ facet, isPending, startTransition }: Props) => {
96
122
  facet: Facet;
97
123
  choice: FacetChoice;
98
124
  }) => {
125
+ setIsDrawerOpen(false);
99
126
  setPendingChoice(choice.label);
100
127
  startTransition(() => {
101
128
  if (facet.key === 'category_ids') {
@@ -114,50 +141,119 @@ export const FilterItem = ({ facet, isPending, startTransition }: Props) => {
114
141
  const Component = getComponentByWidgetType(facet.widget_type, facet.key);
115
142
  const choices = sortChoices(facet?.key, [...(facet?.data?.choices || [])]);
116
143
 
117
- return (
118
- <Accordion
119
- key={facet.key}
120
- title={facet.name}
121
- isCollapse={choices.some((choice) => choice.is_selected)}
122
- dataTestId={`filter-${facet.name}`}
123
- >
124
- <div
125
- className={clsx('flex gap-4', {
126
- 'flex-wrap flex-row': facet.key === sizeKey,
127
- 'flex-col': facet.key !== sizeKey
128
- })}
144
+ const choiceItemStyles = {
145
+ paddingTop: `${itemPaddingY}px`,
146
+ paddingBottom: `${itemPaddingY}px`,
147
+ paddingLeft: `${itemPaddingX}px`,
148
+ paddingRight: `${itemPaddingX}px`,
149
+ marginBottom: `${itemMarginBottom}px`
150
+ };
151
+
152
+ const renderChoice = (choice: FacetChoice, index: number) => (
153
+ <div key={choice.label} className="relative" style={choiceItemStyles}>
154
+ <Component
155
+ data={choice}
156
+ name={facet.key}
157
+ onChange={() => handleSelectFilter({ facet, choice })}
158
+ onClick={() =>
159
+ facet.key === sizeKey && handleSelectFilter({ facet, choice })
160
+ }
161
+ checked={choice.is_selected}
162
+ data-testid={`${choice.label.trim()}`}
163
+ disabled={isPending}
129
164
  >
130
- {choices.map((choice, index) => (
131
- <div key={choice.label} className="relative">
132
- <Component
133
- key={choice.label}
134
- data={choice}
135
- name={facet.key}
136
- onChange={() => handleSelectFilter({ facet, choice })}
137
- onClick={() =>
138
- facet.key === sizeKey && handleSelectFilter({ facet, choice })
139
- }
140
- checked={choice.is_selected}
141
- data-testid={`${choice.label.trim()}`}
142
- disabled={isPending}
165
+ {choice.label} (
166
+ <span data-testid={`filter-count-${facet.name.toLowerCase()}-${index}`}>
167
+ {choice.quantity}
168
+ </span>
169
+ )
170
+ </Component>
171
+
172
+ {isPending && pendingChoice === choice.label && (
173
+ <div className="absolute inset-0 flex items-center justify-center z-50">
174
+ <LoaderSpinner />
175
+ </div>
176
+ )}
177
+ </div>
178
+ );
179
+
180
+ const renderChoices = (className: string) => (
181
+ <div className={className}>
182
+ {choices.map((choice, index) => renderChoice(choice, index))}
183
+ </div>
184
+ );
185
+
186
+ const containerStyles = {
187
+ paddingTop: `${itemPaddingY}px`,
188
+ paddingBottom: `${itemPaddingY}px`,
189
+ paddingLeft: `${itemPaddingX}px`,
190
+ paddingRight: `${itemPaddingX}px`,
191
+ marginBottom: `${itemMarginBottom}px`
192
+ };
193
+
194
+ return (
195
+ <div style={containerStyles}>
196
+ {isDropdown ? (
197
+ renderChoices(
198
+ clsx({
199
+ 'flex flex-wrap gap-4': facet.key === sizeKey,
200
+ 'space-y-2': facet.key !== sizeKey
201
+ })
202
+ )
203
+ ) : (
204
+ <>
205
+ <div className="block lg:hidden">
206
+ <Button
207
+ className="w-full flex justify-between items-center text-base hover:bg-transparent hover:text-black-750 p-0"
208
+ appearance="ghost"
209
+ onClick={() => setIsDrawerOpen(true)}
143
210
  >
144
- {choice.label} (
145
- <span
146
- data-testid={`filter-count-${facet.name.toLowerCase()}-${index}`}
147
- >
148
- {choice.quantity}
149
- </span>
150
- )
151
- </Component>
152
-
153
- {isPending && pendingChoice === choice.label && (
154
- <div className="absolute inset-0 flex items-center justify-center z-50">
155
- <LoaderSpinner />
211
+ <span>{facet.name}</span>
212
+ <Icon name="arrow-right" size={20} />
213
+ </Button>
214
+
215
+ {isDrawerOpen && (
216
+ <div className="absolute w-full top-16 inset-x-0 bottom-0 z-50 bg-white">
217
+ <div className="flex items-center text-black-750 text-sm">
218
+ <Button
219
+ type="button"
220
+ className="text-sm hover:bg-transparent hover:text-black-750"
221
+ appearance="ghost"
222
+ onClick={() => setIsDrawerOpen(false)}
223
+ >
224
+ <Icon name="arrow-left" size={16} />
225
+ </Button>
226
+ <span className="text-sm">{facet.name}</span>
227
+ </div>
228
+ <div className="p-4 overflow-y-auto h-full">
229
+ {renderChoices(
230
+ clsx('flex gap-4', {
231
+ 'flex-wrap flex-row': facet.key === sizeKey,
232
+ 'flex-col': facet.key !== sizeKey
233
+ })
234
+ )}
235
+ </div>
156
236
  </div>
157
237
  )}
158
238
  </div>
159
- ))}
160
- </div>
161
- </Accordion>
239
+
240
+ <div className="hidden lg:block">
241
+ <Accordion
242
+ key={facet.key}
243
+ title={facet.name}
244
+ isCollapse={choices.some((choice) => choice.is_selected)}
245
+ dataTestId={`filter-${facet.name}`}
246
+ >
247
+ {renderChoices(
248
+ clsx('flex gap-4', {
249
+ 'flex-wrap flex-row': facet.key === sizeKey,
250
+ 'flex-col': facet.key !== sizeKey
251
+ })
252
+ )}
253
+ </Accordion>
254
+ </div>
255
+ </>
256
+ )}
257
+ </div>
162
258
  );
163
259
  };