For discussing the development and usage of Checkout UI extensions, post-purchase extensions, web pixels, Customer Accounts UI extensions, and POS UI extensions
Hi there, i'm facing an understandable issue in my app.
I'm building an app using checkout-ui extensions and functions.
Several of them are sharing the same configuration values such as third-party url, properties etc.
To make that app more manageable, i store this config in a metafield on my shop.
Metafield retrieved with useAppMetafields in my extensions.
That's for the context.
Now, the issue.
To make this configuration fetch/init more manageable, i dev a custom hook and intend to call it in each extension that need to access the config values.
It's this hook which do use the useAppMetafields hook.
Here is the code :
import { useState, useEffect } from "react"; import { useAppMetafields } from "@shopify/ui-extensions-react/checkout"; type Configuration = { debugMode: boolean; middlewareUrl: string; middlewareToken: string; cartPropertiesPrefix: string; metafieldNamespace: string; operatorShopName: string; operatorShopId: number; cartMaxItems: number; }; export function useConfiguration() { const appMetafields = useAppMetafields({ type: "shop", namespace: "mktp", key: "middleware_configuration", }); const [config, setConfig] = useState<Configuration>({ debugMode: false, middlewareUrl: "", middlewareToken: "", cartPropertiesPrefix: "mktp_", metafieldNamespace: "mktp", operatorShopName: "Operator", operatorShopId: 2000, cartMaxItems: 20, }); const [configInit, setConfigInit] = useState(false); const [configurationError, setConfigurationError] = useState(false); useEffect(() => { const initConfiguration = async () => { try { const configuration = JSON.parse( String(appMetafields[0]?.metafield?.value || "{}") ) as Configuration; if (!configInit && configuration.debugMode !== undefined) { console.log("configuration (init)", configuration); if ( configuration.middlewareUrl === "" || configuration.middlewareToken === "" ) { setConfigurationError(true); } else { setConfig(configuration); setConfigInit(true); } } } catch (error) { console.error("Error fetching configuration:", error); setConfigurationError(true); } }; initConfiguration(); }, [appMetafields, configInit]); return { config, configInit, configurationError }; }
This hook is working fine in the first extension on which i implement it.
But when i try on another extension (same target) i got this error :
ExtensionUsageError: Error: Uncaught CheckoutUIExtensionError: You can only call this hook when running as a UI extension.
Even if this is obviously a UI Extension...
Here is some code on how the code is called :
import { OrderType, getCartAttributeKey, } from "../../../app/components/Utils.ts"; import { useConfiguration } from "../../../app/hooks/useConfiguration.ts"; import { useState, useCallback, useEffect } from "react"; import { Loader, ShippingMethods, DiscountCode, ShippingProvidersIcons, } from "./components"; import { getShippingMethods, getShopFromShippingMethods } from "./utils.js"; import { reactExtension, useApi, useBuyerJourneyIntercept, BlockStack, Banner, useCartLines, useApplyCartLinesChange, useApplyMetafieldsChange, useApplyAttributeChange, useCheckoutToken, useShippingAddress, useAttributeValues, useDiscountCodes, } from "@shopify/ui-extensions-react/checkout"; export default reactExtension( "purchase.checkout.shipping-option-list.render-before", () => <Extension /> ); const Extension = () => { const { i18n, localization } = useApi(); const translate = i18n.translate; const checkoutToken = useCheckoutToken(); const cartLines = useCartLines(); const shippingAddress = useShippingAddress(); const applyMetafieldsChange = useApplyMetafieldsChange(); const applyCartLinesChange = useApplyCartLinesChange(); const applyAttributeChange = useApplyAttributeChange(); const discountCodes = useDiscountCodes(); // HERE IS THE USAGE OF THE USECONFIGURATION HOOK const { config } = useConfiguration(); console.log("configuration (re-use from 2nd extension)", config); const middlewareUrl = config.middlewareUrl; const token = config.middlewareToken; const cartPropertiesPrefix = config.cartPropertiesPrefix; const metafieldNamespaces = config.metafieldNamespace; (....)
I try to implement my hook only on this extension (removing it from the working one) and same error.
I don't know what i'm missing because the 2 extensions are not so different.
Any ideas ? Or suggestions on how to share configurations across several UI extension ?
Thanks for your help.
PS : Please not that i'm not an experienced react dev 😉