Embedded app
Prerequisites
- You know how to create an app. If not, please visit https://shopline-developers.readme.io/docs/create-a-draft-app
- You know how to configure the app settings. If not, please visit https://shopline-developers.readme.io/docs/configure-apps-settings
- You know how to submit the app for approval. If not, please visit https://shopline-developers.readme.io/docs/subscribe-to-webhook
Intro
Admin app extension allows app page path configuration. It loads your configured web application through iframe when accessing designated SHOPLINE admin page.
Your web application can then trigger admin actions through admin app extension.
Integration
We provide a standardized tool app bridge for your frontend web application to communicate with admin.
It provides several abilities, here list out some
- Get admin current user language (
getLanguage()) & listen to its change (onLanguageChanged()) - Trigger admin intercom (
intercom()) - Redirect user to arbitrary url (
redirect(<url>)) - Redirect to designated admin page (
redirectAdminPage(<page>)), page includesAppDetail - Get merchant authority (
getMerchantAuthority()) - Trigger oauth flow (
oauth())
Full list can be found in here
Install
npm
npm i https://github.com/shoplineapp/app-bridge-js.gityarn
yarn add https://github.com/shoplineapp/app-bridge-js.gitUsage
First initialize app bridge
import { AppBridge } from "@shopline/app-bridge-js";
const client = await AppBridge.init({
clientId: '{{client id}}',
authUrl: '{{auth url}}',
});Then you may use the client provided functions
client.redirect('/products');Example
A demonstration on react to verify merchant has installed provided embedded app or not, if no, redirect to designated page
This example requires app bridge version >= 1.4.0
import { AppBridge, AppBridgeClient } from "@shopline/app-bridge-js";
interface InitConfig {
clientId: string;
authUrl: string;
}
class AppBridgeInstance {
private static instance: AppBridgeInstance | null = null;
client!: AppBridgeClient;
constructor() {
if (AppBridgeInstance.instance) {
return AppBridgeInstance.instance;
}
AppBridgeInstance.instance = this;
}
async init(initConfig: InitConfig): Promise<string> {
// set timeout on init
const timeoutPromise = new Promise<never>((_, reject) => {
setTimeout(() => {
reject(new Error("Promise timed out"));
}, 5000);
});
return Promise.race([AppBridge.init(initConfig), timeoutPromise])
.then((client) => {
this.client = client;
return "success";
})
.catch((err) => {
console.log("appBridge error", err);
return "failed";
});
}
}
const appBridge = new AppBridgeInstance();
export default appBridge;
import { Suspense, use } from "react";
import appBridge from "./AppBridgeSingleton";
async function initAppBridge() {
return appBridge.init({
clientId: "",
authUrl: "",
});
}
async function isMerchantInstalledEmbeddedApp() {
const authority = await appBridge?.client?.getMerchantAuthorities();
return authority.authorized;
}
const Fallback = () => <p>Loading...</p>;
const AppContent = ({
authorityPromise,
}: {
authorityPromise: Promise<boolean>;
}) => {
const isInstalled = use<boolean>(authorityPromise);
if (isInstalled) {
return <p>You have installed this app.</p>;
}
setTimeout(() => {
appBridge.client.redirectAdminPage("AppDetail");
}, 3000);
return <p>You have not installed this app, redirect soon...</p>;
};
const LandingComponent = ({ promise }: { promise: Promise<string> }) => {
const initResult = use<string>(promise);
if (initResult === "success") {
const authorityPromise = isMerchantInstalledEmbeddedApp();
return (
<Suspense fallback={<Fallback />}>
<AppContent authorityPromise={authorityPromise} />
</Suspense>
);
}
return <p>App bridge init error</p>;
};
export default function App() {
const initAppBridgePromise = initAppBridge();
return (
<Suspense fallback={<Fallback />}>
<LandingComponent promise={initAppBridgePromise} />
</Suspense>
);
}
Updated about 6 hours ago
