@revenexx/cover 0.1.0

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 (408) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/app/api/account.ts +8 -0
  4. package/app/api/categories.ts +3 -0
  5. package/app/api/checkout.ts +6 -0
  6. package/app/api/images.ts +4 -0
  7. package/app/api/markets.ts +3 -0
  8. package/app/api/product.ts +3 -0
  9. package/app/api/products.ts +4 -0
  10. package/app/api/search.ts +4 -0
  11. package/app/app.config.ts +29 -0
  12. package/app/assets/css/cover.css +25 -0
  13. package/app/components/account/AccountMenu.vue +30 -0
  14. package/app/components/account/AccountShell.vue +18 -0
  15. package/app/components/account/AccountSidebar.vue +90 -0
  16. package/app/components/account/address/AccountAddressCard.vue +287 -0
  17. package/app/components/account/carts/AccountCartsTable.vue +284 -0
  18. package/app/components/account/dashboard/AccountDashboard.vue +351 -0
  19. package/app/components/account/directorder/AccountDirectOrder.vue +512 -0
  20. package/app/components/account/governance/AccountApprovalLimitsTable.vue +221 -0
  21. package/app/components/account/governance/AccountCostCenterDetail.vue +276 -0
  22. package/app/components/account/governance/AccountCostCentersTable.vue +252 -0
  23. package/app/components/account/governance/AccountRequisitionDetail.vue +295 -0
  24. package/app/components/account/governance/AccountRequisitionsTable.vue +255 -0
  25. package/app/components/account/governance/AccountWorkflowDetail.vue +215 -0
  26. package/app/components/account/governance/AccountWorkflowsTable.vue +168 -0
  27. package/app/components/account/governance/GovernanceApprovalLimitModal.vue +183 -0
  28. package/app/components/account/governance/GovernanceCostCenterModal.vue +188 -0
  29. package/app/components/account/governance/GovernanceWorkflowModal.vue +191 -0
  30. package/app/components/account/orderlists/AccountOrderListDetail.vue +349 -0
  31. package/app/components/account/orderlists/AccountOrderListsTable.vue +352 -0
  32. package/app/components/account/orders/AccountOrderDetail.vue +376 -0
  33. package/app/components/account/orders/AccountOrdersTable.vue +281 -0
  34. package/app/components/account/preferences/AccountPreferences.vue +50 -0
  35. package/app/components/auth/AuthForgotPasswordPanel.vue +88 -0
  36. package/app/components/auth/AuthLoginPanel.vue +103 -0
  37. package/app/components/auth/AuthLoginTeaser.vue +24 -0
  38. package/app/components/auth/AuthPageHeader.vue +21 -0
  39. package/app/components/auth/AuthRegisterPanel.vue +431 -0
  40. package/app/components/auth/AuthRegisterTeaser.vue +24 -0
  41. package/app/components/auth/AuthResetPasswordPanel.vue +115 -0
  42. package/app/components/cart/CartButton.vue +42 -0
  43. package/app/components/cart/actions/CartCostCenterModal.vue +110 -0
  44. package/app/components/cart/actions/CartExportModal.vue +82 -0
  45. package/app/components/cart/actions/CartPositionTextsModal.vue +92 -0
  46. package/app/components/cart/actions/CartSaveToListModal.vue +177 -0
  47. package/app/components/cart/actions/CartWorkflowPickerModal.vue +64 -0
  48. package/app/components/cart/drawer/CartDrawer.vue +49 -0
  49. package/app/components/cart/item/CartItem.vue +318 -0
  50. package/app/components/cart/manage/CartNameModal.vue +68 -0
  51. package/app/components/cart/position/CartPosition.vue +369 -0
  52. package/app/components/cart/quickadd/CartQuickAdd.vue +145 -0
  53. package/app/components/cart/recommend/CartCrossSell.vue +102 -0
  54. package/app/components/cart/recommend/CartRecommendCard.vue +59 -0
  55. package/app/components/cart/recommend/CartReorderStrip.vue +108 -0
  56. package/app/components/cart/requisition/CartRequisitionGroup.vue +74 -0
  57. package/app/components/cart/skeleton/CartSkeleton.vue +18 -0
  58. package/app/components/cart/summary/CartSummary.vue +25 -0
  59. package/app/components/cart/summary/CartSummaryBreakdown.vue +35 -0
  60. package/app/components/cart/switcher/CartSwitcher.vue +147 -0
  61. package/app/components/cart/target/CartTargetModal.vue +129 -0
  62. package/app/components/cart/view/CartApprovalsPanel.vue +89 -0
  63. package/app/components/cart/view/CartListHeader.vue +86 -0
  64. package/app/components/cart/view/CartPositionList.vue +94 -0
  65. package/app/components/cart/view/CartSummaryPanel.vue +254 -0
  66. package/app/components/cart/view/CartView.vue +310 -0
  67. package/app/components/category/info/CategoryPrice.vue +47 -0
  68. package/app/components/category/info/CategorySku.vue +15 -0
  69. package/app/components/category/info/CategoryStock.vue +25 -0
  70. package/app/components/category/list/CategoryItemCount.vue +27 -0
  71. package/app/components/category/list/CategoryListPagination.vue +81 -0
  72. package/app/components/category/skeleton/CategoryDetailSkeleton.vue +12 -0
  73. package/app/components/category/skeleton/CategoryListSkeleton.vue +65 -0
  74. package/app/components/category/view/CategoryViewToggle.vue +33 -0
  75. package/app/components/category/view/GridView.vue +78 -0
  76. package/app/components/category/view/ListView.vue +80 -0
  77. package/app/components/checkout/confirmation/CheckoutConfirmationView.vue +289 -0
  78. package/app/components/checkout/form/CheckoutSchemaForm.vue +72 -0
  79. package/app/components/checkout/onepage/CheckoutAddressPickerModal.vue +260 -0
  80. package/app/components/checkout/onepage/CheckoutAddressSection.vue +186 -0
  81. package/app/components/checkout/onepage/CheckoutDeliverySection.vue +158 -0
  82. package/app/components/checkout/onepage/CheckoutGate.vue +67 -0
  83. package/app/components/checkout/onepage/CheckoutGuestDetailsSection.vue +154 -0
  84. package/app/components/checkout/onepage/CheckoutNotesSection.vue +62 -0
  85. package/app/components/checkout/onepage/CheckoutOnePageView.vue +77 -0
  86. package/app/components/checkout/onepage/CheckoutPaymentSection.vue +181 -0
  87. package/app/components/checkout/onepage/CheckoutSectionTitle.vue +18 -0
  88. package/app/components/checkout/onepage/CheckoutSummarySection.vue +211 -0
  89. package/app/components/checkout/onepage/CheckoutWorkflowPanel.vue +38 -0
  90. package/app/components/layout/AppLogo.vue +21 -0
  91. package/app/components/layout/footer/Footer.vue +148 -0
  92. package/app/components/layout/header/AppBar.vue +75 -0
  93. package/app/components/layout/header/CategoryNav.vue +93 -0
  94. package/app/components/layout/header/HeaderActionItem.vue +81 -0
  95. package/app/components/layout/header/LocaleSwitcher.vue +123 -0
  96. package/app/components/layout/header/MainNav.vue +61 -0
  97. package/app/components/layout/header/MobileMenu.vue +81 -0
  98. package/app/components/layout/header/TopBar.vue +63 -0
  99. package/app/components/listing/ListingView.vue +227 -0
  100. package/app/components/product/detail/ProductDetailAddToCart.vue +188 -0
  101. package/app/components/product/detail/ProductDetailDescription.vue +20 -0
  102. package/app/components/product/detail/ProductDetailImageGallery.vue +58 -0
  103. package/app/components/product/detail/ProductDetailPricing.vue +108 -0
  104. package/app/components/product/detail/ProductDetailSaveToList.vue +291 -0
  105. package/app/components/product/detail/ProductDetailSpecifications.vue +33 -0
  106. package/app/components/product/detail/ProductDetailStock.vue +36 -0
  107. package/app/components/search/filter/SearchFacets.vue +256 -0
  108. package/app/components/search/filter/SearchFacetsDrawer.vue +58 -0
  109. package/app/components/ui/AppShell.vue +7 -0
  110. package/app/components/ui/debug/PiniaStateCard.vue +106 -0
  111. package/app/components/ui/feedback/EmptyState.vue +30 -0
  112. package/app/components/ui/feedback/ErrorBoundary.vue +44 -0
  113. package/app/components/ui/feedback/NotFound.vue +34 -0
  114. package/app/components/ui/forms/CountrySelection.vue +14 -0
  115. package/app/components/ui/forms/FormKitDatePicker.vue +124 -0
  116. package/app/components/ui/forms/PasswordInput.vue +136 -0
  117. package/app/components/ui/forms/SearchInput.vue +213 -0
  118. package/app/components/ui/table/TableSortButton.vue +51 -0
  119. package/app/components/ui/table/TableToolbar.vue +66 -0
  120. package/app/composables/useAccount.ts +27 -0
  121. package/app/composables/useAccountAddresses.ts +116 -0
  122. package/app/composables/useAccountOrders.ts +18 -0
  123. package/app/composables/useAppUrl.ts +38 -0
  124. package/app/composables/useAuthStore.ts +202 -0
  125. package/app/composables/useB2BContext.ts +23 -0
  126. package/app/composables/useCartActions.ts +25 -0
  127. package/app/composables/useCartCalculation.ts +90 -0
  128. package/app/composables/useCartSelection.ts +46 -0
  129. package/app/composables/useCartStore.ts +837 -0
  130. package/app/composables/useCartSummaryFormatting.ts +28 -0
  131. package/app/composables/useCategories.ts +29 -0
  132. package/app/composables/useCheckoutOnePage.ts +438 -0
  133. package/app/composables/useCheckoutProfileSource.ts +8 -0
  134. package/app/composables/useCheckoutSchema.ts +28 -0
  135. package/app/composables/useDataTable.ts +14 -0
  136. package/app/composables/useFormValidation.ts +29 -0
  137. package/app/composables/useIcons.ts +17 -0
  138. package/app/composables/useLocalePreferences.ts +45 -0
  139. package/app/composables/useMarkets.ts +15 -0
  140. package/app/composables/useProduct.ts +89 -0
  141. package/app/composables/useProductCard.ts +8 -0
  142. package/app/composables/useProductCardActions.ts +106 -0
  143. package/app/composables/useProductImage.ts +12 -0
  144. package/app/composables/useProductListing.ts +210 -0
  145. package/app/composables/useProductUrl.ts +17 -0
  146. package/app/composables/useProducts.ts +130 -0
  147. package/app/composables/useSearch.ts +12 -0
  148. package/app/composables/useThemeStore.ts +81 -0
  149. package/app/composables/useViewMode.ts +18 -0
  150. package/app/config/countries.ts +74 -0
  151. package/app/config/icons.ts +283 -0
  152. package/app/config/navigation.ts +191 -0
  153. package/app/config/palette.ts +13 -0
  154. package/app/config/themes.ts +20 -0
  155. package/app/formkit.config.ts +50 -0
  156. package/app/interfaces/account/address-list.ts +34 -0
  157. package/app/interfaces/account/order-list.ts +47 -0
  158. package/app/interfaces/account/order-lists.ts +35 -0
  159. package/app/interfaces/account/profile.ts +17 -0
  160. package/app/interfaces/account.ts +3 -0
  161. package/app/interfaces/address.ts +9 -0
  162. package/app/interfaces/auth.ts +104 -0
  163. package/app/interfaces/b2b.ts +234 -0
  164. package/app/interfaces/cart-calculation.ts +131 -0
  165. package/app/interfaces/cart-item.ts +45 -0
  166. package/app/interfaces/checkout-draft.ts +4 -0
  167. package/app/interfaces/checkout.ts +43 -0
  168. package/app/interfaces/delivery.ts +13 -0
  169. package/app/interfaces/market.ts +24 -0
  170. package/app/interfaces/payment.ts +19 -0
  171. package/app/interfaces/persisted-cart.ts +10 -0
  172. package/app/interfaces/product-detail.ts +54 -0
  173. package/app/interfaces/product-list.ts +33 -0
  174. package/app/interfaces/search-facets.ts +14 -0
  175. package/app/interfaces/validation.ts +14 -0
  176. package/app/layouts/default.vue +78 -0
  177. package/app/layouts/focus.vue +80 -0
  178. package/app/plugins/formkit-locale.client.ts +23 -0
  179. package/app/shared/constants.ts +1 -0
  180. package/app/validations/companyName.ts +18 -0
  181. package/app/validations/emailFormat.ts +10 -0
  182. package/app/validations/formValidationConfig.ts +50 -0
  183. package/app/validations/maxLength.ts +12 -0
  184. package/app/validations/minLength.ts +9 -0
  185. package/app/validations/optionalCompanyName.ts +23 -0
  186. package/app/validations/passwordsMatch.ts +5 -0
  187. package/app/validations/phoneNumber.ts +19 -0
  188. package/app/validations/required.ts +11 -0
  189. package/app/validations/termsRequired.ts +4 -0
  190. package/app/validations/types.ts +10 -0
  191. package/app/validations/zipCode.ts +15 -0
  192. package/i18n/locales/de/account.json +458 -0
  193. package/i18n/locales/de/auth.json +155 -0
  194. package/i18n/locales/de/cart.json +263 -0
  195. package/i18n/locales/de/checkout.json +217 -0
  196. package/i18n/locales/de/common.json +80 -0
  197. package/i18n/locales/de/cover.json +33 -0
  198. package/i18n/locales/de/order.json +1 -0
  199. package/i18n/locales/de/product.json +71 -0
  200. package/i18n/locales/de/search.json +54 -0
  201. package/i18n/locales/de/validation.json +12 -0
  202. package/i18n/locales/en/account.json +458 -0
  203. package/i18n/locales/en/auth.json +155 -0
  204. package/i18n/locales/en/cart.json +263 -0
  205. package/i18n/locales/en/checkout.json +217 -0
  206. package/i18n/locales/en/common.json +80 -0
  207. package/i18n/locales/en/cover.json +33 -0
  208. package/i18n/locales/en/order.json +1 -0
  209. package/i18n/locales/en/product.json +71 -0
  210. package/i18n/locales/en/search.json +54 -0
  211. package/i18n/locales/en/validation.json +12 -0
  212. package/nuxt.config.ts +109 -0
  213. package/package.json +65 -0
  214. package/public/img/product-placeholder.svg +8 -0
  215. package/public/templates/direct-order-template.csv +3 -0
  216. package/public/templates/direct-order-template.xlsx +0 -0
  217. package/server/api/account/address/[id].delete.ts +51 -0
  218. package/server/api/account/address/[id].put.ts +83 -0
  219. package/server/api/account/address/index.post.ts +60 -0
  220. package/server/api/account/addresses.get.ts +25 -0
  221. package/server/api/account/context.get.ts +16 -0
  222. package/server/api/account/governance/[domain]/[id].put.ts +57 -0
  223. package/server/api/account/governance/[domain].post.ts +111 -0
  224. package/server/api/account/order-lists/[id].delete.ts +22 -0
  225. package/server/api/account/order-lists/[id].get.ts +17 -0
  226. package/server/api/account/order-lists/[id].put.ts +46 -0
  227. package/server/api/account/order-lists/index.get.ts +14 -0
  228. package/server/api/account/order-lists/index.post.ts +38 -0
  229. package/server/api/account/orders/[id].get.ts +35 -0
  230. package/server/api/account/orders.get.ts +35 -0
  231. package/server/api/account/profile.get.ts +56 -0
  232. package/server/api/account/profile.put.ts +128 -0
  233. package/server/api/account/requisitions/[id].get.ts +15 -0
  234. package/server/api/account/requisitions.get.ts +23 -0
  235. package/server/api/auth/login.post.ts +37 -0
  236. package/server/api/auth/logout.post.ts +4 -0
  237. package/server/api/auth/me.get.ts +3 -0
  238. package/server/api/auth/personas.get.ts +7 -0
  239. package/server/api/auth/recovery.post.ts +32 -0
  240. package/server/api/auth/recovery.put.ts +37 -0
  241. package/server/api/auth/register.post.ts +126 -0
  242. package/server/api/cart/calculate.post.ts +25 -0
  243. package/server/api/cart/export.post.ts +81 -0
  244. package/server/api/cart/index.delete.ts +10 -0
  245. package/server/api/cart/index.get.ts +10 -0
  246. package/server/api/cart/sync.post.ts +14 -0
  247. package/server/api/carts/[id]/activate.post.ts +18 -0
  248. package/server/api/carts/[id]/index.delete.ts +18 -0
  249. package/server/api/carts/[id]/index.put.ts +19 -0
  250. package/server/api/carts/[id]/items.post.ts +21 -0
  251. package/server/api/carts/index.get.ts +14 -0
  252. package/server/api/carts/index.post.ts +14 -0
  253. package/server/api/categories/[slug].get.ts +22 -0
  254. package/server/api/categories/index.get.ts +11 -0
  255. package/server/api/checkout/profile.get.ts +21 -0
  256. package/server/api/checkout/schema/[key].get.ts +19 -0
  257. package/server/api/checkout/session.post.ts +8 -0
  258. package/server/api/images/detail/[filename].get.ts +18 -0
  259. package/server/api/images/list/[filename].get.ts +17 -0
  260. package/server/api/markets.get.ts +9 -0
  261. package/server/api/orders/index.post.ts +376 -0
  262. package/server/api/payment/methods.post.ts +65 -0
  263. package/server/api/product/[id].get.ts +29 -0
  264. package/server/api/products/[id].get.ts +30 -0
  265. package/server/api/products/index.get.ts +21 -0
  266. package/server/api/requisitions/index.post.ts +67 -0
  267. package/server/api/shipping/rates.post.ts +70 -0
  268. package/server/api/themes/index.get.ts +9 -0
  269. package/server/api/typesense/drop.get.ts +22 -0
  270. package/server/api/typesense/health.get.ts +9 -0
  271. package/server/api/typesense/search.post.ts +199 -0
  272. package/server/api/typesense/seed.get.ts +112 -0
  273. package/server/api/typesense/suggest.post.ts +69 -0
  274. package/server/config/account/organization.json +146 -0
  275. package/server/config/account/personas.json +169 -0
  276. package/server/config/account/user.json +8 -0
  277. package/server/config/account/workflows.json +19 -0
  278. package/server/data/account/address-list.json +103 -0
  279. package/server/data/account/order-list.json +491 -0
  280. package/server/data/account/order-lists.json +149 -0
  281. package/server/data/account/profile.json +9 -0
  282. package/server/data/account/registration-requests.json +3 -0
  283. package/server/data/account/requisitions.json +686 -0
  284. package/server/data/categories.json +186 -0
  285. package/server/data/forms/checkout/add-address.json +24 -0
  286. package/server/data/list/5137-1.png +0 -0
  287. package/server/data/list/5498-1.png +0 -0
  288. package/server/data/list/5498-2.png +0 -0
  289. package/server/data/list/5498-3.png +0 -0
  290. package/server/data/list/5498-4.png +0 -0
  291. package/server/data/list/5498-5.png +0 -0
  292. package/server/data/list/5498-6.png +0 -0
  293. package/server/data/list/5519-1.png +0 -0
  294. package/server/data/list/5713-1.png +0 -0
  295. package/server/data/list/5789-1.png +0 -0
  296. package/server/data/list/5930-1.png +0 -0
  297. package/server/data/list/6127-1.png +0 -0
  298. package/server/data/list/6234-1.png +0 -0
  299. package/server/data/list/6238-1.png +0 -0
  300. package/server/data/list/6246-1.png +0 -0
  301. package/server/data/list/6270-1.png +0 -0
  302. package/server/data/list/6330-1.png +0 -0
  303. package/server/data/list/6336-1.png +0 -0
  304. package/server/data/list/6360-1.png +0 -0
  305. package/server/data/list/6363-1.png +0 -0
  306. package/server/data/list/6375-1.png +0 -0
  307. package/server/data/list/6385-1.png +0 -0
  308. package/server/data/list/6413-1.png +0 -0
  309. package/server/data/list/6418-1.png +0 -0
  310. package/server/data/list/6465-1.png +0 -0
  311. package/server/data/list/6477-1.png +0 -0
  312. package/server/data/list/6509-1.png +0 -0
  313. package/server/data/list/6545-1.png +0 -0
  314. package/server/data/list/6548-1.png +0 -0
  315. package/server/data/list/6566-1.png +0 -0
  316. package/server/data/list/6581-1.png +0 -0
  317. package/server/data/list/6609-1.png +0 -0
  318. package/server/data/list/6611-1.png +0 -0
  319. package/server/data/list/6641-1.png +0 -0
  320. package/server/data/list/6659-1.png +0 -0
  321. package/server/data/list/6662-1.png +0 -0
  322. package/server/data/list/6689-1.png +0 -0
  323. package/server/data/list/6698-1.png +0 -0
  324. package/server/data/list/6701-1.png +0 -0
  325. package/server/data/list/6752-1.png +0 -0
  326. package/server/data/list/6755-1.png +0 -0
  327. package/server/data/list/6837-1.png +0 -0
  328. package/server/data/list/6841-1.png +0 -0
  329. package/server/data/list/6844-1.png +0 -0
  330. package/server/data/list/6846-1.png +0 -0
  331. package/server/data/list/6886-1.png +0 -0
  332. package/server/data/list/6895-1.png +0 -0
  333. package/server/data/list/6897-1.png +0 -0
  334. package/server/data/list/6919-1.png +0 -0
  335. package/server/data/list/6977-1.png +0 -0
  336. package/server/data/list/6983-1.png +0 -0
  337. package/server/data/list/6984-1.png +0 -0
  338. package/server/data/list/6985-1.png +0 -0
  339. package/server/data/list/6986-1.png +0 -0
  340. package/server/data/list/6989-1.png +0 -0
  341. package/server/data/list/6995-1.png +0 -0
  342. package/server/data/list/6998-1.png +0 -0
  343. package/server/data/markets.json +24 -0
  344. package/server/data/product-detail.json +2450 -0
  345. package/server/data/product-list.json +2450 -0
  346. package/server/data/themes.json +8 -0
  347. package/server/interfaces/account.ts +20 -0
  348. package/server/interfaces/auth.ts +32 -0
  349. package/server/interfaces/b2bContext.ts +23 -0
  350. package/server/interfaces/cart.ts +46 -0
  351. package/server/interfaces/cartCalculation.ts +17 -0
  352. package/server/interfaces/category.ts +12 -0
  353. package/server/interfaces/checkoutProfile.ts +5 -0
  354. package/server/interfaces/log.ts +3 -0
  355. package/server/interfaces/market.ts +10 -0
  356. package/server/interfaces/product.ts +21 -0
  357. package/server/interfaces/schema.ts +20 -0
  358. package/server/interfaces/theme.ts +10 -0
  359. package/server/services/ApiAuthService.ts +138 -0
  360. package/server/services/ApiCartService.ts +254 -0
  361. package/server/services/ApiCategoryService.ts +25 -0
  362. package/server/services/ApiMarketService.ts +71 -0
  363. package/server/services/ApiProductService.ts +53 -0
  364. package/server/services/LocalFileCategoryService.ts +23 -0
  365. package/server/services/LocalFileCheckoutProfileService.ts +117 -0
  366. package/server/services/LocalFileProductService.ts +128 -0
  367. package/server/services/LocalFileSchemaService.ts +70 -0
  368. package/server/services/LocalFileThemeService.ts +18 -0
  369. package/server/services/LogService.ts +28 -0
  370. package/server/services/MockAccountService.ts +58 -0
  371. package/server/services/MockAuthService.ts +105 -0
  372. package/server/services/MockB2BContextService.ts +149 -0
  373. package/server/services/MockCartCalculationService.ts +395 -0
  374. package/server/services/MockMarketService.ts +18 -0
  375. package/server/services/SdkAccountService.ts +56 -0
  376. package/server/services/SdkAuthService.ts +83 -0
  377. package/server/services/SessionCartService.ts +31 -0
  378. package/server/utils/accountService.ts +30 -0
  379. package/server/utils/authCookie.ts +13 -0
  380. package/server/utils/authService.ts +43 -0
  381. package/server/utils/b2bService.ts +49 -0
  382. package/server/utils/cartService.ts +59 -0
  383. package/server/utils/categoryService.ts +19 -0
  384. package/server/utils/checkoutProfileService.ts +9 -0
  385. package/server/utils/checkoutSession.ts +38 -0
  386. package/server/utils/coverData.ts +84 -0
  387. package/server/utils/governanceStore.ts +38 -0
  388. package/server/utils/i18n.ts +76 -0
  389. package/server/utils/inventoryService.ts +14 -0
  390. package/server/utils/liveCatalog.ts +234 -0
  391. package/server/utils/liveInventories.ts +76 -0
  392. package/server/utils/liveOrders.ts +139 -0
  393. package/server/utils/livePrices.ts +93 -0
  394. package/server/utils/locale.ts +39 -0
  395. package/server/utils/logService.ts +19 -0
  396. package/server/utils/marketService.ts +24 -0
  397. package/server/utils/orderService.ts +14 -0
  398. package/server/utils/paymentService.ts +14 -0
  399. package/server/utils/priceService.ts +14 -0
  400. package/server/utils/productService.ts +28 -0
  401. package/server/utils/productsSchema.ts +30 -0
  402. package/server/utils/revenexxApi.ts +136 -0
  403. package/server/utils/schemaService.ts +25 -0
  404. package/server/utils/serviceMode.ts +70 -0
  405. package/server/utils/shippingService.ts +14 -0
  406. package/server/utils/shopSdk.ts +88 -0
  407. package/server/utils/themeService.ts +16 -0
  408. package/server/utils/typesense.ts +27 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Storefront view of the markets app: a market bundles currency and
3
+ * locales (language + country); the locale selector is driven by this.
4
+ */
5
+ export interface ShopMarketLocale {
6
+ /** BCP-47 code, e.g. "de-DE". */
7
+ code: string;
8
+ /** ISO 639-1 language, e.g. "de" — matched against the UI locales. */
9
+ language: string;
10
+ /** ISO 3166-1 alpha-2 country, e.g. "DE". */
11
+ country: string;
12
+ isDefault: boolean;
13
+ }
14
+
15
+ export interface ShopMarket {
16
+ id: string;
17
+ /** Stable market code, e.g. "de". */
18
+ code: string;
19
+ name: string;
20
+ /** ISO 4217, e.g. "EUR". */
21
+ currency: string;
22
+ isDefault: boolean;
23
+ locales: ShopMarketLocale[];
24
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Payment method codes come from the payments app (live) or the demo
3
+ * profile (mock) — generic strings, e.g. "invoice", "card", "paypal",
4
+ * "po_number". The demo-only methods po_number/cost_center keep their
5
+ * extra input fields in the checkout.
6
+ */
7
+ export type PaymentMethod = string;
8
+
9
+ export interface PaymentOption {
10
+ method: PaymentMethod;
11
+ label: string;
12
+ /** Payment terms shown beneath the method (e.g. "30 days net"). */
13
+ description?: string;
14
+ /** Surcharge for this method at the current order value. */
15
+ fee?: number;
16
+ feeType?: "none" | "fixed" | "percent";
17
+ /** self_managed | psp — informational. */
18
+ kind?: string;
19
+ }
@@ -0,0 +1,10 @@
1
+ import type { Requisition } from "../interfaces/b2b";
2
+ import type { CartItem } from "../interfaces/cart-item";
3
+
4
+ export type CartRequisitionMeta = Omit<Requisition, "items">;
5
+
6
+ export interface PersistedCart {
7
+ readonly items: CartItem[];
8
+ readonly requisitions?: CartRequisitionMeta[];
9
+ readonly lastActivityAt: string;
10
+ }
@@ -0,0 +1,54 @@
1
+ export interface ProductDetailProduct {
2
+ id: string;
3
+ version: number;
4
+ name: string;
5
+ sku: string;
6
+ manufacturer: string;
7
+ createdAt: string;
8
+ updatedAt: string;
9
+ deletedAt: string | null;
10
+ available: boolean;
11
+ }
12
+
13
+ export interface ProductDetailStock {
14
+ quantity: number;
15
+ maxOrderQuantity: number;
16
+ }
17
+
18
+ export interface ProductDetailTax {
19
+ rate: number;
20
+ includedInPrice?: boolean;
21
+ }
22
+
23
+ export interface ProductDetailDescription {
24
+ type: string;
25
+ content: string;
26
+ }
27
+
28
+ export interface ProductDetailCategory {
29
+ type: string;
30
+ name: string;
31
+ }
32
+
33
+ export interface ProductDetailImage {
34
+ type: string;
35
+ priority: number;
36
+ url: string;
37
+ }
38
+
39
+ export interface ProductDetailAttribute {
40
+ id: number;
41
+ name: string;
42
+ value: string;
43
+ }
44
+
45
+ export interface ProductDetail {
46
+ product: ProductDetailProduct[];
47
+ stocks: ProductDetailStock[];
48
+ tax: ProductDetailTax;
49
+ descriptions: ProductDetailDescription[];
50
+ categories: ProductDetailCategory[];
51
+ images: ProductDetailImage[];
52
+ attributes: ProductDetailAttribute[];
53
+ prices: { [key: string]: number }[];
54
+ }
@@ -0,0 +1,33 @@
1
+ export interface ProductListStock {
2
+ quantity: number;
3
+ maxOrderQuantity: number;
4
+ }
5
+
6
+ export interface ProductListTax {
7
+ rate: number;
8
+ includedInPrice?: boolean;
9
+ }
10
+
11
+ export interface ProductList {
12
+ /** Platform entity id — UUID live, numeric string in demo data. */
13
+ id: string;
14
+ sku: string;
15
+ name: string;
16
+ available: boolean;
17
+ isOutOfStock?: boolean;
18
+ prices: { [key: string]: number }[];
19
+ stocks?: ProductListStock[];
20
+ tax: ProductListTax;
21
+ maxOrderQuantity?: number;
22
+ image: string;
23
+ category: string;
24
+ categorySlug: string;
25
+ subcategory?: string;
26
+ subcategorySlug?: string;
27
+ }
28
+
29
+ export interface ProductPriceTier {
30
+ quantity: number;
31
+ totalCents: number;
32
+ unitCents: number;
33
+ }
@@ -0,0 +1,14 @@
1
+ export interface FacetCount {
2
+ value: string;
3
+ count: number;
4
+ }
5
+
6
+ export interface SearchFacet {
7
+ fieldName: string;
8
+ counts: FacetCount[];
9
+ }
10
+
11
+ export interface PriceRange {
12
+ min?: number;
13
+ max?: number;
14
+ }
@@ -0,0 +1,14 @@
1
+ import type { CrossFieldValidator, SimpleValidator } from "../validations/types";
2
+
3
+ export type FormKey = "login" | "register" | "forgotPassword" | "resetPassword" | "accountProfile" | "accountAddress";
4
+
5
+ export interface FieldValidationRule {
6
+ readonly kind: "simple" | "cross";
7
+ readonly fn: SimpleValidator | CrossFieldValidator;
8
+ readonly options?: Readonly<Record<string, unknown>>;
9
+ }
10
+
11
+ export interface FieldConfig {
12
+ readonly field: string;
13
+ readonly rules: ReadonlyArray<FieldValidationRule>;
14
+ }
@@ -0,0 +1,78 @@
1
+ <script setup lang="ts">
2
+ const head = useLocaleHead({ seo: true });
3
+ const { query: searchQuery } = useSearch();
4
+ const route = useRoute();
5
+ const cart = useCartStore();
6
+
7
+ const isCartOrCheckoutPage = computed(() => /\/(cart|checkout)(\/|$)/.test(route.path));
8
+
9
+ watch(isCartOrCheckoutPage, (isRestrictedPage) => {
10
+ if (isRestrictedPage) {
11
+ cart.closeCart();
12
+ }
13
+ }, { immediate: true });
14
+
15
+ async function handleSearch(q: string): Promise<void> {
16
+ searchQuery.value = q;
17
+ await navigateTo("/search");
18
+ }
19
+ </script>
20
+
21
+ <template>
22
+ <Html
23
+ :lang="head.htmlAttrs?.lang"
24
+ :dir="head.htmlAttrs?.dir"
25
+ >
26
+ <Head>
27
+ <template
28
+ v-for="link in head.link"
29
+ :key="link.id"
30
+ >
31
+ <Link
32
+ :id="link.id"
33
+ :rel="link.rel"
34
+ :href="link.href"
35
+ :hreflang="link.hreflang"
36
+ />
37
+ </template>
38
+ <template
39
+ v-for="meta in head.meta"
40
+ :key="meta.id"
41
+ >
42
+ <Meta
43
+ :id="meta.id"
44
+ :property="meta.property"
45
+ :content="meta.content"
46
+ />
47
+ </template>
48
+ </Head>
49
+ <Body>
50
+ <div class="flex flex-col min-h-screen">
51
+ <a
52
+ href="#main-content"
53
+ tabindex="0"
54
+ class="sr-only focus:not-sr-only focus:absolute focus:z-50 focus:top-4 focus:left-4
55
+ focus:px-4 focus:py-2 focus:bg-(--ui-primary) focus:text-white focus:rounded-lg"
56
+ >
57
+ Skip to main content
58
+ </a>
59
+ <LayoutHeaderTopBar />
60
+ <LayoutHeaderAppBar />
61
+ <div class="md:hidden border-b border-(--ui-border) px-4 py-2">
62
+ <UiFormsSearchInput
63
+ class="w-full"
64
+ @search="handleSearch"
65
+ />
66
+ </div>
67
+ <LayoutHeaderMainNav />
68
+ <UiDebugPiniaStateCard v-if="false" />
69
+ <UMain id="main-content">
70
+ <slot />
71
+ </UMain>
72
+ <LayoutFooter />
73
+ <CartDrawer v-if="!isCartOrCheckoutPage" />
74
+ <CartTargetModal />
75
+ </div>
76
+ </Body>
77
+ </Html>
78
+ </template>
@@ -0,0 +1,80 @@
1
+ <script setup lang="ts">
2
+ import { legalLinks, shopContact } from "../config/navigation";
3
+
4
+ // Distraction-free layout for conversion-critical pages — authentication
5
+ // (login, register, recovery) and the checkout funnel. No shop chrome:
6
+ // logo + back link on top, the page content, and a slim footer with the
7
+ // essential links (contact + legal).
8
+ const { t } = useI18n();
9
+ const localePath = useLocalePath();
10
+ const head = useLocaleHead({ seo: true });
11
+ const year = new Date().getFullYear();
12
+
13
+ // Checkout gets a subtly tinted page background so the white section
14
+ // cards and the summary stand out from the canvas.
15
+ const route = useRoute();
16
+ const tinted = computed(() => /\/checkout(\/|$)/.test(route.path));
17
+ </script>
18
+
19
+ <template>
20
+ <Html
21
+ :lang="head.htmlAttrs?.lang"
22
+ :dir="head.htmlAttrs?.dir"
23
+ >
24
+ <Body>
25
+ <div
26
+ class="min-h-screen flex flex-col"
27
+ :class="tinted ? 'bg-elevated/50' : ''"
28
+ >
29
+ <div class="w-full max-w-(--ui-container) mx-auto px-4 sm:px-6 lg:px-8 flex-1 pb-20">
30
+ <header class="pt-10 flex items-center">
31
+ <div class="flex-1">
32
+ <LayoutAppLogo />
33
+ </div>
34
+ <NuxtLink
35
+ :to="localePath('/')"
36
+ tabindex="0"
37
+ class="hover:underline underline-offset-4 decoration-2 text-sm"
38
+ >
39
+ {{ t('nav.backToShop') }}
40
+ </NuxtLink>
41
+ </header>
42
+ <main>
43
+ <slot />
44
+ </main>
45
+ </div>
46
+
47
+ <footer class="border-t border-default mt-auto">
48
+ <div
49
+ class="w-full max-w-(--ui-container) mx-auto px-4 sm:px-6 lg:px-8 py-5
50
+ flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3"
51
+ >
52
+ <p class="text-xs text-dimmed">
53
+ {{ t('footer.copyright', { year }) }}
54
+ </p>
55
+ <nav
56
+ class="flex flex-wrap gap-x-5 gap-y-2"
57
+ aria-label="Legal"
58
+ >
59
+ <a
60
+ :href="`mailto:${shopContact.email}`"
61
+ class="text-xs text-dimmed hover:text-default transition-colors"
62
+ >
63
+ {{ shopContact.email }}
64
+ </a>
65
+ <NuxtLink
66
+ v-for="link in legalLinks"
67
+ :key="link.to"
68
+ :to="link.to"
69
+ tabindex="0"
70
+ class="text-xs text-dimmed hover:text-default transition-colors"
71
+ >
72
+ {{ link.label }}
73
+ </NuxtLink>
74
+ </nav>
75
+ </div>
76
+ </footer>
77
+ </div>
78
+ </Body>
79
+ </Html>
80
+ </template>
@@ -0,0 +1,23 @@
1
+ import type { Composer } from "vue-i18n";
2
+
3
+ import { changeLocale } from "@formkit/vue";
4
+
5
+ /**
6
+ * Keeps FormKit's built-in validation messages (required, matches, …) in
7
+ * sync with the app locale. The form schemas themselves are translated
8
+ * server-side per request; this only switches FormKit's locale pack.
9
+ */
10
+ export default defineNuxtPlugin((nuxtApp) => {
11
+ const i18n = nuxtApp.$i18n as Composer | undefined;
12
+ if (!i18n) {
13
+ return;
14
+ }
15
+
16
+ watch(
17
+ i18n.locale,
18
+ (locale) => {
19
+ changeLocale(locale);
20
+ },
21
+ { immediate: true },
22
+ );
23
+ });
@@ -0,0 +1 @@
1
+ export const EMAIL_VALIDATION_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$/;
@@ -0,0 +1,18 @@
1
+ import type { SimpleValidator } from "./types";
2
+
3
+ // checks if the input is a valid company name (basic validation)
4
+ export const companyName: SimpleValidator = (value) => {
5
+ const companyNameRegex = /^[a-zA-Z0-9äöüÄÖÜß\s.,'-]+$/;
6
+
7
+ if (typeof value !== "string") {
8
+ return null; // Not a string, let other validators handle this
9
+ }
10
+
11
+ const trimmedValue = value.trim();
12
+
13
+ if (!companyNameRegex.test(trimmedValue)) {
14
+ return "invalidCompanyName"; // Invalid company name format
15
+ }
16
+
17
+ return null; // Valid company name
18
+ };
@@ -0,0 +1,10 @@
1
+ import { EMAIL_VALIDATION_REGEX } from "../shared/constants";
2
+
3
+ import type { SimpleValidator } from "./types";
4
+
5
+ export const emailFormat: SimpleValidator = (value) => {
6
+ if (typeof value !== "string" || !EMAIL_VALIDATION_REGEX.test(value)) {
7
+ return "auth.register.errors.emailFormat";
8
+ }
9
+ return null;
10
+ };
@@ -0,0 +1,50 @@
1
+ import type { FieldConfig, FormKey } from "../interfaces/validation";
2
+
3
+ import { companyName } from "./companyName";
4
+ import { emailFormat } from "./emailFormat";
5
+ import { maxLength } from "./maxLength";
6
+ import { minLength } from "./minLength";
7
+ import { optionalCompanyName } from "./optionalCompanyName";
8
+ import { passwordsMatch } from "./passwordsMatch";
9
+ import { phoneNumber } from "./phoneNumber";
10
+ import { required } from "./required";
11
+ import { termsRequired } from "./termsRequired";
12
+ import { zipCode } from "./zipCode";
13
+
14
+ export const formValidationConfig: Record<FormKey, FieldConfig[]> = {
15
+ login: [
16
+ { field: "email", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: emailFormat }] },
17
+ { field: "password", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: minLength, options: { min: 8 } }] },
18
+ ],
19
+ register: [
20
+ { field: "email", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: emailFormat }] },
21
+ { field: "password", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: minLength, options: { min: 8 } }] },
22
+ { field: "passwordConfirm", rules: [{ kind: "cross", fn: passwordsMatch }] },
23
+ { field: "firstName", rules: [{ kind: "simple", fn: required }] },
24
+ { field: "lastName", rules: [{ kind: "simple", fn: required }] },
25
+ { field: "company", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: companyName }] },
26
+ { field: "acceptTerms", rules: [{ kind: "simple", fn: termsRequired }] },
27
+ ],
28
+ forgotPassword: [
29
+ { field: "email", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: emailFormat }] },
30
+ ],
31
+ resetPassword: [
32
+ { field: "password", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: minLength, options: { min: 8 } }] },
33
+ { field: "passwordConfirm", rules: [{ kind: "cross", fn: passwordsMatch }] },
34
+ ],
35
+ accountProfile: [
36
+ { field: "phone", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: maxLength, options: { max: 16 } }, { kind: "simple", fn: phoneNumber }, { kind: "simple", fn: minLength, options: { min: 8 } }] },
37
+ { field: "company", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: maxLength, options: { max: 64 } }, { kind: "simple", fn: minLength, options: { min: 3 } }, { kind: "simple", fn: companyName }] },
38
+ ],
39
+ accountAddress: [
40
+ { field: "label", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: minLength, options: { min: 2 } }] },
41
+ { field: "firstName", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: minLength, options: { min: 2 } }] },
42
+ { field: "lastName", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: minLength, options: { min: 2 } }] },
43
+ { field: "street", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: minLength, options: { min: 2 } }] },
44
+ { field: "streetNumber", rules: [{ kind: "simple", fn: required }] },
45
+ { field: "city", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: minLength, options: { min: 2 } }] },
46
+ { field: "zip", rules: [{ kind: "simple", fn: required }, { kind: "simple", fn: zipCode }] },
47
+ { field: "country", rules: [{ kind: "simple", fn: required }] },
48
+ { field: "company", rules: [{ kind: "simple", fn: optionalCompanyName, options: { min: 3, max: 64 } }] },
49
+ ],
50
+ };
@@ -0,0 +1,12 @@
1
+ import type { SimpleValidator } from "./types";
2
+
3
+ export const maxLength: SimpleValidator = (value, options) => {
4
+ const max = (options?.max as number) ?? Infinity;
5
+ if (typeof value !== "string") {
6
+ return null;
7
+ }
8
+ if (value.trim().length > max) {
9
+ return "maxLength";
10
+ }
11
+ return null;
12
+ };
@@ -0,0 +1,9 @@
1
+ import type { SimpleValidator } from "./types";
2
+
3
+ export const minLength: SimpleValidator = (value, options) => {
4
+ const min = (options?.min as number) ?? 0;
5
+ if (typeof value !== "string" || value.length < min) {
6
+ return "minLength";
7
+ }
8
+ return null;
9
+ };
@@ -0,0 +1,23 @@
1
+ import type { SimpleValidator } from "./types";
2
+
3
+ // Validates company name only when a value is present — field is optional.
4
+ // Options { min, max } are forwarded to minLength/maxLength translation keys.
5
+ export const optionalCompanyName: SimpleValidator = (value) => {
6
+ if (typeof value !== "string" || value.trim() === "") {
7
+ return null;
8
+ }
9
+ const trimmed = value.trim();
10
+ const min = 3;
11
+ const max = 64;
12
+ if (trimmed.length < min) {
13
+ return "minLength";
14
+ }
15
+ if (trimmed.length > max) {
16
+ return "maxLength";
17
+ }
18
+ const companyNameRegex = /^[a-zA-Z0-9äöüÄÖÜß\s.,'-]+$/;
19
+ if (!companyNameRegex.test(trimmed)) {
20
+ return "invalidCompanyName";
21
+ }
22
+ return null;
23
+ };
@@ -0,0 +1,5 @@
1
+ import type { CrossFieldValidator } from "./types";
2
+
3
+ export const passwordsMatch: CrossFieldValidator = (value, state) => {
4
+ return value !== state.password ? "auth.register.errors.passwordsMismatch" : null;
5
+ };
@@ -0,0 +1,19 @@
1
+ import type { SimpleValidator } from "./types";
2
+
3
+ // checks if the input is a valid phone number (basic validation)
4
+ export const phoneNumber: SimpleValidator = (value) => {
5
+ if (typeof value !== "string") {
6
+ return null; // Not a string, let other validators handle this
7
+ }
8
+
9
+ const trimmedValue = value.trim();
10
+
11
+ // Basic regex for phone numbers (allows digits, spaces, dashes, parentheses, and plus sign)
12
+ const phoneRegex = /^[+\d]?(?:[\d\s-().]*)$/;
13
+
14
+ if (!phoneRegex.test(trimmedValue)) {
15
+ return "invalidPhoneNumber"; // Invalid phone number format
16
+ }
17
+
18
+ return null; // Valid phone number
19
+ };
@@ -0,0 +1,11 @@
1
+ import type { SimpleValidator } from "./types";
2
+
3
+ export const required: SimpleValidator = (value) => {
4
+ if (typeof value === "boolean") {
5
+ return value === false ? "required" : null;
6
+ }
7
+ if (typeof value === "string") {
8
+ return value.trim() === "" ? "required" : null;
9
+ }
10
+ return value === null || value === undefined ? "required" : null;
11
+ };
@@ -0,0 +1,4 @@
1
+ import type { SimpleValidator } from "./types";
2
+
3
+ export const termsRequired: SimpleValidator = value =>
4
+ value !== true ? "termsRequired" : null;
@@ -0,0 +1,10 @@
1
+ export type SimpleValidator = (
2
+ value: unknown,
3
+ options?: Record<string, unknown>,
4
+ ) => string | null;
5
+
6
+ export type CrossFieldValidator = (
7
+ value: unknown,
8
+ state: Record<string, unknown>,
9
+ options?: Record<string, unknown>,
10
+ ) => string | null;
@@ -0,0 +1,15 @@
1
+ import type { SimpleValidator } from "./types";
2
+
3
+ export const zipCode: SimpleValidator = (value) => {
4
+ if (typeof value !== "string") {
5
+ return "invalidZipCode";
6
+ }
7
+ const trimmed = value.trim();
8
+ if (!/^\d{3,5}$/.test(trimmed)) {
9
+ return "invalidZipCode";
10
+ }
11
+ if (/^0+$/.test(trimmed) || trimmed === "99999") {
12
+ return "invalidZipCode";
13
+ }
14
+ return null;
15
+ };