@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
package/jest.config.js ADDED
@@ -0,0 +1,50 @@
1
+ /*
2
+ * Copyright (c) 2022, 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
+ const path = require('path')
9
+ const base = require('@salesforce/pwa-kit-dev/configs/jest/jest.config.js')
10
+
11
+ module.exports = {
12
+ ...base,
13
+ moduleNameMapper: {
14
+ ...base.moduleNameMapper,
15
+ '^react$': '<rootDir>/node_modules/react/index.js',
16
+ '^react-router-dom(.*)$': '<rootDir>/node_modules/react-router-dom/index.js',
17
+ '^@salesforce\/retail-react-app(.*)$': '<rootDir>$1',
18
+ '^@tanstack/react-query$':
19
+ '<rootDir>/node_modules/@tanstack/react-query/build/lib/index.js',
20
+ '^is-what$': '<rootDir>/node_modules/is-what/dist/cjs/index.cjs',
21
+ '^copy-anything$': '<rootDir>/node_modules/copy-anything/dist/cjs/index.cjs'
22
+ },
23
+ setupFilesAfterEnv: [path.join(__dirname, 'jest-setup.js')],
24
+ collectCoverageFrom: [
25
+ 'app/**/*.{js,jsx}',
26
+ 'non-pwa/**/*.{js,jsx}',
27
+ 'worker/**/*.{js,jsx}',
28
+ 'scripts/generator/*.{js,jsx}',
29
+ '!app/pages/test-container/**/*.{js,jsx}',
30
+ '!app/utils/test-utils.js',
31
+ '!app/mocks/*.js',
32
+ '!app/main.jsx',
33
+ '!app/loader.js',
34
+ '!app/ssr.js',
35
+ '!app/static/**',
36
+ '!app/theme/**',
37
+ '!node_modules/**'
38
+ ],
39
+ //@TODO: Revert this threshold back to original numbers stattements: 80, branches: 72, functions: 78, lines: 83
40
+ coverageThreshold: {
41
+ global: {
42
+ statements: 73,
43
+ branches: 60,
44
+ functions: 65,
45
+ lines: 74
46
+ }
47
+ },
48
+ // Increase to: 6 x default timeout of 5 seconds
49
+ ...(process.env.CI ? {testTimeout: 30000} : {})
50
+ }
package/jsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ // for development convenience, this file helps IDE's find relative paths prefixed with
2
+ // the self-reference (to this package) 'retail-react-app'
3
+
4
+ // jsconfig.json
5
+ {
6
+ "compilerOptions": {
7
+ "target": "ES6",
8
+ "baseUrl": "./",
9
+ "paths": {
10
+ "retail-react-app/*": ["./*"]
11
+ }
12
+ }
13
+ }
package/package.json ADDED
@@ -0,0 +1,105 @@
1
+ {
2
+ "name": "@salesforce/retail-react-app",
3
+ "version": "1.0.0-preview.0",
4
+ "license": "See license in LICENSE",
5
+ "author": "cc-pwa-kit@salesforce.com",
6
+ "ccExtensibility": {
7
+ "extendable": [
8
+ "@salesforce/retail-react-app"
9
+ ]
10
+ },
11
+ "scripts": {
12
+ "analyze-build": "cross-env MOBIFY_ANALYZE=true npm run build",
13
+ "build": "npm run build-translations && pwa-kit-dev build",
14
+ "build-translations": "npm run extract-default-translations && npm run compile-translations",
15
+ "compile-translations": "formatjs compile-folder --ast translations translations/compiled",
16
+ "compile-translations:pseudo": "formatjs compile --ast translations/en-US.json --out-file translations/compiled/en-XA.json --pseudo-locale en-XA",
17
+ "extract-default-translations": "node ./scripts/extract-default-messages.js en-US",
18
+ "format": "pwa-kit-dev format \"**/*.{js,jsx}\"",
19
+ "lint": "pwa-kit-dev lint \"**/*.{js,jsx}\"",
20
+ "lint:fix": "npm run lint -- --fix",
21
+ "push": "npm run build && pwa-kit-dev push",
22
+ "save-credentials": "pwa-kit-dev save-credentials",
23
+ "start": "cross-env NODE_ICU_DATA=node_modules/full-icu pwa-kit-dev start",
24
+ "start:inspect": "npm run start -- --inspect",
25
+ "start:pseudolocale": "npm run extract-default-translations && npm run compile-translations:pseudo && cross-env USE_PSEUDOLOCALE=true npm run start",
26
+ "tail-logs": "pwa-kit-dev tail-logs",
27
+ "test": "pwa-kit-dev test",
28
+ "test:lighthouse": "cross-env NODE_ENV=production lhci autorun --config=tests/lighthouserc.js",
29
+ "test:max-file-size": "npm run build && bundlesize"
30
+ },
31
+ "browserslist": [
32
+ "iOS >= 9.0",
33
+ "Android >= 4.4.4",
34
+ "last 4 ChromeAndroid versions"
35
+ ],
36
+ "dependencies": {
37
+ "@chakra-ui/icons": "^2.0.19",
38
+ "@chakra-ui/react": "^2.6.0",
39
+ "@chakra-ui/skip-nav": "^2.0.15",
40
+ "@chakra-ui/system": "^2.5.6",
41
+ "@emotion/react": "^11.10.6",
42
+ "@emotion/styled": "^11.10.6",
43
+ "@formatjs/cli": "^6.0.4",
44
+ "@lhci/cli": "^0.11.0",
45
+ "@loadable/component": "^5.15.3",
46
+ "@peculiar/webcrypto": "^1.4.2",
47
+ "@salesforce/commerce-sdk-react": "1.0.0-preview.0",
48
+ "@salesforce/pwa-kit-dev": "3.0.0-preview.0",
49
+ "@salesforce/pwa-kit-react-sdk": "3.0.0-preview.0",
50
+ "@salesforce/pwa-kit-runtime": "3.0.0-preview.0",
51
+ "@tanstack/react-query": "^4.0.10",
52
+ "@tanstack/react-query-devtools": "^4.29.1",
53
+ "@testing-library/dom": "^9.0.1",
54
+ "@testing-library/jest-dom": "^5.16.5",
55
+ "@testing-library/react": "^14.0.0",
56
+ "@testing-library/user-event": "^14.4.3",
57
+ "base64-arraybuffer": "^0.2.0",
58
+ "bundlesize2": "^0.0.31",
59
+ "card-validator": "^8.1.1",
60
+ "cross-env": "^5.2.1",
61
+ "focus-visible": "^5.2.0",
62
+ "framer-motion": "^10.12.9",
63
+ "full-icu": "^1.5.0",
64
+ "helmet": "^4.6.0",
65
+ "jest-fetch-mock": "^2.1.2",
66
+ "js-cookie": "^3.0.1",
67
+ "jsonwebtoken": "^9.0.0",
68
+ "jwt-decode": "^3.1.2",
69
+ "lodash": "^4.17.21",
70
+ "msw": "^1.2.1",
71
+ "nanoid": "^3.3.4",
72
+ "njwt": "^1.2.0",
73
+ "prop-types": "^15.8.1",
74
+ "query-string": "^7.1.3",
75
+ "raf": "^3.4.1",
76
+ "randomstring": "^1.2.3",
77
+ "react": "^18.2.0",
78
+ "react-dom": "^18.2.0",
79
+ "react-helmet": "^6.1.0",
80
+ "react-hook-form": "^7.43.9",
81
+ "react-intl": "^5.25.1",
82
+ "react-router-dom": "^5.3.4"
83
+ },
84
+ "devDependencies": {
85
+ "cross-env": "^5.2.1"
86
+ },
87
+ "engines": {
88
+ "node": "^16.11.0 || ^18.0.0",
89
+ "npm": "^8.0.0 || ^9.0.0"
90
+ },
91
+ "bundlesize": [
92
+ {
93
+ "path": "build/main.js",
94
+ "maxSize": "42 kB"
95
+ },
96
+ {
97
+ "path": "build/vendor.js",
98
+ "maxSize": "320 kB"
99
+ }
100
+ ],
101
+ "overrides": {
102
+ "nwsapi": "2.2.2"
103
+ },
104
+ "gitHead": "a9f820893b7714244a0af509a5aefecc1344153c"
105
+ }
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Copyright (c) 2023, Salesforce, Inc.
4
+ * All rights reserved.
5
+ * SPDX-License-Identifier: BSD-3-Clause
6
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
7
+ */
8
+ /* eslint @typescript-eslint/no-var-requires: "off" */
9
+
10
+ /**
11
+ * This script will extract messages from base template and extended app and output all translations in the extended app
12
+ * If a file is overridden, it won't extract messages from that file in the base template
13
+ */
14
+ const {exec} = require('child_process')
15
+ const fs = require('fs')
16
+ const path = require('path')
17
+ const packagePath = path.join(process.cwd(), 'package.json')
18
+ const pkgJSON = JSON.parse(fs.readFileSync(packagePath))
19
+ const locale = process.argv[2]
20
+
21
+ const getAllFilesByExtensions = (dirPath, arrayOfFiles = [], extensions = []) => {
22
+ const files = fs.readdirSync(dirPath)
23
+
24
+ files.forEach(function (file) {
25
+ if (fs.statSync(path.join(dirPath, file)).isDirectory()) {
26
+ arrayOfFiles = getAllFilesByExtensions(
27
+ path.join(dirPath, file),
28
+ arrayOfFiles,
29
+ extensions
30
+ )
31
+ } else {
32
+ arrayOfFiles.push(path.join(dirPath, file))
33
+ }
34
+ })
35
+ if (extensions.length) {
36
+ return arrayOfFiles.filter((filePath) => {
37
+ const getExtension = path.extname(filePath).replace('.', '')
38
+ return extensions.includes(getExtension)
39
+ })
40
+ }
41
+
42
+ return arrayOfFiles
43
+ }
44
+
45
+ try {
46
+ const overridesDir = pkgJSON.ccExtensibility?.overridesDir
47
+ if (!overridesDir) {
48
+ const command = `formatjs extract "app/**/*.{js,jsx,ts,tsx}" --out-file translations/${locale}.json --id-interpolation-pattern [sha512:contenthash:base64:6]`
49
+ exec(command, (err) => {
50
+ if (err) {
51
+ console.error(err)
52
+ }
53
+ })
54
+ } else {
55
+ const overridesPath = path.join(process.cwd(), pkgJSON.ccExtensibility?.overridesDir)
56
+ // get all the files in extended app
57
+ const files = getAllFilesByExtensions(
58
+ path.join(overridesPath, 'app'),
59
+ [],
60
+ ['js', 'jsx', 'ts', 'tsx']
61
+ )
62
+ // get the file names that are overridden in base template
63
+ const overriddenFiles = files
64
+ .map((path) => {
65
+ const replacedPath = path.replace(
66
+ overridesDir,
67
+ `node_modules/${pkgJSON.ccExtensibility?.extends}`
68
+ )
69
+ // check if this file does exist in base template
70
+ const isFileExist = fs.existsSync(replacedPath)
71
+ return isFileExist ? replacedPath : ''
72
+ })
73
+ .filter(Boolean)
74
+ // rename the files needs to ignore to have .ignore extensions so it won't be recognized by formatjs
75
+ overriddenFiles.forEach((filePath) => {
76
+ fs.rename(filePath, `${filePath}.ignore`, (err) => err && console.error(err))
77
+ })
78
+
79
+ const extractCommand = `formatjs extract "./node_modules/${pkgJSON.ccExtensibility?.extends}/app/**/*.{js,jsx,ts,tsx}" "${pkgJSON.ccExtensibility?.overridesDir}/app/**/*.{js,jsx,ts,tsx}" --out-file translations/${locale}.json --id-interpolation-pattern [sha512:contenthash:base64:6]`
80
+ exec(extractCommand, (err) => {
81
+ if (err) {
82
+ console.error(err)
83
+ }
84
+ // restore file names
85
+ overriddenFiles.forEach((filePath) => {
86
+ fs.rename(`${filePath}.ignore`, filePath, (err) => err && console.error(err))
87
+ })
88
+ })
89
+ }
90
+ } catch (error) {
91
+ console.error(error)
92
+ }
@@ -0,0 +1,37 @@
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
+ module.exports = {
8
+ // The different Lighthouse CI configuration options:
9
+ // https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/configuration.md
10
+ ci: {
11
+ collect: {
12
+ startServerCommand: 'npm run start',
13
+ //NOTE: Adjust the key pages URLs that you find important to your website.
14
+ url: [
15
+ 'http://localhost:3000/',
16
+ 'http://localhost:3000/global/en-GB/category/womens',
17
+ 'http://localhost:3000/global/en-GB/product/25493613M',
18
+ 'http://localhost:3000/global/en-GB/search?q=suit'
19
+ ],
20
+ startServerReadyPattern: 'First build complete',
21
+ startServerReadyTimeout: 90000
22
+ },
23
+ upload: {
24
+ target: 'temporary-public-storage'
25
+ },
26
+ assert: {
27
+ aggregationMethod: 'median',
28
+ assertions: {
29
+ // NOTE: Adjust the scores accordingly as the performance is improved
30
+ 'categories:performance': ['error', {minScore: 0.3}],
31
+ 'categories:pwa': ['error', {minScore: 0.9}],
32
+ 'categories:seo': ['error', {minScore: 0.85}],
33
+ 'categories:accessibility': ['error', {minScore: 0.88}]
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,127 @@
1
+ # Translations
2
+
3
+ Most of the files in this folder are generated by `react-intl` **CLI tool**:
4
+
5
+ - `<root>/translations/en-US.json` <- output of _extracting_ the default messages, which you can send to your translators.
6
+ - `<root>/translations/[locale].json` <- the files that your translators make for the other locales
7
+ - `<root>/translations/compiled/[locale].json` <- output of _compiling_ the messages into AST format
8
+ - Compiling helps improve the performance because it allows `react-intl` to skip the parsing step
9
+
10
+ Several **npm scripts** are available to you that make it easier to use the CLI tool. See `package.json` for more details.
11
+
12
+ - To **extract the default messages**, run `npm run extract-default-translations` to have all the default messages extracted into a json file. By default, en-US.json is the file that's generated. If you wish to extract your messages into a different json file, simply update the script by replacing `en-US` with your desired locale.
13
+ - To **compile the translations** from all the locales, run `npm run compile-translations`.
14
+ - To run **both an extract and compile**, run `npm run build-translations`.
15
+
16
+ ## Formatting Messages
17
+
18
+ For all the hardcoded translations in your site, write them...
19
+
20
+ - _inline_ in the components, so it’s easier to see where in the page or component that they get used in
21
+ - and in the _default/fallback locale_ (for example, in English)
22
+
23
+ For example, in your React component, you can add formatted messages like `intl.formatMessage({defaultMessage: '...'})` or `<FormattedMessage defaultMessage="..." />`
24
+
25
+ ### Adding Message Id
26
+
27
+ At the minimum, only defaultMessage is the required parameter. The message id is optional. If you don’t specify it, the id is auto-generated for you.
28
+
29
+ ## Testing with a Pseudo Locale
30
+
31
+ To check whether you’ve wrapped all the hardcoded strings with either `intl.formatMessage()` or `<FormattedMessage />` , there’s a quick way to test that by running `npm run start:pseudolocale`. It runs your local dev server with the locale forced to the pseudo locale.
32
+
33
+ Loading the site in your browser, you can quickly see that those messages that have been formatted would look like this: `[!! Ṕŕíííṿâćććẏ ṔṔṔŏĺíííćẏ !!]`
34
+
35
+ # Localization
36
+
37
+ Since the Retail React App supports **multiple sites** feature, this means each site can have its own localization setup. In each site,
38
+ the default locale, supported locales, and currency settings are defined in a site object in `config/sites.js` under `ll0n`.
39
+
40
+ The locale ids `l10n.supportedLocales[n].id` follow the format supported by OCAPI and Commerce API: `<language code>-<country code>` as defined in this InfoCenter topic: [OCAPI localization 21.8](https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/OCAPI/current/usage/Localization.html).
41
+
42
+ The currency code in `l10n.supportedCurrencies` and `l10n.supportedLocales[n].preferredCurrency` follow the ISO 4217 standard.
43
+
44
+ **Important**: The supported locale settings `l10n.supportedLocales` must match the locale settings for your B2C Commerce instance. For more information about configuring locales on a B2C Commerce instance, see this InfoCenter topic: [Configure Site Locales](https://documentation.b2c.commercecloud.salesforce.com/DOC2/topic/com.demandware.dochelp/content/b2c_commerce/topics/admin/b2c_configuring_site_locales.html).
45
+
46
+ Here’s an example of locale configuration in sites configuration:
47
+
48
+ ```js
49
+ // config/sites.js
50
+ modules.exports = [
51
+ {
52
+ id: 'site-id',
53
+ l10n: {
54
+ supportedCurrencies: ['GBP', 'EUR', 'CNY', 'JPY'],
55
+ defaultCurrency: 'GBP',
56
+ supportedLocales: [
57
+ {
58
+ id: 'de-DE',
59
+ preferredCurrency: 'EUR'
60
+ },
61
+ {
62
+ id: 'en-GB',
63
+ preferredCurrency: 'GBP'
64
+ },
65
+ {
66
+ id: 'es-MX',
67
+ preferredCurrency: 'MXN'
68
+ },
69
+ // other locales
70
+ ],
71
+ defaultLocale: 'en-GB'
72
+ }
73
+ }
74
+ ]
75
+ ```
76
+
77
+ ## How to Add a New Locale
78
+
79
+ The process for adding a new locale is as follows:
80
+
81
+ 1. Create/enable the new locale in Business Manager of your B2C Commerce instance
82
+ 2. Enable the locale's currency too in Business Manager
83
+ 3. Add the new locale and its currency to your targeted site in `config/sites.js`
84
+ 4. If the new locale is also going to be the locale of your inline default messages:
85
+ - Update those default messages to be in that locale's language
86
+ - Run `npm run extract-default-translations` to extract the new translations
87
+ - Send the extracted translations to your translation team
88
+ 5. Place the files you receive from your translation team into the `<root>/translations/` folder
89
+ 6. Run `npm run compile-translations`
90
+
91
+ ## Tips
92
+
93
+ Here are a few useful things to know for developers.
94
+
95
+ ### User-Preferred Locales vs. App-Supported Locales
96
+
97
+ How a locale gets chosen depends on whether there’s a match found between 2 sets of locales. On a high level, it looks like this:
98
+
99
+ 1. Get the app-supported locales, which are defined in each site object in `config/sites.js` (under `l10n.supportedLocales` of your targeted site).
100
+ 2. Get the user-preferred locales, which are what the visitors prefer to see. The developer is responsible for fully implementing them in their own projects within the special `_app` component.
101
+ 3. If there’s a match between these 2 sets of locales, then the app would use it as the target locale.
102
+ 4. Otherwise, the app would fall back to the locale of the inline `defaultMessage`s.
103
+
104
+ ### How to Detect the Active Locale
105
+
106
+ - Within component render, `useLocale` hook is available to you: `const locale = useLocale()`
107
+ - Within a page’s `getProps` you can call utility function `resolveLocaleFromUrl` like this:
108
+
109
+ ```js
110
+ ProductDetail.getProps = async ({res, params, location, api}) => {
111
+ const locale = resolveLocaleFromUrl(`${location.pathname}${location.search}`)
112
+ ...
113
+ }
114
+ ```
115
+
116
+ ### Dynamic Loading of the Translation Files
117
+
118
+ Using dynamic import, regardless of how many locales the app supports, it would load only one locale at a time.
119
+
120
+ Initially, on app load, the translated messages are part of the server-rendered html. Afterwards on the client side, when dynamically changing the locale, the app would download the JSON file associated with that locale.
121
+
122
+ - Each locale is a separate JSON file in the bundle. And it’s served with a 1-year cache header.
123
+ - When a new bundle is deployed, you must download the JSON files again.
124
+
125
+ ### Link Component
126
+
127
+ The generated project comes with its own `Link` component. It automatically inserts the locale in the URLs for you.