├── app
├── static
│ ├── robots.txt
│ ├── img
│ │ ├── hero.png
│ │ └── global
│ │ │ ├── app-icon-192.png
│ │ │ ├── app-icon-512.png
│ │ │ └── apple-touch-icon.png
│ ├── ico
│ │ └── favicon.ico
│ └── manifest.json
├── request-processor.js
├── assets
│ └── svg
│ │ ├── close.svg
│ │ ├── plus.svg
│ │ ├── lock.svg
│ │ ├── file.svg
│ │ ├── payment.svg
│ │ ├── social-facebook.svg
│ │ ├── hamburger.svg
│ │ ├── check.svg
│ │ ├── chevron-up.svg
│ │ ├── chevron-left.svg
│ │ ├── chevron-down.svg
│ │ ├── chevron-right.svg
│ │ ├── heart-solid.svg
│ │ ├── alert.svg
│ │ ├── info.svg
│ │ ├── location.svg
│ │ ├── check-circle.svg
│ │ ├── dashboard.svg
│ │ ├── flag-fr.svg
│ │ ├── visibility.svg
│ │ ├── social-youtube.svg
│ │ ├── brand-logo.svg
│ │ ├── account.svg
│ │ ├── heart.svg
│ │ ├── flag-gb.svg
│ │ ├── search.svg
│ │ ├── social-twitter.svg
│ │ ├── figma-logo.svg
│ │ ├── user.svg
│ │ ├── plug.svg
│ │ ├── flag-cn.svg
│ │ ├── basket.svg
│ │ ├── signout.svg
│ │ ├── social-pinterest.svg
│ │ ├── flag-ca.svg
│ │ ├── visibility-off.svg
│ │ ├── cc-visa.svg
│ │ ├── social-instagram.svg
│ │ ├── receipt.svg
│ │ ├── filter.svg
│ │ ├── cc-cvv.svg
│ │ ├── cc-mastercard.svg
│ │ └── like.svg
├── theme
│ ├── foundations
│ │ ├── space.js
│ │ ├── gradients.js
│ │ ├── shadows.js
│ │ ├── sizes.js
│ │ ├── styles.js
│ │ └── layerStyles.js
│ └── components
│ │ ├── base
│ │ ├── modal.js
│ │ ├── skeleton.js
│ │ ├── formLabel.js
│ │ ├── icon.js
│ │ ├── select.js
│ │ ├── container.js
│ │ ├── alert.js
│ │ ├── accordion.js
│ │ ├── tooltip.js
│ │ ├── badge.js
│ │ ├── drawer.js
│ │ ├── checkbox.js
│ │ ├── radio.js
│ │ ├── input.js
│ │ └── popover.js
│ │ └── project
│ │ ├── pagination.js
│ │ ├── breadcrumb.js
│ │ ├── _app.js
│ │ ├── offline-banner.js
│ │ ├── nested-accordion.js
│ │ ├── product-tile.js
│ │ ├── checkout-footer.js
│ │ ├── locale-selector.js
│ │ ├── links-list.js
│ │ ├── social-icons.js
│ │ ├── drawer-menu.js
│ │ └── image-gallery.js
├── utils
│ ├── builder.js
│ ├── phone-utils.test.js
│ ├── queue.js
│ ├── phone-utils.js
│ ├── password-utils.js
│ └── queue.test.js
├── routes.test.js
├── main.jsx
├── hooks
│ ├── use-categories.js
│ ├── use-currency.js
│ ├── use-wishlist.js
│ ├── index.js
│ ├── use-site.js
│ ├── use-locale.js
│ ├── use-limit-urls.js
│ ├── use-sort-urls.js
│ ├── use-page-urls.js
│ ├── use-variation-params.js
│ ├── use-limit-urls.test.js
│ ├── use-variant.js
│ ├── use-currency.test.js
│ ├── use-page-urls.test.js
│ ├── use-sort-urls.test.js
│ ├── use-categories.test.js
│ ├── use-locale.test.js
│ ├── use-navigation.js
│ ├── use-site.test.js
│ └── use-toast.test.js
├── request-processor.test.js
├── pages
│ ├── checkout
│ │ └── partials
│ │ │ ├── checkout-header.test.js
│ │ │ ├── checkout-footer.test.js
│ │ │ └── contact-info.test.js
│ ├── login-redirect
│ │ ├── index.test.js
│ │ └── index.jsx
│ ├── home
│ │ └── index.test.js
│ ├── cart
│ │ └── partials
│ │ │ ├── cart-title.jsx
│ │ │ └── cart-cta.jsx
│ ├── account
│ │ ├── orders.jsx
│ │ ├── wishlist
│ │ │ └── partials
│ │ │ │ └── wishlist-primary-action.test.js
│ │ └── constant.js
│ ├── page-not-found
│ │ └── index.test.js
│ ├── product-list
│ │ └── partials
│ │ │ ├── link-refinements.jsx
│ │ │ ├── checkbox-refinements.jsx
│ │ │ └── page-header.jsx
│ └── marketing-pages
│ │ └── index.jsx
├── components
│ ├── offline-banner
│ │ ├── index.test.js
│ │ └── index.jsx
│ ├── blocks
│ │ ├── product-box
│ │ │ └── product-box.builder.jsx
│ │ ├── products-grid
│ │ │ └── prouducts-grid.builder.js
│ │ └── einstein-products-grid
│ │ │ ├── index.jsx
│ │ │ └── einstein-products-grid.builder.jsx
│ ├── basic-tile
│ │ └── index.test.js
│ ├── icons
│ │ └── index.test.js
│ ├── breadcrumb
│ │ └── index.test.js
│ ├── footer
│ │ └── index.test.js
│ ├── scroll-to-top
│ │ ├── index.jsx
│ │ └── index.test.js
│ ├── address-display
│ │ └── index.jsx
│ ├── pagination
│ │ └── index.test.js
│ ├── _app-config
│ │ └── index.test.js
│ ├── forms
│ │ ├── reset-password-fields.jsx
│ │ ├── login-fields.jsx
│ │ ├── usePromoCodeFields.jsx
│ │ ├── useResetPasswordFields.jsx
│ │ ├── profile-fields.jsx
│ │ ├── registration-fields.jsx
│ │ ├── promo-code-fields.jsx
│ │ ├── post-checkout-registration-fields.jsx
│ │ ├── useLoginFields.jsx
│ │ ├── address-fields.jsx
│ │ ├── update-password-fields.jsx
│ │ └── form-action-buttons.jsx
│ ├── item-variant
│ │ ├── item-name.jsx
│ │ └── index.jsx
│ ├── _error
│ │ └── index.test.js
│ ├── social-icons
│ │ └── index.test.js
│ ├── seo
│ │ └── index.jsx
│ ├── responsive
│ │ └── index.jsx
│ ├── product-item
│ │ └── index.test.js
│ ├── locale-text
│ │ └── index.test.js
│ ├── hero
│ │ └── index.test.js
│ ├── product-tile
│ │ └── index.test.js
│ ├── loading-spinner
│ │ └── index.jsx
│ ├── link
│ │ └── index.jsx
│ ├── locale-selector
│ │ └── index.test.js
│ ├── search
│ │ └── partials
│ │ │ ├── suggestions.jsx
│ │ │ └── search-suggestions.jsx
│ ├── drawer-menu
│ │ └── index.test.js
│ ├── page-action-placeholder
│ │ └── index.jsx
│ ├── product-view-modal
│ │ ├── index.jsx
│ │ └── index.test.js
│ └── links-list
│ │ └── index.test.js
└── commerce-api
│ ├── shopper-baskets.js
│ ├── mocks
│ └── empty-basket.js
│ ├── hooks
│ ├── useSearchSuggestions.js
│ ├── useRefinementToggle.js
│ └── useEinstein.js
│ ├── pkce.js
│ └── __mocks__
│ └── einstein.js
├── .prettierignore
├── .eslintignore
├── .prettierrc.yaml
├── cache-hash-config.json
├── babel.config.js
├── .eslintrc.js
├── .gitignore
├── config
├── sites.js
└── .gitignore
├── worker
└── main.js
├── jest.config.js
├── LICENSE
└── tests
└── lighthouserc.js
/app/static/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | build
2 | docs
3 | coverage
4 | scripts/generator/assets
5 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build
2 | coverage
3 | docs
4 | app/static
5 | jest.config.js
6 | webpack
7 | scripts/generator/assets
8 |
--------------------------------------------------------------------------------
/app/static/img/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BuilderIO/sfcc-composable-storefront-example/main/app/static/img/hero.png
--------------------------------------------------------------------------------
/app/static/ico/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BuilderIO/sfcc-composable-storefront-example/main/app/static/ico/favicon.ico
--------------------------------------------------------------------------------
/.prettierrc.yaml:
--------------------------------------------------------------------------------
1 | printWidth: 100
2 | singleQuote: true
3 | semi: false
4 | bracketSpacing: false
5 | tabWidth: 4
6 | arrowParens: 'always'
7 |
--------------------------------------------------------------------------------
/app/static/img/global/app-icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BuilderIO/sfcc-composable-storefront-example/main/app/static/img/global/app-icon-192.png
--------------------------------------------------------------------------------
/app/static/img/global/app-icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BuilderIO/sfcc-composable-storefront-example/main/app/static/img/global/app-icon-512.png
--------------------------------------------------------------------------------
/app/request-processor.js:
--------------------------------------------------------------------------------
1 | export const processRequest = ({path, querystring}) => {
2 | return {
3 | path,
4 | querystring
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/app/static/img/global/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BuilderIO/sfcc-composable-storefront-example/main/app/static/img/global/apple-touch-icon.png
--------------------------------------------------------------------------------
/cache-hash-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | "app/static/**/*"
4 | ],
5 | "baseDir": "app",
6 | "hashLength": 8,
7 | "destinationFolder": "app"
8 | }
9 |
--------------------------------------------------------------------------------
/app/assets/svg/close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
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 = require('pwa-kit-dev/configs/babel/babel-config')
8 |
--------------------------------------------------------------------------------
/app/theme/foundations/space.js:
--------------------------------------------------------------------------------
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 | export default {
8 | 11: '2.75rem'
9 | }
10 |
--------------------------------------------------------------------------------
/app/utils/builder.js:
--------------------------------------------------------------------------------
1 | export default {
2 | apiKey: 'd1ed12c3338144da8dd6b63b35d14c30',
3 | announcementBarModel: 'announcement-bar',
4 | categoryHeroModel: 'category-hero',
5 | productFooterModel: 'product-footer',
6 | pageModel: 'page',
7 | cartUpsellModel: 'cart-modal-upsell',
8 | blogArticleModel: 'blog-article'
9 | }
10 |
--------------------------------------------------------------------------------
/app/theme/foundations/gradients.js:
--------------------------------------------------------------------------------
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 | export default {
8 | imageBackground: 'linear(270deg, #E6E5EA, #EEEEEE)'
9 | }
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
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 | module.exports = {
9 | extends: require.resolve('pwa-kit-dev/configs/eslint/eslint-config')
10 | }
11 |
--------------------------------------------------------------------------------
/app/theme/components/base/modal.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | dialog: {borderRadius: 'base'}
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/theme/foundations/shadows.js:
--------------------------------------------------------------------------------
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 | export default {
8 | top: '0px -1px 3px rgba(0, 0, 0, 0.1), 0px -1px 2px rgba(0, 0, 0, 0.06)'
9 | }
10 |
--------------------------------------------------------------------------------
/app/static/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "start_url": "/?homescreen=1",
3 | "background_color": "#fff",
4 | "theme_color": "#4e439b",
5 | "display": "standalone",
6 | "icons": [
7 | {
8 | "src": "./img/global/app-icon-192.png",
9 | "sizes": "192x192"
10 | },
11 | {
12 | "src": "./img/global/app-icon-512.png",
13 | "sizes": "512x512"
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/app/theme/components/base/skeleton.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | borderRadius: 'base',
10 | opacity: 0.3
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/assets/svg/plus.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/svg/lock.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/theme/components/base/formLabel.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | marginBottom: 1,
10 | fontSize: 'sm',
11 | fontWeight: 'semibold'
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/theme/components/base/icon.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | display: 'inline-block',
10 | verticalAlign: 'bottom',
11 | boxSize: 6
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/assets/svg/file.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/theme/components/base/select.js:
--------------------------------------------------------------------------------
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 | const mdSize = {height: 11, h: 11, borderRadius: 'base'}
8 |
9 | export default {
10 | sizes: {
11 | md: {
12 | field: mdSize
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/routes.test.js:
--------------------------------------------------------------------------------
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 routes from './routes'
8 |
9 | describe('Routes', () => {
10 | test('exports a valid react-router configuration', () => {
11 | expect(Array.isArray(routes) || typeof routes === 'function').toBe(true)
12 | })
13 | })
14 |
--------------------------------------------------------------------------------
/app/theme/components/base/container.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | maxWidth: 'container.xxl'
10 | },
11 | variants: {
12 | form: {
13 | maxWidth: '522px',
14 | px: 0
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/assets/svg/payment.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/theme/foundations/sizes.js:
--------------------------------------------------------------------------------
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 | export default {
8 | 11: '2.75rem',
9 |
10 | container: {
11 | sm: '640px',
12 | md: '768px',
13 | lg: '1024px',
14 | xl: '1200px',
15 | xxl: '1440px',
16 | xxxl: '1560px'
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/main.jsx:
--------------------------------------------------------------------------------
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 {start, registerServiceWorker} from 'pwa-kit-react-sdk/ssr/browser/main'
8 |
9 | const main = () => {
10 | // The path to your service worker should match what is set up in ssr.js
11 | return Promise.all([start(), registerServiceWorker('/worker.js')])
12 | }
13 |
14 | main()
15 |
--------------------------------------------------------------------------------
/app/hooks/use-categories.js:
--------------------------------------------------------------------------------
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 {useContext} from 'react'
8 | import {CategoriesContext} from '../contexts'
9 |
10 | /**
11 | * Custom React hook to get the categories
12 | * @returns {{categories: Object, setCategories: function}[]}
13 | */
14 | export const useCategories = () => useContext(CategoriesContext)
15 |
--------------------------------------------------------------------------------
/app/theme/components/base/alert.js:
--------------------------------------------------------------------------------
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 | export default {
8 | variants: {
9 | subtle: (props) => ({
10 | container: {
11 | borderColor: `${props.colorScheme || 'green'}.600`,
12 | borderWidth: 1,
13 | borderStyle: 'solid'
14 | }
15 | })
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .nyc_output
2 | build.tar
3 |
4 | coverage
5 | tests/reports
6 | tests/screenshots
7 | tests/lighthouse-reports/
8 | lighthouse/audit*
9 | .lighthouseci
10 |
11 | .tern-port
12 | app/integration-manager/docs
13 | messaging/*.csr
14 |
15 | # Local App Configuration Files
16 | config/local.*
17 |
18 | # Elastic Beanstalk Files
19 | .elasticbeanstalk/*
20 | !.elasticbeanstalk/*.cfg.yml
21 | !.elasticbeanstalk/*.global.yml
22 |
23 | build/
24 | tmp/
25 | *.log
26 | node_modules
27 |
28 | # Generated files
29 | app/cache-hash-manifest.json
30 | app/loader-cache-hash-manifest.json
31 |
32 | .vscode
--------------------------------------------------------------------------------
/app/theme/components/base/accordion.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | button: {
10 | paddingLeft: 0,
11 |
12 | _hover: {
13 | background: 'none'
14 | }
15 | },
16 | panel: {
17 | paddingTop: 0,
18 | paddingBottom: 0
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/hooks/use-currency.js:
--------------------------------------------------------------------------------
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 {useContext} from 'react'
8 | import {CurrencyContext} from '../contexts'
9 |
10 | /**
11 | * Custom React hook to get the currency for the active locale and to change it to a different currency
12 | * @returns {{currency: string, setCurrency: function}[]}
13 | */
14 | export const useCurrency = () => useContext(CurrencyContext)
15 |
--------------------------------------------------------------------------------
/app/hooks/use-wishlist.js:
--------------------------------------------------------------------------------
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 useCustomerProductList from '../commerce-api/hooks/useCustomerProductList'
8 |
9 | const PWA_DEFAULT_WISHLIST_NAME = 'PWA wishlist'
10 | const PWA_DEFAULT_WISHLIST_TYPE = 'wish_list'
11 |
12 | const useWishlist = () =>
13 | useCustomerProductList(PWA_DEFAULT_WISHLIST_NAME, PWA_DEFAULT_WISHLIST_TYPE)
14 |
15 | export default useWishlist
16 |
--------------------------------------------------------------------------------
/app/assets/svg/social-facebook.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/svg/hamburger.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/theme/foundations/styles.js:
--------------------------------------------------------------------------------
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 | export default {
8 | global: {
9 | 'html, body': {
10 | backgroundColor: 'white',
11 | color: 'gray.900'
12 | },
13 | body: {
14 | minHeight: '100vh'
15 | },
16 | '.react-target': {
17 | display: 'flex',
18 | minHeight: '100vh'
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/theme/components/base/tooltip.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | '--tooltip-bg': `colors.blue.800`,
10 | px: 2,
11 | py: 2,
12 | bg: 'var(--tooltip-bg)',
13 | '--popper-arrow-bg': 'var(--tooltip-bg)',
14 | color: 'whiteAlpha.900',
15 | borderRadius: 'base',
16 | maxW: '280px',
17 | lineHeight: '1.5em'
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/request-processor.test.js:
--------------------------------------------------------------------------------
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 {processRequest} from './request-processor'
8 |
9 | describe('processRequest', () => {
10 | test('returns valid values', () => {
11 | const result = processRequest({path: 'path', querystring: 'querystring'})
12 |
13 | expect(result.path).toEqual(expect.any(String))
14 | expect(result.querystring).toEqual(expect.any(String))
15 | })
16 | })
17 |
--------------------------------------------------------------------------------
/app/assets/svg/check.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/pages/checkout/partials/checkout-header.test.js:
--------------------------------------------------------------------------------
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 {screen} from '@testing-library/react'
9 |
10 | import CheckoutHeader from './checkout-header'
11 | import {renderWithProviders} from '../../../utils/test-utils'
12 |
13 | test('renders component', () => {
14 | renderWithProviders()
15 | expect(screen.getByTitle(/back to homepage/i)).toBeInTheDocument()
16 | })
17 |
--------------------------------------------------------------------------------
/app/pages/checkout/partials/checkout-footer.test.js:
--------------------------------------------------------------------------------
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 {screen} from '@testing-library/react'
9 |
10 | import CheckoutFooter from './checkout-footer'
11 | import {renderWithProviders} from '../../../utils/test-utils'
12 |
13 | test('renders component', () => {
14 | renderWithProviders()
15 | expect(screen.getByRole('link', {name: 'Shipping'})).toBeInTheDocument()
16 | })
17 |
--------------------------------------------------------------------------------
/app/assets/svg/chevron-up.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/svg/chevron-left.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/offline-banner/index.test.js:
--------------------------------------------------------------------------------
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 {renderWithProviders} from '../../utils/test-utils'
9 | import OfflineBanner from './index'
10 | import {screen} from '@testing-library/react'
11 |
12 | test('OfflineBanner component is rendered appropriately', () => {
13 | renderWithProviders()
14 | expect(screen.getByText("You're currently browsing in offline mode")).toBeInTheDocument()
15 | })
16 |
--------------------------------------------------------------------------------
/app/theme/components/project/pagination.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | button: {
10 | color: 'black'
11 | },
12 | container: {},
13 | text: {
14 | whiteSpace: 'nowrap',
15 | paddingLeft: 4,
16 | paddingRight: 4,
17 | paddingTop: 2,
18 | paddingBottom: 2
19 | }
20 | },
21 | parts: ['button', 'container', 'text']
22 | }
23 |
--------------------------------------------------------------------------------
/app/utils/phone-utils.test.js:
--------------------------------------------------------------------------------
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 * as utils from './phone-utils'
8 |
9 | test('formats a phone number', () => {
10 | expect(utils.formatPhoneNumber()).toBeUndefined()
11 | expect(utils.formatPhoneNumber('')).toEqual('')
12 | expect(utils.formatPhoneNumber('727')).toEqual('727')
13 | expect(utils.formatPhoneNumber('727555')).toEqual('(727) 555')
14 | expect(utils.formatPhoneNumber('7275551234')).toEqual('(727) 555-1234')
15 | })
16 |
--------------------------------------------------------------------------------
/config/sites.js:
--------------------------------------------------------------------------------
1 | // Provide the sites for your app. Each site includes site id, and its localization configuration.
2 | // You can also provide aliases for your locale. They will be used in place of your locale id when generating paths across the app
3 | module.exports = [
4 | {
5 | id: 'RefArch',
6 | l10n: {
7 | supportedCurrencies: ['USD'],
8 | defaultCurrency: 'USD',
9 | defaultLocale: 'en-US',
10 | supportedLocales: [
11 | {
12 | id: 'en-US',
13 | // alias: 'us',
14 | preferredCurrency: 'USD'
15 | }
16 | ]
17 | }
18 | }
19 | ]
20 |
--------------------------------------------------------------------------------
/app/assets/svg/chevron-down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/blocks/product-box/product-box.builder.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Builder} from '@builder.io/react'
3 | import loadable from '@loadable/component'
4 | import {Skeleton} from '@chakra-ui/react'
5 | const fallback =
6 |
7 | const ProductBox = loadable(() => import('./index'), {fallback})
8 |
9 | Builder.registerComponent(ProductBox, {
10 | name: 'ProductBox',
11 | image: 'https://unpkg.com/css.gg@2.0.0/icons/svg/box.svg',
12 | inputs: [
13 | {
14 | name: 'productRef',
15 | friendlyName: 'Product',
16 | type: 'SFCommerceProduct',
17 | required: true
18 | }
19 | ]
20 | })
21 |
--------------------------------------------------------------------------------
/app/pages/login-redirect/index.test.js:
--------------------------------------------------------------------------------
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 {renderWithReactIntl} from '../../utils/test-utils'
9 | import LoginRedirect from './index'
10 |
11 | test('Login Redirect renders without errors', () => {
12 | const {getByRole} = renderWithReactIntl()
13 |
14 | expect(getByRole('heading', {name: /login redirect/i})).toBeInTheDocument()
15 | expect(typeof LoginRedirect.getTemplateName()).toEqual('string')
16 | })
17 |
--------------------------------------------------------------------------------
/app/pages/home/index.test.js:
--------------------------------------------------------------------------------
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 {renderWithProviders} from '../../utils/test-utils'
9 | import HomePage from './index'
10 |
11 | jest.mock('../../commerce-api/einstein')
12 |
13 | test('Home Page renders without errors', async () => {
14 | const {getByTestId} = renderWithProviders()
15 |
16 | expect(getByTestId('home-page')).toBeInTheDocument()
17 | expect(typeof HomePage.getTemplateName()).toEqual('string')
18 | })
19 |
--------------------------------------------------------------------------------
/app/theme/components/project/breadcrumb.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | container: {
10 | minHeight: 4,
11 | fontSize: 'sm'
12 | },
13 | icon: {
14 | display: 'flex',
15 | boxSize: 4,
16 | color: 'grey'
17 | },
18 | link: {
19 | paddingTop: 3,
20 | paddingBottom: 3
21 | }
22 | },
23 | parts: ['container', 'icon', 'link']
24 | }
25 |
--------------------------------------------------------------------------------
/app/assets/svg/chevron-right.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/blocks/products-grid/prouducts-grid.builder.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Builder} from '@builder.io/react'
3 | import loadable from '@loadable/component'
4 | import {Skeleton} from '@chakra-ui/react'
5 | const fallback =
6 |
7 | const ProductsGrid = loadable(() => import('./index'), {fallback})
8 |
9 | Builder.registerComponent(ProductsGrid, {
10 | name: 'ProductsGrid',
11 | image: 'https://unpkg.com/css.gg@2.0.0/icons/svg/list.svg',
12 | inputs: [
13 | {
14 | name: 'productIds',
15 | friendlyName: 'Products',
16 | type: 'SFCommerceProductsList',
17 | required: true
18 | }
19 | ]
20 | })
21 |
--------------------------------------------------------------------------------
/app/assets/svg/heart-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/assets/svg/alert.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/svg/info.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/hooks/index.js:
--------------------------------------------------------------------------------
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 | /* istanbul ignore file */
9 | export {useSearchParams} from './use-search-params'
10 | export {useLimitUrls} from './use-limit-urls'
11 | export {usePageUrls} from './use-page-urls'
12 | export {useSortUrls} from './use-sort-urls'
13 | export {useVariant} from './use-variant'
14 | export {useVariationAttributes} from './use-variation-attributes'
15 | export {useVariationParams} from './use-variation-params'
16 | export {useProduct} from './use-product'
17 | export {useCurrency} from './use-currency'
18 |
--------------------------------------------------------------------------------
/app/pages/login-redirect/index.jsx:
--------------------------------------------------------------------------------
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 | // This page is here along witht the `callback` route to handle the redirect
9 | // after a user logs in using the SLAS Implementation
10 |
11 | import React, {Fragment} from 'react'
12 |
13 | const LoginRedirect = () => {
14 | return (
15 |
16 | Login Redirect
17 |
18 | )
19 | }
20 |
21 | LoginRedirect.getTemplateName = () => 'login-redirect'
22 |
23 | export default LoginRedirect
24 |
--------------------------------------------------------------------------------
/app/assets/svg/location.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/theme/components/project/_app.js:
--------------------------------------------------------------------------------
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 theme from '@chakra-ui/theme'
8 |
9 | export default {
10 | baseStyle: {
11 | container: {
12 | flex: 1,
13 | display: 'flex',
14 | flexDirection: 'column',
15 | backgroundColor: 'white',
16 | minWidth: '375px'
17 | },
18 | headerWrapper: {
19 | position: 'sticky',
20 | top: 0,
21 | zIndex: theme.zIndices.sticky
22 | }
23 | },
24 | parts: ['container']
25 | }
26 |
--------------------------------------------------------------------------------
/app/theme/components/project/offline-banner.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | container: {
10 | paddingTop: 4,
11 | paddingBottom: 4,
12 | paddingLeft: [4, 4, 6, 6, 8],
13 | paddingRight: [4, 4, 6, 6, 8]
14 | },
15 | icon: {
16 | height: 5,
17 | width: 5
18 | },
19 | message: {
20 | paddingLeft: 2,
21 | fontWeight: 700
22 | }
23 | },
24 | parts: ['container', 'icon', 'message']
25 | }
26 |
--------------------------------------------------------------------------------
/app/assets/svg/check-circle.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/basic-tile/index.test.js:
--------------------------------------------------------------------------------
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 {renderWithProviders} from '../../utils/test-utils'
9 | import BasicTile from './index'
10 |
11 | test('BasicTile renders without errors', () => {
12 | const data = {
13 | title: 'title',
14 | href: '/category/womens-outfits',
15 | img: {
16 | src: 'src',
17 | alt: 'alt'
18 | }
19 | }
20 | const {getByText} = renderWithProviders()
21 |
22 | expect(getByText('title')).toBeInTheDocument()
23 | })
24 |
--------------------------------------------------------------------------------
/app/components/blocks/einstein-products-grid/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import RecommendedProducts from '../../recommended-products'
4 |
5 | export function EinsteinProductsGrid({recommender, title, product}) {
6 | return (
7 |
8 |
14 |
15 | )
16 | }
17 |
18 | EinsteinProductsGrid.propTypes = {
19 | /** recommender id */
20 | recommender: PropTypes.string,
21 | product: PropTypes.object,
22 | title: PropTypes.string
23 | }
24 |
25 | export default EinsteinProductsGrid
26 |
--------------------------------------------------------------------------------
/app/hooks/use-site.js:
--------------------------------------------------------------------------------
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 {useLocation} from 'react-router-dom'
9 | import {resolveSiteFromUrl} from '../utils/site-utils'
10 | import {useMemo} from 'react'
11 |
12 | /**
13 | * This hook returns the current site based on current location
14 | *
15 | * @returns {Object} - current site
16 | */
17 | const useSite = () => {
18 | const {pathname, search} = useLocation()
19 | const site = useMemo(() => {
20 | return resolveSiteFromUrl(`${pathname}${search}`)
21 | }, [pathname, search])
22 | return site
23 | }
24 |
25 | export default useSite
26 |
--------------------------------------------------------------------------------
/app/theme/components/base/badge.js:
--------------------------------------------------------------------------------
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 | export default {
8 | variants: {
9 | notification: {
10 | display: 'inline-flex',
11 | justifyContent: 'center',
12 | position: 'absolute',
13 | top: 0,
14 | right: 0,
15 | minWidth: 5,
16 | height: 5,
17 | color: 'white',
18 | fontSize: 'xs',
19 | backgroundColor: 'blue.500',
20 | border: '1px solid',
21 | borderColor: 'white',
22 | borderRadius: 'full'
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/theme/components/base/drawer.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | header: {
10 | paddingTop: 1,
11 | paddingRight: [4, 4, 6, 6],
12 | paddingBottom: 1,
13 | paddingLeft: [4, 4, 6, 6],
14 | boxShadow: 'base'
15 | },
16 | body: {
17 | padding: [4, 4, 6, 6]
18 | },
19 | footer: {
20 | paddingTop: 6,
21 | paddingRight: [4, 4, 6, 6],
22 | paddingBottom: 11,
23 | paddingLest: [4, 4, 6, 6]
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/assets/svg/dashboard.svg:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/app/assets/svg/flag-fr.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/theme/components/project/nested-accordion.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | container: {},
10 | nestedAccordion: {
11 | paddingLeft: 4
12 | },
13 | internalButton: {},
14 | internalButtonIcon: {
15 | color: 'grey',
16 | marginRight: 2
17 | },
18 | leafButton: {
19 | color: 'black',
20 | paddingLeft: 8,
21 | paddingTop: 2,
22 | paddingBottom: 2
23 | }
24 | },
25 | parts: ['container', 'nestedAccordion', 'internalButton', 'leafButtonIcon', 'leafButton']
26 | }
27 |
--------------------------------------------------------------------------------
/app/assets/svg/visibility.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/hooks/use-locale.js:
--------------------------------------------------------------------------------
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 useSite from './use-site'
9 | import {useMemo} from 'react'
10 | import {resolveLocaleFromUrl} from '../utils/utils'
11 | import {useLocation} from 'react-router-dom'
12 |
13 | /**
14 | * This hook returns the locale object based on current location
15 | * @return {object} locale
16 | */
17 | const useLocale = () => {
18 | const {pathname, search} = useLocation()
19 | const site = useSite()
20 | const locale = useMemo(() => {
21 | return resolveLocaleFromUrl(`${pathname}${search}`)
22 | }, [pathname, search, site])
23 |
24 | return locale
25 | }
26 |
27 | export default useLocale
28 |
--------------------------------------------------------------------------------
/app/components/icons/index.test.js:
--------------------------------------------------------------------------------
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 {within} from '@testing-library/dom'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 | import * as Icons from './index'
11 |
12 | test('renders svg icons with Chakra Icon component', () => {
13 | renderWithProviders()
14 | const svg = document.querySelector('.chakra-icon')
15 | const use = within(svg).getByRole('presentation')
16 | expect(svg).toBeInTheDocument()
17 | expect(use).toBeInTheDocument()
18 | expect(svg).toHaveAttribute('viewBox', '0 0 24 24')
19 | expect(use).toHaveAttribute('xlink:href', '#check')
20 | })
21 |
--------------------------------------------------------------------------------
/app/assets/svg/social-youtube.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/config/.gitignore:
--------------------------------------------------------------------------------
1 | ### macOS ###
2 | # General
3 | .DS_Store
4 | .AppleDouble
5 | .LSOverride
6 |
7 | # Thumbnails
8 | ._*
9 |
10 | ### react ###
11 | .DS_*
12 | *.log
13 | logs
14 | **/*.backup.*
15 | **/*.back.*
16 |
17 | node_modules
18 | bower_components
19 |
20 | *.sublime*
21 |
22 |
23 | ### TortoiseGit ###
24 | # Project-level settings
25 | /.tgitconfig
26 |
27 | ### VisualStudioCode ###
28 | .vscode/*
29 | !.vscode/settings.json
30 | !.vscode/tasks.json
31 | !.vscode/launch.json
32 | !.vscode/extensions.json
33 | *.code-workspace
34 |
35 |
36 | ### Windows ###
37 | # Windows thumbnail cache files
38 | Thumbs.db
39 | Thumbs.db:encryptable
40 | ehthumbs.db
41 | ehthumbs_vista.db
42 |
43 | # Folder config file
44 | [Dd]esktop.ini
45 |
46 | # Recycle Bin used on file shares
47 | $RECYCLE.BIN/
48 |
49 | # build dist folders
50 | build/
51 |
52 | # Layer0 generated build directory
53 | .layer0
54 |
--------------------------------------------------------------------------------
/app/components/breadcrumb/index.test.js:
--------------------------------------------------------------------------------
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 Breadcrumb from './index'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 |
11 | const mockCategories = [
12 | {
13 | id: 1,
14 | name: 'Category 1'
15 | },
16 | {
17 | id: 2,
18 | name: 'Category 2'
19 | },
20 | {
21 | id: 3,
22 | name: 'Category 3'
23 | }
24 | ]
25 |
26 | test('Renders Breadcrum', () => {
27 | const {getAllByTestId} = renderWithProviders()
28 |
29 | expect(getAllByTestId('sf-crumb-item').length).toEqual(mockCategories.length)
30 | })
31 |
--------------------------------------------------------------------------------
/app/components/footer/index.test.js:
--------------------------------------------------------------------------------
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 {screen} from '@testing-library/react'
9 |
10 | import Footer from './index'
11 | import {renderWithProviders} from '../../utils/test-utils'
12 |
13 | test('renders component', () => {
14 | renderWithProviders()
15 | expect(screen.getByRole('link', {name: 'Privacy Policy'})).toBeInTheDocument()
16 | })
17 |
18 | test('renders mobile version by default', () => {
19 | renderWithProviders()
20 | // This link is hidden initially, but would be shown for desktop
21 | expect(screen.getByRole('link', {name: 'About Us', hidden: true})).toBeInTheDocument()
22 | })
23 |
--------------------------------------------------------------------------------
/app/components/scroll-to-top/index.jsx:
--------------------------------------------------------------------------------
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 {useEffect} from 'react'
8 | import {useLocation} from 'react-router-dom'
9 |
10 | /**
11 | * ScrollToTop will scroll the viewport to the top whenever the current URL
12 | * changes. If this component doesn't meet the needs of your layout, take a look
13 | * at this [guide]{@link https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/guides/scroll-restoration.md}.
14 | *
15 | */
16 | export default function ScrollToTop() {
17 | const {pathname} = useLocation()
18 |
19 | useEffect(() => {
20 | window.scrollTo(0, 0)
21 | }, [pathname])
22 |
23 | return null
24 | }
25 |
--------------------------------------------------------------------------------
/app/utils/queue.js:
--------------------------------------------------------------------------------
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 | // A standard FIFO queue implementation
9 | export default class Queue {
10 | constructor() {
11 | this._queue = []
12 | }
13 |
14 | get length() {
15 | return this._queue.length
16 | }
17 |
18 | get isEmpty() {
19 | return this._queue.length === 0
20 | }
21 |
22 | enqueue(item) {
23 | this._queue.push(item)
24 | }
25 |
26 | dequeue() {
27 | return this._queue.shift()
28 | }
29 |
30 | async process(callback) {
31 | while (!this.isEmpty) {
32 | const item = this.dequeue()
33 | await callback(item)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/theme/components/base/checkbox.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | container: {style: {alignItems: 'baseline'}},
10 | label: {
11 | width: 'full'
12 | },
13 | control: {
14 | marginTop: '2px',
15 | _checked: {
16 | backgroundColor: 'blue.600',
17 | borderColor: 'blue.600',
18 | _hover: {
19 | bg: 'blue.700',
20 | borderColor: 'blue.700'
21 | }
22 | }
23 | }
24 | },
25 | sizes: {
26 | md: {
27 | label: {fontSize: 'sm'}
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/assets/svg/brand-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/utils/phone-utils.js:
--------------------------------------------------------------------------------
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 | /**
9 | * Formats the given phone number to add spaces and symbols
10 | * @param {string} - Phone number to be formatted
11 | * @returns {string} - Formatted phone number
12 | */
13 | export const formatPhoneNumber = (value) => {
14 | if (!value) return value
15 | const phoneNumber = value.replace(/[^\d]/g, '')
16 | const phoneNumberLength = phoneNumber.length
17 | if (phoneNumberLength < 4) return phoneNumber
18 | if (phoneNumberLength < 7) {
19 | return `(${phoneNumber.slice(0, 3)}) ${phoneNumber.slice(3)}`
20 | }
21 | return `(${phoneNumber.slice(0, 3)}) ${phoneNumber.slice(3, 6)}-${phoneNumber.slice(6, 10)}`
22 | }
23 |
--------------------------------------------------------------------------------
/app/assets/svg/account.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/utils/password-utils.js:
--------------------------------------------------------------------------------
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 | /**
9 | * Provides mapping of password requirements that have/haven't been met
10 | * @param {string} value - The password to validate
11 | * @returns {Object} - True/false for each password validation rule
12 | */
13 | export const validatePassword = (value) => {
14 | return {
15 | hasMinChars: value && value.length >= 8 ? true : false,
16 | hasUppercase: value && /[A-Z]/.test(value) ? true : false,
17 | hasLowercase: value && /[a-z]/.test(value) ? true : false,
18 | hasNumber: value && /\d/.test(value) ? true : false,
19 | hasSpecialChar: value && /[!@#$%^&*(),.?":{}|<>]/.test(value) ? true : false
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/assets/svg/heart.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/address-display/index.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Box, Text} from '@chakra-ui/react'
10 |
11 | const AddressDisplay = ({address}) => {
12 | return (
13 |
14 |
15 | {address.firstName} {address.lastName}
16 |
17 | {address.address1}
18 |
19 | {address.city}, {address.stateCode} {address.postalCode}
20 |
21 | {address.countryCode}
22 |
23 | )
24 | }
25 |
26 | AddressDisplay.propTypes = {
27 | address: PropTypes.object
28 | }
29 |
30 | export default AddressDisplay
31 |
--------------------------------------------------------------------------------
/app/components/pagination/index.test.js:
--------------------------------------------------------------------------------
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 Pagination from './index'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 |
11 | const mockUrls = ['/test?offset=0', '/test?offset=25', '/test?offset=50', '/test?offset=75']
12 | const mockCurrentUrl = '/test?offset=25'
13 |
14 | test('Renders Breadcrum', () => {
15 | const {getAllByRole} = renderWithProviders(
16 |
17 | )
18 |
19 | const [prev, next] = getAllByRole('link')
20 | const option = getAllByRole('option')
21 |
22 | expect(prev).toBeDefined()
23 | expect(next).toBeDefined()
24 | expect(option.length).toEqual(mockUrls.length)
25 | })
26 |
--------------------------------------------------------------------------------
/app/assets/svg/flag-gb.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/commerce-api/shopper-baskets.js:
--------------------------------------------------------------------------------
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 | import OcapiShopperBaskets from './ocapi-shopper-baskets'
8 | import * as sdk from 'commerce-sdk-isomorphic'
9 |
10 | // This class is an extension to OcapiShopperBaskets class to include basket functions implemented in SCAPI.
11 | // Current implementation has ShopperBaskets interactiing with OCAPI which misses new functions implemented in newer SCAPI releases.
12 | class ShopperBaskets extends OcapiShopperBaskets {
13 | constructor(config) {
14 | super(config)
15 | this.shopperBasketsClient = new sdk.ShopperBaskets(config)
16 | }
17 |
18 | mergeBasket(args) {
19 | return this.shopperBasketsClient.mergeBasket(args)
20 | }
21 | }
22 | export default ShopperBaskets
23 |
--------------------------------------------------------------------------------
/app/components/_app-config/index.test.js:
--------------------------------------------------------------------------------
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 {render} from '@testing-library/react'
9 | import AppConfig from './index.jsx'
10 |
11 | describe('AppConfig', () => {
12 | test('renders', () => {
13 | const {container} = render()
14 | expect(container).toBeDefined()
15 | })
16 |
17 | test('AppConfig static methods behave as expected', () => {
18 | const mockAPI = {}
19 | expect(AppConfig.restore()).toBe(undefined)
20 | expect(AppConfig.restore({frozen: 'any values here'})).toBe(undefined)
21 | expect(AppConfig.freeze()).toBe(undefined)
22 | expect(AppConfig.extraGetPropsArgs({api: mockAPI}).api).toEqual(mockAPI)
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/app/pages/cart/partials/cart-title.jsx:
--------------------------------------------------------------------------------
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 {FormattedMessage} from 'react-intl'
9 | import {Text} from '@chakra-ui/react'
10 | import useBasket from '../../../commerce-api/hooks/useBasket'
11 |
12 | const CartTitle = () => {
13 | const basket = useBasket()
14 | return (
15 |
16 |
21 |
22 | )
23 | }
24 |
25 | export default CartTitle
26 |
--------------------------------------------------------------------------------
/app/hooks/use-limit-urls.js:
--------------------------------------------------------------------------------
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 {useMemo} from 'react'
9 | import {useLocation} from 'react-router-dom'
10 |
11 | // Constants
12 | import {DEFAULT_LIMIT_VALUES} from '../constants'
13 |
14 | // Utils
15 | import {buildUrlSet} from '../utils/url'
16 |
17 | /*
18 | * Generate a memoized list of page size urls. Chaning the page size will reset
19 | * the offset to zero to simplify things.
20 | */
21 | export const useLimitUrls = () => {
22 | const location = useLocation()
23 |
24 | return useMemo(
25 | () =>
26 | buildUrlSet(`${location.pathname}${location.search}`, 'limit', DEFAULT_LIMIT_VALUES, {
27 | offset: 0
28 | }),
29 | [location.search, location.pathname]
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/app/theme/components/project/product-tile.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: () => ({
9 | container: {},
10 | favIcon: {
11 | position: 'absolute',
12 | variant: 'unstyled',
13 | top: 2,
14 | right: 2
15 | },
16 | imageWrapper: {
17 | position: 'relative',
18 | marginBottom: 2
19 | },
20 | image: {
21 | ratio: 1,
22 | paddingBottom: 2
23 | },
24 | price: {},
25 | title: {
26 | fontWeight: 600
27 | },
28 | rating: {},
29 | variations: {}
30 | }),
31 | parts: ['container', 'imageWrapper', 'image', 'price', 'title', 'rating', 'variations']
32 | }
33 |
--------------------------------------------------------------------------------
/app/assets/svg/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/theme/foundations/layerStyles.js:
--------------------------------------------------------------------------------
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 | const card = {
8 | py: 6,
9 | px: 4,
10 | backgroundColor: 'white',
11 | rounded: 'base',
12 | boxShadow: 'base'
13 | }
14 |
15 | const cardBordered = {
16 | ...card,
17 | px: [4, 4, 5, 6],
18 | border: '1px solid',
19 | borderColor: 'gray.50'
20 | }
21 |
22 | export default {
23 | card,
24 |
25 | cardBordered,
26 |
27 | ccIcon: {
28 | width: '34px',
29 | height: '22px'
30 | },
31 |
32 | page: {
33 | px: [4, 4, 6, 6, 8],
34 | paddingTop: [4, 4, 6, 6, 8],
35 | paddingBottom: 32,
36 | width: '100%',
37 | maxWidth: 'container.xxxl',
38 | marginLeft: 'auto',
39 | marginRight: 'auto'
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/components/forms/reset-password-fields.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Box} from '@chakra-ui/react'
10 | import useResetPasswordFields from './useResetPasswordFields'
11 | import Field from '../field'
12 |
13 | const ResetPasswordFields = ({form, prefix = ''}) => {
14 | const fields = useResetPasswordFields({form, prefix})
15 |
16 | return (
17 |
18 |
19 |
20 | )
21 | }
22 |
23 | ResetPasswordFields.propTypes = {
24 | /** Object returned from `useForm` */
25 | form: PropTypes.object.isRequired,
26 |
27 | /** Optional prefix for field names */
28 | prefix: PropTypes.string
29 | }
30 |
31 | export default ResetPasswordFields
32 |
--------------------------------------------------------------------------------
/app/components/forms/login-fields.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Stack} from '@chakra-ui/react'
10 | import useLoginFields from './useLoginFields'
11 | import Field from '../field'
12 |
13 | const LoginFields = ({form, prefix = ''}) => {
14 | const fields = useLoginFields({form, prefix})
15 |
16 | return (
17 |
18 |
19 |
20 |
21 | )
22 | }
23 |
24 | LoginFields.propTypes = {
25 | /** Object returned from `useForm` */
26 | form: PropTypes.object.isRequired,
27 |
28 | /** Optional prefix for field names */
29 | prefix: PropTypes.string
30 | }
31 |
32 | export default LoginFields
33 |
--------------------------------------------------------------------------------
/app/assets/svg/social-twitter.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/blocks/einstein-products-grid/einstein-products-grid.builder.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Builder} from '@builder.io/react'
3 | import loadable from '@loadable/component'
4 | import {Skeleton} from '@chakra-ui/react'
5 |
6 | const fallback =
7 | const EinsteinProductsGrid = loadable(() => import('./index'), {fallback})
8 |
9 | Builder.registerComponent(EinsteinProductsGrid, {
10 | name: 'EinsteinProductsGrid',
11 | image:
12 | 'https://cdn.builder.io/api/v1/image/assets%2Fd1ed12c3338144da8dd6b63b35d14c30%2F671167ab7faa41d59624c88acf109360',
13 | defaults: {
14 | bindings: {
15 | 'component.options.product': 'state.product'
16 | }
17 | },
18 | inputs: [
19 | {
20 | name: 'title',
21 | type: 'text',
22 | required: true
23 | },
24 | {
25 | name: 'recommender',
26 | type: 'SFCommerceRecommender',
27 | required: true
28 | }
29 | ]
30 | })
31 |
--------------------------------------------------------------------------------
/app/hooks/use-sort-urls.js:
--------------------------------------------------------------------------------
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 {useMemo} from 'react'
9 | import {useLocation} from 'react-router-dom'
10 |
11 | // Utils
12 | import {buildUrlSet} from '../utils/url'
13 |
14 | /*
15 | * Generate a memoized list of page size urls. Chaning the page size will reset
16 | * the offset to zero to simplify things.
17 | */
18 | export const useSortUrls = ({options = []}) => {
19 | const location = useLocation()
20 |
21 | return useMemo(
22 | () =>
23 | buildUrlSet(
24 | `${location.pathname}${location.search}`,
25 | 'sort',
26 | options.map(({id}) => id),
27 | {
28 | offset: 0
29 | }
30 | ),
31 | [location.pathname, location.search, options]
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/app/theme/components/base/radio.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | container: {display: 'flex'},
10 | label: {
11 | width: 'full'
12 | },
13 | control: {
14 | backgroundColor: 'white',
15 | _checked: {
16 | backgroundColor: 'blue.600',
17 | borderColor: 'blue.600',
18 | _hover: {
19 | backgroundColor: 'blue.700',
20 | borderColor: 'blue.700'
21 | }
22 | },
23 | _indeterminate: {}
24 | }
25 | },
26 | sizes: {
27 | md: {
28 | container: {alignItems: 'flex-start'},
29 | control: {marginTop: '0.25em'},
30 | label: {marginLeft: 3}
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/theme/components/project/checkout-footer.js:
--------------------------------------------------------------------------------
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 Footer from './footer'
8 |
9 | const {baseStyle} = Footer
10 |
11 | export default {
12 | parts: [
13 | 'container',
14 | 'content',
15 | 'horizontalRule',
16 | 'bottomHalf',
17 | 'copyright',
18 | 'creditCardIcon',
19 | 'customerService'
20 | ],
21 | baseStyle: {
22 | container: baseStyle.container,
23 | content: baseStyle.content,
24 | horizontalRule: baseStyle.horizontalRule,
25 | bottomHalf: baseStyle.bottomHalf,
26 | copyright: baseStyle.copyright,
27 | creditCardIcon: {
28 | width: '38px',
29 | height: '22px'
30 | },
31 | customerService: {
32 | marginBottom: 6
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/assets/svg/figma-logo.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/app/assets/svg/user.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/item-variant/item-name.jsx:
--------------------------------------------------------------------------------
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 {useItemVariant} from '.'
9 | import Link from '../link'
10 |
11 | /**
12 | * In the context of a cart product item variant, this components simply renders
13 | * the item's name using the cart item field `productName`. We use this field
14 | * rather than variant `name` field as the variant detail may not yet be
15 | * available upon rendering.
16 | */
17 | const ItemName = (props) => {
18 | const variant = useItemVariant()
19 |
20 | return (
21 |
27 | {variant.productName || variant.name}
28 |
29 | )
30 | }
31 |
32 | export default ItemName
33 |
--------------------------------------------------------------------------------
/app/assets/svg/plug.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/_error/index.test.js:
--------------------------------------------------------------------------------
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 {screen} from '@testing-library/react'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 | import Error from './index'
11 |
12 | test('Error renders without errors', () => {
13 | expect(renderWithProviders())
14 | })
15 |
16 | test('Error status 500', () => {
17 | renderWithProviders()
18 | expect(screen.getByRole('heading', {level: 2})).toHaveTextContent("This page isn't working")
19 | })
20 |
21 | test('Error status 500 with stack trace', () => {
22 | renderWithProviders()
23 | expect(screen.getByRole('heading', {level: 2})).toHaveTextContent("This page isn't working")
24 | expect(screen.getByText(/stack trace error message/i)).toBeInTheDocument()
25 | })
26 |
--------------------------------------------------------------------------------
/app/assets/svg/flag-cn.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/utils/queue.test.js:
--------------------------------------------------------------------------------
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 Queue from './queue'
8 |
9 | test('Queue length', () => {
10 | const q = new Queue()
11 | q.enqueue(1)
12 | q.enqueue(2)
13 | expect(q.length).toEqual(2)
14 | })
15 |
16 | test('Queue isEmpty', () => {
17 | const q = new Queue()
18 | expect(q.isEmpty).toEqual(true)
19 | q.enqueue(1)
20 | expect(q.isEmpty).toEqual(false)
21 | })
22 |
23 | test('Queue FIFO', () => {
24 | const q = new Queue()
25 | q.enqueue(1)
26 | q.enqueue(2)
27 | expect(q.dequeue()).toEqual(1)
28 | expect(q.dequeue()).toEqual(2)
29 | })
30 |
31 | test('Queue async process', async () => {
32 | const q = new Queue()
33 | q.enqueue(1)
34 |
35 | return await q.process(async (item) => {
36 | await new Promise((resolve) => setTimeout(resolve, 10))
37 | expect(item).toEqual(1)
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/app/components/social-icons/index.test.js:
--------------------------------------------------------------------------------
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 SocialIcons from './index'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 | import {fireEvent} from '@testing-library/react'
11 |
12 | describe('Social Icons Component', () => {
13 | test('Renders SocialIcons', () => {
14 | renderWithProviders()
15 |
16 | const links = document.querySelectorAll('button')
17 |
18 | expect(links.length).toBeGreaterThan(0)
19 | })
20 |
21 | test('should open a new windown when an icon is clicked', () => {
22 | window.open = jest.fn()
23 | renderWithProviders()
24 |
25 | const links = document.querySelectorAll('button')
26 | // click the first link
27 | fireEvent.click(links[0])
28 | expect(global.open).toBeCalled()
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/app/components/seo/index.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import Helmet from 'react-helmet'
10 |
11 | import {DEFAULT_SITE_TITLE} from '../../constants'
12 |
13 | const Seo = ({title, description, noIndex, children, ...props}) => {
14 | const fullTitle = title ? `${title} | ${DEFAULT_SITE_TITLE}` : DEFAULT_SITE_TITLE
15 |
16 | return (
17 |
18 | {fullTitle}
19 | {description && }
20 | {noIndex && }
21 | {children}
22 |
23 | )
24 | }
25 |
26 | Seo.propTypes = {
27 | title: PropTypes.string,
28 | description: PropTypes.string,
29 | noIndex: PropTypes.bool,
30 | children: PropTypes.node
31 | }
32 |
33 | export default Seo
34 |
--------------------------------------------------------------------------------
/app/pages/account/orders.jsx:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import {Route, Switch, useRouteMatch} from 'react-router'
10 | import OrderHistory from './order-history'
11 | import OrderDetail from './order-detail'
12 | import {AccountOrdersProvider} from './util/order-context'
13 |
14 | const AccountOrders = () => {
15 | const {path} = useRouteMatch()
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | )
29 | }
30 |
31 | AccountOrders.getTemplateName = () => 'account-order-history'
32 |
33 | export default AccountOrders
34 |
--------------------------------------------------------------------------------
/app/components/item-variant/index.jsx:
--------------------------------------------------------------------------------
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, {createContext, useContext} from 'react'
8 | import PropTypes from 'prop-types'
9 |
10 | /**
11 | * This component and associated context/hook provide a convenient wrapper
12 | * around a group of components used for rendering product variant details.
13 | */
14 |
15 | const ItemVariantContext = createContext()
16 |
17 | export const useItemVariant = () => {
18 | return useContext(ItemVariantContext)
19 | }
20 |
21 | /**
22 | * The Provider component for rendering product item and variant detail.
23 | */
24 | const ItemVariantProvider = ({variant, children}) => {
25 | return {children}
26 | }
27 |
28 | ItemVariantProvider.propTypes = {
29 | variant: PropTypes.object,
30 | children: PropTypes.any
31 | }
32 |
33 | export default ItemVariantProvider
34 |
--------------------------------------------------------------------------------
/app/pages/page-not-found/index.test.js:
--------------------------------------------------------------------------------
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 PageNotFound from './index'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 | import {screen} from '@testing-library/react'
11 |
12 | // Set up and clean up
13 | beforeEach(() => {
14 | jest.resetModules()
15 | })
16 |
17 | const MockedComponent = () => {
18 | return
19 | }
20 |
21 | test('renders product item name, attributes and price', () => {
22 | renderWithProviders()
23 |
24 | expect(screen.getByText(/The page you're looking for can't be found/i)).toBeInTheDocument()
25 | expect(
26 | screen.getByText(
27 | /Please try retyping the address, going back to the previous page, or going to the home page./i
28 | )
29 | ).toBeInTheDocument()
30 | expect(screen.getByText(/Go to home page/i)).toBeInTheDocument()
31 | })
32 |
--------------------------------------------------------------------------------
/app/components/responsive/index.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Box} from '@chakra-ui/react'
10 |
11 | /**
12 | * Render the children in the DOM but visually hide them on desktop
13 | * @param children - isomorphic components used within a responsive design
14 | */
15 | export const HideOnDesktop = ({children}) => (
16 | {children}
17 | )
18 | HideOnDesktop.propTypes = {children: PropTypes.node}
19 |
20 | /**
21 | * Render the children in the DOM but visually hide them on mobile
22 | * @param children - isomorphic components used within a responsive design
23 | */
24 | export const HideOnMobile = ({children}) => (
25 | {children}
26 | )
27 | HideOnMobile.propTypes = {children: PropTypes.node}
28 |
29 | export default {HideOnMobile, HideOnDesktop}
30 |
--------------------------------------------------------------------------------
/app/components/offline-banner/index.jsx:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import {useIntl} from 'react-intl'
10 |
11 | // Components
12 | import {
13 | Alert,
14 | Text,
15 |
16 | // Hooks
17 | useStyleConfig
18 | } from '@chakra-ui/react'
19 |
20 | // Icons
21 | import {AlertIcon} from '../icons'
22 |
23 | const OfflineBanner = () => {
24 | const intl = useIntl()
25 | const style = useStyleConfig('OfflineBanner')
26 |
27 | return (
28 |
29 |
30 |
31 | {intl.formatMessage({
32 | id: 'offline_banner.description.browsing_offline_mode',
33 | defaultMessage: "You're currently browsing in offline mode"
34 | })}
35 |
36 |
37 | )
38 | }
39 |
40 | export default OfflineBanner
41 |
--------------------------------------------------------------------------------
/app/theme/components/project/locale-selector.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | accordion: {},
10 | container: {},
11 | selectedButtonIcon: {
12 | color: 'grey'
13 | },
14 | selectedButton: {
15 | paddingLeft: 0
16 | },
17 | selectedText: {
18 | flex: '1',
19 | textAlign: 'left',
20 | paddingLeft: 2
21 | },
22 | selectedIcon: {
23 | color: 'blue.600'
24 | },
25 | optionButton: {
26 | paddingLeft: 2
27 | },
28 | optionText: {
29 | paddingLeft: 2,
30 | paddingRight: 4,
31 | textAlign: 'left'
32 | }
33 | },
34 | parts: [
35 | 'accordion',
36 | 'container',
37 | 'selectedButton',
38 | 'selectedText',
39 | 'optionButton',
40 | 'optionText'
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/app/components/forms/usePromoCodeFields.jsx:
--------------------------------------------------------------------------------
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 {useIntl} from 'react-intl'
8 |
9 | export default function usePromoCodeFields({form: {control, errors}, prefix = ''}) {
10 | const {formatMessage} = useIntl()
11 |
12 | const fields = {
13 | code: {
14 | name: `${prefix}code`,
15 | label: formatMessage({
16 | defaultMessage: 'Promo Code',
17 | id: 'use_promo_code_fields.label.promo_code'
18 | }),
19 | type: 'text',
20 | defaultValue: '',
21 | rules: {
22 | required: formatMessage({
23 | defaultMessage: 'Please provide a valid promo code.',
24 | id: 'use_promo_code_fields.error.required_promo_code'
25 | })
26 | },
27 | error: errors[`${prefix}code`],
28 | control
29 | }
30 | }
31 |
32 | return fields
33 | }
34 |
--------------------------------------------------------------------------------
/app/assets/svg/basket.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/commerce-api/mocks/empty-basket.js:
--------------------------------------------------------------------------------
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 | export default {
8 | _v: '21.3',
9 | _resource_state: '860cde3040519cce439cd99e209f8a87c3ad0b7e2813edbf6f5501f763b73bd5',
10 | _type: 'basket',
11 | _flash: [],
12 | basket_id: 'bczFTaOjgEqUkaaadkvHwbgrP5',
13 | currency: 'USD',
14 | customer_info: {
15 | _type: 'customer_info',
16 | customer_id: 'customerid',
17 | email: ''
18 | },
19 | order_total: 0.0,
20 | product_sub_total: 0.0,
21 | product_total: 0.0,
22 | shipments: [
23 | {
24 | _type: 'shipment',
25 | id: 'me',
26 | shipment_id: 'bc5OTaOjgEqUoaaadkvHwbgrP5'
27 | }
28 | ],
29 | shipping_items: [
30 | {
31 | shipment_id: 'me',
32 | item_id: 'bcwsbaOjgEqUsaaadkvHwbgrP5'
33 | }
34 | ],
35 | shipping_total: 0.0,
36 | shipping_total_tax: 0.0,
37 | taxation: 'net',
38 | tax_total: 0.0
39 | }
40 |
--------------------------------------------------------------------------------
/app/components/product-item/index.test.js:
--------------------------------------------------------------------------------
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 ProductItem from './index'
9 | import {mockedCustomerProductListsDetails} from '../../commerce-api/mock-data'
10 | import {renderWithProviders} from '../../utils/test-utils'
11 | import {screen} from '@testing-library/react'
12 |
13 | // Set up and clean up
14 | beforeEach(() => {
15 | jest.resetModules()
16 | })
17 |
18 | jest.setTimeout(60000)
19 | const MockedComponent = () => {
20 | const product = mockedCustomerProductListsDetails.data[0]
21 | return
22 | }
23 |
24 | test('renders product item name, attributes and price', () => {
25 | renderWithProviders()
26 |
27 | expect(screen.getByText(/apple ipod nano/i)).toBeInTheDocument()
28 | expect(screen.getByText(/color: green/i)).toBeInTheDocument()
29 | expect(screen.getByText(/memory size: 16 GB/i)).toBeInTheDocument()
30 | })
31 |
--------------------------------------------------------------------------------
/app/assets/svg/signout.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/hooks/use-page-urls.js:
--------------------------------------------------------------------------------
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 {useMemo} from 'react'
9 | import {useLocation} from 'react-router-dom'
10 |
11 | // Utils
12 | import {buildUrlSet} from '../utils/url'
13 |
14 | // Hooks
15 | import {useSearchParams} from './use-search-params'
16 |
17 | /*
18 | * Generate a memoized list of page size urls. Chaning the page size will reset
19 | * the offset to zero to simplify things.
20 | */
21 | export const usePageUrls = ({total = 0, limit}) => {
22 | const location = useLocation()
23 | const [searchParams] = useSearchParams()
24 | const _limit = limit || searchParams.limit
25 |
26 | return useMemo(() => {
27 | const pageCount = Math.ceil(total / _limit)
28 |
29 | return buildUrlSet(
30 | `${location.pathname}${location.search}`,
31 | 'offset',
32 | new Array(pageCount).fill(0).map((_, index) => index * _limit)
33 | )
34 | }, [location.pathname, location.search, _limit, total])
35 | }
36 |
--------------------------------------------------------------------------------
/app/hooks/use-variation-params.js:
--------------------------------------------------------------------------------
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 {useLocation} from 'react-router-dom'
9 |
10 | /*
11 | * This hook will return only the params that are also product attributes for the
12 | * passed in product object.
13 | */
14 | export const useVariationParams = (product = {}) => {
15 | const {variationAttributes = [], variationValues = {}} = product
16 | const variationParams = variationAttributes.map(({id}) => id)
17 |
18 | const {search} = useLocation()
19 | const params = new URLSearchParams(search)
20 | // Using all the variation attribute id from the array generated above, get
21 | // the value if there is one from the location search params and add it to the
22 | // accumulator.
23 | const filteredVariationParams = variationParams.reduce((acc, key) => {
24 | let value = params.get(`${key}`) || variationValues?.[key]
25 | return value ? {...acc, [key]: value} : acc
26 | }, {})
27 |
28 | return filteredVariationParams
29 | }
30 |
--------------------------------------------------------------------------------
/app/components/forms/useResetPasswordFields.jsx:
--------------------------------------------------------------------------------
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 {useIntl} from 'react-intl'
8 |
9 | export default function useResetPasswordFields({form: {control, errors}, prefix = ''}) {
10 | const {formatMessage} = useIntl()
11 |
12 | const fields = {
13 | email: {
14 | name: `${prefix}email`,
15 | label: formatMessage({
16 | defaultMessage: 'Email',
17 | id: 'use_reset_password_fields.label.email'
18 | }),
19 | placeholder: 'you@email.com',
20 | defaultValue: '',
21 | type: 'email',
22 | rules: {
23 | required: formatMessage({
24 | defaultMessage: 'Please enter a valid email address.',
25 | id: 'use_reset_password_fields.error.required_email'
26 | })
27 | },
28 | error: errors[`${prefix}email`],
29 | control
30 | }
31 | }
32 |
33 | return fields
34 | }
35 |
--------------------------------------------------------------------------------
/app/components/forms/profile-fields.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {SimpleGrid, Stack} from '@chakra-ui/react'
10 | import useProfileFields from './useProfileFields'
11 | import Field from '../field'
12 |
13 | const ProfileFields = ({form, prefix = ''}) => {
14 | const fields = useProfileFields({form, prefix})
15 |
16 | return (
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | )
26 | }
27 |
28 | ProfileFields.propTypes = {
29 | /** Object returned from `useForm` */
30 | form: PropTypes.object.isRequired,
31 |
32 | /** Optional prefix for field names */
33 | prefix: PropTypes.string
34 | }
35 |
36 | export default ProfileFields
37 |
--------------------------------------------------------------------------------
/app/theme/components/project/links-list.js:
--------------------------------------------------------------------------------
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 | export default {
8 | parts: ['container', 'list', 'listItem', 'listItemSx', 'heading'],
9 | baseStyle: {
10 | container: {
11 | color: 'white'
12 | },
13 | list: {
14 | fontSize: 'sm'
15 | },
16 | headingLink: {
17 | display: 'inline-flex'
18 | },
19 | heading: {
20 | fontSize: 'md',
21 | paddingTop: 3,
22 | paddingBottom: 3
23 | }
24 | },
25 | variants: {
26 | vertical: {},
27 | horizontal: {
28 | listItem: {
29 | borderLeft: '1px solid',
30 | paddingLeft: 2
31 | },
32 | listItemSx: {
33 | '&:first-of-type': {
34 | borderLeft: 0,
35 | paddingLeft: 0
36 | }
37 | }
38 | }
39 | },
40 | defaultProps: {
41 | variant: 'vertical'
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/pages/product-list/partials/link-refinements.jsx:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import {Stack, Text} from '@chakra-ui/react'
10 | import PropTypes from 'prop-types'
11 | import Link from '../../../components/link'
12 |
13 | const LinkRefinements = ({filter}) => {
14 | return (
15 |
16 | {filter.values.map((value) => {
17 | return (
18 |
26 | {value.label}
27 |
28 | )
29 | })}
30 |
31 | )
32 | }
33 |
34 | LinkRefinements.propTypes = {
35 | filter: PropTypes.object
36 | }
37 |
38 | export default LinkRefinements
39 |
--------------------------------------------------------------------------------
/app/theme/components/base/input.js:
--------------------------------------------------------------------------------
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 | const mdSize = {height: 11, borderRadius: 'base'}
8 |
9 | export default {
10 | sizes: {
11 | md: {
12 | field: {...mdSize, px: 3},
13 | addon: mdSize
14 | }
15 | },
16 | baseStyle: {
17 | field: {
18 | _focus: {
19 | borderColor: 'blue.600'
20 | }
21 | }
22 | },
23 | variants: {
24 | filled: {
25 | // we use filled variant for
26 | // search input
27 | field: {
28 | backgroundColor: 'gray.50',
29 | _focus: {
30 | backgroundColor: 'white'
31 | },
32 | _hover: {
33 | backgroundColor: 'gray.100',
34 | _focus: {
35 | backgroundColor: 'white'
36 | }
37 | },
38 | _placeholder: {
39 | color: 'gray.700'
40 | }
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/worker/main.js:
--------------------------------------------------------------------------------
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 | /* global workbox, DEBUG */
9 | /* istanbul ignore file */
10 | /**
11 | * This is your project's Service Worker. For information on customizing your
12 | * Service Worker, see:
13 | *
14 | * - https://developers.google.com/web/fundamentals/primers/service-workers/
15 | * - https://developers.google.com/web/tools/workbox/
16 | */
17 |
18 | self.importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.6.1/workbox-sw.js')
19 |
20 | workbox.setConfig({debug: DEBUG})
21 |
22 | // Place your Workbox route configurations here, eg:
23 | // workbox.routing.registerRoute(...)
24 |
25 | // Never cache dev-server internals.
26 | workbox.routing.registerRoute(
27 | /^http:\/\/localhost:3000\/__mrt/,
28 | new workbox.strategies.NetworkOnly()
29 | )
30 |
31 | // Minimum viable configuration to get offline mode.
32 | workbox.routing.registerRoute(/^http:\/\/localhost:3000/, new workbox.strategies.NetworkFirst())
33 | workbox.routing.registerRoute(
34 | /^https:\/\/.+\.mobify-storefront.com/,
35 | new workbox.strategies.NetworkFirst()
36 | )
37 |
--------------------------------------------------------------------------------
/app/hooks/use-limit-urls.test.js:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import {Router} from 'react-router'
10 |
11 | import {render} from '@testing-library/react'
12 | import {createMemoryHistory} from 'history'
13 | import {useLimitUrls} from './use-limit-urls'
14 |
15 | const MockComponent = () => {
16 | const urls = useLimitUrls()
17 |
18 | return (
19 |
22 | )
23 | }
24 |
25 | describe('The useLimitUrls', () => {
26 | test('returns an array of urls, one values for each limit value.', () => {
27 | const history = createMemoryHistory()
28 | history.push('/test/path')
29 |
30 | const wrapper = render(
31 |
32 |
33 |
34 | )
35 |
36 | expect(wrapper.getByTestId('limits').text).toEqual(
37 | '["/test/path?limit=25&offset=0","/test/path?limit=50&offset=0","/test/path?limit=100&offset=0"]'
38 | )
39 | })
40 | })
41 |
--------------------------------------------------------------------------------
/app/assets/svg/social-pinterest.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
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('pwa-kit-dev/configs/jest/jest.config.js')
10 |
11 | module.exports = {
12 | ...base,
13 | moduleNameMapper: {
14 | ...base.moduleNameMapper,
15 | '^react-router-dom(.*)$': '/node_modules/react-router-dom/index.js'
16 | },
17 | setupFilesAfterEnv: [path.join(__dirname, 'jest-setup.js')],
18 | collectCoverageFrom: [
19 | 'app/**/*.{js,jsx}',
20 | 'non-pwa/**/*.{js,jsx}',
21 | 'worker/**/*.{js,jsx}',
22 | 'scripts/generator/*.{js,jsx}',
23 | '!app/pages/test-container/**/*.{js,jsx}',
24 | '!app/utils/test-utils.js',
25 | '!app/commerce-api/mocks/*js',
26 | '!app/main.jsx',
27 | '!app/loader.js',
28 | '!app/ssr.js',
29 | '!app/static/**',
30 | '!app/theme/**',
31 | '!node_modules/**'
32 | ],
33 | coverageThreshold: {
34 | global: {
35 | statements: 80,
36 | branches: 72,
37 | functions: 78,
38 | lines: 83
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/components/locale-text/index.test.js:
--------------------------------------------------------------------------------
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 LocaleText from './index'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 |
11 | test('Renders LocaleText', () => {
12 | renderWithProviders()
13 | const text = document.querySelector('.chakra-text')
14 |
15 | expect(text).toBeInTheDocument()
16 | })
17 |
18 | test('Renders LocaleText with as type', () => {
19 | renderWithProviders()
20 |
21 | const text = document.querySelector('option.test-class')
22 |
23 | expect(text).toBeInTheDocument()
24 | })
25 |
26 | test('Warns on missing shortCode message definition', () => {
27 | jest.spyOn(console, 'error')
28 |
29 | renderWithProviders()
30 |
31 | const text = document.querySelector('.chakra-text')
32 |
33 | expect(console.error.mock.calls[0][0]).toContain(
34 | `No locale message found for "fa-KE". Please update the list accordingly.`
35 | )
36 | expect(text).toBeInTheDocument()
37 | })
38 |
--------------------------------------------------------------------------------
/app/hooks/use-variant.js:
--------------------------------------------------------------------------------
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 | // Hooks
9 | import {useVariationParams} from './use-variation-params'
10 |
11 | /**
12 | * This hook returns the currently selected
13 | * variant or undefined. NOTE: All attributes must be selected before a variant
14 | * will be returned.
15 | *
16 | * @param {Object} product
17 | * @returns {Object} the currently selected `Variant` object.
18 | */
19 | export const useVariant = (product = {}) => {
20 | const {variants = []} = product
21 | const variationParams = useVariationParams(product)
22 |
23 | // Get a filtered array of variants. The resulting array will only have variants
24 | // which have all the current variation params values set.
25 | const filteredVariants = variants.filter(({variationValues}) =>
26 | // A single liner that will return true if the current variation has all the
27 | // same attribute values as the passing in params.
28 | Object.keys(variationParams).every((key) => variationValues[key] === variationParams[key])
29 | )
30 |
31 | return filteredVariants.length === 1 ? filteredVariants[0] : undefined
32 | }
33 |
--------------------------------------------------------------------------------
/app/commerce-api/hooks/useSearchSuggestions.js:
--------------------------------------------------------------------------------
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 {useState} from 'react'
8 | import {useCommerceAPI} from '../contexts'
9 |
10 | /**
11 | * Hook for retrieving and managing state of Search Suggestions
12 | */
13 | const useSearchSuggestions = () => {
14 | const api = useCommerceAPI()
15 | const [state, setState] = useState({results: {}})
16 | return {
17 | ...state,
18 | /**
19 | * Retrieves search suggestions from api based on input
20 | *
21 | * @param {input} string
22 | */
23 | async getSearchSuggestions(input) {
24 | setState({loading: true})
25 | const searchSuggestions = await api.shopperSearch.getSearchSuggestions({
26 | parameters: {
27 | q: input
28 | }
29 | })
30 | setState({results: searchSuggestions})
31 | },
32 | /**
33 | * Clears results
34 | */
35 | async clearSuggestedSearch() {
36 | setState({results: {}})
37 | }
38 | }
39 | }
40 |
41 | export default useSearchSuggestions
42 |
--------------------------------------------------------------------------------
/app/assets/svg/flag-ca.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/components/hero/index.test.js:
--------------------------------------------------------------------------------
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 {fireEvent} from '@testing-library/react'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 | import Hero from './index'
11 |
12 | test('Hero renders without errors', () => {
13 | const data = {
14 | title: 'title',
15 | actions: undefined,
16 | img: {
17 | src: 'src',
18 | alt: 'alt'
19 | }
20 | }
21 | const {getByText} = renderWithProviders()
22 | expect(getByText(/title/i)).toBeInTheDocument()
23 | })
24 |
25 | test('Hero renders actions and event handlers', () => {
26 | const onClick = jest.fn()
27 | const data = {
28 | title: 'title',
29 | actions: ,
30 | img: {
31 | src: 'src',
32 | alt: 'alt'
33 | }
34 | }
35 | const {getByTestId} = renderWithProviders()
36 | const button = getByTestId('button')
37 | expect(button).toBeInTheDocument()
38 | fireEvent.click(button)
39 | expect(onClick).toHaveBeenCalledTimes(1)
40 | })
41 |
--------------------------------------------------------------------------------
/app/theme/components/project/social-icons.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | container: {
10 | flex: 1
11 | },
12 | icon: {
13 | width: 5,
14 | height: 5
15 | },
16 | item: {
17 | textAlign: 'center',
18 | paddingLeft: 2,
19 | paddingRight: 2
20 | }
21 | },
22 | variants: {
23 | 'flex-start': {
24 | container: {
25 | justifyContent: 'flex-start'
26 | },
27 | item: {
28 | flex: 0
29 | }
30 | },
31 | 'flex-end': {
32 | container: {
33 | justifyContent: 'flex-end'
34 | },
35 | item: {
36 | flex: 0
37 | }
38 | },
39 | flex: {
40 | container: {
41 | justifyContent: 'center'
42 | },
43 | item: {
44 | flex: 1
45 | }
46 | }
47 | },
48 | parts: ['container', 'item', 'icon'],
49 | defaultProps: {
50 | variant: 'flex-start'
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/hooks/use-currency.test.js:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import {renderHook} from '@testing-library/react-hooks'
10 | import {useCurrency} from './use-currency'
11 | import {CurrencyProvider} from '../contexts'
12 | import {DEFAULT_CURRENCY} from '../constants'
13 |
14 | const wrapper = ({children}) => {children}
15 |
16 | let resultCurrency = {}
17 |
18 | const mockSetCurrency = jest.fn().mockImplementation((currency) => {
19 | resultCurrency = {currency}
20 |
21 | return resultCurrency
22 | })
23 |
24 | const mockUseContext = jest.fn().mockImplementation(() => ({
25 | currency: {},
26 | setCurrency: mockSetCurrency
27 | }))
28 |
29 | React.useContext = mockUseContext
30 | describe('useCurrency', () => {
31 | it('should set initial currency', () => {
32 | const {result} = renderHook(() => useCurrency(), {wrapper})
33 |
34 | expect(resultCurrency).toMatchObject({})
35 |
36 | result.current.setCurrency(DEFAULT_CURRENCY)
37 |
38 | expect(mockUseContext).toHaveBeenCalled()
39 | expect(resultCurrency).toMatchObject({currency: DEFAULT_CURRENCY})
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/app/hooks/use-page-urls.test.js:
--------------------------------------------------------------------------------
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 {Router} from 'react-router'
9 |
10 | import {render} from '@testing-library/react'
11 | import {createMemoryHistory} from 'history'
12 | import {usePageUrls} from './use-page-urls'
13 |
14 | const MockComponent = () => {
15 | const urls = usePageUrls({total: 100})
16 |
17 | return (
18 |
21 | )
22 | }
23 |
24 | describe('The usePageUrls', () => {
25 | test('returns an array of urls, one values for each page with the correct offset value.', () => {
26 | const history = createMemoryHistory()
27 | history.push('/test/path?limit=25')
28 |
29 | const wrapper = render(
30 |
31 |
32 |
33 | )
34 |
35 | expect(wrapper.getByTestId('limits').text).toEqual(
36 | '["/test/path?limit=25&offset=0","/test/path?limit=25&offset=25","/test/path?limit=25&offset=50","/test/path?limit=25&offset=75"]'
37 | )
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/app/hooks/use-sort-urls.test.js:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import {Router} from 'react-router'
10 |
11 | import {render} from '@testing-library/react'
12 | import {createMemoryHistory} from 'history'
13 | import {useSortUrls} from './use-sort-urls'
14 |
15 | const MOCK_SORT_OPTIONS = [{id: 'high-to-low'}, {id: 'low-to-high'}]
16 |
17 | const MockComponent = () => {
18 | const urls = useSortUrls({options: MOCK_SORT_OPTIONS})
19 |
20 | return (
21 |
24 | )
25 | }
26 |
27 | describe('The useSortUrls', () => {
28 | test('returns an array of urls, one values for each sort value.', () => {
29 | const history = createMemoryHistory()
30 | history.push('/test/path')
31 |
32 | const wrapper = render(
33 |
34 |
35 |
36 | )
37 |
38 | expect(wrapper.getByTestId('limits').text).toEqual(
39 | '["/test/path?sort=high-to-low&offset=0","/test/path?sort=low-to-high&offset=0"]'
40 | )
41 | })
42 | })
43 |
--------------------------------------------------------------------------------
/app/assets/svg/visibility-off.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/components/product-tile/index.test.js:
--------------------------------------------------------------------------------
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 ProductTile, {Skeleton} from './index'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 |
11 | const mockProductSearchItem = {
12 | currency: 'USD',
13 | image: {
14 | alt: 'Charcoal Single Pleat Wool Suit, , large',
15 | disBaseLink:
16 | 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw4de8166b/images/large/PG.33698RUBN4Q.CHARCWL.PZ.jpg'
17 | },
18 | price: 299.99,
19 | productName: 'Charcoal Single Pleat Wool Suit'
20 | }
21 |
22 | test('Renders Breadcrumb', () => {
23 | const {getAllByRole} = renderWithProviders()
24 |
25 | const link = getAllByRole('link')
26 | const img = getAllByRole('img')
27 |
28 | expect(link).toBeDefined()
29 | expect(img).toBeDefined()
30 | })
31 |
32 | test('Renders Skeleton', () => {
33 | const {getAllByTestId} = renderWithProviders()
34 |
35 | const skeleton = getAllByTestId('sf-product-tile-skeleton')
36 |
37 | expect(skeleton).toBeDefined()
38 | })
39 |
--------------------------------------------------------------------------------
/app/components/loading-spinner/index.jsx:
--------------------------------------------------------------------------------
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 {Box, Spinner} from '@chakra-ui/react'
9 | import PropTypes from 'prop-types'
10 |
11 | const LoadingSpinner = ({wrapperStyles = {}, spinnerStyles = {}}) => {
12 | return (
13 |
23 |
37 |
38 | )
39 | }
40 |
41 | LoadingSpinner.propTypes = {
42 | wrapperStyles: PropTypes.object,
43 | spinnerStyles: PropTypes.object
44 | }
45 |
46 | export default LoadingSpinner
47 |
--------------------------------------------------------------------------------
/app/hooks/use-categories.test.js:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import {renderHook} from '@testing-library/react-hooks'
10 | import {useCategories} from './use-categories'
11 | import {CategoriesProvider} from '../contexts'
12 | import {mockCategories as initialMockCategories} from '../commerce-api/mock-data'
13 |
14 | const wrapper = ({children}) => {children}
15 |
16 | let resultCategories = {}
17 |
18 | const mockSetCategories = jest.fn().mockImplementation((categories) => {
19 | resultCategories = {categories}
20 |
21 | return resultCategories
22 | })
23 |
24 | const mockUseContext = jest.fn().mockImplementation(() => ({
25 | categories: {},
26 | setCategories: mockSetCategories
27 | }))
28 |
29 | React.useContext = mockUseContext
30 | describe('useCategories', () => {
31 | it('should set initial categories', () => {
32 | const {result} = renderHook(() => useCategories(), {wrapper})
33 |
34 | expect(resultCategories).toMatchObject({})
35 |
36 | result.current.setCategories(initialMockCategories)
37 |
38 | expect(mockUseContext).toHaveBeenCalled()
39 | expect(resultCategories).toHaveProperty('categories')
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/app/components/link/index.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Link as ChakraLink} from '@chakra-ui/react'
10 | import {Link as SPALink, NavLink as NavSPALink} from 'react-router-dom'
11 | import {buildPathWithUrlConfig} from '../../utils/url'
12 | import useSite from '../../hooks/use-site'
13 | import useLocale from '../../hooks/use-locale'
14 |
15 | const Link = React.forwardRef(({href, to, useNavLink = false, ...props}, ref) => {
16 | const _href = to || href
17 | const site = useSite()
18 | const locale = useLocale()
19 |
20 | // if alias is not defined, use site id
21 | const updatedHref = buildPathWithUrlConfig(_href, {
22 | locale: locale.alias || locale.id,
23 | site: site.alias || site.id
24 | })
25 | return (
26 |
33 | )
34 | })
35 |
36 | Link.displayName = 'Link'
37 |
38 | Link.propTypes = {href: PropTypes.string, to: PropTypes.string, useNavLink: PropTypes.bool}
39 |
40 | export default React.memo(Link)
41 |
--------------------------------------------------------------------------------
/app/components/locale-selector/index.test.js:
--------------------------------------------------------------------------------
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 {fireEvent} from '@testing-library/react'
9 | import LocaleSelector from './index'
10 | import {renderWithProviders} from '../../utils/test-utils'
11 |
12 | const supportedLocales = ['en-GB', 'fr-FR', 'it-IT', 'zh-CN', 'ja-JP']
13 |
14 | test('Renders LocaleSelector', () => {
15 | renderWithProviders()
16 | const accordion = document.querySelector('.chakra-accordion')
17 | const selectedLocale = document.querySelector('button[aria-expanded="false"]')
18 |
19 | expect(accordion).toBeInTheDocument()
20 | expect(selectedLocale).toBeInTheDocument()
21 | })
22 |
23 | test('Renders LocaleSelector with event handlers', () => {
24 | const onSelect = jest.fn()
25 |
26 | renderWithProviders(
27 |
28 | )
29 |
30 | const firstLocale = document.querySelector(
31 | '.chakra-accordion .chakra-accordion button.chakra-accordion__button'
32 | )
33 |
34 | fireEvent.click(firstLocale)
35 | expect(onSelect).toHaveBeenCalledTimes(1)
36 | expect(onSelect).toBeCalledWith('en-GB')
37 | })
38 |
--------------------------------------------------------------------------------
/app/components/forms/registration-fields.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Stack} from '@chakra-ui/react'
10 | import useRegistrationFields from './useRegistrationFields'
11 | import Field from '../field'
12 | import PasswordRequirements from './password-requirements'
13 |
14 | const RegistrationFields = ({form, prefix = ''}) => {
15 | const fields = useRegistrationFields({form, prefix})
16 | const password = form.watch('password')
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | )
32 | }
33 |
34 | RegistrationFields.propTypes = {
35 | /** Object returned from `useForm` */
36 | form: PropTypes.object.isRequired,
37 |
38 | /** Optional prefix for field names */
39 | prefix: PropTypes.string
40 | }
41 |
42 | export default RegistrationFields
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2021, Salesforce.com, Inc.
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11 |
12 | 3. Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 |
--------------------------------------------------------------------------------
/app/components/forms/promo-code-fields.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {FormattedMessage} from 'react-intl'
10 | import {Box, Button} from '@chakra-ui/react'
11 | import usePromoCodeFields from './usePromoCodeFields'
12 | import Field from '../field'
13 |
14 | const PromoCodeFields = ({form, prefix = '', ...props}) => {
15 | const fields = usePromoCodeFields({form, prefix})
16 |
17 | const code = form.watch('code')
18 |
19 | return (
20 |
21 |
22 |
30 |
31 |
32 | )
33 | }
34 |
35 | PromoCodeFields.propTypes = {
36 | /** Object returned from `useForm` */
37 | form: PropTypes.object.isRequired,
38 |
39 | /** Optional prefix for field names */
40 | prefix: PropTypes.string
41 | }
42 |
43 | export default PromoCodeFields
44 |
--------------------------------------------------------------------------------
/app/components/search/partials/suggestions.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Text, Button, Stack, Box} from '@chakra-ui/react'
10 |
11 | const Suggestions = ({suggestions, closeAndNavigate}) => {
12 | if (!suggestions) {
13 | return null
14 | }
15 | return (
16 |
17 |
18 | {suggestions.map((suggestion, idx) => (
19 |
32 | ))}
33 |
34 |
35 | )
36 | }
37 |
38 | Suggestions.propTypes = {
39 | suggestions: PropTypes.array,
40 | closeAndNavigate: PropTypes.func
41 | }
42 |
43 | export default Suggestions
44 |
--------------------------------------------------------------------------------
/app/pages/cart/partials/cart-cta.jsx:
--------------------------------------------------------------------------------
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, {Fragment} from 'react'
8 | import {FormattedMessage} from 'react-intl'
9 | import {Flex, Button} from '@chakra-ui/react'
10 | import {AmexIcon, DiscoverIcon, LockIcon, MastercardIcon, VisaIcon} from '../../../components/icons'
11 | import Link from '../../../components/link'
12 |
13 | const CartCta = () => {
14 | return (
15 |
16 | }
23 | variant="solid"
24 | >
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | )
38 | }
39 |
40 | export default CartCta
41 |
--------------------------------------------------------------------------------
/app/components/scroll-to-top/index.test.js:
--------------------------------------------------------------------------------
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 {render, waitFor} from '@testing-library/react'
9 | import ScrollToTop from './index'
10 | import {Router} from 'react-router-dom'
11 | import {createMemoryHistory} from 'history'
12 |
13 | global.scrollTo = jest.fn()
14 |
15 | describe('ScrollToTop', () => {
16 | let history = createMemoryHistory({initialEntries: ['/']})
17 |
18 | beforeEach(() => {
19 | render(
20 |
21 |
22 |
23 | )
24 | })
25 |
26 | afterEach(() => {
27 | jest.clearAllMocks()
28 | })
29 |
30 | test('calls window.scrollTo when route changes', async () => {
31 | expect(global.scrollTo).toHaveBeenCalledTimes(1)
32 | expect(global.scrollTo).toHaveBeenCalledWith(0, 0)
33 |
34 | history.push('/new-url')
35 | await waitFor(() => {
36 | expect(global.scrollTo).toHaveBeenCalledTimes(2)
37 | })
38 | expect(global.scrollTo).toHaveBeenCalledWith(0, 0)
39 |
40 | history.push('/new-url2')
41 | await waitFor(() => {
42 | expect(global.scrollTo).toHaveBeenCalledTimes(3)
43 | })
44 | expect(global.scrollTo).toHaveBeenCalledWith(0, 0)
45 | })
46 | })
47 |
--------------------------------------------------------------------------------
/app/components/forms/post-checkout-registration-fields.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Stack, Box} from '@chakra-ui/react'
10 | import useRegistrationFields from './useRegistrationFields'
11 | import PasswordRequirements from './password-requirements'
12 | import Field from '../field'
13 |
14 | const PostCheckoutRegistrationFields = ({form, prefix = ''}) => {
15 | const fields = useRegistrationFields({form, prefix})
16 | const password = form.watch(`${prefix}password`)
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 |
35 | PostCheckoutRegistrationFields.propTypes = {
36 | /** Object returned from `useForm` */
37 | form: PropTypes.object.isRequired,
38 |
39 | /** Optional prefix for field names */
40 | prefix: PropTypes.string
41 | }
42 |
43 | export default PostCheckoutRegistrationFields
44 |
--------------------------------------------------------------------------------
/app/assets/svg/cc-visa.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/assets/svg/social-instagram.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/pages/checkout/partials/contact-info.test.js:
--------------------------------------------------------------------------------
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 {screen, within} from '@testing-library/react'
9 | import user from '@testing-library/user-event'
10 |
11 | import ContactInfo from './contact-info'
12 | import {renderWithProviders} from '../../../utils/test-utils'
13 |
14 | jest.mock('../util/checkout-context', () => {
15 | return {
16 | useCheckout: jest.fn().mockReturnValue({
17 | customer: null,
18 | basket: {},
19 | isGuestCheckout: true,
20 | setIsGuestCheckout: jest.fn(),
21 | step: 0,
22 | login: null,
23 | setCheckoutStep: null,
24 | goToNextStep: null
25 | })
26 | }
27 | })
28 |
29 | test('renders component', () => {
30 | renderWithProviders()
31 |
32 | // switch to login
33 | const trigger = screen.getByText(/Already have an account\? Log in/i)
34 | user.click(trigger)
35 |
36 | // open forgot password modal
37 | const withinCard = within(screen.getByTestId('sf-toggle-card-step-0'))
38 | const openModal = withinCard.getByText(/Forgot password\?/i)
39 | user.click(openModal)
40 |
41 | // check that forgot password modal is open
42 | const withinForm = within(screen.getByTestId('sf-auth-modal-form'))
43 | expect(withinForm.getByText(/Reset Password/i)).toBeInTheDocument()
44 | })
45 |
--------------------------------------------------------------------------------
/tests/lighthouserc.js:
--------------------------------------------------------------------------------
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 | }
38 |
--------------------------------------------------------------------------------
/app/commerce-api/pkce.js:
--------------------------------------------------------------------------------
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 {nanoid} from 'nanoid'
8 | import {encode as base64encode} from 'base64-arraybuffer'
9 |
10 | // Server Side
11 | const randomstring = require('randomstring')
12 |
13 | // Globals
14 | const isServer = typeof window === 'undefined'
15 |
16 | /**
17 | * Creates Code Verifier use for PKCE auth flow.
18 | *
19 | * @returns {String} The 128 character length code verifier.
20 | */
21 | export const createCodeVerifier = () => {
22 | return isServer ? randomstring.generate(128) : nanoid(128)
23 | }
24 |
25 | /**
26 | * Creates Code Challenge based on Code Verifier
27 | *
28 | * @param {String} codeVerifier
29 | * @returns {String}
30 | */
31 | export const generateCodeChallenge = async (codeVerifier) => {
32 | let base64Digest
33 |
34 | if (isServer) {
35 | await import('crypto').then((module) => {
36 | const crypto = module.default
37 | base64Digest = crypto
38 | .createHash('sha256')
39 | .update(codeVerifier)
40 | .digest('base64')
41 | })
42 | } else {
43 | const encoder = new TextEncoder()
44 | const data = encoder.encode(codeVerifier)
45 | const digest = await window.crypto.subtle.digest('SHA-256', data)
46 |
47 | base64Digest = base64encode(digest)
48 | }
49 |
50 | return base64Digest
51 | .replace(/\+/g, '-')
52 | .replace(/\//g, '_')
53 | .replace(/=/g, '')
54 | }
55 |
--------------------------------------------------------------------------------
/app/commerce-api/hooks/useRefinementToggle.js:
--------------------------------------------------------------------------------
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 {useState} from 'react'
8 |
9 | /**
10 | * Hook for handling the UI state of refinements
11 | */
12 | const useRefinementToggle = () => {
13 | const [state, setState] = useState({selectedRefinements: undefined})
14 | return {
15 | ...state,
16 | /**
17 | * Manages an array of selected refinements for the UI to use for instant feedback
18 | *
19 | * @param {string} value
20 | * @param {boolean} selected
21 | */
22 | applyUIFeedback(value, selected) {
23 | if (!selected) {
24 | const updatedSelectedRefinements = state.selectedRefinements || []
25 | updatedSelectedRefinements.push(value.value)
26 | setState({selectedRefinements: updatedSelectedRefinements})
27 | } else {
28 | const updatedSelectedRefinements = state.selectedRefinements.filter(
29 | (item) => item !== value.value
30 | )
31 | setState({selectedRefinements: updatedSelectedRefinements})
32 | }
33 | },
34 | /**
35 | * Updates the state when the selected refinements are updated
36 | *
37 | * @param {array} refinements
38 | */
39 | setSelectedRefinements(refinements) {
40 | setState({selectedRefinements: refinements})
41 | }
42 | }
43 | }
44 |
45 | export default useRefinementToggle
46 |
--------------------------------------------------------------------------------
/app/hooks/use-locale.test.js:
--------------------------------------------------------------------------------
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 {createMemoryHistory} from 'history'
9 | import {screen} from '@testing-library/react'
10 | import {Router} from 'react-router'
11 | import React from 'react'
12 |
13 | import useLocale from './use-locale'
14 | import {renderWithReactIntl} from '../utils/test-utils'
15 |
16 | const MockComponent = () => {
17 | const locale = useLocale()
18 | return {JSON.stringify(locale)}
19 | }
20 |
21 | describe('useLocale', function() {
22 | test('return the default locale', () => {
23 | const history = createMemoryHistory()
24 | history.push('/test/path')
25 | renderWithReactIntl(
26 |
27 |
28 |
29 | )
30 | expect(screen.getByTestId('locale')).toHaveTextContent(
31 | '{"id":"en-GB","preferredCurrency":"GBP"}'
32 | )
33 | })
34 |
35 | test('return the locale object that matches the site (from the url) and the locale from intl', () => {
36 | const history = createMemoryHistory()
37 | history.push('/us/en-CA/test/path')
38 | renderWithReactIntl(
39 |
40 |
41 | ,
42 | 'en-CA'
43 | )
44 | expect(screen.getByTestId('locale')).toHaveTextContent(
45 | '{"id":"en-CA","preferredCurrency":"USD"}'
46 | )
47 | })
48 | })
49 |
--------------------------------------------------------------------------------
/app/assets/svg/receipt.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/components/drawer-menu/index.test.js:
--------------------------------------------------------------------------------
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 DrawerMenu from './index'
9 | import {renderWithProviders} from '../../utils/test-utils'
10 |
11 | const mockRoot = {
12 | id: 't1',
13 | name: 'Test One',
14 | categories: [
15 | {
16 | id: 't1-1',
17 | name: 'Test One One'
18 | },
19 | {
20 | id: 't1-2',
21 | name: 'Test One Two',
22 | categories: [
23 | {
24 | id: 't1-2-1',
25 | name: 'Test One Two One'
26 | },
27 | {
28 | id: 't1-2-2',
29 | name: 'Test One Two Two'
30 | }
31 | ]
32 | }
33 | ]
34 | }
35 |
36 | test('Renders DrawerMenu with root', () => {
37 | renderWithProviders()
38 |
39 | const drawer = document.querySelector('.chakra-portal')
40 | const accordion = document.querySelector('.chakra-accordion')
41 | const socialIcons = document.querySelector('.sf-social-icons')
42 |
43 | expect(drawer).toBeInTheDocument()
44 | expect(accordion).toBeInTheDocument()
45 | expect(socialIcons).toBeInTheDocument()
46 | })
47 |
48 | test('Renders DrawerMenu Spinner without root', () => {
49 | renderWithProviders()
50 |
51 | const spinner = document.querySelector('.chakra-spinner')
52 |
53 | expect(spinner).toBeInTheDocument()
54 | })
55 |
--------------------------------------------------------------------------------
/app/pages/product-list/partials/checkbox-refinements.jsx:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import {Box, Checkbox, Stack} from '@chakra-ui/react'
10 | import PropTypes from 'prop-types'
11 |
12 | const CheckboxRefinements = ({filter, toggleFilter, selectedFilters}) => {
13 | return (
14 |
15 | {filter.values
16 | ?.filter((refinementValue) => refinementValue.hitCount > 0)
17 | .map((value) => {
18 | return (
19 |
20 |
23 | toggleFilter(
24 | value,
25 | filter.attributeId,
26 | !!selectedFilters,
27 | false
28 | )
29 | }
30 | >
31 | {value.label}
32 |
33 |
34 | )
35 | })}
36 |
37 | )
38 | }
39 |
40 | CheckboxRefinements.propTypes = {
41 | filter: PropTypes.object,
42 | toggleFilter: PropTypes.func,
43 | selectedFilters: PropTypes.array
44 | }
45 |
46 | export default CheckboxRefinements
47 |
--------------------------------------------------------------------------------
/app/theme/components/base/popover.js:
--------------------------------------------------------------------------------
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 | export default {
8 | parts: ['popper'],
9 | baseStyle: {
10 | popper: {
11 | borderColor: 'transparent',
12 | borderRadius: 'base',
13 | boxShadow: '0px 1px 12px rgba(0, 0, 0, 0.25)'
14 | }
15 | },
16 | variants: {
17 | small: {},
18 | normal: {
19 | popper: {
20 | width: 286
21 | },
22 | header: {
23 | textAlign: 'left',
24 | fontWeight: 700,
25 | borderBottom: 'none',
26 | fontSize: 18,
27 | px: 7,
28 | paddingTop: 6
29 | },
30 | footer: {
31 | textAlign: 'left',
32 | fontSize: 14,
33 | px: 3,
34 | borderTop: 'none'
35 | },
36 | content: {
37 | width: 286
38 | },
39 | body: {
40 | py: 0
41 | }
42 | },
43 | fullWidth: {
44 | popper: {
45 | width: '100%',
46 | maxWidth: '100%',
47 | boxShadow: 'none',
48 | top: '0',
49 | right: 'auto',
50 | bottom: 'auto',
51 | left: '0'
52 | },
53 | content: {
54 | width: 'auto'
55 | }
56 | }
57 | },
58 | defaultProps: {
59 | variant: 'normal'
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/assets/svg/filter.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/commerce-api/hooks/useEinstein.js:
--------------------------------------------------------------------------------
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 {useState} from 'react'
8 | import {useCommerceAPI} from '../contexts'
9 |
10 | const useEinstein = () => {
11 | const api = useCommerceAPI()
12 | const [state, setState] = useState({loading: false, recommendations: []})
13 |
14 | return {
15 | ...state,
16 |
17 | api: api.einstein,
18 |
19 | async sendViewProduct(...args) {
20 | return api.einstein.sendViewProduct(...args)
21 | },
22 | async sendViewReco(...args) {
23 | return api.einstein.sendViewReco(...args)
24 | },
25 | async sendClickReco(...args) {
26 | return api.einstein.sendClickReco(...args)
27 | },
28 | async sendAddToCart(...args) {
29 | return api.einstein.sendAddToCart(...args)
30 | },
31 | async getRecommenders(...args) {
32 | return api.einstein.getRecommenders(...args)
33 | },
34 | async getRecommendations(...args) {
35 | setState((s) => ({...s, loading: true}))
36 | const recommendations = await api.einstein.getRecommendations(...args)
37 | setState({loading: false, recommendations})
38 | },
39 | async getZoneRecommendations(...args) {
40 | setState((s) => ({...s, loading: true}))
41 | const recommendations = await api.einstein.getZoneRecommendations(...args)
42 | setState({loading: false, recommendations})
43 | }
44 | }
45 | }
46 |
47 | export default useEinstein
48 |
--------------------------------------------------------------------------------
/app/components/forms/useLoginFields.jsx:
--------------------------------------------------------------------------------
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 {useIntl} from 'react-intl'
8 |
9 | export default function useLoginFields({form: {control, errors}, prefix = ''}) {
10 | const {formatMessage} = useIntl()
11 |
12 | const fields = {
13 | email: {
14 | name: `${prefix}email`,
15 | label: formatMessage({defaultMessage: 'Email', id: 'use_login_fields.label.email'}),
16 | placeholder: 'you@email.com',
17 | defaultValue: '',
18 | type: 'email',
19 | rules: {
20 | required: formatMessage({
21 | defaultMessage: 'Please enter your email address.',
22 | id: 'use_login_fields.error.required_email'
23 | })
24 | },
25 | error: errors[`${prefix}email`],
26 | control
27 | },
28 | password: {
29 | name: `${prefix}password`,
30 | label: formatMessage({
31 | defaultMessage: 'Password',
32 | id: 'use_login_fields.label.password'
33 | }),
34 | defaultValue: '',
35 | type: 'password',
36 | rules: {
37 | required: formatMessage({
38 | defaultMessage: 'Please enter your password.',
39 | id: 'use_login_fields.error.required_password'
40 | })
41 | },
42 | error: errors[`${prefix}password`],
43 | control
44 | }
45 | }
46 |
47 | return fields
48 | }
49 |
--------------------------------------------------------------------------------
/app/components/page-action-placeholder/index.jsx:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import PropTypes from 'prop-types'
10 | import {Box, Button, Stack, Text} from '@chakra-ui/react'
11 | import {PlusIcon} from '../../components/icons'
12 |
13 | const PageActionPlaceHolder = ({heading, text, icon, buttonText, buttonProps, onButtonClick}) => {
14 | return (
15 |
23 | {icon}
24 |
25 |
26 |
27 | {heading}
28 |
29 |
30 | {text}
31 |
32 |
33 | } {...buttonProps}>
34 | {buttonText}
35 |
36 |
37 |
38 | )
39 | }
40 |
41 | PageActionPlaceHolder.propTypes = {
42 | heading: PropTypes.string,
43 | text: PropTypes.string,
44 | buttonText: PropTypes.string,
45 | icon: PropTypes.any,
46 | buttonProps: PropTypes.object,
47 | onButtonClick: PropTypes.func
48 | }
49 |
50 | export default PageActionPlaceHolder
51 |
--------------------------------------------------------------------------------
/app/assets/svg/cc-cvv.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/assets/svg/cc-mastercard.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/hooks/use-navigation.js:
--------------------------------------------------------------------------------
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 {useCallback} from 'react'
8 | import {useHistory} from 'react-router'
9 | import {useIntl} from 'react-intl'
10 | import {buildPathWithUrlConfig} from '../utils/url'
11 | import useSite from './use-site'
12 | import {getLocaleByReference} from '../utils/utils'
13 |
14 | /**
15 | * A convenience hook for programmatic navigation uses history's `push` or `replace`. The proper locale
16 | * is automatically prepended to the provided path. Additional args are passed through to `history`.
17 | * @returns {function} - Returns a navigate function that passes args to history methods.
18 | */
19 | const useNavigation = () => {
20 | const history = useHistory()
21 |
22 | const {locale: localeShortCode} = useIntl()
23 | const site = useSite()
24 | return useCallback(
25 | /**
26 | *
27 | * @param {string} path - path to navigate to
28 | * @param {('push'|'replace')} action - which history method to use
29 | * @param {...any} args - additional args passed to `.push` or `.replace`
30 | */
31 | (path, action = 'push', ...args) => {
32 | const locale = getLocaleByReference(site, localeShortCode)
33 |
34 | const updatedHref = buildPathWithUrlConfig(path, {
35 | locale: locale.alias || locale.id,
36 | site: site.alias || site.id
37 | })
38 | history[action](path === '/' ? '/' : updatedHref, ...args)
39 | },
40 | [localeShortCode, site]
41 | )
42 | }
43 |
44 | export default useNavigation
45 |
--------------------------------------------------------------------------------
/app/theme/components/project/drawer-menu.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | container: {},
10 | socialsContainer: {
11 | flex: 1,
12 | justifyContent: 'flex-start'
13 | },
14 | icon: {
15 | color: 'gray.900',
16 | width: 5,
17 | height: 5
18 | },
19 | logo: {
20 | width: 12,
21 | height: 8
22 | },
23 | socialsItem: {
24 | textAlign: 'center',
25 | paddingLeft: 2,
26 | paddingRight: 2
27 | },
28 | actions: {
29 | paddingLeft: 4,
30 | paddingRight: 4
31 | },
32 | actionsItem: {
33 | paddingTop: 3,
34 | paddingBottom: 3
35 | },
36 | localeSelector: {
37 | paddingTop: 1,
38 | paddingBottom: 1
39 | },
40 | signout: {
41 | width: '100%',
42 | paddingLeft: 8,
43 | paddingTop: 2,
44 | paddingBottom: 2,
45 | _focus: {
46 | borderRadius: 0,
47 | boxShadow: 'outline'
48 | }
49 | },
50 | signoutText: {
51 | marginLeft: 2,
52 | fontSize: 14,
53 | fontWeight: 'normal'
54 | }
55 | },
56 | parts: [
57 | 'actions',
58 | 'actionsItem',
59 | 'container',
60 | 'icon',
61 | 'localeSelector',
62 | 'socials',
63 | 'socialsItem',
64 | 'signout'
65 | ]
66 | }
67 |
--------------------------------------------------------------------------------
/app/components/search/partials/search-suggestions.jsx:
--------------------------------------------------------------------------------
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, {Fragment} from 'react'
8 | import PropTypes from 'prop-types'
9 | import {Stack} from '@chakra-ui/react'
10 | import RecentSearches from './recent-searches'
11 | import Suggestions from './suggestions'
12 |
13 | const SearchSuggestions = ({recentSearches, searchSuggestions, closeAndNavigate}) => {
14 | const useSuggestions = searchSuggestions && searchSuggestions?.categorySuggestions?.length
15 | return (
16 |
17 | {useSuggestions ? (
18 |
19 |
23 | {/* */}
27 | {/* */}
28 |
29 | ) : (
30 |
34 | )}
35 |
36 | )
37 | }
38 |
39 | SearchSuggestions.propTypes = {
40 | recentSearches: PropTypes.array,
41 | searchSuggestions: PropTypes.object,
42 | closeAndNavigate: PropTypes.func
43 | }
44 |
45 | export default SearchSuggestions
46 |
--------------------------------------------------------------------------------
/app/components/forms/address-fields.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {Grid, GridItem, SimpleGrid, Stack} from '@chakra-ui/react'
10 | import useCustomer from '../../commerce-api/hooks/useCustomer'
11 | import useAddressFields from './useAddressFields'
12 | import Field from '../field'
13 |
14 | const AddressFields = ({form, prefix = ''}) => {
15 | const customer = useCustomer()
16 | const fields = useAddressFields({form, prefix})
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | {customer.isRegistered && }
37 |
38 | )
39 | }
40 |
41 | AddressFields.propTypes = {
42 | /** Object returned from `useForm` */
43 | form: PropTypes.object.isRequired,
44 |
45 | /** Optional prefix for field names */
46 | prefix: PropTypes.string
47 | }
48 |
49 | export default AddressFields
50 |
--------------------------------------------------------------------------------
/app/components/product-view-modal/index.jsx:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import PropTypes from 'prop-types'
10 | import {Modal, ModalBody, ModalCloseButton, ModalContent, ModalOverlay} from '@chakra-ui/react'
11 | import ProductView from '../../partials/product-view'
12 | import {useProductViewModal} from '../../hooks/use-product-view-modal'
13 |
14 | /**
15 | * A Modal that contains Product View
16 | */
17 | const ProductViewModal = ({product, isOpen, onClose, ...props}) => {
18 | const productViewModalData = useProductViewModal(product)
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
32 |
33 |
34 |
35 | )
36 | }
37 |
38 | ProductViewModal.propTypes = {
39 | isOpen: PropTypes.bool.isRequired,
40 | onOpen: PropTypes.func.isRequired,
41 | onClose: PropTypes.func.isRequired,
42 | product: PropTypes.object,
43 | isLoading: PropTypes.bool,
44 | actionButtons: PropTypes.node,
45 | onModalClose: PropTypes.func
46 | }
47 |
48 | export default ProductViewModal
49 |
--------------------------------------------------------------------------------
/app/theme/components/project/image-gallery.js:
--------------------------------------------------------------------------------
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 | export default {
8 | baseStyle: {
9 | container: {},
10 | heroImage: {},
11 | heroImageGroup: {
12 | marginBottom: 2
13 | },
14 | heroImageSkeleton: {
15 | marginBottom: 2
16 | },
17 | thumbnailImageGroup: {},
18 | thumbnailImageItem: {
19 | flexShrink: 0,
20 | cursor: 'pointer',
21 | flexBasis: [20, 20, 24],
22 | borderStyle: 'solid',
23 | marginBottom: [1, 1, 2, 2],
24 | marginRight: [1, 1, 2, 2],
25 | _focus: {
26 | boxShadow: 'outline'
27 | },
28 | _focusVisible: {
29 | outline: 0
30 | }
31 | },
32 | thumbnailImageSkeleton: {
33 | marginRight: 2,
34 | width: [20, 20, 24, 24]
35 | }
36 | },
37 | sizes: {
38 | sm: {
39 | heroImageSkeleton: {
40 | maxWidth: ['none', 'none', 'none', '500px']
41 | },
42 | heroImage: {
43 | maxWidth: ['none', 'none', 'none', '500px']
44 | }
45 | },
46 | md: {
47 | heroImageSkeleton: {
48 | maxWidth: ['none', 'none', 'none', '680px']
49 | },
50 | heroImage: {
51 | maxWidth: ['none', 'none', 'none', '680px']
52 | }
53 | }
54 | },
55 | defaultProps: {
56 | size: 'md'
57 | },
58 | parts: ['container', 'heroImageGroup', 'heroImage', 'heroImageSkeleton', 'thumbnailImageGroup']
59 | }
60 |
--------------------------------------------------------------------------------
/app/pages/account/wishlist/partials/wishlist-primary-action.test.js:
--------------------------------------------------------------------------------
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 {mockedCustomerProductListsDetails} from '../../../../commerce-api/mock-data'
9 | import ItemVariantProvider from '../../../../components/item-variant'
10 | import {renderWithProviders} from '../../../../utils/test-utils'
11 | import WishlistPrimaryAction from './wishlist-primary-action'
12 | import user from '@testing-library/user-event'
13 | import {screen, waitFor} from '@testing-library/react'
14 |
15 | const MockedComponent = (variant) => {
16 | return (
17 |
18 |
19 |
20 | )
21 | }
22 |
23 | jest.mock('../../../../commerce-api/hooks/useBasket', () => {
24 | return () => {
25 | return {
26 | addItemToBasket: jest.fn()
27 | }
28 | }
29 | })
30 |
31 | beforeEach(() => {
32 | jest.resetModules()
33 | })
34 |
35 | test('renders primary action component', async () => {
36 | const {getByRole} = renderWithProviders(
37 |
38 | )
39 | const addToCartButton = getByRole('button', {
40 | name: /add to cart/i
41 | })
42 | expect(addToCartButton).toBeInTheDocument()
43 | user.click(addToCartButton)
44 |
45 | await waitFor(() => {
46 | // Chakra UI renders multiple elements with toast title in DOM for accessibility.
47 | // We need to assert the actual text within the alert
48 | expect(screen.getByRole('alert')).toHaveTextContent(/items added to cart/i)
49 | })
50 | })
51 |
--------------------------------------------------------------------------------
/app/components/forms/update-password-fields.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {FormattedMessage} from 'react-intl'
10 | import {Box, Button, Stack, StackDivider} from '@chakra-ui/react'
11 | import useUpdatePasswordFields from './useUpdatePasswordFields'
12 | import Field from '../field'
13 | import PasswordRequirements from './password-requirements'
14 |
15 | const UpdatePasswordFields = ({form, prefix = ''}) => {
16 | const fields = useUpdatePasswordFields({form, prefix})
17 | const password = form.watch('password')
18 |
19 | return (
20 | }>
21 |
22 |
23 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | )
39 | }
40 |
41 | UpdatePasswordFields.propTypes = {
42 | /** Object returned from `useForm` */
43 | form: PropTypes.object.isRequired,
44 |
45 | /** Optional prefix for field names */
46 | prefix: PropTypes.string
47 | }
48 |
49 | export default UpdatePasswordFields
50 |
--------------------------------------------------------------------------------
/app/commerce-api/__mocks__/einstein.js:
--------------------------------------------------------------------------------
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 {
8 | mockGetZoneRecommendationsResponse,
9 | mockRecommendationsResponse,
10 | mockRecommendersResponse
11 | } from '../mocks/einstein-mock-data'
12 | import {keysToCamel} from '../utils'
13 |
14 | class EinsteinAPI {
15 | constructor(commerceAPI) {
16 | this.commerceAPI = commerceAPI
17 | this.config = commerceAPI._config.einsteinConfig
18 | }
19 |
20 | async sendViewProduct() {
21 | return {requestId: 'test-req-id', uuid: 'test-uuid'}
22 | }
23 |
24 | async sendViewReco() {
25 | return {requestId: 'test-req-id', uuid: 'test-uuid'}
26 | }
27 |
28 | async sendClickReco() {
29 | return {requestId: 'test-req-id', uuid: 'test-uuid'}
30 | }
31 |
32 | async sendAddToCart() {
33 | return {requestId: 'test-req-id', uuid: 'test-uuid'}
34 | }
35 |
36 | async getRecommenders() {
37 | return keysToCamel(mockRecommendersResponse)
38 | }
39 |
40 | async getRecommendations() {
41 | return this.fetchRecProductDetails(mockRecommendationsResponse)
42 | }
43 |
44 | async getZoneRecommendations() {
45 | return this.fetchRecProductDetails(mockGetZoneRecommendationsResponse)
46 | }
47 |
48 | async fetchRecProductDetails(reco) {
49 | return {
50 | ...reco,
51 | recs: keysToCamel(reco).recs.map((r) => ({
52 | ...r,
53 | productId: r.id,
54 | image: {disBaseLink: r.imageUrl},
55 | currency: 'USD',
56 | price: 5.99
57 | }))
58 | }
59 | }
60 | }
61 |
62 | export default EinsteinAPI
63 |
--------------------------------------------------------------------------------
/app/hooks/use-site.test.js:
--------------------------------------------------------------------------------
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 {createMemoryHistory} from 'history'
9 | import {render, screen} from '@testing-library/react'
10 | import {Router} from 'react-router'
11 | import React from 'react'
12 | import useSite from './use-site'
13 |
14 | afterEach(() => {
15 | jest.clearAllMocks()
16 | })
17 |
18 | const MockComponent = () => {
19 | const site = useSite()
20 | return {JSON.stringify(site)}
21 | }
22 |
23 | describe('useSite', function() {
24 | test('returns the default site when there is no ref in the url ', () => {
25 | const history = createMemoryHistory()
26 | history.push('/test/path')
27 | render(
28 |
29 |
30 |
31 | )
32 | expect(screen.getByTestId('site')).toHaveTextContent(
33 | '{"id":"site-1","l10n":{"defaultLocale":"en-GB","supportedLocales":[{"id":"en-GB","preferredCurrency":"GBP"},{"id":"fr-FR","alias":"fr","preferredCurrency":"EUR"},{"id":"it-IT","preferredCurrency":"EUR"}]},"alias":"uk"}'
34 | )
35 | })
36 |
37 | test('returns site-2 as the result ', () => {
38 | const history = createMemoryHistory()
39 | history.push('/us/test/path')
40 | render(
41 |
42 |
43 |
44 | )
45 | expect(screen.getByTestId('site')).toHaveTextContent(
46 | '{"id":"site-2","l10n":{"defaultLocale":"en-US","supportedLocales":[{"id":"en-US","preferredCurrency":"USD"},{"id":"en-CA","preferredCurrency":"USD"}]},"alias":"us"}'
47 | )
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/app/pages/product-list/partials/page-header.jsx:
--------------------------------------------------------------------------------
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 React, {Fragment} from 'react'
9 | import PropTypes from 'prop-types'
10 | import {isServer} from '../../../utils/utils'
11 | // Components
12 | import {Box, Heading, Flex, Text, Fade} from '@chakra-ui/react'
13 |
14 | // Project Components
15 | import Breadcrumb from '../../../components/breadcrumb'
16 |
17 | const PageHeader = ({category, productSearchResult, isLoading, searchQuery, ...otherProps}) => {
18 | return (
19 |
20 | {/* Breadcrumb */}
21 | {category && }
22 | {searchQuery && Search Results for}
23 | {/* Category Title */}
24 |
25 |
26 | {`${category?.name || searchQuery || ''}`}
27 |
28 |
29 | {isServer ? (
30 | ({productSearchResult?.total})
31 | ) : (
32 | // Fade in the total when available. When it's changed or not available yet, do not render it
33 | !isLoading && ({productSearchResult?.total})
34 | )}
35 |
36 |
37 |
38 | )
39 | }
40 |
41 | PageHeader.propTypes = {
42 | category: PropTypes.object,
43 | productSearchResult: PropTypes.object,
44 | isLoading: PropTypes.bool,
45 | searchQuery: PropTypes.string
46 | }
47 |
48 | export default PageHeader
49 |
--------------------------------------------------------------------------------
/app/hooks/use-toast.test.js:
--------------------------------------------------------------------------------
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 {useToast} from './use-toast'
9 | import {Button} from '@chakra-ui/react'
10 | import {renderWithProviders} from '../utils/test-utils'
11 | import {screen, waitFor} from '@testing-library/react'
12 | import user from '@testing-library/user-event'
13 |
14 | jest.setTimeout(60000)
15 | const MockedComponent = (props) => {
16 | const showToast = useToast()
17 |
18 | const renderToast = () => {
19 | showToast({
20 | ...props,
21 | title: 'Demo Notification',
22 | status: 'success',
23 | duration: 1000,
24 | variant: 'subtle'
25 | })
26 | }
27 | return (
28 | <>
29 |
30 | >
31 | )
32 | }
33 |
34 | // Set up and clean up
35 | beforeEach(() => {
36 | jest.resetModules()
37 | })
38 |
39 | test('renders toast with action', async () => {
40 | const handleActionClick = jest.fn()
41 | const toastAction =
42 |
43 | renderWithProviders()
44 |
45 | const toastTrigger = await screen.findByRole('button', {name: /show toast/i})
46 | user.click(toastTrigger)
47 |
48 | await waitFor(() => {
49 | // Chakra UI renders multiple elements with toast title in DOM for accessibility.
50 | // We need to assert the actual text within the alert
51 | expect(screen.getByRole('alert')).toHaveTextContent(/demo notification/i)
52 | })
53 |
54 | const toastActionTrigger = await screen.findByRole('button', {name: /action/i})
55 | user.click(toastActionTrigger)
56 | expect(handleActionClick).toHaveBeenCalledTimes(1)
57 | })
58 |
--------------------------------------------------------------------------------
/app/assets/svg/like.svg:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/app/pages/marketing-pages/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {BuilderComponent, builder, useIsPreviewing} from '@builder.io/react'
3 | import PageNotFound from '../page-not-found'
4 | import Seo from '../../components/seo'
5 | import {Box, Skeleton} from '@chakra-ui/react'
6 | import PropTypes from 'prop-types'
7 | import builderConfig from '../../utils/builder'
8 |
9 | export const MarketingPage = ({page, isLoading}) => {
10 | const isPreviewing = useIsPreviewing()
11 | if (isLoading) {
12 | return (
13 |
14 |
15 |
16 | )
17 | }
18 |
19 | if (!isPreviewing && !page) {
20 | return
21 | }
22 | let header =
23 | if (page) {
24 | const {title, description, keywords, noIndex} = page.data
25 | header = (
26 |
32 | )
33 | }
34 |
35 | return (
36 |
37 | {header}
38 |
43 |
44 | )
45 | }
46 |
47 | // eslint-disable-next-line
48 | MarketingPage.getProps = async ({res, api, location}) => {
49 | const page = await builder
50 | .get(builderConfig.pageModel, {
51 | url: location.pathname,
52 | options: {
53 | includeRefs: true
54 | }
55 | })
56 | .toPromise()
57 |
58 | if (!page && res) {
59 | res.status(404)
60 | }
61 |
62 | return {page}
63 | }
64 |
65 | MarketingPage.propTypes = {
66 | page: PropTypes.any,
67 | isLoading: PropTypes.bool
68 | }
69 |
70 | export default MarketingPage
71 |
--------------------------------------------------------------------------------
/app/components/forms/form-action-buttons.jsx:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {FormattedMessage} from 'react-intl'
10 | import {Button, Stack} from '@chakra-ui/react'
11 | import {MESSAGE_PROPTYPE} from '../../utils/locale.js'
12 |
13 | /**
14 | * Renders a form submit button and a cancel button with configurable labels and callbacks
15 | * in a responsive layout. Used primarily in forms that can be toggled opened/closed.
16 | */
17 | const FormActionButtons = ({
18 | saveButtonProps = {},
19 | cancelButtonProps = {},
20 | saveButtonLabel,
21 | cancelButtonLabel,
22 | onCancel = () => {}
23 | }) => {
24 | return (
25 |
26 |
33 |
43 |
44 | )
45 | }
46 |
47 | FormActionButtons.propTypes = {
48 | saveButtonProps: PropTypes.object,
49 | cancelButtonProps: PropTypes.object,
50 | saveButtonLabel: MESSAGE_PROPTYPE,
51 | cancelButtonLabel: MESSAGE_PROPTYPE,
52 | onCancel: PropTypes.func
53 | }
54 |
55 | export default FormActionButtons
56 |
--------------------------------------------------------------------------------
/app/components/links-list/index.test.js:
--------------------------------------------------------------------------------
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 PropTypes from 'prop-types'
9 | import {StylesProvider, useMultiStyleConfig} from '@chakra-ui/react'
10 | import {screen} from '@testing-library/react'
11 |
12 | import {renderWithProviders} from '../../utils/test-utils'
13 | import LinksList from './index'
14 |
15 | const links = [
16 | {
17 | href: '/',
18 | text: 'Privacy Policy'
19 | }
20 | ]
21 | const horizontalVariantSelector = 'ul > .chakra-stack > li'
22 |
23 | const FooterStylesProvider = ({children}) => {
24 | const styles = useMultiStyleConfig('Footer')
25 | return {children}
26 | }
27 | FooterStylesProvider.propTypes = {
28 | children: PropTypes.node
29 | }
30 |
31 | test('renders LinksList with default arguments', () => {
32 | renderWithProviders(
33 |
34 |
35 |
36 | )
37 |
38 | expect(screen.getAllByRole('listitem')).toHaveLength(1)
39 | expect(screen.getByRole('link', {name: links[0].text})).toBeInTheDocument()
40 | expect(screen.queryByRole('heading')).toBeNull()
41 | expect(document.querySelector(horizontalVariantSelector)).toBeNull()
42 | })
43 |
44 | test('renders LinksList with heading', () => {
45 | renderWithProviders(
46 |
47 |
48 |
49 | )
50 |
51 | expect(screen.getByRole('heading')).toBeInTheDocument()
52 | })
53 |
54 | test('renders LinksList with horizontal variant', () => {
55 | renderWithProviders(
56 |
57 |
58 |
59 | )
60 |
61 | expect(document.querySelector(horizontalVariantSelector)).toBeInTheDocument()
62 | })
63 |
--------------------------------------------------------------------------------
/app/components/product-view-modal/index.test.js:
--------------------------------------------------------------------------------
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 React from 'react'
9 | import PropTypes from 'prop-types'
10 | import ProductViewModal from './index'
11 | import {renderWithProviders} from '../../utils/test-utils'
12 | import {fireEvent, screen} from '@testing-library/react'
13 | import {useDisclosure} from '@chakra-ui/react'
14 | import mockProductDetail from '../../commerce-api/mocks/variant-750518699578M'
15 |
16 | const MockComponent = ({updateCart}) => {
17 | const {isOpen, onOpen, onClose} = useDisclosure()
18 |
19 | return (
20 |
21 |
22 | {isOpen && (
23 |
30 | )}
31 |
32 | )
33 | }
34 |
35 | MockComponent.propTypes = {
36 | updateCart: PropTypes.func
37 | }
38 |
39 | test('renders product view modal by default', () => {
40 | renderWithProviders()
41 |
42 | // open the modal
43 | const trigger = screen.getByText(/open modal/i)
44 | fireEvent.click(trigger)
45 |
46 | expect(screen.getAllByText(/Black Single Pleat Athletic Fit Wool Suit/i).length).toEqual(2)
47 | })
48 |
49 | test('renders product view modal with handleUpdateCart handler', () => {
50 | const handleUpdateCart = jest.fn()
51 | renderWithProviders()
52 |
53 | // open the modal
54 | const trigger = screen.getByText(/open modal/i)
55 | fireEvent.click(trigger)
56 |
57 | // click on update
58 | const updateButton = screen.getAllByText(/Update/)[0]
59 | fireEvent.click(updateButton)
60 |
61 | expect(handleUpdateCart).toHaveBeenCalledTimes(1)
62 | })
63 |
--------------------------------------------------------------------------------
/app/pages/account/constant.js:
--------------------------------------------------------------------------------
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 {defineMessages} from 'react-intl'
9 | import {
10 | AccountIcon,
11 | LocationIcon,
12 | PaymentIcon,
13 | ReceiptIcon,
14 | HeartIcon
15 | } from '../../components/icons'
16 |
17 | export const messages = defineMessages({
18 | profile: {defaultMessage: 'Account Details', id: 'global.account.link.account_details'},
19 | addresses: {defaultMessage: 'Addresses', id: 'global.account.link.addresses'},
20 | orders: {defaultMessage: 'Order History', id: 'global.account.link.order_history'},
21 | payments: {defaultMessage: 'Payment Methods', id: 'global.account.link.payment_methods'},
22 | wishlist: {defaultMessage: 'Wishlist', id: 'global.account.link.wishlist'}
23 | })
24 |
25 | export const navLinks = [
26 | {
27 | name: 'profile',
28 | path: '',
29 | icon: AccountIcon
30 | },
31 | {
32 | name: 'wishlist',
33 | path: '/wishlist',
34 | icon: HeartIcon
35 | },
36 | {
37 | name: 'orders',
38 | path: '/orders',
39 | icon: ReceiptIcon
40 | },
41 | {
42 | name: 'addresses',
43 | path: '/addresses',
44 | icon: LocationIcon
45 | },
46 | {
47 | name: 'payments',
48 | path: '/payments',
49 | icon: PaymentIcon
50 | }
51 | ]
52 |
53 | export const CONFIRMATION_DIALOG_DEFAULT_CONFIG = defineMessages({
54 | dialogTitle: {
55 | defaultMessage: 'Confirm Action',
56 | id: 'confirmation_modal.default.title.confirm_action'
57 | },
58 | confirmationMessage: {
59 | defaultMessage: 'Are you sure you want to continue?',
60 | id: 'confirmation_modal.default.message.you_want_to_continue'
61 | },
62 | primaryActionLabel: {defaultMessage: 'Yes', id: 'confirmation_modal.default.action.yes'},
63 | alternateActionLabel: {defaultMessage: 'No', id: 'confirmation_modal.default.action.no'}
64 | })
65 |
--------------------------------------------------------------------------------