@shopgate/pwa-common
Version:
Common library for the Shopgate Connect PWA.
45 lines • 11.4 kB
JavaScript
import _regeneratorRuntime from"@babel/runtime/regenerator";function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg);var value=info.value;}catch(error){reject(error);return;}if(info.done){resolve(value);}else{Promise.resolve(value).then(_next,_throw);}}function _asyncToGenerator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value);}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err);}_next(undefined);});};}import queryString from'query-string';import{router,ACTION_POP,ACTION_PUSH,ACTION_REPLACE,ACTION_RESET}from'@virtuous/conductor';import Route from'@virtuous/conductor/Route';import{HISTORY_RESET_TO}from'@shopgate/pwa-common/constants/ActionTypes';import{logger}from'@shopgate/pwa-core';import{getCurrentRoute,getRouterStackIndex}from"../selectors/router";import{LoadingProvider}from"../providers";import{redirects}from"../collections";import{navigate}from"../action-creators";import{historyRedirect,historyPush,windowOpenOverride}from"../actions/router";import*as handler from"./helpers/handleLinks";import{navigate$,userDidLogin$,appWillStart$,windowOpenOverride$}from"../streams";import{isUserLoggedIn}from"../selectors/user";import{getIsConnected}from"../selectors/client";import{INDEX_PATH}from"../constants/RoutePaths";import appConfig from"../helpers/config";import authRoutes from"../collections/AuthRoutes";import ToastProvider from"../providers/toast";/**
* Router subscriptions.
* @param {Function} subscribe The subscribe function.
*/export default function routerSubscriptions(subscribe){subscribe(navigate$,/*#__PURE__*/function(){var _ref=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(params){var action,dispatch,getState,events,showConnectivityError,_action$params,silent,steps,resetToPathname,historyAction,routeState,location,state,historyLength,historyEmpty,_ref2,currentPathname,protector,_ref3,redirect,matcher,pathParams,queryParams,_getCurrentRoute2,pathname,pattern,_ref5,transform,route,parsedLocation,parsedRedirect,stringifiedQuery,finalRedirect,parsed,_ref7,_pathname,search;return _regeneratorRuntime.wrap(function _callee$(_context){while(1)switch(_context.prev=_context.next){case 0:action=params.action,dispatch=params.dispatch,getState=params.getState,events=params.events;/**
* Triggers a connectivity error toast message
*/showConnectivityError=function showConnectivityError(){events.emit(ToastProvider.ADD,{id:'navigate.error',message:'error.general'});};_action$params=action.params,silent=_action$params.silent,steps=_action$params.steps,resetToPathname=_action$params.pathname,historyAction=_action$params.action,routeState=_action$params.state;location=action.params.pathname;state=getState();historyLength=getRouterStackIndex(state)+1;historyEmpty=historyLength===1;_ref2=getCurrentRoute(state)||{},currentPathname=_ref2.pathname;if(!(historyEmpty&&[ACTION_POP,ACTION_RESET,HISTORY_RESET_TO].includes(historyAction))){_context.next=13;break;}if(!(currentPathname&¤tPathname===INDEX_PATH)){_context.next=11;break;}return _context.abrupt("return");case 11:/**
* Replace the current route with the index, when a history action is supposed to be
* dispatched which reduces the router stack, but the route which triggered the action
* is the only one within the stack.
*/router.replace({pathname:INDEX_PATH});return _context.abrupt("return");case 13:_context.t0=historyAction;_context.next=_context.t0===ACTION_POP?16:_context.t0===ACTION_RESET?18:_context.t0===HISTORY_RESET_TO?20:25;break;case 16:router.pop(_extends({},typeof steps==='number'&&{steps:steps}));return _context.abrupt("return");case 18:/**
* We don't use the native reset function here, since it contains a bug that causes
* a history pop right after the reset. That can cause side effects when the previous
* route briefly renders - same for HISTORY_RESET_TO
*/router.pop({steps:steps||historyLength-1});return _context.abrupt("return");case 20:_context.next=22;return router.pop({steps:historyLength-1,state:routeState,emitBefore:false,emitAfter:false});case 22:_context.next=24;return router.replace({pathname:resetToPathname,state:routeState});case 24:return _context.abrupt("return");case 25:return _context.abrupt("break",26);case 26:// Remove trailing slashes from internal links, since they might break the routing mechanism.
// External links are treated as valid, since we don't know about the requirements at the
// 3rd party server (e.g. google maps links might require trailing slashes).
if(location&&!handler.isExternalLink(location)){location=handler.sanitizeLink(location);}// Stop further processing if the location is empty.
if(location){_context.next=29;break;}return _context.abrupt("return");case 29:if(!(historyAction===ACTION_PUSH&&location===currentPathname)){_context.next=31;break;}return _context.abrupt("return");case 31:if(getIsConnected(state)){_context.next=34;break;}showConnectivityError();return _context.abrupt("return");case 34:if(isUserLoggedIn(state)){_context.next=39;break;}// Determine whether or not this location is protected.
protector=authRoutes.getProtector(location);// If protected then navigate to the protector instead.
if(!protector){_context.next=39;break;}dispatch(navigate({action:historyAction,pathname:protector,state:{redirect:{location:location,state:routeState}}}));return _context.abrupt("return");case 39:/* eslint-disable prefer-const */ // Check for a redirect and change location if one is found.
_ref3=redirects.getRedirectExtended(location)||{},redirect=_ref3.handler,matcher=_ref3.matcher,pathParams=_ref3.pathParams,queryParams=_ref3.queryParams;/* eslint-enable prefer-const */if(!redirect){_context.next=65;break;}if(!(typeof redirect==='function'||redirect instanceof Promise)){_context.next=60;break;}_getCurrentRoute2=getCurrentRoute(state),pathname=_getCurrentRoute2.pathname;LoadingProvider.setLoading(pathname);pattern=router.findPattern(location.split('?')[0]);_ref5=router.patterns[pattern]||{},transform=_ref5.transform;route=new Route({pathname:location,pattern:pattern,routeState:routeState,transform:transform});_context.prev=47;_context.next=50;return redirect(_extends({},params,{action:_extends({},params.action,{params:_extends({},params.action.params,{// Merge the sanitized location into the redirect handler payload.
pathname:location}),route:route,redirectMeta:{location:location,matcher:matcher,pathParams:pathParams,queryParams:queryParams}})}));case 50:redirect=_context.sent;_context.next=57;break;case 53:_context.prev=53;_context.t1=_context["catch"](47);redirect=null;logger.error(_context.t1);case 57:LoadingProvider.unsetLoading(pathname);if(redirect){_context.next=60;break;}return _context.abrupt("return");case 60:// Add query parameters from the original location to the redirect
parsedLocation=queryString.parseUrl(location);parsedRedirect=queryString.parseUrl(redirect);stringifiedQuery=queryString.stringify(_extends({},parsedLocation.query,{},parsedRedirect.query));finalRedirect=stringifiedQuery?"".concat(parsedRedirect.url,"?").concat(stringifiedQuery):parsedRedirect.url;location=finalRedirect;case 65:parsed=queryString.parseUrl(location);if(parsed.url){_context.next=69;break;}// The URL is not valid - show a toast message
showConnectivityError();return _context.abrupt("return");case 69:// Override the location if is Shop link is found.
if(handler.isShopLink(location)){_ref7=new URL(location),_pathname=_ref7.pathname,search=_ref7.search;location="".concat(_pathname).concat(search);}// If there is one of the known protocols in the url.
if(!(location&&handler.hasKnownProtocols(location))){_context.next=73;break;}if(handler.isExternalLink(location)){handler.openExternalLink(location,historyAction,state,routeState);}else if(handler.isNativeLink(location)){handler.openNativeLink(location);}return _context.abrupt("return");case 73:if(!(location&&handler.isLegacyPage(location))){_context.next=76;break;}handler.openLegacy(location,historyAction,state);return _context.abrupt("return");case 76:if(!(location&&handler.isLegacyLink(location))){_context.next=79;break;}handler.openLegacyLink(location,historyAction,state);return _context.abrupt("return");case 79:_context.t2=historyAction;_context.next=_context.t2===ACTION_PUSH?82:_context.t2===ACTION_REPLACE?84:86;break;case 82:router.push({pathname:location,state:routeState,emitBefore:silent,emitAfter:silent});return _context.abrupt("break",87);case 84:router.replace({pathname:location,state:routeState,emitBefore:silent,emitAfter:silent});return _context.abrupt("break",87);case 86:return _context.abrupt("break",87);case 87:case"end":return _context.stop();}},_callee,null,[[47,53]]);}));return function(_x){return _ref.apply(this,arguments);};}());/**
* Added a 100ms delay here to allow the Redux action to complete.
* Without it the store would show that the user is still not
* logged in during the upcoming navigate() action.
*/var redirectUser$=userDidLogin$.delay(100);subscribe(redirectUser$,function(_ref8){var action=_ref8.action,dispatch=_ref8.dispatch;if(appConfig.webCheckoutShopify===null){dispatch(historyRedirect(action.redirect));}});subscribe(appWillStart$,function(_ref9){var dispatch=_ref9.dispatch;var windowOpenOriginal=window.open;/**
* Override for the window.open method which is usually used by external SDKs to open URLs.
* Calls of this method would usually replace the PWA with the passed url. The override ensures
* that the URL is passed through the router system which implements logic for various URL
* formats.
*
* With debugging in mind "historyPush" is not directly dispatched. Instead it dispatches
* a dedicated action which is eventually transformed to "historyPush".
*
* @param {string} url A string indicating the URL or path of the resource to be loaded.
* @param {string} target @link https://developer.mozilla.org/en-US/docs/Web/API/Window/open#target
* @param {string} windowFeatures @link https://developer.mozilla.org/en-US/docs/Web/API/Window/open#windowfeatures
* @param {boolean} [isInternal=false] Whether the method is called by internal logic. This will
* invoke the original window.open with the method parameters.
* @returns {null}
*/window.open=function(){var url=arguments.length>0&&arguments[0]!==undefined?arguments[0]:'';var target=arguments.length>1?arguments[1]:undefined;var windowFeatures=arguments.length>2?arguments[2]:undefined;var isInternal=arguments.length>3&&arguments[3]!==undefined?arguments[3]:false;if(!isInternal){dispatch(windowOpenOverride({pathname:url}));}else{windowOpenOriginal(url,target,windowFeatures);}return null;};});subscribe(windowOpenOverride$,function(_ref10){var action=_ref10.action,dispatch=_ref10.dispatch;if(action.pathname){dispatch(historyPush({pathname:action.pathname}));}});}