@salesforce/retail-react-app 1.0.0-preview.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 (425) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.js +25 -0
  3. package/.prettierignore +4 -0
  4. package/.prettierrc.yaml +7 -0
  5. package/CHANGELOG.md +173 -0
  6. package/LICENSE +14 -0
  7. package/README.md +48 -0
  8. package/app/assets/svg/account.svg +3 -0
  9. package/app/assets/svg/alert.svg +3 -0
  10. package/app/assets/svg/basket.svg +3 -0
  11. package/app/assets/svg/brand-logo.svg +10 -0
  12. package/app/assets/svg/cc-amex.svg +7 -0
  13. package/app/assets/svg/cc-cvv.svg +8 -0
  14. package/app/assets/svg/cc-discover.svg +14 -0
  15. package/app/assets/svg/cc-mastercard.svg +8 -0
  16. package/app/assets/svg/cc-visa.svg +11 -0
  17. package/app/assets/svg/check-circle.svg +3 -0
  18. package/app/assets/svg/check.svg +3 -0
  19. package/app/assets/svg/chevron-down.svg +3 -0
  20. package/app/assets/svg/chevron-left.svg +3 -0
  21. package/app/assets/svg/chevron-right.svg +3 -0
  22. package/app/assets/svg/chevron-up.svg +3 -0
  23. package/app/assets/svg/close.svg +3 -0
  24. package/app/assets/svg/dashboard.svg +4 -0
  25. package/app/assets/svg/figma-logo.svg +14 -0
  26. package/app/assets/svg/file.svg +3 -0
  27. package/app/assets/svg/filter.svg +3 -0
  28. package/app/assets/svg/flag-ca.svg +5 -0
  29. package/app/assets/svg/flag-cn.svg +19 -0
  30. package/app/assets/svg/flag-fr.svg +19 -0
  31. package/app/assets/svg/flag-gb.svg +16 -0
  32. package/app/assets/svg/flag-it.svg +29 -0
  33. package/app/assets/svg/flag-jp.svg +10 -0
  34. package/app/assets/svg/flag-us.svg +7 -0
  35. package/app/assets/svg/github-logo.svg +40 -0
  36. package/app/assets/svg/hamburger.svg +8 -0
  37. package/app/assets/svg/heart-solid.svg +7 -0
  38. package/app/assets/svg/heart.svg +3 -0
  39. package/app/assets/svg/info.svg +3 -0
  40. package/app/assets/svg/like.svg +4 -0
  41. package/app/assets/svg/location.svg +3 -0
  42. package/app/assets/svg/lock.svg +3 -0
  43. package/app/assets/svg/paypal.svg +19 -0
  44. package/app/assets/svg/plug.svg +3 -0
  45. package/app/assets/svg/plus.svg +3 -0
  46. package/app/assets/svg/receipt.svg +3 -0
  47. package/app/assets/svg/search.svg +8 -0
  48. package/app/assets/svg/signout.svg +3 -0
  49. package/app/assets/svg/social-facebook.svg +3 -0
  50. package/app/assets/svg/social-instagram.svg +3 -0
  51. package/app/assets/svg/social-pinterest.svg +4 -0
  52. package/app/assets/svg/social-twitter.svg +3 -0
  53. package/app/assets/svg/social-youtube.svg +3 -0
  54. package/app/assets/svg/user.svg +3 -0
  55. package/app/assets/svg/visibility-off.svg +5 -0
  56. package/app/assets/svg/visibility.svg +3 -0
  57. package/app/components/_app/index.jsx +401 -0
  58. package/app/components/_app/index.test.js +85 -0
  59. package/app/components/_app/partials/above-header.jsx +10 -0
  60. package/app/components/_app-config/index.jsx +125 -0
  61. package/app/components/_app-config/index.test.js +77 -0
  62. package/app/components/_error/index.jsx +142 -0
  63. package/app/components/_error/index.test.js +25 -0
  64. package/app/components/action-card/index.jsx +75 -0
  65. package/app/components/address-display/index.jsx +30 -0
  66. package/app/components/basic-tile/index.jsx +65 -0
  67. package/app/components/basic-tile/index.test.js +23 -0
  68. package/app/components/breadcrumb/index.jsx +67 -0
  69. package/app/components/breadcrumb/index.test.js +30 -0
  70. package/app/components/confirmation-modal/index.jsx +111 -0
  71. package/app/components/confirmation-modal/index.test.js +98 -0
  72. package/app/components/drawer-menu/index.jsx +405 -0
  73. package/app/components/drawer-menu/index.test.js +33 -0
  74. package/app/components/dynamic-image/index.jsx +56 -0
  75. package/app/components/field/index.jsx +161 -0
  76. package/app/components/footer/index.jsx +269 -0
  77. package/app/components/footer/index.test.js +22 -0
  78. package/app/components/forms/address-fields.jsx +49 -0
  79. package/app/components/forms/credit-card-fields.jsx +149 -0
  80. package/app/components/forms/form-action-buttons.jsx +55 -0
  81. package/app/components/forms/login-fields.jsx +31 -0
  82. package/app/components/forms/password-requirements.jsx +99 -0
  83. package/app/components/forms/post-checkout-registration-fields.jsx +43 -0
  84. package/app/components/forms/profile-fields.jsx +36 -0
  85. package/app/components/forms/promo-code-fields.jsx +43 -0
  86. package/app/components/forms/registration-fields.jsx +42 -0
  87. package/app/components/forms/reset-password-fields.jsx +31 -0
  88. package/app/components/forms/state-province-options.jsx +75 -0
  89. package/app/components/forms/update-password-fields.jsx +49 -0
  90. package/app/components/forms/useAddressFields.jsx +196 -0
  91. package/app/components/forms/useCreditCardFields.jsx +146 -0
  92. package/app/components/forms/useLoginFields.jsx +52 -0
  93. package/app/components/forms/useProfileFields.jsx +95 -0
  94. package/app/components/forms/usePromoCodeFields.jsx +39 -0
  95. package/app/components/forms/useRegistrationFields.jsx +136 -0
  96. package/app/components/forms/useResetPasswordFields.jsx +40 -0
  97. package/app/components/forms/useUpdatePasswordFields.jsx +89 -0
  98. package/app/components/header/index.jsx +290 -0
  99. package/app/components/header/index.test.js +217 -0
  100. package/app/components/hero/index.jsx +84 -0
  101. package/app/components/hero/index.test.js +40 -0
  102. package/app/components/icons/index.jsx +158 -0
  103. package/app/components/icons/index.test.js +20 -0
  104. package/app/components/image-gallery/index.jsx +176 -0
  105. package/app/components/image-gallery/index.test.js +485 -0
  106. package/app/components/item-variant/index.jsx +33 -0
  107. package/app/components/item-variant/item-attributes.jsx +107 -0
  108. package/app/components/item-variant/item-image.jsx +73 -0
  109. package/app/components/item-variant/item-name.jsx +28 -0
  110. package/app/components/item-variant/item-price.jsx +117 -0
  111. package/app/components/link/index.jsx +32 -0
  112. package/app/components/link/index.test.js +72 -0
  113. package/app/components/links-list/index.jsx +89 -0
  114. package/app/components/links-list/index.test.js +62 -0
  115. package/app/components/list-menu/index.jsx +280 -0
  116. package/app/components/list-menu/index.test.js +44 -0
  117. package/app/components/loading-spinner/index.jsx +46 -0
  118. package/app/components/locale-selector/index.jsx +124 -0
  119. package/app/components/locale-selector/index.test.js +37 -0
  120. package/app/components/locale-text/index.jsx +97 -0
  121. package/app/components/locale-text/index.test.js +36 -0
  122. package/app/components/login/index.jsx +96 -0
  123. package/app/components/nested-accordion/index.jsx +185 -0
  124. package/app/components/nested-accordion/index.test.js +98 -0
  125. package/app/components/offline-banner/index.jsx +40 -0
  126. package/app/components/offline-banner/index.test.js +15 -0
  127. package/app/components/offline-boundary/index.jsx +104 -0
  128. package/app/components/offline-boundary/index.test.js +123 -0
  129. package/app/components/order-summary/index.jsx +331 -0
  130. package/app/components/page-action-placeholder/index.jsx +50 -0
  131. package/app/components/pagination/index.jsx +134 -0
  132. package/app/components/pagination/index.test.js +25 -0
  133. package/app/components/product-item/index.jsx +146 -0
  134. package/app/components/product-item/index.test.js +38 -0
  135. package/app/components/product-scroller/index.jsx +172 -0
  136. package/app/components/product-scroller/index.test.js +98 -0
  137. package/app/components/product-tile/index.jsx +195 -0
  138. package/app/components/product-tile/index.test.js +96 -0
  139. package/app/components/product-view/index.jsx +538 -0
  140. package/app/components/product-view/index.test.js +224 -0
  141. package/app/components/product-view-modal/index.jsx +48 -0
  142. package/app/components/product-view-modal/index.test.js +72 -0
  143. package/app/components/promo-code/index.jsx +162 -0
  144. package/app/components/promo-popover/index.jsx +83 -0
  145. package/app/components/quantity-picker/index.jsx +58 -0
  146. package/app/components/radio-card/index.jsx +75 -0
  147. package/app/components/recommended-products/index.jsx +227 -0
  148. package/app/components/register/index.jsx +114 -0
  149. package/app/components/reset-password/index.jsx +87 -0
  150. package/app/components/responsive/index.jsx +29 -0
  151. package/app/components/scroll-to-top/index.jsx +24 -0
  152. package/app/components/scroll-to-top/index.test.js +46 -0
  153. package/app/components/search/index.jsx +279 -0
  154. package/app/components/search/index.test.js +127 -0
  155. package/app/components/search/partials/recent-searches.jsx +76 -0
  156. package/app/components/search/partials/search-suggestions.jsx +45 -0
  157. package/app/components/search/partials/suggestions.jsx +43 -0
  158. package/app/components/section/index.jsx +68 -0
  159. package/app/components/seo/index.jsx +33 -0
  160. package/app/components/social-icons/index.jsx +101 -0
  161. package/app/components/social-icons/index.test.js +30 -0
  162. package/app/components/swatch-group/index.jsx +77 -0
  163. package/app/components/swatch-group/index.test.js +136 -0
  164. package/app/components/swatch-group/swatch.jsx +94 -0
  165. package/app/components/toggle-card/index.jsx +97 -0
  166. package/app/components/with-registration/index.jsx +58 -0
  167. package/app/components/with-registration/index.test.js +85 -0
  168. package/app/constants.js +109 -0
  169. package/app/contexts/index.js +92 -0
  170. package/app/hooks/einstein-mock-data.js +916 -0
  171. package/app/hooks/index.js +17 -0
  172. package/app/hooks/use-add-to-cart-modal.js +344 -0
  173. package/app/hooks/use-add-to-cart-modal.test.js +625 -0
  174. package/app/hooks/use-auth-modal.js +337 -0
  175. package/app/hooks/use-auth-modal.test.js +365 -0
  176. package/app/hooks/use-currency.js +20 -0
  177. package/app/hooks/use-currency.test.js +41 -0
  178. package/app/hooks/use-current-basket.js +39 -0
  179. package/app/hooks/use-current-customer.js +29 -0
  180. package/app/hooks/use-derived-product.js +77 -0
  181. package/app/hooks/use-derived-product.test.js +69 -0
  182. package/app/hooks/use-einstein.js +512 -0
  183. package/app/hooks/use-einstein.test.js +224 -0
  184. package/app/hooks/use-intersection-observer.js +64 -0
  185. package/app/hooks/use-limit-urls.js +31 -0
  186. package/app/hooks/use-limit-urls.test.js +40 -0
  187. package/app/hooks/use-multi-site.js +36 -0
  188. package/app/hooks/use-multi-site.test.js +53 -0
  189. package/app/hooks/use-navigation.js +37 -0
  190. package/app/hooks/use-navigation.test.js +109 -0
  191. package/app/hooks/use-page-urls.js +35 -0
  192. package/app/hooks/use-page-urls.test.js +39 -0
  193. package/app/hooks/use-pdp-search-params.js +16 -0
  194. package/app/hooks/use-pdp-search-params.test.js +52 -0
  195. package/app/hooks/use-previous.js +17 -0
  196. package/app/hooks/use-product-view-modal.js +93 -0
  197. package/app/hooks/use-product-view-modal.test.js +172 -0
  198. package/app/hooks/use-search-params.js +96 -0
  199. package/app/hooks/use-search-params.test.js +91 -0
  200. package/app/hooks/use-sort-urls.js +33 -0
  201. package/app/hooks/use-sort-urls.test.js +42 -0
  202. package/app/hooks/use-toast.js +68 -0
  203. package/app/hooks/use-toast.test.js +58 -0
  204. package/app/hooks/use-variant.js +32 -0
  205. package/app/hooks/use-variant.test.js +81 -0
  206. package/app/hooks/use-variation-attributes.js +138 -0
  207. package/app/hooks/use-variation-attributes.test.js +119 -0
  208. package/app/hooks/use-variation-params.js +31 -0
  209. package/app/hooks/use-variation-params.test.js +73 -0
  210. package/app/hooks/use-wish-list.js +42 -0
  211. package/app/main.jsx +14 -0
  212. package/app/mocks/basket-with-suit.js +146 -0
  213. package/app/mocks/empty-basket.js +39 -0
  214. package/app/mocks/mock-data.js +5632 -0
  215. package/app/mocks/product-set-winter-lookM.js +1224 -0
  216. package/app/mocks/searchResults.js +144 -0
  217. package/app/mocks/variant-750518699578M.js +434 -0
  218. package/app/page-designer/README.md +102 -0
  219. package/app/page-designer/assets/image-tile/index.jsx +51 -0
  220. package/app/page-designer/assets/image-tile/index.test.js +30 -0
  221. package/app/page-designer/assets/image-with-text/index.jsx +140 -0
  222. package/app/page-designer/assets/image-with-text/index.test.js +38 -0
  223. package/app/page-designer/assets/index.js +9 -0
  224. package/app/page-designer/index.js +10 -0
  225. package/app/page-designer/layouts/carousel/index.jsx +222 -0
  226. package/app/page-designer/layouts/carousel/index.test.js +43 -0
  227. package/app/page-designer/layouts/index.js +14 -0
  228. package/app/page-designer/layouts/mobileGrid1r1c/index.jsx +36 -0
  229. package/app/page-designer/layouts/mobileGrid1r1c/index.test.js +35 -0
  230. package/app/page-designer/layouts/mobileGrid2r1c/index.jsx +37 -0
  231. package/app/page-designer/layouts/mobileGrid2r1c/index.test.js +47 -0
  232. package/app/page-designer/layouts/mobileGrid2r2c/index.jsx +37 -0
  233. package/app/page-designer/layouts/mobileGrid2r2c/index.test.js +71 -0
  234. package/app/page-designer/layouts/mobileGrid2r3c/index.jsx +37 -0
  235. package/app/page-designer/layouts/mobileGrid2r3c/index.test.js +95 -0
  236. package/app/page-designer/layouts/mobileGrid3r1c/index.jsx +37 -0
  237. package/app/page-designer/layouts/mobileGrid3r1c/index.test.js +59 -0
  238. package/app/page-designer/layouts/mobileGrid3r2c/index.jsx +37 -0
  239. package/app/page-designer/layouts/mobileGrid3r2c/index.test.js +95 -0
  240. package/app/page-designer/utils.js +14 -0
  241. package/app/pages/account/addresses.jsx +382 -0
  242. package/app/pages/account/addresses.test.js +120 -0
  243. package/app/pages/account/constant.js +57 -0
  244. package/app/pages/account/index.jsx +237 -0
  245. package/app/pages/account/index.test.js +188 -0
  246. package/app/pages/account/order-detail.jsx +397 -0
  247. package/app/pages/account/order-history.jsx +264 -0
  248. package/app/pages/account/orders.jsx +30 -0
  249. package/app/pages/account/orders.test.js +95 -0
  250. package/app/pages/account/profile.jsx +357 -0
  251. package/app/pages/account/wishlist/index.jsx +195 -0
  252. package/app/pages/account/wishlist/index.mock.js +1481 -0
  253. package/app/pages/account/wishlist/index.test.js +56 -0
  254. package/app/pages/account/wishlist/partials/wishlist-primary-action.jsx +170 -0
  255. package/app/pages/account/wishlist/partials/wishlist-primary-action.mock.js +1623 -0
  256. package/app/pages/account/wishlist/partials/wishlist-primary-action.test.js +99 -0
  257. package/app/pages/account/wishlist/partials/wishlist-secondary-button-group.jsx +120 -0
  258. package/app/pages/account/wishlist/partials/wishlist-secondary-button-group.test.js +391 -0
  259. package/app/pages/cart/index.jsx +476 -0
  260. package/app/pages/cart/index.test.js +481 -0
  261. package/app/pages/cart/partials/cart-cta.jsx +46 -0
  262. package/app/pages/cart/partials/cart-secondary-button-group.jsx +135 -0
  263. package/app/pages/cart/partials/cart-secondary-button-group.test.js +103 -0
  264. package/app/pages/cart/partials/cart-skeleton.jsx +93 -0
  265. package/app/pages/cart/partials/cart-title.jsx +27 -0
  266. package/app/pages/cart/partials/empty-cart.jsx +86 -0
  267. package/app/pages/checkout/confirmation.jsx +541 -0
  268. package/app/pages/checkout/confirmation.mock.js +450 -0
  269. package/app/pages/checkout/confirmation.test.js +114 -0
  270. package/app/pages/checkout/index.jsx +169 -0
  271. package/app/pages/checkout/index.test.js +582 -0
  272. package/app/pages/checkout/partials/cc-radio-group.jsx +122 -0
  273. package/app/pages/checkout/partials/checkout-footer.jsx +140 -0
  274. package/app/pages/checkout/partials/checkout-footer.test.js +16 -0
  275. package/app/pages/checkout/partials/checkout-header.jsx +54 -0
  276. package/app/pages/checkout/partials/checkout-header.test.js +16 -0
  277. package/app/pages/checkout/partials/checkout-skeleton.jsx +52 -0
  278. package/app/pages/checkout/partials/contact-info.jsx +251 -0
  279. package/app/pages/checkout/partials/contact-info.test.js +43 -0
  280. package/app/pages/checkout/partials/payment-form.jsx +97 -0
  281. package/app/pages/checkout/partials/payment.jsx +276 -0
  282. package/app/pages/checkout/partials/shipping-address-selection.jsx +377 -0
  283. package/app/pages/checkout/partials/shipping-address.jsx +132 -0
  284. package/app/pages/checkout/partials/shipping-options.jsx +232 -0
  285. package/app/pages/checkout/util/checkout-context.js +94 -0
  286. package/app/pages/home/data.js +134 -0
  287. package/app/pages/home/index.jsx +301 -0
  288. package/app/pages/home/index.test.js +23 -0
  289. package/app/pages/login/index.jsx +123 -0
  290. package/app/pages/login/index.test.js +229 -0
  291. package/app/pages/login-redirect/index.jsx +23 -0
  292. package/app/pages/login-redirect/index.test.js +16 -0
  293. package/app/pages/page-not-found/index.jsx +90 -0
  294. package/app/pages/page-not-found/index.test.js +31 -0
  295. package/app/pages/product-detail/index.jsx +394 -0
  296. package/app/pages/product-detail/index.mock.js +197 -0
  297. package/app/pages/product-detail/index.test.js +162 -0
  298. package/app/pages/product-detail/partials/information-accordion.jsx +121 -0
  299. package/app/pages/product-list/index.jsx +735 -0
  300. package/app/pages/product-list/index.test.js +180 -0
  301. package/app/pages/product-list/partials/above-page-header.jsx +10 -0
  302. package/app/pages/product-list/partials/checkbox-refinements.jsx +41 -0
  303. package/app/pages/product-list/partials/checkbox-refinements.test.js +53 -0
  304. package/app/pages/product-list/partials/color-refinements.jsx +88 -0
  305. package/app/pages/product-list/partials/empty-results.jsx +118 -0
  306. package/app/pages/product-list/partials/link-refinements.jsx +38 -0
  307. package/app/pages/product-list/partials/page-header.jsx +42 -0
  308. package/app/pages/product-list/partials/radio-refinements.jsx +60 -0
  309. package/app/pages/product-list/partials/refinements.jsx +144 -0
  310. package/app/pages/product-list/partials/selected-refinements.jsx +100 -0
  311. package/app/pages/product-list/partials/size-refinements.jsx +55 -0
  312. package/app/pages/registration/index.jsx +87 -0
  313. package/app/pages/registration/index.test.jsx +132 -0
  314. package/app/pages/reset-password/index.jsx +112 -0
  315. package/app/pages/reset-password/index.test.jsx +141 -0
  316. package/app/request-processor.js +118 -0
  317. package/app/request-processor.test.js +23 -0
  318. package/app/routes.jsx +111 -0
  319. package/app/routes.test.js +13 -0
  320. package/app/ssr.js +70 -0
  321. package/app/static/ico/favicon.ico +0 -0
  322. package/app/static/img/global/app-icon-192.png +0 -0
  323. package/app/static/img/global/app-icon-512.png +0 -0
  324. package/app/static/img/global/apple-touch-icon.png +0 -0
  325. package/app/static/img/hero.png +0 -0
  326. package/app/static/manifest.json +19 -0
  327. package/app/static/robots.txt +2 -0
  328. package/app/theme/components/base/accordion.js +21 -0
  329. package/app/theme/components/base/alert.js +17 -0
  330. package/app/theme/components/base/badge.js +25 -0
  331. package/app/theme/components/base/button.js +77 -0
  332. package/app/theme/components/base/checkbox.js +30 -0
  333. package/app/theme/components/base/container.js +17 -0
  334. package/app/theme/components/base/drawer.js +26 -0
  335. package/app/theme/components/base/formLabel.js +13 -0
  336. package/app/theme/components/base/icon.js +13 -0
  337. package/app/theme/components/base/input.js +44 -0
  338. package/app/theme/components/base/modal.js +11 -0
  339. package/app/theme/components/base/popover.js +61 -0
  340. package/app/theme/components/base/radio.js +33 -0
  341. package/app/theme/components/base/select.js +15 -0
  342. package/app/theme/components/base/skeleton.js +12 -0
  343. package/app/theme/components/base/tooltip.js +19 -0
  344. package/app/theme/components/project/_app.js +25 -0
  345. package/app/theme/components/project/breadcrumb.js +25 -0
  346. package/app/theme/components/project/checkout-footer.js +35 -0
  347. package/app/theme/components/project/drawer-menu.js +66 -0
  348. package/app/theme/components/project/footer.js +84 -0
  349. package/app/theme/components/project/header.js +84 -0
  350. package/app/theme/components/project/image-gallery.js +59 -0
  351. package/app/theme/components/project/links-list.js +43 -0
  352. package/app/theme/components/project/list-menu.js +91 -0
  353. package/app/theme/components/project/locale-selector.js +42 -0
  354. package/app/theme/components/project/nested-accordion.js +26 -0
  355. package/app/theme/components/project/offline-banner.js +25 -0
  356. package/app/theme/components/project/pagination.js +22 -0
  357. package/app/theme/components/project/product-tile.js +32 -0
  358. package/app/theme/components/project/social-icons.js +52 -0
  359. package/app/theme/components/project/swatch-group.js +115 -0
  360. package/app/theme/foundations/colors.js +170 -0
  361. package/app/theme/foundations/gradients.js +9 -0
  362. package/app/theme/foundations/layerStyles.js +41 -0
  363. package/app/theme/foundations/shadows.js +9 -0
  364. package/app/theme/foundations/sizes.js +18 -0
  365. package/app/theme/foundations/space.js +9 -0
  366. package/app/theme/foundations/styles.js +21 -0
  367. package/app/theme/index.js +104 -0
  368. package/app/utils/cc-utils.js +112 -0
  369. package/app/utils/cc-utils.test.js +41 -0
  370. package/app/utils/image-groups-utils.js +62 -0
  371. package/app/utils/image-groups-utils.test.js +65 -0
  372. package/app/utils/locale.js +78 -0
  373. package/app/utils/locale.test.js +112 -0
  374. package/app/utils/password-utils.js +21 -0
  375. package/app/utils/phone-utils.js +22 -0
  376. package/app/utils/phone-utils.test.js +15 -0
  377. package/app/utils/product-utils.js +35 -0
  378. package/app/utils/product-utils.test.js +51 -0
  379. package/app/utils/responsive-image.js +198 -0
  380. package/app/utils/responsive-image.test.js +170 -0
  381. package/app/utils/routes-utils.js +111 -0
  382. package/app/utils/routes-utils.test.js +291 -0
  383. package/app/utils/site-utils.js +222 -0
  384. package/app/utils/site-utils.test.js +376 -0
  385. package/app/utils/test-utils.js +257 -0
  386. package/app/utils/url.js +291 -0
  387. package/app/utils/url.test.js +421 -0
  388. package/app/utils/utils.js +201 -0
  389. package/app/utils/utils.test.js +182 -0
  390. package/babel.config.js +7 -0
  391. package/cache-hash-config.json +8 -0
  392. package/config/default.js +64 -0
  393. package/config/mocks/default.js +131 -0
  394. package/config/sites.js +78 -0
  395. package/jest-setup.js +191 -0
  396. package/jest.config.js +50 -0
  397. package/jsconfig.json +13 -0
  398. package/package.json +105 -0
  399. package/scripts/extract-default-messages.js +92 -0
  400. package/tests/lighthouserc.js +37 -0
  401. package/translations/README.md +127 -0
  402. package/translations/compiled/de-DE.json +3212 -0
  403. package/translations/compiled/en-GB.json +3212 -0
  404. package/translations/compiled/en-US.json +3212 -0
  405. package/translations/compiled/en-XA.json +6948 -0
  406. package/translations/compiled/es-MX.json +3216 -0
  407. package/translations/compiled/fr-FR.json +3216 -0
  408. package/translations/compiled/it-IT.json +3188 -0
  409. package/translations/compiled/ja-JP.json +3200 -0
  410. package/translations/compiled/ko-KR.json +3180 -0
  411. package/translations/compiled/pt-BR.json +3220 -0
  412. package/translations/compiled/zh-CN.json +3212 -0
  413. package/translations/compiled/zh-TW.json +3208 -0
  414. package/translations/de-DE.json +1417 -0
  415. package/translations/en-GB.json +1417 -0
  416. package/translations/en-US.json +1417 -0
  417. package/translations/es-MX.json +1417 -0
  418. package/translations/fr-FR.json +1417 -0
  419. package/translations/it-IT.json +1417 -0
  420. package/translations/ja-JP.json +1417 -0
  421. package/translations/ko-KR.json +1417 -0
  422. package/translations/pt-BR.json +1417 -0
  423. package/translations/zh-CN.json +1417 -0
  424. package/translations/zh-TW.json +1417 -0
  425. package/worker/main.js +36 -0
@@ -0,0 +1,291 @@
1
+ /*
2
+ * Copyright (c) 2021, salesforce.com, inc.
3
+ * All rights reserved.
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
+ */
7
+ import React from 'react'
8
+ import {configureRoutes} from '@salesforce/retail-react-app/app/utils/routes-utils'
9
+
10
+ describe('configureRoutes', function () {
11
+ const cases = [
12
+ {
13
+ urlConfig: {
14
+ site: 'path',
15
+ locale: 'path',
16
+ showDefaults: true
17
+ },
18
+ expectedRes: [
19
+ '/uk/',
20
+ '/uk/en-GB/',
21
+ '/en-GB/',
22
+ '/uk/fr/',
23
+ '/fr/',
24
+ '/uk/fr-FR/',
25
+ '/fr-FR/',
26
+ '/uk/it-IT/',
27
+ '/it-IT/',
28
+ '/site-1/',
29
+ '/site-1/en-GB/',
30
+ '/site-1/fr/',
31
+ '/site-1/fr-FR/',
32
+ '/site-1/it-IT/',
33
+ '/us/',
34
+ '/us/en-US/',
35
+ '/en-US/',
36
+ '/us/en-CA/',
37
+ '/en-CA/',
38
+ '/site-2/',
39
+ '/site-2/en-US/',
40
+ '/site-2/en-CA/',
41
+ '/',
42
+ '/uk/category/:categoryId',
43
+ '/uk/en-GB/category/:categoryId',
44
+ '/en-GB/category/:categoryId',
45
+ '/uk/fr/category/:categoryId',
46
+ '/fr/category/:categoryId',
47
+ '/uk/fr-FR/category/:categoryId',
48
+ '/fr-FR/category/:categoryId',
49
+ '/uk/it-IT/category/:categoryId',
50
+ '/it-IT/category/:categoryId',
51
+ '/site-1/category/:categoryId',
52
+ '/site-1/en-GB/category/:categoryId',
53
+ '/site-1/fr/category/:categoryId',
54
+ '/site-1/fr-FR/category/:categoryId',
55
+ '/site-1/it-IT/category/:categoryId',
56
+ '/us/category/:categoryId',
57
+ '/us/en-US/category/:categoryId',
58
+ '/en-US/category/:categoryId',
59
+ '/us/en-CA/category/:categoryId',
60
+ '/en-CA/category/:categoryId',
61
+ '/site-2/category/:categoryId',
62
+ '/site-2/en-US/category/:categoryId',
63
+ '/site-2/en-CA/category/:categoryId',
64
+ '/category/:categoryId'
65
+ ]
66
+ },
67
+ {
68
+ urlConfig: {
69
+ site: 'path',
70
+ locale: 'path',
71
+ showDefaults: false
72
+ },
73
+ expectedRes: [
74
+ '/uk/',
75
+ '/uk/en-GB/',
76
+ '/en-GB/',
77
+ '/uk/fr/',
78
+ '/fr/',
79
+ '/uk/fr-FR/',
80
+ '/fr-FR/',
81
+ '/uk/it-IT/',
82
+ '/it-IT/',
83
+ '/site-1/',
84
+ '/site-1/en-GB/',
85
+ '/site-1/fr/',
86
+ '/site-1/fr-FR/',
87
+ '/site-1/it-IT/',
88
+ '/us/',
89
+ '/us/en-US/',
90
+ '/en-US/',
91
+ '/us/en-CA/',
92
+ '/en-CA/',
93
+ '/site-2/',
94
+ '/site-2/en-US/',
95
+ '/site-2/en-CA/',
96
+ '/',
97
+ '/uk/category/:categoryId',
98
+ '/uk/en-GB/category/:categoryId',
99
+ '/en-GB/category/:categoryId',
100
+ '/uk/fr/category/:categoryId',
101
+ '/fr/category/:categoryId',
102
+ '/uk/fr-FR/category/:categoryId',
103
+ '/fr-FR/category/:categoryId',
104
+ '/uk/it-IT/category/:categoryId',
105
+ '/it-IT/category/:categoryId',
106
+ '/site-1/category/:categoryId',
107
+ '/site-1/en-GB/category/:categoryId',
108
+ '/site-1/fr/category/:categoryId',
109
+ '/site-1/fr-FR/category/:categoryId',
110
+ '/site-1/it-IT/category/:categoryId',
111
+ '/us/category/:categoryId',
112
+ '/us/en-US/category/:categoryId',
113
+ '/en-US/category/:categoryId',
114
+ '/us/en-CA/category/:categoryId',
115
+ '/en-CA/category/:categoryId',
116
+ '/site-2/category/:categoryId',
117
+ '/site-2/en-US/category/:categoryId',
118
+ '/site-2/en-CA/category/:categoryId',
119
+ '/category/:categoryId'
120
+ ]
121
+ },
122
+ {
123
+ urlConfig: {
124
+ site: 'query_param',
125
+ locale: 'path',
126
+ showDefaults: true
127
+ },
128
+ expectedRes: [
129
+ '/en-GB/',
130
+ '/fr/',
131
+ '/fr-FR/',
132
+ '/it-IT/',
133
+ '/en-US/',
134
+ '/en-CA/',
135
+ '/',
136
+ '/en-GB/category/:categoryId',
137
+ '/fr/category/:categoryId',
138
+ '/fr-FR/category/:categoryId',
139
+ '/it-IT/category/:categoryId',
140
+ '/en-US/category/:categoryId',
141
+ '/en-CA/category/:categoryId',
142
+ '/category/:categoryId'
143
+ ]
144
+ },
145
+ {
146
+ urlConfig: {
147
+ site: 'query_param',
148
+ locale: 'path',
149
+ showDefaults: false
150
+ },
151
+ expectedRes: [
152
+ '/en-GB/',
153
+ '/fr/',
154
+ '/fr-FR/',
155
+ '/it-IT/',
156
+ '/en-US/',
157
+ '/en-CA/',
158
+ '/',
159
+ '/en-GB/category/:categoryId',
160
+ '/fr/category/:categoryId',
161
+ '/fr-FR/category/:categoryId',
162
+ '/it-IT/category/:categoryId',
163
+ '/en-US/category/:categoryId',
164
+ '/en-CA/category/:categoryId',
165
+ '/category/:categoryId'
166
+ ]
167
+ },
168
+ {
169
+ urlConfig: {
170
+ site: 'path',
171
+ locale: 'query_param',
172
+ showDefaults: true
173
+ },
174
+ expectedRes: [
175
+ '/uk/',
176
+ '/site-1/',
177
+ '/us/',
178
+ '/site-2/',
179
+ '/',
180
+ '/uk/category/:categoryId',
181
+ '/site-1/category/:categoryId',
182
+ '/us/category/:categoryId',
183
+ '/site-2/category/:categoryId',
184
+ '/category/:categoryId'
185
+ ]
186
+ },
187
+ {
188
+ urlConfig: {
189
+ site: 'path',
190
+ locale: 'query_param',
191
+ showDefaults: false
192
+ },
193
+ expectedRes: [
194
+ '/uk/',
195
+ '/site-1/',
196
+ '/us/',
197
+ '/site-2/',
198
+ '/',
199
+ '/uk/category/:categoryId',
200
+ '/site-1/category/:categoryId',
201
+ '/us/category/:categoryId',
202
+ '/site-2/category/:categoryId',
203
+ '/category/:categoryId'
204
+ ]
205
+ },
206
+ {
207
+ urlConfig: {
208
+ site: 'query_param',
209
+ locale: 'query_param',
210
+ showDefaults: true
211
+ },
212
+ expectedRes: ['/', '/category/:categoryId']
213
+ },
214
+ {
215
+ urlConfig: {
216
+ site: 'query_param',
217
+ locale: 'query_param',
218
+ showDefaults: false
219
+ },
220
+ expectedRes: ['/', '/category/:categoryId']
221
+ },
222
+ {
223
+ urlConfig: {
224
+ site: 'path',
225
+ locale: 'path',
226
+ showDefaults: true
227
+ },
228
+ expectedRes: [
229
+ '/uk/',
230
+ '/uk/en-GB/',
231
+ '/en-GB/',
232
+ '/uk/fr/',
233
+ '/fr/',
234
+ '/uk/fr-FR/',
235
+ '/fr-FR/',
236
+ '/uk/it-IT/',
237
+ '/it-IT/',
238
+ '/site-1/',
239
+ '/site-1/en-GB/',
240
+ '/site-1/fr/',
241
+ '/site-1/fr-FR/',
242
+ '/site-1/it-IT/',
243
+ '/us/',
244
+ '/us/en-US/',
245
+ '/en-US/',
246
+ '/us/en-CA/',
247
+ '/en-CA/',
248
+ '/site-2/',
249
+ '/site-2/en-US/',
250
+ '/site-2/en-CA/',
251
+ '/',
252
+ '/category/:categoryId'
253
+ ],
254
+ ignoredRoutes: ['/category/:categoryId']
255
+ }
256
+ ]
257
+ beforeEach(() => {
258
+ jest.resetModules()
259
+ })
260
+
261
+ const CompA = () => <div>This is component A</div>
262
+ const CompC = () => <div>This is component C</div>
263
+
264
+ const routes = [
265
+ {
266
+ path: '/',
267
+ component: CompA,
268
+ exact: true
269
+ },
270
+ {
271
+ path: '/category/:categoryId',
272
+ component: CompC,
273
+ exact: true
274
+ }
275
+ ]
276
+
277
+ cases.forEach(({urlConfig, expectedRes, ignoredRoutes = []}) => {
278
+ test(`Should return expected routes based on ${JSON.stringify(urlConfig)} config${
279
+ ignoredRoutes.length ? ` and ignore routes ${ignoredRoutes.join(',')}` : ' '
280
+ }`, () => {
281
+ const config = {
282
+ app: {
283
+ url: urlConfig
284
+ }
285
+ }
286
+ const configuredRoutes = configureRoutes(routes, config, {ignoredRoutes})
287
+ const paths = configuredRoutes.map((route) => route.path)
288
+ expect(paths).toEqual(expectedRes)
289
+ })
290
+ })
291
+ })
@@ -0,0 +1,222 @@
1
+ /*
2
+ * Copyright (c) 2021, salesforce.com, inc.
3
+ * All rights reserved.
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
+ */
7
+
8
+ import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
9
+ import {absoluteUrl} from '@salesforce/retail-react-app/app/utils/url'
10
+
11
+ /**
12
+ * This functions takes an url and returns a site object,
13
+ * an error will be thrown if no url is passed in or no site is found
14
+ * @param {string} url
15
+ * @returns {object} site - a site object
16
+ */
17
+ export const resolveSiteFromUrl = (url) => {
18
+ if (!url) {
19
+ throw new Error('URL is required to find a site object.')
20
+ }
21
+ const {pathname, search} = new URL(absoluteUrl(url))
22
+ const path = `${pathname}${search}`
23
+ let site
24
+
25
+ // get the site identifier from the url
26
+ const {siteRef} = getParamsFromPath(path)
27
+ const sites = getSites()
28
+
29
+ // step 1: use the siteRef to look for the site from the sites in the app config
30
+ // since alias is optional, make sure it is defined before the equality check
31
+ site = sites.find((site) => site.id === siteRef || (site.alias && site.alias === siteRef))
32
+ if (site) {
33
+ return site
34
+ }
35
+
36
+ //Step 2: if step 1 does not work, use the defaultSite value to get the default site
37
+ site = getDefaultSite()
38
+ // Step 3: throw an error if site can't be found by any of the above steps
39
+ if (!site) {
40
+ throw new Error(
41
+ "Can't find a matching default site. Please check your sites configuration."
42
+ )
43
+ }
44
+ return site
45
+ }
46
+
47
+ /**
48
+ * Returns the default site based on the defaultSite value from the app config
49
+ * @returns {object} site - a site object from app config
50
+ */
51
+ export const getDefaultSite = () => {
52
+ const {app} = getConfig()
53
+ const sites = getSites()
54
+
55
+ if (sites.length === 1) {
56
+ return sites[0]
57
+ }
58
+
59
+ return sites.find((site) => site.id === app.defaultSite)
60
+ }
61
+
62
+ /**
63
+ * Return the list of sites that has included their respective aliases
64
+ * @return {array} sites - list of sites including their aliases
65
+ */
66
+ export const getSites = () => {
67
+ const {sites = [], siteAliases = {}} = getConfig().app || {}
68
+
69
+ if (!sites.length) {
70
+ throw new Error("Can't find any sites from the config. Please check your configuration")
71
+ }
72
+
73
+ return sites.map((site) => {
74
+ const alias = siteAliases[site.id]
75
+ return {
76
+ ...site,
77
+ ...(alias ? {alias} : {})
78
+ }
79
+ })
80
+ }
81
+
82
+ /**
83
+ * Given a site reference, return the site object
84
+ * @param siteRef - site reference to look for the site object
85
+ * @returns {object | undefined} found site object or default site object
86
+ */
87
+ export const getSiteByReference = (siteRef) => {
88
+ const defaultSite = getDefaultSite()
89
+ const sites = getSites()
90
+
91
+ return (
92
+ sites.find((site) => {
93
+ return site.alias === siteRef || site.id === siteRef
94
+ }) || defaultSite
95
+ )
96
+ }
97
+
98
+ /**
99
+ * This function return the identifiers (site and locale) from the given url
100
+ * The site will always go before locale if both of them are presented in the pathname
101
+ * @param path {string}
102
+ * @returns {{siteRef: string, localeRef: string}} - site and locale reference (it could either be id or alias)
103
+ */
104
+ export const getParamsFromPath = (path) => {
105
+ const {pathname, search} = new URL(absoluteUrl(path))
106
+
107
+ const config = getConfig()
108
+ const {pathMatcher, searchMatcherForSite, searchMatcherForLocale} = getConfigMatcher(config)
109
+ const pathMatch = pathname.match(pathMatcher)
110
+ const searchMatchForSite = search.match(searchMatcherForSite)
111
+ const searchMatchForLocale = search.match(searchMatcherForLocale)
112
+
113
+ // the value can only either in the path or search query param, there will be no overridden
114
+ const siteRef = pathMatch?.groups.site || searchMatchForSite?.groups.site
115
+
116
+ const localeRef = pathMatch?.groups.locale || searchMatchForLocale?.groups.locale
117
+ return {siteRef, localeRef}
118
+ }
119
+
120
+ /**
121
+ * This function returns the url config from the current configuration
122
+ * @return {object} - url config
123
+ */
124
+ export const getUrlConfig = () => {
125
+ const {app} = getConfig()
126
+ if (!app.url) {
127
+ throw new Error('Cannot find `url` key. Please check your configuration file.')
128
+ }
129
+ return app.url
130
+ }
131
+
132
+ /**
133
+ * Given your application's configuration this function returns a set of regular expressions used to match the site
134
+ * and locale references from an url.
135
+ * @param config
136
+ * @return {{searchMatcherForSite: RegExp, searchMatcherForLocale: RegExp, pathMatcher: RegExp}}
137
+ */
138
+ export const getConfigMatcher = (config) => {
139
+ if (!config) {
140
+ throw new Error('Config is not defined.')
141
+ }
142
+
143
+ const allSites = getSites()
144
+ const siteIds = []
145
+ const siteAliases = []
146
+ const localesIds = []
147
+ const localeAliases = []
148
+ allSites.forEach((site) => {
149
+ siteAliases.push(site.alias)
150
+ siteIds.push(site.id)
151
+ const {l10n} = site
152
+ l10n.supportedLocales.forEach((locale) => {
153
+ localesIds.push(locale.id)
154
+ localeAliases.push(locale.alias)
155
+ })
156
+ })
157
+ const sites = [...siteIds, ...siteAliases].filter(Boolean)
158
+ const locales = [...localesIds, ...localeAliases].filter(Boolean)
159
+
160
+ // prettier-ignore
161
+ const searchPatternForSite = `site=(?<site>${sites.join('|')})`
162
+ // prettier-ignore
163
+ // eslint-disable-next-line
164
+ const pathPattern = `(?:\/(?<site>${sites.join('|')}))?(?:\/(?<locale>${locales.join("|")}))?(?!\\w)`
165
+ // prettier-ignore
166
+ const searchPatternForLocale = `locale=(?<locale>${locales.join('|')})`
167
+ const pathMatcher = new RegExp(pathPattern)
168
+ const searchMatcherForSite = new RegExp(searchPatternForSite)
169
+ const searchMatcherForLocale = new RegExp(searchPatternForLocale)
170
+ return {
171
+ pathMatcher,
172
+ searchMatcherForSite,
173
+ searchMatcherForLocale
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Given a site and a locale reference, return the locale object
179
+ * @param site - site to look for the locale
180
+ * @param localeRef - the locale ref to look for in site supported locales
181
+ * @return {object|undefined}
182
+ */
183
+ export const getLocaleByReference = (site, localeRef) => {
184
+ if (!site) {
185
+ throw new Error('Site is not defined. It is required to look for locale object')
186
+ }
187
+ return site.l10n.supportedLocales.find(
188
+ (locale) => locale.id === localeRef || locale.alias === localeRef
189
+ )
190
+ }
191
+
192
+ /**
193
+ * Determine the locale object from an url
194
+ * If the localeRef is not found from the url, set it to default locale of the current site
195
+ * and use it to find the locale object
196
+ *
197
+ * @param url
198
+ * @return {Object} locale object
199
+ */
200
+ export const resolveLocaleFromUrl = (url) => {
201
+ if (!url) {
202
+ throw new Error('URL is required to look for the locale object')
203
+ }
204
+ let {localeRef} = getParamsFromPath(url)
205
+ const site = resolveSiteFromUrl(url)
206
+ const {supportedLocales} = site.l10n
207
+ // if no localeRef is found, use the default value of the current site
208
+ if (!localeRef) {
209
+ localeRef = site.l10n.defaultLocale
210
+ }
211
+ const locale = supportedLocales.find(
212
+ (locale) => locale.alias === localeRef || locale.id === localeRef
213
+ )
214
+ if (locale) {
215
+ return locale
216
+ }
217
+ // if locale is not defined, use default locale as fallback value
218
+ const defaultLocale = site.l10n.defaultLocale
219
+ return supportedLocales.find(
220
+ (locale) => locale.alias === defaultLocale || locale.id === defaultLocale
221
+ )
222
+ }