Detect locale param from URL in AppBridge (#58)
* Detect locale param from URL in AppBridge * Add docs
This commit is contained in:
parent
910b50a18a
commit
126e949366
6 changed files with 94 additions and 15 deletions
|
@ -39,6 +39,42 @@ type AppBridgeState = {
|
|||
};
|
||||
```
|
||||
|
||||
## AppBridgeProvider
|
||||
|
||||
`AppBridgeProvider` and `useAppBridge` hook are exposed from app-sdk
|
||||
|
||||
```tsx
|
||||
// app.tsx
|
||||
import { AppBridgeProvider } from "@saleor/app-sdk/app-bridge";
|
||||
|
||||
<AppBridgeProvider>
|
||||
<YourApp />
|
||||
</AppBridgeProvider>;
|
||||
```
|
||||
|
||||
`AppBridgeProvider` can optionally receive AppBridge instance in props, otherwise will create one automatically
|
||||
|
||||
### useAppBridge hook
|
||||
|
||||
In components wrapped with `AppBridgeProvider`, `useAppBridge` hook is available
|
||||
|
||||
```tsx
|
||||
import { useAppBridge } from "@saleor/app-sdk/app-bridge";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const MyComponent = () => {
|
||||
const { appBridge, appBridgeState } = useAppBridge();
|
||||
|
||||
useEffect(() => {
|
||||
appBridge?.dispatch(/* Something */);
|
||||
}, [appBridge]);
|
||||
|
||||
return <div>Current locale is: {appBridgeState?.locale}</div>;
|
||||
};
|
||||
```
|
||||
|
||||
`appBridgeState?` and `appBridge` can be nullish, because in server side context it's not available
|
||||
|
||||
## Events
|
||||
|
||||
Events are messages that originate in Saleor Dashboard. AppBridge can subscribe on events and app can react on them
|
||||
|
@ -76,12 +112,15 @@ appBridge.unsubscribeAll();
|
|||
|
||||
### Available event types
|
||||
|
||||
| Event type | Description |
|
||||
| :---------- | :--------------------------------------------------------------------------- |
|
||||
| `handshake` | Fired when iFrame containing the App is initialized or new token is assigned |
|
||||
| `response` | Fired when Dashboard responds to an Action |
|
||||
| `redirect` | Fired when Dashboard changes a subpath within the app path |
|
||||
| `theme` | Fired when Dashboard changes the theme |
|
||||
| Event type | Description |
|
||||
| :-------------- | :--------------------------------------------------------------------------- |
|
||||
| `handshake` | Fired when iFrame containing the App is initialized or new token is assigned |
|
||||
| `response` | Fired when Dashboard responds to an Action |
|
||||
| `redirect` | Fired when Dashboard changes a subpath within the app path |
|
||||
| `theme` | Fired when Dashboard changes the theme |
|
||||
| `localeChanged` | Fired when Dashboard changes locale (and passes locale code in payload) |
|
||||
|
||||
See [source code for detailed payload](./src/app-bridge/events.ts)
|
||||
|
||||
## Actions
|
||||
|
||||
|
|
|
@ -24,10 +24,6 @@ export const AppContext = React.createContext<AppBridgeContext>({
|
|||
mounted: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* Experimental - try to use provider in app-sdk itself
|
||||
* Consider monorepo with dedicated react package
|
||||
*/
|
||||
export function AppBridgeProvider({ appBridgeInstance, ...props }: React.PropsWithChildren<Props>) {
|
||||
debug("Provider mounted");
|
||||
const [appBridge, setAppBridge] = useState<AppBridge | undefined>(appBridgeInstance);
|
||||
|
|
|
@ -220,4 +220,16 @@ describe("AppBridge", () => {
|
|||
|
||||
expect(instance.getState().locale).toBe(locale);
|
||||
});
|
||||
|
||||
it("Detects locale from URL param and set it to be initial", () => {
|
||||
const localeToOverwrite = "pl";
|
||||
|
||||
const currentLocationHref = window.location.href;
|
||||
|
||||
window.location.href = `${origin}?domain=${domain}&id=appid&locale=${localeToOverwrite}`;
|
||||
|
||||
expect(new AppBridge().getState().locale).toBe(localeToOverwrite);
|
||||
|
||||
window.location.href = currentLocationHref;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -71,8 +71,20 @@ export type AppBridgeOptions = {
|
|||
initialLocale?: LocaleCode;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Consider validating locale if wrong code provided
|
||||
*/
|
||||
const getLocaleFromUrl = () =>
|
||||
(new URL(window.location.href).searchParams.get("locale") as LocaleCode) || undefined;
|
||||
|
||||
/**
|
||||
* TODO: Probably remove empty string fallback
|
||||
*/
|
||||
const getDomainFromUrl = () => new URL(window.location.href).searchParams.get("domain") || "";
|
||||
|
||||
const getDefaultOptions = (): AppBridgeOptions => ({
|
||||
targetDomain: new URL(window.location.href).searchParams.get("domain") || "",
|
||||
targetDomain: getDomainFromUrl(),
|
||||
initialLocale: getLocaleFromUrl(),
|
||||
});
|
||||
|
||||
export class AppBridge {
|
||||
|
@ -93,15 +105,15 @@ export class AppBridge {
|
|||
);
|
||||
}
|
||||
|
||||
this.state = new AppBridgeStateContainer({
|
||||
initialLocale: options.initialLocale,
|
||||
});
|
||||
|
||||
this.combinedOptions = {
|
||||
...this.combinedOptions,
|
||||
...options,
|
||||
};
|
||||
|
||||
this.state = new AppBridgeStateContainer({
|
||||
initialLocale: this.combinedOptions.initialLocale,
|
||||
});
|
||||
|
||||
debug("Resolved combined AppBridge options: %j", this.combinedOptions);
|
||||
|
||||
if (!this.refererOrigin) {
|
||||
|
|
|
@ -12,6 +12,7 @@ describe("DashboardEventFactory", () => {
|
|||
type: "handshake",
|
||||
});
|
||||
});
|
||||
|
||||
it("Creates redirect event", () => {
|
||||
expect(DashboardEventFactory.createRedirectEvent("/new-path")).toEqual({
|
||||
payload: {
|
||||
|
@ -20,6 +21,7 @@ describe("DashboardEventFactory", () => {
|
|||
type: "redirect",
|
||||
});
|
||||
});
|
||||
|
||||
it("Creates dispatch response event", () => {
|
||||
expect(DashboardEventFactory.createDispatchResponseEvent("123", true)).toEqual({
|
||||
payload: {
|
||||
|
@ -29,6 +31,7 @@ describe("DashboardEventFactory", () => {
|
|||
type: "response",
|
||||
});
|
||||
});
|
||||
|
||||
it("Creates theme change event", () => {
|
||||
expect(DashboardEventFactory.createThemeChangeEvent("light")).toEqual({
|
||||
payload: {
|
||||
|
@ -37,4 +40,13 @@ describe("DashboardEventFactory", () => {
|
|||
type: "theme",
|
||||
});
|
||||
});
|
||||
|
||||
it("Creates locale change event", () => {
|
||||
expect(DashboardEventFactory.createLocaleChangedEvent("it")).toEqual({
|
||||
payload: {
|
||||
locale: "it",
|
||||
},
|
||||
type: "localeChanged",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -104,4 +104,12 @@ export const DashboardEventFactory = {
|
|||
},
|
||||
};
|
||||
},
|
||||
createLocaleChangedEvent(newLocale: LocaleCode): LocaleChangedEvent {
|
||||
return {
|
||||
type: "localeChanged",
|
||||
payload: {
|
||||
locale: newLocale,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue