-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a default commerce api provider to store locator extension #2194
base: feature/extensibility-v2
Are you sure you want to change the base?
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if there is a way to "automatically" detect the existence of the CommerceApiProvider
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to create a ticket to fix it in the sdk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this comment isn't related to what you are implementing in your PR.. but seeing any
triggered me to ask a question.
* @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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweet 👍
if (!config.commerceApi || !config.commerceApi?.parameters) { | ||
return <WrappedComponent {...(props as P)} /> | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
@@ -35,7 +36,7 @@ class StoreLocatorExtension extends ApplicationExtension<Config> { | |||
) | |||
} | |||
|
|||
return withStoreLocator(withOptionalChakra(App), config) | |||
return withStoreLocator(withOptionalCommerceSdkReactProvider(withOptionalChakra(App), config), config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 .
Description
This PR adds a default
CommerceApiProvider
to 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.It would be nice if the optional HOC can automatically detect when
CommerceApiProvider
isn't avaliable in the react tree. But I don't have a way to reliably detect it. Let me know if you have ideas.Types of Changes
Changes
How to Test-Drive This PR
Checklists
General
Accessibility Compliance
You must check off all items in one of the follow two lists:
or...
Localization