UNPKG

@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
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 };