Skip to content

Commit

Permalink
Merge branch 'v3' into feature/template-extensibility-algo-refactor
Browse files Browse the repository at this point in the history
* v3:
  [v3] Add Convenience Components (#1183)
  Update commerce-sdk-react README (#1176)
  Fix missing commerce-sdk-react logout call (#1180)

# Conflicts:
#	packages/template-retail-react-app/app/components/_app/index.jsx
#	packages/template-retail-react-app/app/pages/product-list/index.jsx
  • Loading branch information
bfeister committed May 10, 2023
2 parents 151b96b + 2422e07 commit 61e32b8
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 44 deletions.
279 changes: 262 additions & 17 deletions packages/commerce-sdk-react/README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
# Commerce SDK React

A library of React hooks for fetching data from Salesforce B2C Commerce.
<p align="center">
A collection of <a href="https://tanstack.com/query/latest/docs/react/overview">react-query</a> hooks for <b>fetching</b>, <b>caching</b>, and <b>mutating data</b> from the <b><a href="https://developer.salesforce.com/docs/commerce/commerce-api/overview">Salesforce B2C Commerce API</a></b> (SCAPI).</p>

## Documentation
## 🎯 Features

The full documentation for PWA Kit and Managed Runtime is hosted on the [Salesforce Developers](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/overview) portal.
- Shopper authentication & token management via [SLAS](https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-login)
- Server side data fetching (in conjuction with PWA Kit)
- Phased Launch support ([plugin_slas](https://github.com/SalesforceCommerceCloud/plugin_slas) compatible)
- Built-in caching for easy state management
- automatic cache invalidations/updates via the library's built-in mutations
- automatic cache key generation

## ⚙️ Installation

## PWA-Kit Integration
```bash
npm install @salesforce/commerce-sdk-react @tanstack/react-query
```

> To integration this library with your PWA-Kit application you can use the `CommerceApiProvider` directly given that you use the `withReactQuery` higher order component to wrap your `AppConfig` component. Below is a snippet of how this is accomplished.
## ⚡️ Quickstart (PWA Kit v2.3.0+)

```
To integrate this library with your PWA Kit application you can use the `CommerceApiProvider` directly assuming that you use the `withReactQuery` higher order component to wrap your `AppConfig` component. Below is a snippet of how this is accomplished.

```jsx
// app/components/_app-config/index.jsx

import {CommerceApiProvider} from '@salesforce/commerce-sdk-react'
import {withReactQuery} from 'pwa-kit-react-sdk/ssr/universal/components/with-react-query'

const AppConfig = ({children}) => {
return (
<CommerceApiProvider {...commerceApiProviderProps}>
<CommerceApiProvider
clientId="12345678-1234-1234-1234-123412341234"
organizationId="f_ecom_aaaa_001"
proxy="localhost:3000/mobify/proxy/api"
redirectURI="localhost:3000/callback"
siteId="RefArch"
shortCode="12345678"
locale="en-US"
currency="USD"
>
{children}
</CommerceApiProvider>
)
Expand All @@ -42,20 +63,30 @@ const options = {
export default withReactQuery(AppConfig, options)
```

## Generic Integration
## ⚡️ Quickstart (Generic React App)

> You can use this library in any React application provided you bring your own QueryClient and QueryClientProvider. Below is a sample integration:
You can use this library in any React application by creating a new QueryClient and wrap your application with `QueryClientProvider`. For example:

```
import {QueryClient, QueryClientConfig, QueryClientProvider} from '@tanstack/react-query'
```jsx
import {CommerceApiProvider} from '@salesforce/commerce-sdk-react'
import {QueryClient, QueryClientProvider} from '@tanstack/react-query'


const App = ({children}) => {
const queryClient = new QueryClient(queryClientConfig)
const queryClient = new QueryClient()

return (
<QueryClientProvider client={queryClient}>
<CommerceApiProvider {...commerceApiProviderProps}>
<CommerceApiProvider
clientId="12345678-1234-1234-1234-123412341234"
organizationId="f_ecom_aaaa_001"
proxy="localhost:3000/mobify/proxy/api"
redirectURI="localhost:3000/callback"
siteId="RefArch"
shortCode="12345678"
locale="en-US"
currency="USD"
>
{children}
</CommerceApiProvider>
</QueryClientProvider>
Expand All @@ -64,7 +95,224 @@ const App = ({children}) => {

export default App
```
### Useful Links:

## Shopper Authentication and Token Management

_💡 This section assumes you have read and completed the [Authorization for Shopper APIs](https://developer.salesforce.com/docs/commerce/commerce-api/guide/authorization-for-shopper-apis.html) guide._

To help reduce boilerplate code for managing shopper authentication, by default, this library automatically initializes shopper session and manages the tokens for developers. Currently, the library supports the [Public Client login flow](https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas-public-client.html).

### Shopper Session Initialization

On `CommerceApiProvider` mount, the provider initializes shopper session by initiating the SLAS __Public Client__ login flow. The tokens are stored/managed/refreshed by the library.

### Authenticate request queue

While the library is fetching/refreshing the access token, the network requests will queue up until there is a valid access token.

### Login helpers

To leverage the managed shopper authentication feature, use the `useAuthHelper` hook for shopper login.

Example:

```jsx
import {AuthHelpers, useAuthHelper} from '@salesforce/commerce-sdk-react'

const Example = () => {
const register = useAuthHelper(AuthHelpers.Register)
const login = useAuthHelper(AuthHelpers.LoginRegisteredUserB2C)
const logout = useAuthHelper(AuthHelpers.LogOut)

return <button onClick={() => {
login.mutate({username: 'kevin', password: 'pa$$word'})
}}>
}
```

### Externally Managed Shopper Authentication

You have the option of handling shopper authentication externally, by providing a SLAS access token. This is useful if you plan on using this library in an application where the authentication mechanism is different.

```jsx
const MyComponent = ({children}) => {
return (
<CommerceApiProvider fetchedToken="xxxxxxxxxxxx">
{children}
</CommerceApiProvider>
)
}
```

## Hooks

The majority of hooks provided in this library are built on top of the [useQuery](https://tanstack.com/query/latest/docs/react/reference/useQuery) and the [useMutation](https://tanstack.com/query/latest/docs/react/reference/useMutation) hook from [react-query](https://tanstack.com/query/latest). React-query provides a declarative way for fetching and updating data. This library takes advantage of the features provided by react-query and combine with the [commerce-sdk-isomorphic](https://github.com/SalesforceCommerceCloud/commerce-sdk-isomorphic) API client to create a collection of hooks to simplify data fetching for SCAPI.

The hooks can be categorized into __Query hooks__ and __Mutation hooks__.

### Query hooks

The query hooks correspond to the http GET endpoints from the SCAPI. The query hooks follow the signature pattern:

```
use<EntityName>(CommerceClientOptions, ReactQueryOptions)
```

Both the __required__ and __optional__ parameters for the underlying `commerce-sdk-isomorphic` call is passed as the first parameter:

```jsx
import {useProduct} from '@salesforce/commerce-sdk-react'

const Example = () => {
const query = useProduct({
parameters: {
id: '25592770M',
locale: 'en-US'
}
})

return <>
<p>isLoading: {query.isLoading}</p>
<p>name: {query.data?.name}</p>
</>
}
```
The second parameter is the react-query query options, for more detail, read [useQuery reference](https://tanstack.com/query/latest/docs/react/reference/useQuery).
```jsx
import {useBasket} from '@salesforce/commerce-sdk-react'

const onServer = typeof window === undefined

const Example = ({basketId}) => {
const query = useBasket({
parameters: {
basketId: basketId
},
}, {
// A common use case for `enabled` is
// to conditionally fetch based on environment
enabled: !onServer && basketId
})
}
```
### Mutation hooks
The query hooks correspond to the http POST, PUT, PATCH, DELETE endpoints from the SCAPI. The mutation hooks follow the signature pattern:
```
use<ApiName>Mutation(EndpointName)
```
For example, the [ShopperBaskets API](https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-baskets?meta=Summary) has a number of endpoints, one of them being the [addItemToBasket](https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-baskets?meta=addItemToBasket) endpoint (`POST /baskets/{basketId}/items`).
```jsx
import {useShopperBasketsMutation} from '@salesforce/commerce-sdk-react'

const Example = ({basketId}) => {
// Typescript IDE intellisense for available options
const addItemToBasket = useShopperBasketsMutation('addItemToBasket')

return <button onClick={() => addItemToBasket.mutate({
parameters: {
basketId
},
body: {
productId: '25592770M',
price: 55,
quantity: 1
}
})} />
}
```
You could also import the mutation options as a constant like:
```jsx
import {useShopperBasketsMutation, ShopperBasketsMutations} from '@salesforce/commerce-sdk-react'

const Example = ({basketId}) => {
const addItemToBasket = useShopperBasketsMutation(ShopperBasketsMutations.AddItemToBasket)
return ...
}
```
### Cache Invalidations and Updates
Since mutations changes data on the server, the cache entries that are potentially affected by the mutation is automatically invalidated.
For example, an `addItemToBasket` mutation automatically update `useBasket` and `useCustomerBaskets` query cache, because the mutation result contains the information for the updated basket. In other cases, when the mutation response do not have the updated data, the library will invalidate the cache and trigger a re-fetch. For the DELETE endpoints, the library removes the cache entries on successful mutations.
_💡 Debugging hint: install and include `@tanstack/react-query-devtools` in your React app to see the queries (inspect the query states and cache keys)._
## Ultilities
Besides the collection of query hooks and mutation hooks, here are some ultility hooks to help you interact with SCAPI.
### `useCommerceApi()`
This hook returns a set of SCAPI clients, which are already initialized using the configurations passed to the provider. Note: this hook doesn't automatically include auth headers.
```jsx
import {useCommerceApi, useAccessToken} from '@salesforce/commerce-sdk-react'

const Example = () => {
const api = useCommerceApi()
const {getTokenWhenReady} = useAccessToken()

const fetchProducts = async () => {
const token = await getTokenWhenReady()
const products = await api.shopperProducts.getProducts({
parameters: {ids: ids.join(',')},
headers: {
Authorization: `Bearer ${token}`
}
})
return products
}

}
```
### `useAccessToken()`
```ts
useAccessToken() => {token: String, getTokenWhenReady: Promise}
```
This ultility hook give access to the managed SLAS access token.
### `useCustomerId()`
```ts
useCustomerId() => null | string
```
### `useCustomerType()`
```ts
useCustomerId() => null | 'guest' | 'registered'
```
### `useEncUserId()`
```ts
useEncUserId() => null | string
```
### `useUsid()`
```ts
useUsid() => null | string
```
## Roadmap
- Optimistic update support
- SLAS private client support
## Useful Links:
- [Get Started](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/getting-started.html)
- [Skills for Success](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/skills-for-success.html)
Expand All @@ -77,6 +325,3 @@ export default App
- [Routing](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/routing.html)
- [Phased Headless Rollouts](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/phased-headless-rollouts.html)
- [Launch Your Storefront](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/launching-your-storefront.html)

## Support Policy
Security patches are provided for 24 months after the general availability of each major version of the SDK (1.0, 2.0, and so on).
7 changes: 5 additions & 2 deletions packages/commerce-sdk-react/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,11 @@ class Auth {
*
*/
async logout() {
// TODO: are we missing a call to /logout?
// Ticket: https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE00001EFF4nYAH/view
// Not awaiting on purpose because there isn't much we can do if this fails.
void helpers.logout(this.client, {
accessToken: this.get('access_token'),
refreshToken: this.get('refresh_token_registered')
})
this.clearStorage()
return this.loginGuestUser()
}
Expand Down
1 change: 1 addition & 0 deletions packages/template-retail-react-app/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## v2.8.0-dev (Mar 03, 2023)
- Add app `above-header` and product-list `above-page-header` convenience components [#1183](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1183)
- Remove `cross-fetch` dependency [#1160](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1160)
- Make `mergeBasket` conditional more robust [#1048](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1048)

Expand Down
Loading

0 comments on commit 61e32b8

Please sign in to comment.