@shopify/app-bridge-host
Version:
App Bridge Host contains components and middleware to be consumed by the app's host, as well as the host itself. The middleware and `Frame` component are responsible for facilitating communication between the client and host, and used to act on actions se
133 lines (130 loc) • 5.71 kB
JavaScript
import { useEffect } from 'react';
import compose from '@shopify/react-compose';
import { Redirect, History } from '@shopify/app-bridge-core/actions';
import { isSafe } from '@shopify/app-bridge-core/validate/safe-redirect';
import { normalizeRelativePath, removeRestrictedParams } from '../utilities/appUrl.js';
import withFeature from '../../withFeature.js';
import { feature } from '../../store/reducers/embeddedApp/navigation/index.js';
import { isMobile } from '../../store/middlewares/mobile/helpers.js';
import { useHostContext } from '../../hooks/useHostContext.js';
import { useRouterContext } from '../../hooks/useRouterContext.js';
import getResourceUrl from './utilities/getResourceUrl.js';
import { resolver } from './utilities/resolver.js';
import { stripTrailingSlash } from './utilities/stripTrailingSlash.js';
/**
* Handles all actions for the Navigation feature
* @public
* @requires RouterContext
* */
function Navigation(props) {
var notifyRouteChange = useHostContext().notifyRouteChange;
var routerContext = useRouterContext();
var updateAction = props.store.updateAction;
useEffect(function () {
var resolveAppUrl = props.resolveAppUrl, actions = props.actions, updateAction = props.store.updateAction;
var appRoot = routerContext.appRoot, hostname = routerContext.hostname, history = routerContext.history, location = routerContext.location, href = routerContext.href, open = routerContext.open;
var currentUrl = "".concat(location.pathname).concat(location.search);
if (!updateAction) {
return;
}
var newUrl;
var newContext;
var type = updateAction.type, target = updateAction.target, payload = updateAction.payload;
switch (target) {
case Redirect.Action.REMOTE:
if (isRemotePayload(payload)) {
newContext = payload.newContext;
newUrl = payload.url;
if (!newContext) {
if (newUrl === href) {
actions.completeRouteUpdate();
return;
}
var urlParts = new URL(newUrl);
if (urlParts.hostname === hostname && !isMobile()) {
history.push("".concat(urlParts.pathname).concat(urlParts.search));
}
else if (isSafe(newUrl)) {
open(newUrl);
}
actions.completeRouteUpdate();
return;
}
}
break;
case Redirect.Action.APP:
if (isAppPayload(payload)) {
var appUrlResolver = resolveAppUrl || resolver.app;
newUrl = appUrlResolver(appRoot, normalizeRelativePath(payload.path));
newUrl = removeRestrictedParams(newUrl);
newUrl = stripTrailingSlash(newUrl);
}
break;
case Redirect.Action.ADMIN_PATH:
if (isAdminPathPayload(payload)) {
newUrl = "".concat(resolver.home()).concat(payload.path);
newContext = payload.newContext;
}
break;
case Redirect.Action.ADMIN_SECTION:
if (isAdminSectionPayload(payload)) {
newUrl = getResourceUrl(resolver, payload.section);
newContext = payload.newContext;
}
break;
}
if (newContext) {
var absNewUrl = new URL(newUrl !== null && newUrl !== void 0 ? newUrl : '', href).href;
open(absNewUrl, '_blank');
actions.completeRouteUpdate();
return;
}
if (!newUrl || currentUrl === newUrl) {
actions.completeRouteUpdate();
return;
}
switch (type) {
case History.Action.PUSH: {
notifyRouteChange({ newUrl: newUrl, shouldNotifyClient: false });
history.push(newUrl);
break;
}
case History.Action.REPLACE: {
notifyRouteChange({ newUrl: newUrl, shouldNotifyClient: false });
history.replace(newUrl);
break;
}
default: {
// This fixes ABv3 and ABN Navigation Menu issue. See https://github.com/Shopify/app-bridge-next-internal/issues/52
var isReplaceAction = target === Redirect.Action.APP && payload.replace;
notifyRouteChange({ newUrl: newUrl, shouldNotifyClient: true });
if (isReplaceAction) {
history.replace(newUrl);
}
else {
history.push(newUrl);
}
}
}
actions.completeRouteUpdate();
}, [updateAction]);
return null;
}
function isAdminPathPayload(payload) {
return payload && Object.prototype.hasOwnProperty.call(payload, 'path');
}
function isAppPayload(payload) {
return payload && Object.prototype.hasOwnProperty.call(payload, 'path');
}
function isRemotePayload(payload) {
return payload && Object.prototype.hasOwnProperty.call(payload, 'url');
}
function isAdminSectionPayload(payload) {
return payload && Object.prototype.hasOwnProperty.call(payload, 'section');
}
/**
* The Navigation feature with its reducer, actions and a navigation actions handler
* @public
* */
var Navigation$1 = compose(withFeature(feature))(Navigation);
export { Navigation, Navigation$1 as default };