> For the complete documentation index, see [llms.txt](https://developer.esw.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.esw.com/shopify/salesforce-commerce-cloud/cartridge-setup/composable-storefront-setup-with-scapi-and-pwa.md).

# Composable Storefront Setup with SCAPI and PWA

### Setup and Configuration

#### Setting up BM cartridge / Cartridge Path

{% stepper %}
{% step %}
Add the following cartridges to your cartridge path:

* `int_eshopworld_core`
* `int_eshopworld_pwa`
  {% endstep %}

{% step %}
The cartridge path should look like this:

* `int_eshopworld_core:int_eshopworld_pwa:app_storefront_base:modules`
  {% endstep %}
  {% endstepper %}

#### Importing site data

After setting up the cartridge path, import PWA-related custom objects, preferences, and content slots from the following paths:

**System objects**

* `link_eshopworld/sitesdata/meta/systemobjects.xml`

**Custom objects**

* `link_eshopworld/sitesdata/meta/customobjects.xml`

**Content assets**

* `link_eshopworld/sitesdata/sites/RefArch/libraries.xml`
* `link_eshopworld/sitesdata/sites/RefArch/content-assets.xml`

#### Configuring PWA-related custom preferences

{% stepper %}
{% step %}
Navigate to **Merchant Tools > Site Preferences > Custom Site Preference Groups > ESW PWA Integration Configuration**.
{% endstep %}

{% step %}
Provide the **PWA Storefront URL** (needed because ESW does not get server reference on MRT).
{% endstep %}

{% step %}
Provide **ESW PWA URL Expansion Pairs**:

* `InventoryCheckFailurePageUrl|cart`
* `BaseUrl|`
* `ContinueShoppingUrl|Base url`
* `BackToCartUrl|cart`
  {% endstep %}
  {% endstepper %}

***

### Configuring Countries and Locales

#### Configuring “Countries” custom object

{% stepper %}
{% step %}
Navigate to **Merchant Tools > Custom Objects > Manage Custom Objects**.
{% endstep %}

{% step %}
Select `ESW_COUNTRIES`.
{% endstep %}

{% step %}
Select the country.
{% endstep %}

{% step %}
Add locale(s) for the country (as per the PDF screenshot guidance).
{% endstep %}

{% step %}
Locale must be in `{lang_Country}` format (for example, `en_IE`, `en_US`, `en_CA`).
{% endstep %}
{% endstepper %}

#### Configuring locales

{% stepper %}
{% step %}
Navigate to **Merchant Tools > Site Preferences > Locales** and check if your locale is present.
{% endstep %}

{% step %}
If present: activate it (check it and click **Apply**).
{% endstep %}

{% step %}
If absent: add it via **Administration > Global Preferences > Locales > New Locale** (generates `{lang_Country}` format).
{% endstep %}
{% endstepper %}

***

### Code Customization

After you set up and run the PWA Kit successfully, ESW-related changes require overrides.

#### Files to override to enable ESW checkout functionality

<details>

<summary>Place the following files in the relevant PWA Kit directories to enable ESW checkout</summary>

| File path                                  | Purpose                                                                          |
| ------------------------------------------ | -------------------------------------------------------------------------------- |
| `config/default.js`                        | To add ESW cartridge-related URLs.                                               |
| `config/sites.js`                          | Override this file so that add only one base country configs.                    |
| `override/main.jsx`                        | Add timezone cookie.                                                             |
| `components/footer/index.js`               | To call ESW init component.                                                      |
| `components/forms/login-fields.jsx`        | Prefilled login email for post-checkout registration.                            |
| `components/forms/registration-fields.jsx` | Prefilled registration fields for post-checkout registration.                    |
| `components/product-item/index.jsx`        | Display return prohibit and restricted product message.                          |
| `components/product-view/index.jsx`        | Display return prohibit and restricted product message.                          |
| `hooks/use-derived-product.js`             | Setting return restricted product message.                                       |
| `hooks/use-add-to-cart-modal.js`           | Override checkout button in add to cart modal.                                   |
| `utils/site-utils.js`                      | Get site/country configs from BM instead of `sites.js`.                          |
| `pages/account/order-detail.jsx`           | Display order tracking information from ESW.                                     |
| `pages/cart/partials/cart-cta.jsx`         | Override checkout button.                                                        |
| `pages/cart/index.jsx`                     | —                                                                                |
| `pages/routes.jsx`                         | —                                                                                |
| `translations/en-US.json`                  | Add message for restricted products; update relevant translation file as needed. |

</details>

***

### Adding ESW-related “.js” configurations

#### `esw-config.js`

Go to `/configs` folder and add `esw-config.js` (as per PDF instruction).

#### `default.js` (add `eswConfigs`)

Add the following configuration in `default.js` in the app (ensure paths are correct):

```js
eswConfigs: {
  ocapiProxyPath: '/mobify/proxy/ocapi',
  siteUri: '/on/demandware.store/Sites-RefArch-Site/default'
}
```

#### `sites.js` (base country configs)

The `sites.js` file should have content shaped like the following (base country example shown in PDF for US / RefArch):

{% code expandable="true" %}

```js
module.exports = [
  {
    id: 'RefArch',
    l10n: {
      supportedCurrencies: ['USD'], // Retailer's base currency
      defaultCurrency: 'USD', // Retailer's base currency
      defaultLocale: 'en-US', // Retailer's base country locale
      supportedLocales: [
        {
          id: 'en-US', // Retailer's base country locale
          alias: 'us', // country code in lowercase for URL
          preferredCurrency: 'USD', // Retailer's base currency
          supportedLocales: ['en-US'], // Retailer's base country locale
          isFixedPriceModel: true,
          isSupportedByESW: true,
          countryCode: 'US' // country code in uppercase for ESW config
        }
      ]
    }
  }
]
```

{% endcode %}

***

### Init ESW Component (Footer override)

This component is responsible for:

* Getting ESW-related configurations.
* Displaying geo-ip alert if the user changes the location.
* Rebuilding the cart when a user comes back to the cart from the ESW checkout.

Steps (per PDF):

1. Navigate to `/overrides/components/footer/index.jsx` (copy file from pwa-kit if absent).
2. Import `EswInit`.
3. Add `EswInit` component.

#### Import `EswInit`

```js
import {EswInit} from '../../esw/components/esw-init'
```

#### Add `EswInit` component (as per screenshot snippet)

```jsx
{/* ESW INIT */}
<EswInit locale={locale} site={site} />
{/* End ESW INIT */}
```

> Note from PDF: EswInit calls the APIs during the initial rendering of the app.

***

### Overriding Registration and Login Forms (optional – ESW shopper registration feature)

<details>

<summary>Optional: Registration and Login Forms override details</summary>

Navigate to `/overrides/components/forms` (create if missing).

* Copy `login-fields.jsx` from ESW PWA cartridge (PDF says to add code snippets there).
* Copy `registration-fields.jsx` from ESW PWA cartridge (PDF says to add code snippets there).

(There are no explicit code blocks shown in the PDF text for these snippets beyond “add the following code snippets”.)

</details>

***

### Overriding Product Item Component (Return Prohibited feature)

Navigate to `/overrides/components/product-item/index.jsx` (copy from PWA cartridge if absent).

#### Import (shown truncated in PDF text; path starts as below)

```js
import {EswReturnProhibitMsg} from '../../esw/components/product-return'
```

#### Call component (screenshot snippet)

```jsx
{/* Esw return prohibit message */}
<EswReturnProhibitMsg product={product} />
{/* End Esw return prohibit message */}
```

***

### Overriding Product View Component (Return Prohibited feature)

Navigate to `/overrides/components/product-view/index.jsx` (copy from PWA cartridge if absent).

#### Import (shown truncated in PDF text; path starts as below)

```js
import {EswReturnProhibitMsg} from '../../esw/components/product-return'
```

***

### Override `use-derived-product` hook (restricted product messaging)

Navigate to `/overrides/hooks/use-derived-product.js` (copy from PWA cartridge if absent) and add code as shown in the PDF screenshot.

#### Add restricted product constant (screenshot snippet)

```js
// Esw modification
const ESW_RESTRICTED_PRODUCT = 'ESW_RESTRICTED_PRODUCT'
// End Esw modification
```

#### Add ESW restricted flags (screenshot snippet)

```js
// Esw modification
const isEswRestricted =
  product && product.c_eswRestrictedProduct ? product.c_eswRestrictedProduct : false
const eswProductRestrictedMsg =
  product && product.c_eswRestrictedProductMsg ? product.c_eswRestrictedProductMsg : ''
// End Esw modification
```

#### Add translation mapping (screenshot snippet)

```js
// Esw modification
[ESW_RESTRICTED_PRODUCT]: intl.formatMessage(
  {
    defaultMessage: '{eswProductRestrictedMsg}',
    id: 'esw.product.restricted.msg'
  },
  { eswProductRestrictedMsg }
)
// End Esw modification
```

#### Update inventory messaging conditions (screenshot snippet)

```js
// Esw modification
const showInventoryMessage =
  product && ((variant && (isOutOfStock || unfulfillable)) || isEswRestricted)
const inventoryMessage =
  (isOutOfStock && inventoryMessages[OUT_OF_STOCK]) ||
  (unfulfillable && inventoryMessages[UNFULFILLABLE]) ||
  (isEswRestricted && inventoryMessages[ESW_RESTRICTED_PRODUCT])
// End Esw modification
```

***

### Add translation key (required after `use-derived-product` override)

Go to `/translations/en-US.json` and add:

```json
"esw.product.restricted.msg": {
  "defaultMessage": "{eswProductRestrictedMsg}"
},
```

***

### Overriding `use-add-to-cart-modal` hook (checkout button in add-to-cart modal)

Navigate to `/overrides/hooks/use-derived-product.js` (PDF text says this path; context indicates overriding hook for add-to-cart modal behavior). If absent, get it from the PWA cartridge.

#### Import required ESW modules&#x20;

```js
// Esw Customization
import { EswCheckoutBtn } from '../esw/components/checkout-btn'
import {
  useShippingMethodsForShipment,
  useShopperBasketsMutation
} from '@salesforce/commerce-sdk-react'
// end Esw Customization
```

#### Replace checkout button in both components

Make sure to change it in both:

* `<ModalBody/>`
* `<ModalFooter/>`

```jsx
<EswCheckoutBtn
  basketIdParam={basket.basketId}
  variant="outline"
  checkOrderAble={false}
/>
```

***

### Overriding `site-utils.js` (get countries from BM config)

Navigate to `/overrides/utils/site-utils.js` (copy from PWA cartridge if absent).

#### Import `getSupportedCountries`&#x20;

```js
import {getSupportedCountries} from '../esw/esw-services'
```

#### Update `getSites()`&#x20;

```js
/**
 * ESW customized function to return the list of sites that has include
 * @return {array} sites - list of sites including their aliases
 */
export const getSites = () => {
  let sitesFromConfig = getConfig().app

  // sites.js from the BM
  getSupportedCountries()
    .then((response) => response.json())
    .then((data) => (sitesFromConfig.sites = data.allowedCountries))

  let {sites = [], siteAliases = {}} = sitesFromConfig || {}

  if (!sites.length) {
    throw new Error("Can't find any sites from the config. Please c")
  }

  return sites.map((site) => {
    const alias = siteAliases[site.id]
    return {
      ...site,
      ...(alias ? {alias} : {})
    }
  })
}
```

***

### Overriding Order Detail Page (order tracking)

Navigate to `/overrides/pages/account/order-detail.jsx` (copy from PWA cartridge if absent).

#### Import `ESWOrderTracking`&#x20;

```js
import ESWOrderTracking from '../../esw/components/order-tracking/index'
```

#### Call component&#x20;

```jsx
{/* Custom for ESW start */}
{selectedOrder && <ESWOrderTracking selectedOrder={selectedOrder} />}
{/* Custom for ESW END */}
```

***

### Overriding Cart Page (redirect to ESW checkout only if supported)

#### Override cart CTA

Navigate to `/overrides/pages/cart/partials/cart-cta.jsx` (copy from PWA cartridge if absent).

**Import `EswCheckoutBtn`**

```js
import {EswCheckoutBtn} from '../../../esw/components/checkout-btn'
```

**Call component**&#x20;

```jsx
{/* Esw Modification */}
<EswCheckoutBtn variant="solid" />
{/* End Modification */}
```

#### Call cart CTA in cart page

Navigate to `/overrides/pages/cart/index.jsx` and modify the import of `cart-cta` as follows (screenshot snippet):

```js
// ESW specific component
import ProductItem from '../../components/product-item'
import CartCta from './partials/cart-cta'
// End ESW specific component
```

***

### Overriding Routes (required after cart override)

Navigate to `/overrides/routes.jsx`

#### Import Cart&#x20;

```js
import Cart from './pages/cart'
```

#### Add route entry&#x20;

```js
{
  path: '/cart',
  component: Cart,
  exact: true
}
```

***

### Add shopper timezone cookie (required if MRT does not provide user’s country)

Navigate to `/overrides/main.jsx` and add (PDF snippet was truncated after `resolv`; completed to a standard Intl timezone cookie value):

```js
// Esw: Customization
document.cookie = "esw.shopperTimezone=" + Intl.DateTimeFormat().resolvedOptions().timeZone
```

***

### Updating Content Slots and Messages

#### Updating Geo-Ip Alert Message

If you are using geo lookup, the alert messages displayed to shoppers can be customized:

* Navigate to the asset: `eswGeoIpChangeWarning`
* Make necessary changes.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.esw.com/shopify/salesforce-commerce-cloud/cartridge-setup/composable-storefront-setup-with-scapi-and-pwa.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
