@vendure-platform/create 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +39 -39
  3. package/dist/add-to-existing.js +1 -1
  4. package/dist/assets/demo-data/initial-data.json +663 -663
  5. package/dist/assets/storefront/components.json +20 -20
  6. package/dist/assets/storefront/eslint.config.mjs +10 -10
  7. package/dist/assets/storefront/graphql.config.yml +1 -1
  8. package/dist/assets/storefront/next.config.ts +5 -4
  9. package/dist/assets/storefront/package.json +1 -1
  10. package/dist/assets/storefront/postcss.config.mjs +1 -1
  11. package/dist/assets/storefront/src/app/[locale]/(catalog)/catalog/page.tsx +17 -21
  12. package/dist/assets/storefront/src/app/[locale]/(catalog)/collection/[slug]/page.tsx +64 -42
  13. package/dist/assets/storefront/src/app/[locale]/(catalog)/layout.tsx +1 -5
  14. package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/actions.ts +69 -65
  15. package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/page.tsx +64 -38
  16. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/page.tsx +24 -27
  17. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/search-results.tsx +11 -9
  18. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/search-term.tsx +4 -4
  19. package/dist/assets/storefront/src/app/[locale]/(scenario)/[...path]/page.tsx +1 -1
  20. package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/accept-invitation-client.tsx +8 -13
  21. package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/actions.ts +11 -14
  22. package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/page.tsx +30 -33
  23. package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/sign-out-and-retry.tsx +6 -6
  24. package/dist/assets/storefront/src/app/[locale]/account/addresses/actions.ts +30 -45
  25. package/dist/assets/storefront/src/app/[locale]/account/addresses/address-form.tsx +166 -159
  26. package/dist/assets/storefront/src/app/[locale]/account/addresses/addresses-client.tsx +35 -26
  27. package/dist/assets/storefront/src/app/[locale]/account/addresses/loading.tsx +1 -3
  28. package/dist/assets/storefront/src/app/[locale]/account/addresses/page.tsx +16 -18
  29. package/dist/assets/storefront/src/app/[locale]/account/approvals/actions.ts +5 -8
  30. package/dist/assets/storefront/src/app/[locale]/account/approvals/page.tsx +77 -69
  31. package/dist/assets/storefront/src/app/[locale]/account/company/actions.ts +10 -11
  32. package/dist/assets/storefront/src/app/[locale]/account/company/addresses/actions.ts +6 -15
  33. package/dist/assets/storefront/src/app/[locale]/account/company/addresses/address-form.tsx +57 -49
  34. package/dist/assets/storefront/src/app/[locale]/account/company/addresses/addresses-client.tsx +23 -25
  35. package/dist/assets/storefront/src/app/[locale]/account/company/addresses/page.tsx +30 -30
  36. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/actions.ts +20 -29
  37. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/business-unit-form.tsx +32 -37
  38. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/business-units-client.tsx +32 -25
  39. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/page.tsx +24 -24
  40. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/types.ts +7 -4
  41. package/dist/assets/storefront/src/app/[locale]/account/company/edit-company-form.tsx +11 -21
  42. package/dist/assets/storefront/src/app/[locale]/account/company/page.tsx +23 -28
  43. package/dist/assets/storefront/src/app/[locale]/account/company/payment-methods/page.tsx +24 -24
  44. package/dist/assets/storefront/src/app/[locale]/account/company/payment-methods/payment-methods-client.tsx +5 -7
  45. package/dist/assets/storefront/src/app/[locale]/account/company/roles/page.tsx +22 -25
  46. package/dist/assets/storefront/src/app/[locale]/account/company/roles/roles-client.tsx +11 -26
  47. package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/actions.ts +6 -10
  48. package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/page.tsx +18 -16
  49. package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/tax-ids-client.tsx +74 -67
  50. package/dist/assets/storefront/src/app/[locale]/account/company/users/actions.ts +16 -25
  51. package/dist/assets/storefront/src/app/[locale]/account/company/users/edit-user-form.tsx +27 -25
  52. package/dist/assets/storefront/src/app/[locale]/account/company/users/invite-user-form.tsx +27 -19
  53. package/dist/assets/storefront/src/app/[locale]/account/company/users/page.tsx +32 -29
  54. package/dist/assets/storefront/src/app/[locale]/account/company/users/users-client.tsx +35 -38
  55. package/dist/assets/storefront/src/app/[locale]/account/error.tsx +1 -3
  56. package/dist/assets/storefront/src/app/[locale]/account/layout.tsx +16 -22
  57. package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/page.tsx +151 -103
  58. package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/reorder-actions.ts +6 -7
  59. package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/reorder-dialog.tsx +22 -48
  60. package/dist/assets/storefront/src/app/[locale]/account/orders/loading.tsx +8 -8
  61. package/dist/assets/storefront/src/app/[locale]/account/orders/page.tsx +101 -61
  62. package/dist/assets/storefront/src/app/[locale]/account/profile/actions.ts +32 -23
  63. package/dist/assets/storefront/src/app/[locale]/account/profile/change-password-form.tsx +6 -16
  64. package/dist/assets/storefront/src/app/[locale]/account/profile/edit-email-form.tsx +7 -17
  65. package/dist/assets/storefront/src/app/[locale]/account/profile/edit-profile-form.tsx +6 -16
  66. package/dist/assets/storefront/src/app/[locale]/account/profile/loading.tsx +12 -18
  67. package/dist/assets/storefront/src/app/[locale]/account/profile/page.tsx +15 -15
  68. package/dist/assets/storefront/src/app/[locale]/account/quick-order/file-upload-tab.tsx +2 -6
  69. package/dist/assets/storefront/src/app/[locale]/account/quick-order/manual-entry-tab.tsx +18 -15
  70. package/dist/assets/storefront/src/app/[locale]/account/quick-order/page.tsx +3 -6
  71. package/dist/assets/storefront/src/app/[locale]/account/quick-order/preview-table.tsx +10 -2
  72. package/dist/assets/storefront/src/app/[locale]/account/quick-order/save-to-list-dialog.tsx +24 -26
  73. package/dist/assets/storefront/src/app/[locale]/account/quick-order/sku-autocomplete.tsx +19 -10
  74. package/dist/assets/storefront/src/app/[locale]/account/quick-order/text-input-tab.tsx +3 -8
  75. package/dist/assets/storefront/src/app/[locale]/account/quotes/[id]/page.tsx +86 -59
  76. package/dist/assets/storefront/src/app/[locale]/account/quotes/actions.ts +38 -45
  77. package/dist/assets/storefront/src/app/[locale]/account/quotes/new/new-quote-form.tsx +3 -5
  78. package/dist/assets/storefront/src/app/[locale]/account/quotes/new/page.tsx +6 -6
  79. package/dist/assets/storefront/src/app/[locale]/account/quotes/page.tsx +92 -59
  80. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/add-item-search.tsx +11 -9
  81. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/add-member-form.tsx +31 -15
  82. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/members-panel.tsx +52 -33
  83. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/page.tsx +22 -14
  84. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/rename-dialog.tsx +34 -13
  85. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/actions.ts +117 -72
  86. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/new/new-shared-cart-form.tsx +21 -14
  87. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/new/page.tsx +10 -10
  88. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/page.tsx +54 -41
  89. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/[id]/page.tsx +22 -8
  90. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/[id]/shopping-list-detail-client.tsx +62 -49
  91. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/actions.ts +9 -4
  92. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/create-shopping-list-form.tsx +5 -11
  93. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/loading.tsx +1 -1
  94. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/page.tsx +32 -42
  95. package/dist/assets/storefront/src/app/[locale]/account/store-credits/actions.ts +8 -8
  96. package/dist/assets/storefront/src/app/[locale]/account/store-credits/claim-form.tsx +6 -10
  97. package/dist/assets/storefront/src/app/[locale]/account/store-credits/page.tsx +76 -55
  98. package/dist/assets/storefront/src/app/[locale]/account/store-credits/reveal-code.tsx +10 -6
  99. package/dist/assets/storefront/src/app/[locale]/account/verify-email/page.tsx +32 -39
  100. package/dist/assets/storefront/src/app/[locale]/cart/actions.ts +29 -23
  101. package/dist/assets/storefront/src/app/[locale]/cart/cart-items.tsx +111 -40
  102. package/dist/assets/storefront/src/app/[locale]/cart/cart-line-actions.tsx +9 -9
  103. package/dist/assets/storefront/src/app/[locale]/cart/cart-quantity-control.tsx +61 -48
  104. package/dist/assets/storefront/src/app/[locale]/cart/cart-remove-button.tsx +15 -9
  105. package/dist/assets/storefront/src/app/[locale]/cart/cart.tsx +38 -41
  106. package/dist/assets/storefront/src/app/[locale]/cart/code-input.tsx +8 -8
  107. package/dist/assets/storefront/src/app/[locale]/cart/order-summary.tsx +50 -32
  108. package/dist/assets/storefront/src/app/[locale]/cart/page.tsx +11 -11
  109. package/dist/assets/storefront/src/app/[locale]/cart/promotion-code.tsx +48 -42
  110. package/dist/assets/storefront/src/app/[locale]/cart/reapproval-confirm.tsx +22 -20
  111. package/dist/assets/storefront/src/app/[locale]/cart/request-quote-button.tsx +7 -16
  112. package/dist/assets/storefront/src/app/[locale]/checkout/actions.ts +39 -65
  113. package/dist/assets/storefront/src/app/[locale]/checkout/cancel-quote-checkout-button.tsx +5 -5
  114. package/dist/assets/storefront/src/app/[locale]/checkout/checkout-flow.tsx +202 -202
  115. package/dist/assets/storefront/src/app/[locale]/checkout/checkout-provider.tsx +142 -142
  116. package/dist/assets/storefront/src/app/[locale]/checkout/order-summary.tsx +158 -139
  117. package/dist/assets/storefront/src/app/[locale]/checkout/page.tsx +56 -47
  118. package/dist/assets/storefront/src/app/[locale]/checkout/steps/delivery-step.tsx +86 -88
  119. package/dist/assets/storefront/src/app/[locale]/checkout/steps/payment-step.tsx +90 -91
  120. package/dist/assets/storefront/src/app/[locale]/checkout/steps/review-step.tsx +166 -161
  121. package/dist/assets/storefront/src/app/[locale]/checkout/steps/shipping-address-step.tsx +573 -494
  122. package/dist/assets/storefront/src/app/[locale]/error.tsx +3 -5
  123. package/dist/assets/storefront/src/app/[locale]/forgot-password/actions.ts +10 -7
  124. package/dist/assets/storefront/src/app/[locale]/forgot-password/forgot-password-form.tsx +10 -25
  125. package/dist/assets/storefront/src/app/[locale]/forgot-password/page.tsx +5 -5
  126. package/dist/assets/storefront/src/app/[locale]/globals.css +48 -48
  127. package/dist/assets/storefront/src/app/[locale]/layout.tsx +53 -47
  128. package/dist/assets/storefront/src/app/[locale]/not-found.tsx +3 -5
  129. package/dist/assets/storefront/src/app/[locale]/order-confirmation/[code]/order-confirmation.tsx +71 -44
  130. package/dist/assets/storefront/src/app/[locale]/order-confirmation/[code]/page.tsx +7 -5
  131. package/dist/assets/storefront/src/app/[locale]/page.tsx +33 -35
  132. package/dist/assets/storefront/src/app/[locale]/register/actions.ts +7 -7
  133. package/dist/assets/storefront/src/app/[locale]/register/page.tsx +22 -16
  134. package/dist/assets/storefront/src/app/[locale]/register/registration-form.tsx +22 -34
  135. package/dist/assets/storefront/src/app/[locale]/register-company/actions.ts +15 -19
  136. package/dist/assets/storefront/src/app/[locale]/register-company/page.tsx +17 -15
  137. package/dist/assets/storefront/src/app/[locale]/register-company/registration-form.tsx +9 -15
  138. package/dist/assets/storefront/src/app/[locale]/reset-password/actions.ts +7 -8
  139. package/dist/assets/storefront/src/app/[locale]/reset-password/page.tsx +18 -12
  140. package/dist/assets/storefront/src/app/[locale]/reset-password/reset-password-form.tsx +8 -16
  141. package/dist/assets/storefront/src/app/[locale]/shopping-list/[code]/add-to-cart-button.tsx +10 -4
  142. package/dist/assets/storefront/src/app/[locale]/shopping-list/[code]/page.tsx +62 -30
  143. package/dist/assets/storefront/src/app/[locale]/sign-in/actions.ts +14 -16
  144. package/dist/assets/storefront/src/app/[locale]/sign-in/login-form.tsx +17 -30
  145. package/dist/assets/storefront/src/app/[locale]/sign-in/page.tsx +35 -30
  146. package/dist/assets/storefront/src/app/[locale]/verify/actions.ts +8 -8
  147. package/dist/assets/storefront/src/app/[locale]/verify/page.tsx +18 -14
  148. package/dist/assets/storefront/src/app/[locale]/verify/verify-content.tsx +25 -27
  149. package/dist/assets/storefront/src/app/[locale]/verify-pending/page.tsx +23 -23
  150. package/dist/assets/storefront/src/app/api/clear-company-context/route.ts +6 -3
  151. package/dist/assets/storefront/src/app/api/revalidate/route.ts +19 -28
  152. package/dist/assets/storefront/src/app/api/search-analytics/route.ts +1 -1
  153. package/dist/assets/storefront/src/components/commerce/account-nav-items.ts +43 -18
  154. package/dist/assets/storefront/src/components/commerce/account-sidebar.tsx +30 -22
  155. package/dist/assets/storefront/src/components/commerce/active-filters.tsx +1 -1
  156. package/dist/assets/storefront/src/components/commerce/add-to-shared-cart.tsx +49 -27
  157. package/dist/assets/storefront/src/components/commerce/approval-decision-form.tsx +9 -13
  158. package/dist/assets/storefront/src/components/commerce/approval-status-badge.tsx +23 -15
  159. package/dist/assets/storefront/src/components/commerce/business-unit-switcher.tsx +11 -11
  160. package/dist/assets/storefront/src/components/commerce/catalog-search-bar.tsx +2 -2
  161. package/dist/assets/storefront/src/components/commerce/category-product-section.tsx +28 -16
  162. package/dist/assets/storefront/src/components/commerce/category-sidebar.tsx +31 -18
  163. package/dist/assets/storefront/src/components/commerce/collection-hero-banner.tsx +2 -4
  164. package/dist/assets/storefront/src/components/commerce/company-state-badge.tsx +10 -16
  165. package/dist/assets/storefront/src/components/commerce/company-switcher.tsx +12 -12
  166. package/dist/assets/storefront/src/components/commerce/configurator-form.tsx +188 -79
  167. package/dist/assets/storefront/src/components/commerce/facet-filters.tsx +29 -49
  168. package/dist/assets/storefront/src/components/commerce/gift-card-pdp.tsx +4 -4
  169. package/dist/assets/storefront/src/components/commerce/gift-card-product-info.tsx +20 -30
  170. package/dist/assets/storefront/src/components/commerce/instant-search-dropdown.tsx +258 -227
  171. package/dist/assets/storefront/src/components/commerce/order-status-badge.tsx +27 -19
  172. package/dist/assets/storefront/src/components/commerce/packaging-unit-selector.tsx +27 -26
  173. package/dist/assets/storefront/src/components/commerce/permission-gate.tsx +4 -4
  174. package/dist/assets/storefront/src/components/commerce/price-range-filter.tsx +5 -5
  175. package/dist/assets/storefront/src/components/commerce/price-tiers.tsx +38 -21
  176. package/dist/assets/storefront/src/components/commerce/price.tsx +3 -3
  177. package/dist/assets/storefront/src/components/commerce/product-card-list.tsx +35 -14
  178. package/dist/assets/storefront/src/components/commerce/product-card.tsx +31 -16
  179. package/dist/assets/storefront/src/components/commerce/product-carousel.tsx +20 -12
  180. package/dist/assets/storefront/src/components/commerce/product-grid.tsx +14 -13
  181. package/dist/assets/storefront/src/components/commerce/product-image-carousel.tsx +10 -8
  182. package/dist/assets/storefront/src/components/commerce/product-info.tsx +118 -74
  183. package/dist/assets/storefront/src/components/commerce/product-list-expansion.tsx +102 -74
  184. package/dist/assets/storefront/src/components/commerce/product-list-view.tsx +1 -1
  185. package/dist/assets/storefront/src/components/commerce/product-sidebar.tsx +36 -11
  186. package/dist/assets/storefront/src/components/commerce/product-view-switcher.tsx +33 -21
  187. package/dist/assets/storefront/src/components/commerce/quote-action-buttons.tsx +54 -36
  188. package/dist/assets/storefront/src/components/commerce/quote-activity-timeline.tsx +126 -50
  189. package/dist/assets/storefront/src/components/commerce/quote-comment-form.tsx +9 -13
  190. package/dist/assets/storefront/src/components/commerce/quote-csv-export-button.tsx +6 -6
  191. package/dist/assets/storefront/src/components/commerce/quote-product-search.tsx +22 -18
  192. package/dist/assets/storefront/src/components/commerce/quote-request-form.tsx +28 -27
  193. package/dist/assets/storefront/src/components/commerce/quote-status-badge.tsx +26 -18
  194. package/dist/assets/storefront/src/components/commerce/quote-validity-indicator.tsx +7 -7
  195. package/dist/assets/storefront/src/components/commerce/quote-version-comparison.tsx +50 -30
  196. package/dist/assets/storefront/src/components/commerce/related-products.tsx +37 -28
  197. package/dist/assets/storefront/src/components/commerce/shared-cart-status-badge.tsx +12 -8
  198. package/dist/assets/storefront/src/components/commerce/shop-by-category.tsx +8 -7
  199. package/dist/assets/storefront/src/components/commerce/shopping-list-toggle.tsx +14 -20
  200. package/dist/assets/storefront/src/components/commerce/sort-dropdown.tsx +9 -16
  201. package/dist/assets/storefront/src/components/commerce/store-credit-summary.tsx +30 -32
  202. package/dist/assets/storefront/src/components/commerce/subcollection-tiles.tsx +11 -13
  203. package/dist/assets/storefront/src/components/layout/auth-page-shell.tsx +2 -2
  204. package/dist/assets/storefront/src/components/layout/draft-mode-indicator.tsx +2 -7
  205. package/dist/assets/storefront/src/components/layout/draft-mode-link.tsx +4 -2
  206. package/dist/assets/storefront/src/components/layout/footer.tsx +70 -28
  207. package/dist/assets/storefront/src/components/layout/navbar/actions.ts +9 -12
  208. package/dist/assets/storefront/src/components/layout/navbar/cart-icon.tsx +9 -9
  209. package/dist/assets/storefront/src/components/layout/navbar/channel-picker-wrapper.tsx +4 -9
  210. package/dist/assets/storefront/src/components/layout/navbar/channel-picker.tsx +13 -8
  211. package/dist/assets/storefront/src/components/layout/navbar/currency-picker-wrapper.tsx +4 -4
  212. package/dist/assets/storefront/src/components/layout/navbar/currency-picker.tsx +11 -6
  213. package/dist/assets/storefront/src/components/layout/navbar/language-picker.tsx +7 -7
  214. package/dist/assets/storefront/src/components/layout/navbar/login-button.tsx +24 -21
  215. package/dist/assets/storefront/src/components/layout/navbar/mobile-nav.tsx +8 -8
  216. package/dist/assets/storefront/src/components/layout/navbar/nav-menu-items.tsx +4 -6
  217. package/dist/assets/storefront/src/components/layout/navbar/navbar-cart.tsx +1 -1
  218. package/dist/assets/storefront/src/components/layout/navbar/navbar-collections.tsx +41 -42
  219. package/dist/assets/storefront/src/components/layout/navbar/navbar-link.tsx +7 -10
  220. package/dist/assets/storefront/src/components/layout/navbar/navbar-user.tsx +18 -23
  221. package/dist/assets/storefront/src/components/layout/navbar/theme-switcher.tsx +9 -9
  222. package/dist/assets/storefront/src/components/layout/navbar.tsx +36 -31
  223. package/dist/assets/storefront/src/components/layout/search-input.tsx +35 -32
  224. package/dist/assets/storefront/src/components/providers/awaiting-approval-banner.tsx +12 -10
  225. package/dist/assets/storefront/src/components/providers/cart-count-server.tsx +14 -12
  226. package/dist/assets/storefront/src/components/providers/company-context-guard.tsx +4 -4
  227. package/dist/assets/storefront/src/components/providers/company-permissions-server.tsx +2 -6
  228. package/dist/assets/storefront/src/components/providers/theme-provider.tsx +3 -3
  229. package/dist/assets/storefront/src/components/shared/breadcrumbs.tsx +4 -1
  230. package/dist/assets/storefront/src/components/shared/country-select.tsx +63 -67
  231. package/dist/assets/storefront/src/components/shared/pagination.tsx +15 -28
  232. package/dist/assets/storefront/src/components/shared/prefetch-link.tsx +1 -1
  233. package/dist/assets/storefront/src/components/shared/skeletons/search-input-skeleton.tsx +1 -3
  234. package/dist/assets/storefront/src/components/ui/accordion.tsx +46 -51
  235. package/dist/assets/storefront/src/components/ui/alert-dialog.tsx +94 -121
  236. package/dist/assets/storefront/src/components/ui/alert.tsx +48 -54
  237. package/dist/assets/storefront/src/components/ui/aspect-ratio.tsx +5 -7
  238. package/dist/assets/storefront/src/components/ui/avatar.tsx +29 -44
  239. package/dist/assets/storefront/src/components/ui/badge.tsx +28 -37
  240. package/dist/assets/storefront/src/components/ui/breadcrumb.tsx +82 -89
  241. package/dist/assets/storefront/src/components/ui/button.tsx +43 -49
  242. package/dist/assets/storefront/src/components/ui/calendar.tsx +157 -198
  243. package/dist/assets/storefront/src/components/ui/card.tsx +53 -76
  244. package/dist/assets/storefront/src/components/ui/carousel.tsx +194 -212
  245. package/dist/assets/storefront/src/components/ui/chart.tsx +274 -317
  246. package/dist/assets/storefront/src/components/ui/checkbox.tsx +24 -27
  247. package/dist/assets/storefront/src/components/ui/collapsible.tsx +9 -21
  248. package/dist/assets/storefront/src/components/ui/command.tsx +114 -159
  249. package/dist/assets/storefront/src/components/ui/context-menu.tsx +167 -199
  250. package/dist/assets/storefront/src/components/ui/dialog.tsx +97 -114
  251. package/dist/assets/storefront/src/components/ui/drawer.tsx +93 -107
  252. package/dist/assets/storefront/src/components/ui/dropdown-menu.tsx +171 -206
  253. package/dist/assets/storefront/src/components/ui/empty-state.tsx +5 -5
  254. package/dist/assets/storefront/src/components/ui/field.tsx +196 -208
  255. package/dist/assets/storefront/src/components/ui/form.tsx +115 -139
  256. package/dist/assets/storefront/src/components/ui/hover-card.tsx +27 -33
  257. package/dist/assets/storefront/src/components/ui/input-otp.tsx +50 -59
  258. package/dist/assets/storefront/src/components/ui/input.tsx +17 -17
  259. package/dist/assets/storefront/src/components/ui/kbd-shortcut.tsx +3 -1
  260. package/dist/assets/storefront/src/components/ui/label.tsx +16 -19
  261. package/dist/assets/storefront/src/components/ui/menubar.tsx +193 -223
  262. package/dist/assets/storefront/src/components/ui/navigation-menu.tsx +123 -130
  263. package/dist/assets/storefront/src/components/ui/pagination.tsx +87 -108
  264. package/dist/assets/storefront/src/components/ui/popover.tsx +29 -35
  265. package/dist/assets/storefront/src/components/ui/progress.tsx +19 -26
  266. package/dist/assets/storefront/src/components/ui/radio-group.tsx +32 -38
  267. package/dist/assets/storefront/src/components/ui/resizable.tsx +37 -42
  268. package/dist/assets/storefront/src/components/ui/scroll-area.tsx +41 -47
  269. package/dist/assets/storefront/src/components/ui/select.tsx +130 -152
  270. package/dist/assets/storefront/src/components/ui/separator.tsx +21 -21
  271. package/dist/assets/storefront/src/components/ui/sheet.tsx +90 -111
  272. package/dist/assets/storefront/src/components/ui/sidebar.tsx +611 -649
  273. package/dist/assets/storefront/src/components/ui/skeleton.tsx +10 -10
  274. package/dist/assets/storefront/src/components/ui/slider.tsx +50 -55
  275. package/dist/assets/storefront/src/components/ui/sonner.tsx +20 -20
  276. package/dist/assets/storefront/src/components/ui/switch.tsx +23 -26
  277. package/dist/assets/storefront/src/components/ui/table.tsx +65 -97
  278. package/dist/assets/storefront/src/components/ui/tabs.tsx +39 -55
  279. package/dist/assets/storefront/src/components/ui/textarea.tsx +14 -14
  280. package/dist/assets/storefront/src/components/ui/toggle-group.tsx +56 -62
  281. package/dist/assets/storefront/src/components/ui/toggle.tsx +37 -38
  282. package/dist/assets/storefront/src/components/ui/tooltip.tsx +38 -46
  283. package/dist/assets/storefront/src/config/scenario-meta.ts +2 -2
  284. package/dist/assets/storefront/src/config/scenario.ts +14 -16
  285. package/dist/assets/storefront/src/contexts/auth-context.tsx +5 -6
  286. package/dist/assets/storefront/src/graphql.ts +5 -5
  287. package/dist/assets/storefront/src/hooks/use-mobile.ts +13 -13
  288. package/dist/assets/storefront/src/i18n/locale-utils.ts +3 -3
  289. package/dist/assets/storefront/src/i18n/navigation.ts +4 -4
  290. package/dist/assets/storefront/src/i18n/request.ts +4 -4
  291. package/dist/assets/storefront/src/i18n/routing.ts +5 -5
  292. package/dist/assets/storefront/src/i18n/server.ts +3 -3
  293. package/dist/assets/storefront/src/lib/actions/switch-channel.ts +9 -9
  294. package/dist/assets/storefront/src/lib/actions/switch-currency.ts +7 -7
  295. package/dist/assets/storefront/src/lib/auth.ts +1 -1
  296. package/dist/assets/storefront/src/lib/backend-health.ts +3 -3
  297. package/dist/assets/storefront/src/lib/cart-count-context.tsx +10 -4
  298. package/dist/assets/storefront/src/lib/cart-guard-utils.ts +2 -1
  299. package/dist/assets/storefront/src/lib/cart-guard.ts +7 -6
  300. package/dist/assets/storefront/src/lib/channel-server.ts +4 -4
  301. package/dist/assets/storefront/src/lib/company-context.ts +1 -1
  302. package/dist/assets/storefront/src/lib/company-permissions-context.tsx +1 -5
  303. package/dist/assets/storefront/src/lib/currency-server.ts +4 -4
  304. package/dist/assets/storefront/src/lib/format.ts +16 -7
  305. package/dist/assets/storefront/src/lib/metadata.ts +39 -44
  306. package/dist/assets/storefront/src/lib/quantity.ts +2 -4
  307. package/dist/assets/storefront/src/lib/search-bar-context.tsx +7 -4
  308. package/dist/assets/storefront/src/lib/use-recent-searches.ts +8 -6
  309. package/dist/assets/storefront/src/lib/utils.ts +3 -3
  310. package/dist/assets/storefront/src/lib/vendure/actions.ts +18 -16
  311. package/dist/assets/storefront/src/lib/vendure/api.ts +36 -23
  312. package/dist/assets/storefront/src/lib/vendure/approval-utils.ts +9 -8
  313. package/dist/assets/storefront/src/lib/vendure/cached.ts +20 -15
  314. package/dist/assets/storefront/src/lib/vendure/queries.ts +15 -5
  315. package/dist/assets/storefront/src/middleware.ts +1 -1
  316. package/dist/assets/storefront/src/scenarios/customer/hero.tsx +2 -2
  317. package/dist/assets/storefront/src/scenarios/customer/meta.ts +1 -1
  318. package/dist/bin/run.js +1 -1
  319. package/dist/cli.d.ts +1 -1
  320. package/dist/index.d.ts +5 -5
  321. package/dist/index.js +1 -1
  322. package/dist/scaffold-storefront-only.js +1 -1
  323. package/dist/scaffolder.js +1 -1
  324. package/dist/template-renderer.js +1 -1
  325. package/package.json +2 -2
@@ -1,20 +1,20 @@
1
1
  'use client';
2
2
 
3
- import { useState, useEffect, useMemo, useTransition } from 'react';
4
- import Image from 'next/image';
5
- import {Link} from '@/i18n/navigation';
6
- import { Warehouse, Minus, Plus, ShoppingCart, CheckCircle2, ArrowRight } from 'lucide-react';
7
- import { useTranslations } from 'next-intl';
8
- import { Button } from '@/components/ui/button';
9
- import { Input } from '@/components/ui/input';
10
- import { Skeleton } from '@/components/ui/skeleton';
3
+ import { addToCart, getProductBySlug } from '@/app/[locale]/(catalog)/product/[slug]/actions';
11
4
  import { Price } from '@/components/commerce/price';
12
5
  import type { PriceTier } from '@/components/commerce/price-tiers';
6
+ import { Button } from '@/components/ui/button';
7
+ import { Input } from '@/components/ui/input';
13
8
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
14
- import { getProductBySlug, addToCart } from '@/app/[locale]/(catalog)/product/[slug]/actions';
9
+ import { Skeleton } from '@/components/ui/skeleton';
10
+ import { Link } from '@/i18n/navigation';
11
+ import { useCartCount } from '@/lib/cart-count-context';
15
12
  import { MIN_ORDER_QUANTITY, normalizeQuantity, sanitizeQuantityInput } from '@/lib/quantity';
13
+ import { ArrowRight, CheckCircle2, Minus, Plus, ShoppingCart, Warehouse } from 'lucide-react';
14
+ import { useTranslations } from 'next-intl';
15
+ import Image from 'next/image';
16
+ import { useEffect, useMemo, useState, useTransition } from 'react';
16
17
  import { toast } from 'sonner';
17
- import { useCartCount } from '@/lib/cart-count-context';
18
18
 
19
19
  interface ProductListExpansionProps {
20
20
  slug: string;
@@ -42,14 +42,19 @@ function getStockDisplay(stockLevel: string, t: ReturnType<typeof useTranslation
42
42
  const numeric = Number(stockLevel);
43
43
  if (!isNaN(numeric) && stockLevel.trim() !== '') {
44
44
  if (numeric <= 0) return { text: t('outOfStock'), className: 'text-red-600' };
45
- if (numeric < 10) return { text: t('availableCount', {count: numeric}), className: 'text-amber-600' };
46
- return { text: t('availableCount', {count: numeric}), className: 'text-emerald-600' };
45
+ if (numeric < 10)
46
+ return { text: t('availableCount', { count: numeric }), className: 'text-amber-600' };
47
+ return { text: t('availableCount', { count: numeric }), className: 'text-emerald-600' };
47
48
  }
48
49
  switch (stockLevel) {
49
- case 'IN_STOCK': return { text: t('inStock'), className: 'text-emerald-600' };
50
- case 'LOW_STOCK': return { text: t('lowStock'), className: 'text-amber-600' };
51
- case 'OUT_OF_STOCK': return { text: t('outOfStock'), className: 'text-red-600' };
52
- default: return { text: stockLevel, className: 'text-muted-foreground' };
50
+ case 'IN_STOCK':
51
+ return { text: t('inStock'), className: 'text-emerald-600' };
52
+ case 'LOW_STOCK':
53
+ return { text: t('lowStock'), className: 'text-amber-600' };
54
+ case 'OUT_OF_STOCK':
55
+ return { text: t('outOfStock'), className: 'text-red-600' };
56
+ default:
57
+ return { text: stockLevel, className: 'text-muted-foreground' };
53
58
  }
54
59
  }
55
60
 
@@ -77,7 +82,7 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
77
82
  const [quantityInput, setQuantityInput] = useState('1');
78
83
  const [isPending, startTransition] = useTransition();
79
84
  const [isAdded, setIsAdded] = useState(false);
80
- const {setCount} = useCartCount();
85
+ const { setCount } = useCartCount();
81
86
 
82
87
  useEffect(() => {
83
88
  let cancelled = false;
@@ -85,7 +90,8 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
85
90
  const applyData = (data: ProductDetail) => {
86
91
  if (cancelled) return;
87
92
  setProduct(data);
88
- const firstInStock = data.variants.find((v) => v.stockLevel !== 'OUT_OF_STOCK') ?? data.variants[0];
93
+ const firstInStock =
94
+ data.variants.find((v) => v.stockLevel !== 'OUT_OF_STOCK') ?? data.variants[0];
89
95
  if (firstInStock) {
90
96
  setSelectedVariantId(firstInStock.id);
91
97
  }
@@ -109,7 +115,9 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
109
115
  if (!cancelled) setLoading(false);
110
116
  }
111
117
  });
112
- return () => { cancelled = true; };
118
+ return () => {
119
+ cancelled = true;
120
+ };
113
121
  }, [slug]);
114
122
 
115
123
  const selectedVariant = useMemo(
@@ -118,13 +126,13 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
118
126
  );
119
127
 
120
128
  const packagingUnits = selectedVariant?.packagingUnits ?? [];
121
- const selectedPU = packagingUnits.find(pu => pu.packagingUnit.id === selectedPackagingUnitId);
129
+ const selectedPU = packagingUnits.find((pu) => pu.packagingUnit.id === selectedPackagingUnitId);
122
130
 
123
131
  // Auto-select base packaging unit when variant changes
124
132
  // eslint-disable-next-line react-hooks/set-state-in-effect -- syncing local state to prop-derived data
125
133
  useEffect(() => {
126
134
  if (packagingUnits.length > 0) {
127
- const base = packagingUnits.find(pu => pu.isBaseUnit) ?? packagingUnits[0];
135
+ const base = packagingUnits.find((pu) => pu.isBaseUnit) ?? packagingUnits[0];
128
136
  setSelectedPackagingUnitId(base.packagingUnit.id);
129
137
  setQuantityInput(String(base.minQuantity));
130
138
  } else {
@@ -136,7 +144,7 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
136
144
  const effectiveIncrement = selectedPU?.quantityIncrement ?? 1;
137
145
 
138
146
  const stockDisplay = useMemo(
139
- () => selectedVariant ? getStockDisplay(selectedVariant.stockLevel, t) : null,
147
+ () => (selectedVariant ? getStockDisplay(selectedVariant.stockLevel, t) : null),
140
148
  [selectedVariant, t],
141
149
  );
142
150
 
@@ -161,7 +169,10 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
161
169
  setIsAdded(true);
162
170
  const unitLabel = selectedPU ? ` (${selectedPU.packagingUnit.name})` : '';
163
171
  toast.success(t('addedToCartMessage'), {
164
- description: t('addedToCartDescriptionWithQty', {qty, name: `${productName}${unitLabel}`}),
172
+ description: t('addedToCartDescriptionWithQty', {
173
+ qty,
174
+ name: `${productName}${unitLabel}`,
175
+ }),
165
176
  });
166
177
  setTimeout(() => setIsAdded(false), 2000);
167
178
  } else {
@@ -177,11 +188,7 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
177
188
  }
178
189
 
179
190
  if (!product || product.variants.length === 0) {
180
- return (
181
- <div className="p-4 text-sm text-muted-foreground">
182
- {t('productDetailsUnavailable')}
183
- </div>
184
- );
191
+ return <div className="p-4 text-sm text-muted-foreground">{t('productDetailsUnavailable')}</div>;
185
192
  }
186
193
 
187
194
  const imageUrl = product.assets?.[0]?.preview;
@@ -226,10 +233,21 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
226
233
  }`}
227
234
  >
228
235
  <span className="truncate flex-1 text-left">{variant.name}</span>
229
- <Warehouse className={`h-3.5 w-3.5 flex-shrink-0 ${inStock ? 'text-emerald-500' : 'text-red-500'}`} />
230
- <span className="font-mono text-muted-foreground flex-shrink-0">{variant.sku}</span>
236
+ <Warehouse
237
+ className={`h-3.5 w-3.5 flex-shrink-0 ${
238
+ inStock ? 'text-emerald-500' : 'text-red-500'
239
+ }`}
240
+ />
241
+ <span className="font-mono text-muted-foreground flex-shrink-0">
242
+ {variant.sku}
243
+ </span>
231
244
  <span className="font-medium flex-shrink-0 whitespace-nowrap">
232
- <Price value={Math.round(variant.price * (selectedPU?.conversionFactor ?? 1))} currencyCode={currencyCode} />
245
+ <Price
246
+ value={Math.round(
247
+ variant.price * (selectedPU?.conversionFactor ?? 1),
248
+ )}
249
+ currencyCode={currencyCode}
250
+ />
233
251
  </span>
234
252
  </button>
235
253
  );
@@ -280,7 +298,7 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
280
298
  value={selectedPackagingUnitId}
281
299
  onValueChange={(id) => {
282
300
  setSelectedPackagingUnitId(id);
283
- const pu = packagingUnits.find(p => p.packagingUnit.id === id);
301
+ const pu = packagingUnits.find((p) => p.packagingUnit.id === id);
284
302
  if (pu) setQuantityInput(String(pu.minQuantity));
285
303
  }}
286
304
  >
@@ -288,15 +306,20 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
288
306
  <SelectValue />
289
307
  </SelectTrigger>
290
308
  <SelectContent>
291
- {packagingUnits.map(pu => (
309
+ {packagingUnits.map((pu) => (
292
310
  <SelectItem
293
311
  key={pu.packagingUnit.id}
294
312
  value={pu.packagingUnit.id}
295
- disabled={pu.effectiveStockLevel !== null && pu.effectiveStockLevel <= 0}
313
+ disabled={
314
+ pu.effectiveStockLevel !== null && pu.effectiveStockLevel <= 0
315
+ }
296
316
  >
297
317
  {pu.conversionFactor === 1
298
318
  ? pu.packagingUnit.name
299
- : t('packagingUnitWithConversion', {name: pu.packagingUnit.name, conversion: pu.conversionFactor})}
319
+ : t('packagingUnitWithConversion', {
320
+ name: pu.packagingUnit.name,
321
+ conversion: pu.conversionFactor,
322
+ })}
300
323
  </SelectItem>
301
324
  ))}
302
325
  </SelectContent>
@@ -306,7 +329,7 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
306
329
  {/* Total pieces summary — only when qty > 1 so it adds info */}
307
330
  {selectedPU && selectedPU.conversionFactor > 1 && quantity > 1 && (
308
331
  <span className="text-xs text-muted-foreground">
309
- {t('equalsNPcs', {count: quantity * selectedPU.conversionFactor})}
332
+ {t('equalsNPcs', { count: quantity * selectedPU.conversionFactor })}
310
333
  </span>
311
334
  )}
312
335
 
@@ -340,44 +363,49 @@ export function ProductListExpansion({ slug, productName, currencyCode }: Produc
340
363
  )}
341
364
 
342
365
  {/* Compact price tiers */}
343
- {selectedVariant?.priceTiers && (() => {
344
- const sorted = [...selectedVariant.priceTiers]
345
- .filter((tier): tier is PriceTier => tier.minQuantity != null)
346
- .sort((a, b) => a.minQuantity! - b.minQuantity!);
347
- if (sorted.length < 2) return null;
348
- const baseTier = sorted[0];
349
- const activeTierIndex = sorted.reduce((acc, tier, i) =>
350
- quantity >= tier.minQuantity! ? i : acc, -1
351
- );
352
- return (
353
- <div className="flex items-center gap-1.5 flex-wrap text-[11px]">
354
- {sorted.map((tier, i) => {
355
- const savings = tier.price < baseTier.price
356
- ? Math.round((1 - tier.price / baseTier.price) * 100)
357
- : 0;
358
- const isActive = i === activeTierIndex && i > 0;
359
- return (
360
- <button
361
- type="button"
362
- key={tier.minQuantity}
363
- onClick={() => setQuantityInput(String(tier.minQuantity))}
364
- className={`inline-flex items-center gap-1 px-1.5 py-0.5 rounded transition-colors cursor-pointer ${
365
- isActive
366
- ? 'border border-primary/50 bg-primary/10 font-medium'
367
- : 'border border-transparent bg-muted hover:bg-accent'
368
- }`}
369
- >
370
- <span className="text-xs font-semibold text-muted-foreground">{tier.minQuantity}+:</span>
371
- <Price value={tier.price} currencyCode={currencyCode} />
372
- {savings > 0 && (
373
- <span className="text-green-600">-{savings}%</span>
374
- )}
375
- </button>
376
- );
377
- })}
378
- </div>
379
- );
380
- })()}
366
+ {selectedVariant?.priceTiers &&
367
+ (() => {
368
+ const sorted = [...selectedVariant.priceTiers]
369
+ .filter((tier): tier is PriceTier => tier.minQuantity != null)
370
+ .sort((a, b) => a.minQuantity! - b.minQuantity!);
371
+ if (sorted.length < 2) return null;
372
+ const baseTier = sorted[0];
373
+ const activeTierIndex = sorted.reduce(
374
+ (acc, tier, i) => (quantity >= tier.minQuantity! ? i : acc),
375
+ -1,
376
+ );
377
+ return (
378
+ <div className="flex items-center gap-1.5 flex-wrap text-[11px]">
379
+ {sorted.map((tier, i) => {
380
+ const savings =
381
+ tier.price < baseTier.price
382
+ ? Math.round((1 - tier.price / baseTier.price) * 100)
383
+ : 0;
384
+ const isActive = i === activeTierIndex && i > 0;
385
+ return (
386
+ <button
387
+ type="button"
388
+ key={tier.minQuantity}
389
+ onClick={() => setQuantityInput(String(tier.minQuantity))}
390
+ className={`inline-flex items-center gap-1 px-1.5 py-0.5 rounded transition-colors cursor-pointer ${
391
+ isActive
392
+ ? 'border border-primary/50 bg-primary/10 font-medium'
393
+ : 'border border-transparent bg-muted hover:bg-accent'
394
+ }`}
395
+ >
396
+ <span className="text-xs font-semibold text-muted-foreground">
397
+ {tier.minQuantity}+:
398
+ </span>
399
+ <Price value={tier.price} currencyCode={currencyCode} />
400
+ {savings > 0 && (
401
+ <span className="text-green-600">-{savings}%</span>
402
+ )}
403
+ </button>
404
+ );
405
+ })}
406
+ </div>
407
+ );
408
+ })()}
381
409
 
382
410
  {/* Footer link */}
383
411
  <Link
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { useState } from 'react';
4
3
  import { FragmentOf, readFragment } from '@/graphql';
5
4
  import { ProductCardFragment } from '@/lib/vendure/fragments';
5
+ import { useState } from 'react';
6
6
  import { ProductCardList } from './product-card-list';
7
7
 
8
8
  interface ProductListViewProps {
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
 
3
- import { useState } from 'react';
4
- import { useSearchParams } from 'next/navigation';
5
- import { usePathname, useRouter } from '@/i18n/navigation';
6
- import { useTranslations } from 'next-intl';
7
3
  import { PrefetchLink } from '@/components/shared/prefetch-link';
8
- import { ChevronRight, Package, Tag, Layers, Warehouse, ChevronDown, ChevronUp } from 'lucide-react';
9
4
  import { Badge } from '@/components/ui/badge';
5
+ import { usePathname, useRouter } from '@/i18n/navigation';
10
6
  import type { ProductDetail } from '@/lib/vendure/queries';
7
+ import { ChevronDown, ChevronRight, ChevronUp, Layers, Package, Tag, Warehouse } from 'lucide-react';
8
+ import { useTranslations } from 'next-intl';
9
+ import { useSearchParams } from 'next/navigation';
10
+ import { useState } from 'react';
11
11
 
12
12
  export interface ProductSidebarProps {
13
13
  collections: ProductDetail['collections'];
@@ -33,7 +33,14 @@ function isVariantSelected(
33
33
  });
34
34
  }
35
35
 
36
- export function ProductSidebar({ collections, variants, productName, optionGroups, searchParams, slug }: ProductSidebarProps) {
36
+ export function ProductSidebar({
37
+ collections,
38
+ variants,
39
+ productName,
40
+ optionGroups,
41
+ searchParams,
42
+ slug,
43
+ }: ProductSidebarProps) {
37
44
  const tCatalog = useTranslations('Catalog');
38
45
  const tProduct = useTranslations('Product');
39
46
  const pathname = usePathname();
@@ -105,13 +112,25 @@ export function ProductSidebar({ collections, variants, productName, optionGroup
105
112
  <div className="flex items-center justify-between">
106
113
  <dt className="text-muted-foreground">Stock</dt>
107
114
  <dd className="flex items-center gap-1.5">
108
- <Warehouse className={`h-3.5 w-3.5 ${variants[0].stockLevel === 'OUT_OF_STOCK' ? 'text-red-500' : 'text-emerald-500'}`} />
115
+ <Warehouse
116
+ className={`h-3.5 w-3.5 ${
117
+ variants[0].stockLevel === 'OUT_OF_STOCK'
118
+ ? 'text-red-500'
119
+ : 'text-emerald-500'
120
+ }`}
121
+ />
109
122
  {variants[0].stockLevel === 'OUT_OF_STOCK' ? (
110
- <Badge variant="secondary" className="bg-red-900/80 text-red-300 border-0 text-[10px] uppercase tracking-wider">
123
+ <Badge
124
+ variant="secondary"
125
+ className="bg-red-900/80 text-red-300 border-0 text-[10px] uppercase tracking-wider"
126
+ >
111
127
  {tProduct('outOfStock')}
112
128
  </Badge>
113
129
  ) : (
114
- <Badge variant="secondary" className="bg-emerald-900/80 text-emerald-300 border-0 text-[10px] uppercase tracking-wider">
130
+ <Badge
131
+ variant="secondary"
132
+ className="bg-emerald-900/80 text-emerald-300 border-0 text-[10px] uppercase tracking-wider"
133
+ >
115
134
  {tProduct('inStock')}
116
135
  </Badge>
117
136
  )}
@@ -141,8 +160,14 @@ export function ProductSidebar({ collections, variants, productName, optionGroup
141
160
  }`}
142
161
  >
143
162
  <span className="truncate">{v.name}</span>
144
- <Warehouse className={`h-3.5 w-3.5 flex-shrink-0 ml-auto ${inStock ? 'text-emerald-500' : 'text-red-500'}`} />
145
- <span className="font-mono text-muted-foreground flex-shrink-0">{v.sku}</span>
163
+ <Warehouse
164
+ className={`h-3.5 w-3.5 flex-shrink-0 ml-auto ${
165
+ inStock ? 'text-emerald-500' : 'text-red-500'
166
+ }`}
167
+ />
168
+ <span className="font-mono text-muted-foreground flex-shrink-0">
169
+ {v.sku}
170
+ </span>
146
171
  </button>
147
172
  );
148
173
  })}
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
 
3
- import { useState, useCallback, type ReactNode } from 'react';
4
- import { useSearchParams } from 'next/navigation';
3
+ import { FragmentOf, readFragment } from '@/graphql';
5
4
  import { usePathname, useRouter } from '@/i18n/navigation';
6
- import { useTranslations } from 'next-intl';
7
- import { LayoutGrid, List } from 'lucide-react';
8
5
  import { cn } from '@/lib/utils';
9
- import { FragmentOf, readFragment } from '@/graphql';
10
6
  import { ProductCardFragment } from '@/lib/vendure/fragments';
7
+ import { LayoutGrid, List } from 'lucide-react';
8
+ import { useTranslations } from 'next-intl';
9
+ import { useSearchParams } from 'next/navigation';
10
+ import { useCallback, useState, type ReactNode } from 'react';
11
11
  import { ProductCard } from './product-card';
12
12
  import { ProductListView } from './product-list-view';
13
13
 
@@ -31,31 +31,39 @@ interface ProductViewSwitcherProps {
31
31
  children?: ReactNode;
32
32
  }
33
33
 
34
- export function ProductViewSwitcher({ products, totalItems, urlView, currentPage, take, children }: ProductViewSwitcherProps) {
34
+ export function ProductViewSwitcher({
35
+ products,
36
+ totalItems,
37
+ urlView,
38
+ currentPage,
39
+ take,
40
+ children,
41
+ }: ProductViewSwitcherProps) {
35
42
  const t = useTranslations('Product');
36
43
  const pathname = usePathname();
37
44
  const searchParams = useSearchParams();
38
45
  const router = useRouter();
39
46
  const [view, setViewState] = useState<'grid' | 'list'>(() => getInitialView(urlView));
40
47
 
41
- const setView = useCallback((newView: 'grid' | 'list') => {
42
- setViewState(newView);
43
- localStorage.setItem(STORAGE_KEY, newView);
44
- const params = new URLSearchParams(searchParams);
45
- if (newView === 'grid') {
46
- params.delete('view');
47
- } else {
48
- params.set('view', newView);
49
- }
50
- router.replace(`${pathname}?${params.toString()}`, { scroll: false });
51
- }, [pathname, searchParams, router]);
48
+ const setView = useCallback(
49
+ (newView: 'grid' | 'list') => {
50
+ setViewState(newView);
51
+ localStorage.setItem(STORAGE_KEY, newView);
52
+ const params = new URLSearchParams(searchParams);
53
+ if (newView === 'grid') {
54
+ params.delete('view');
55
+ } else {
56
+ params.set('view', newView);
57
+ }
58
+ router.replace(`${pathname}?${params.toString()}`, { scroll: false });
59
+ },
60
+ [pathname, searchParams, router],
61
+ );
52
62
 
53
63
  return (
54
64
  <>
55
65
  <div className="flex items-center justify-between">
56
- <p className="text-sm text-muted-foreground">
57
- {t('productCount', {count: totalItems})}
58
- </p>
66
+ <p className="text-sm text-muted-foreground">{t('productCount', { count: totalItems })}</p>
59
67
  <div className="flex items-center gap-2">
60
68
  <div className="flex items-center border border-border rounded-md">
61
69
  <button
@@ -95,7 +103,11 @@ export function ProductViewSwitcher({ products, totalItems, urlView, currentPage
95
103
  const { productId } = readFragment(ProductCardFragment, product);
96
104
  const position = currentPage && take ? (currentPage - 1) * take + i + 1 : undefined;
97
105
  return (
98
- <div key={productId} data-search-product-id={productId} data-search-position={position}>
106
+ <div
107
+ key={productId}
108
+ data-search-product-id={productId}
109
+ data-search-position={position}
110
+ >
99
111
  <ProductCard product={product} />
100
112
  </div>
101
113
  );
@@ -1,19 +1,19 @@
1
1
  'use client';
2
2
 
3
- import {useState, useTransition, useCallback, useEffect, useRef} from 'react';
4
- import {useRouter} from '@/i18n/navigation';
5
- import {Button} from '@/components/ui/button';
6
- import {Textarea} from '@/components/ui/textarea';
7
- import {XCircle, MessageSquare, ShoppingCart, Send, Loader2, AlertTriangle} from 'lucide-react';
8
- import {useTranslations} from 'next-intl';
9
3
  import {
10
- submitQuote,
4
+ acceptAndConvertQuote,
11
5
  acceptQuote,
6
+ checkQuoteStock,
12
7
  rejectQuote,
13
8
  requestQuoteChanges,
14
- acceptAndConvertQuote,
15
- checkQuoteStock,
9
+ submitQuote,
16
10
  } from '@/app/[locale]/account/quotes/actions';
11
+ import { Button } from '@/components/ui/button';
12
+ import { Textarea } from '@/components/ui/textarea';
13
+ import { useRouter } from '@/i18n/navigation';
14
+ import { AlertTriangle, Loader2, MessageSquare, Send, ShoppingCart, XCircle } from 'lucide-react';
15
+ import { useTranslations } from 'next-intl';
16
+ import { useCallback, useEffect, useRef, useState, useTransition } from 'react';
17
17
 
18
18
  const TERMINAL_STATUSES = new Set(['ACCEPTED', 'REJECTED', 'CANCELLED', 'EXPIRED']);
19
19
  const POLL_INTERVAL_MS = 1000;
@@ -25,12 +25,12 @@ interface QuoteActionButtonsProps {
25
25
  convertedOrderId?: string | null;
26
26
  }
27
27
 
28
- export function QuoteActionButtons({quoteId, status, convertedOrderId}: QuoteActionButtonsProps) {
28
+ export function QuoteActionButtons({ quoteId, status, convertedOrderId }: QuoteActionButtonsProps) {
29
29
  const router = useRouter();
30
30
  const t = useTranslations('Quotes');
31
31
  const [reason, setReason] = useState('');
32
32
  const [isPending, startTransition] = useTransition();
33
- const [result, setResult] = useState<{success: boolean; message?: string} | null>(null);
33
+ const [result, setResult] = useState<{ success: boolean; message?: string } | null>(null);
34
34
  const [polling, setPolling] = useState(false);
35
35
  const pollCount = useRef(0);
36
36
  const initialStatus = useRef(status);
@@ -66,19 +66,22 @@ export function QuoteActionButtons({quoteId, status, convertedOrderId}: QuoteAct
66
66
  return () => clearInterval(timer);
67
67
  }, [polling, router]);
68
68
 
69
- const handleAction = useCallback((action: () => Promise<{success: boolean; message?: string; redirectTo?: string}>) => {
70
- startTransition(async () => {
71
- const res = await action();
72
- setResult(res);
73
- if (res.success && 'redirectTo' in res && res.redirectTo) {
74
- router.push(res.redirectTo);
75
- } else if (res.success) {
76
- pollCount.current = 0;
77
- setPolling(true);
78
- router.refresh();
79
- }
80
- });
81
- }, [router]);
69
+ const handleAction = useCallback(
70
+ (action: () => Promise<{ success: boolean; message?: string; redirectTo?: string }>) => {
71
+ startTransition(async () => {
72
+ const res = await action();
73
+ setResult(res);
74
+ if (res.success && 'redirectTo' in res && res.redirectTo) {
75
+ router.push(res.redirectTo);
76
+ } else if (res.success) {
77
+ pollCount.current = 0;
78
+ setPolling(true);
79
+ router.refresh();
80
+ }
81
+ });
82
+ },
83
+ [router],
84
+ );
82
85
 
83
86
  if (TERMINAL_STATUSES.has(status) && status !== 'ACCEPTED') {
84
87
  return null;
@@ -91,7 +94,7 @@ export function QuoteActionButtons({quoteId, status, convertedOrderId}: QuoteAct
91
94
  if (polling) {
92
95
  return (
93
96
  <div className="flex items-center gap-2 rounded-md border border-blue-200 bg-blue-50 p-3 text-sm text-blue-800">
94
- <Loader2 className="h-4 w-4 animate-spin"/>
97
+ <Loader2 className="h-4 w-4 animate-spin" />
95
98
  {t('actionProcessing')}
96
99
  </div>
97
100
  );
@@ -106,7 +109,7 @@ export function QuoteActionButtons({quoteId, status, convertedOrderId}: QuoteAct
106
109
  disabled={isPending}
107
110
  className="w-full"
108
111
  >
109
- <Send className="h-4 w-4 mr-1"/>
112
+ <Send className="h-4 w-4 mr-1" />
110
113
  {t('actionSubmitQuoteRequest')}
111
114
  </Button>
112
115
  )}
@@ -116,14 +119,23 @@ export function QuoteActionButtons({quoteId, status, convertedOrderId}: QuoteAct
116
119
  {stockWarning && (
117
120
  <div className="rounded-md border border-amber-200 bg-amber-50 p-4 space-y-3">
118
121
  <div className="flex items-start gap-2">
119
- <AlertTriangle className="h-4 w-4 text-amber-600 mt-0.5 shrink-0"/>
122
+ <AlertTriangle className="h-4 w-4 text-amber-600 mt-0.5 shrink-0" />
120
123
  <div>
121
- <p className="text-sm font-medium text-amber-900">{t('stockWarningTitle')}</p>
124
+ <p className="text-sm font-medium text-amber-900">
125
+ {t('stockWarningTitle')}
126
+ </p>
122
127
  <ul className="text-xs text-amber-800 mt-1.5 space-y-1">
123
- {stockWarning.map(item => (
128
+ {stockWarning.map((item) => (
124
129
  <li key={item.sku}>
125
130
  <span className="font-medium">{item.productName}</span>
126
- <span className="text-amber-700"> — {t('stockWarningNeedAvailable', {needed: item.requestedQuantity, available: item.availableStock})}</span>
131
+ <span className="text-amber-700">
132
+ {' '}
133
+ —{' '}
134
+ {t('stockWarningNeedAvailable', {
135
+ needed: item.requestedQuantity,
136
+ available: item.availableStock,
137
+ })}
138
+ </span>
127
139
  </li>
128
140
  ))}
129
141
  </ul>
@@ -194,29 +206,35 @@ export function QuoteActionButtons({quoteId, status, convertedOrderId}: QuoteAct
194
206
  disabled={isPending}
195
207
  className="w-full"
196
208
  >
197
- <ShoppingCart className="h-4 w-4 mr-2"/>
198
- {status === 'ACCEPTED' ? t('actionProceedToCheckout') : t('actionAcceptAndCheckout')}
209
+ <ShoppingCart className="h-4 w-4 mr-2" />
210
+ {status === 'ACCEPTED'
211
+ ? t('actionProceedToCheckout')
212
+ : t('actionAcceptAndCheckout')}
199
213
  </Button>
200
214
  {status === 'QUOTED' && (
201
215
  <>
202
216
  <Button
203
217
  variant="outline"
204
218
  size="sm"
205
- onClick={() => handleAction(() => requestQuoteChanges(quoteId, reason))}
219
+ onClick={() =>
220
+ handleAction(() => requestQuoteChanges(quoteId, reason))
221
+ }
206
222
  disabled={isPending || !reason.trim()}
207
223
  className="w-full"
208
224
  >
209
- <MessageSquare className="h-4 w-4 mr-1"/>
225
+ <MessageSquare className="h-4 w-4 mr-1" />
210
226
  {t('actionRequestChanges')}
211
227
  </Button>
212
228
  <Button
213
229
  variant="destructive"
214
230
  size="sm"
215
- onClick={() => handleAction(() => rejectQuote(quoteId, reason || undefined))}
231
+ onClick={() =>
232
+ handleAction(() => rejectQuote(quoteId, reason || undefined))
233
+ }
216
234
  disabled={isPending}
217
235
  className="w-full"
218
236
  >
219
- <XCircle className="h-4 w-4 mr-1"/>
237
+ <XCircle className="h-4 w-4 mr-1" />
220
238
  {t('actionRejectQuote')}
221
239
  </Button>
222
240
  </>