Add a default commerce api provider to store locator extension#2194
Conversation
| if (!config.commerceApi || !config.commerceApi?.parameters) { | ||
| return <WrappedComponent {...(props as P)} /> | ||
| } |
There was a problem hiding this comment.
It would be nice if there is a way to "automatically" detect the existence of the CommerceApiProvider.
There was a problem hiding this comment.
I wish the commerce-sdk-react package can throw a "Context not found" error, but currently it throws a weird error
pwa-kit-react-sdk.react-rendering.render ERROR TypeError: Cannot read properties of undefined (reading 'clientConfig')
at mergeOptions (/Users/kevin.he/dev/pwa-kit/packages/template-typescript-minimal/build/main-server.js:9348:56)
at useSearchStores (/Users/kevin.he/dev/pwa-kit/packages/template-typescript-minimal/build/main-server.js:7780:81)
I'm hesitant to catch this "unofficial" error
There was a problem hiding this comment.
I'm going to create a ticket to fix it in the sdk
There was a problem hiding this comment.
As mentioned in our meeting, it is a common pattern to use a hook to see if it throws or not like this:
import {useCommerceApi} from '@salesforce/commerce-sdk-react'
const hasCommerceApiProvider = () => {
const hasProvider = true
try {
const api = useCommerceApi() // you can technically use other hooks here, but we might want to stick to using one that has it's own context defined in the lib, and not one relying on react query contexts.
}
catch () {
hasProvider = false
}
return hasProvider
}
Then inside this file you can use this locally defined hook to determine if there is already a provider.
| @@ -0,0 +1,48 @@ | |||
| /* | |||
| * Copyright (c) 2024, salesforce.com, inc. | |||
There was a problem hiding this comment.
Get with the times man.. it's 2025 😄
| import {CommerceApiProvider} from '@salesforce/commerce-sdk-react' | ||
| import {UserConfig} from '../types/config' | ||
|
|
||
| type WithOptionalCommerceSdkReactProvider = React.ComponentPropsWithoutRef<any> |
There was a problem hiding this comment.
I know this comment isn't related to what you are implementing in your PR.. but seeing any triggered me to ask a question.
There was a problem hiding this comment.
I'm not sure if there is a better option for this, maybe I should use unknown? since the underlying wrapped component props is unknown?
| * @param config - The configuration object for the CommerceApiProvider. | ||
| * @returns A component that wraps the given component with CommerceApiProvider if it is not already present in the component tree. | ||
| */ | ||
| export const withOptionalCommerceSdkReactProvider = <P extends object>( |
There was a problem hiding this comment.
Not required, but if this is going to be a pattern that we intend on suggesting extension developers use, then it might be worth while to create a utility that will take a provider component and a hook that is used to determine if there is a preexisting provider already and spit out an optional provider. Something like this:
import {withOptional} from '@salesforce/pwa-kit-react-sdk/...'
import {useCommerceApi} from '@salesforce/commerce-sdk-react'
const withOptionalCommerceSdkReactprovider = withOptional(CommerceApiProvider, {assertionHook: useCommerceApi})
Where the first arg is the component that you want to optionally wrap and assertionHook option is a hook that will best tested to see if it returns a truthy value.
| commerceApi?: { | ||
| proxyPath: string | ||
| parameters: { | ||
| shortCode: string | ||
| clientId: string | ||
| organizationId: string | ||
| siteId: string | ||
| locale: string | ||
| currency: string | ||
| } | ||
| } |
| const useHasCommerceApiProvider = () => { | ||
| let hasProvider = false | ||
|
|
||
| try { | ||
| const api = useCommerceApi() | ||
|
|
||
| // the api object is an object with a bunch of api clients like ShopperProduct, ShopperOrder, etc. | ||
| // if the object is empty, then the CommerceApiProvider is not installed | ||
| if (Object.keys(api).length > 0) { | ||
| hasProvider = true | ||
| } | ||
| } catch (_) { | ||
| hasProvider = false | ||
| } | ||
|
|
||
| return hasProvider | ||
| } |
There was a problem hiding this comment.
thanks to your good suggestion!
| if (!config.commerceApi || !config.commerceApi?.parameters) { | ||
| return <WrappedComponent {...(props as P)} /> | ||
| } |
There was a problem hiding this comment.
Should we be we be warning or erroring out don't have a configuration supplied instead of not using the provider. I think thing would end up erroring out and that error wouldn't be as close to the source as this warning/error.
There was a problem hiding this comment.
added a logger.error
| } | ||
|
|
||
| return withStoreLocator(withOptionalChakra(App), config) | ||
| return withStoreLocator(withOptionalCommerceSdkReactProvider(withOptionalChakra(App), config), config) |
There was a problem hiding this comment.
There is a utility in the extensibility sdk that allows you to apply multiple hoc's. import {applyHOCs} from '@salesforce/pwa-kit-extension-sdk/react/utils' Can you give that a shot? It's possible that it might require some modification to allow each hoc to provide it's own configuration. But I think it's worth it since extension developers will end up using that utility .
…mmerce-provider-store-locator
| const HOCs = [ | ||
| (component: React.ComponentType<any>) => withStoreLocator(component, config), | ||
| (component: React.ComponentType<any>) => | ||
| withOptionalCommerceSdkReactProvider(component, config), | ||
| (component: React.ComponentType<any>) => withOptionalChakra(component) | ||
| ] |
Description
This PR adds a default
CommerceApiProviderto the store locator extension. This allows the extension to be run as a standalone project, without having to be coupled with the storefront extension. Before this change, the store locator page throws error by default.Types of Changes
Changes
How to Test-Drive This PR
npm startin the typescript-minimal example project, add configs if necessaryChecklists
General
Accessibility Compliance
You must check off all items in one of the follow two lists:
or...
Localization