Open egillanton opened 1 year ago
@egillanton , @paweljedrzejczyk - Not able to ge the shop name in the App Providers file. I'm getting the host as encoded value. Why atob is not working? HOST=YWRtaW4uc2hvcGlmeS5jb20vc3RvcmUvZGV2ZWxvcGVycy1zYW5kYm94
import { PropsWithChildren, useMemo, useState } from "react";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { Provider } from "@shopify/app-bridge-react";
import { Banner, Layout, Page } from "@shopify/polaris";
import { To } from "history";
const sanitizedShopName = (shop: string): string =>
shop
.replace(/^https:\/\//, "")
.replace(".myshopify.com", "")
.replace("/admin", "")
.replace(/-/g, "_")
.toUpperCase();
declare global {
interface Window {
__SHOPIFY_DEV_HOST: string;
}
}
/**
* A component to configure App Bridge.
* @desc A thin wrapper around AppBridgeProvider that provides the following capabilities:
*
* 1. Ensures that navigating inside the app updates the host URL.
* 2. Configures the App Bridge Provider, which unlocks functionality provided by the host.
*
* See: https://shopify.dev/apps/tools/app-bridge/getting-started/using-react
*/
export function AppBridgeProvider({ children }: PropsWithChildren) {
const location = useLocation();
const navigate = useNavigate();
const history = useMemo(
() => ({
replace: (path: To) => {
navigate(path, { replace: true });
},
}),
[navigate]
);
const routerConfig = useMemo(
() => ({ history, location }),
[history, location]
);
console.log(useParams(), location, navigate, history);
// The host may be present initially, but later removed by navigation.
// By caching this in state, we ensure that the host is never lost.
// During the lifecycle of an app, these values should never be updated anyway.
// Using state in this way is preferable to useMemo.
// See: https://stackoverflow.com/questions/60482318/version-of-usememo-for-caching-a-value-that-will-never-change
const [appBridgeConfig] = useState(() => {
const host =
new URLSearchParams(location.search).get("host") ||
window.__SHOPIFY_DEV_HOST;
window.__SHOPIFY_DEV_HOST = host;
console.log("HOST", host, sanitizedShopName(host));
const customApiKey = process.env.SHOPIFY_API_KEYS?.[
`SHOPIFY_API_KEY_${sanitizedShopName(
host ? window.atob(host) : ""
)}` as keyof typeof process.env.SHOPIFY_API_KEYS
] as string;
return {
host,
apiKey: customApiKey || process.env.SHOPIFY_API_KEY || "",
forceRedirect: true,
};
<img width="817" alt="Screenshot 2024-07-06 at 3 47 30 PM" src="https://github.com/paweljedrzejczyk/shopify-multistore-app-middleware/assets/77852628/52b280a2-b04f-4c3d-9196-1ccce9d9a232">
});
if (!appBridgeConfig.apiKey || !appBridgeConfig.host) {
const bannerProps = !appBridgeConfig.apiKey
? {
title: "Missing Shopify API Key",
children: (
<>
Your app is running without the SHOPIFY_API_KEY environment
variable. Please ensure that it is set when running or building
your React app.
</>
),
}
: {
title: "Missing host query argument",
children: (
<>
Your app can only load if the URL has a <b>host</b> argument.
Please ensure that it is set, or access your app using the
Partners Dashboard <b>Test your app</b> feature
</>
),
};
return (
<Page narrowWidth>
<Layout>
<Layout.Section>
<div style={{ marginTop: "100px" }}>
<Banner {...bannerProps} tone="critical" />
</div>
</Layout.Section>
</Layout>
</Page>
);
}
return (
<Provider config={appBridgeConfig} router={routerConfig}>
{children}
</Provider>
);
}
Also what about the build because if we deploy the app on Heroku it will use Shopify API Key from Docker for the first time?
Instead of passing a list object of API keys to the frontend as process.env.SHOPIFY_APIKEYS and expose at the same time all the store to api key value mapping, why not create a route /apiKey_ for example that will return the corresponding apikey for a given store passed by query?
In my API route I also return a cookie so it will improve the performance and prevent redundant calls to this rout.
PROS:
CONS: