import Snackbar from './classes/Snackbar';
import customEvent from '../utils/customEvent';
import Cookies from '../vendor/jscookie';
import getQueryParam from '../utils/getQueryParam';
/**
* Adds custom logic and analytics events to track PWA app installation activity
*
* @module PWAInstaller
* @prop {string} promptEvent - Browser event that will prompt the PWA installation workflow.
* @prop {object} deferredPrompt - Stored reference to the native PWA prompt event object.
* @prop {int} limitWidth - Max width at which PWA prompt is shown.
*/
const PWAInstaller = {
promptEvent: 'beforeinstallprompt',
cookieName: 'PWAShowPrompt',
onsignalSelector: '#onesignal-slidedown-container',
deferredPrompt: null,
limitWidth: 768,
button: {
container: '.l-header__actions',
selector: '.l-header__secondary--pwa',
modifier: 'l-header__actions--pwa',
template: `
<button class="l-header__button l-header__secondary l-header__secondary--pwa c-headerButton">
<svg class="c-icon c-icon--red c-headerButton__icon l-header__icon u-show-tablet-portrait" focusable="false">
<use xlink:href="/wp-content/themes/shaw-globalnews/assets/dist/icons/out/symbol/svg/sprite.symbol.svg#plus"></use>
</svg>
<span>Add shortcut</span>
</button>
`,
},
/**
* Bind initial PWA prompt event listeners.
*
* @method init
*/
init() {
// Show a header button prompt on tablet / desktop
if ( window.matchMedia( `(min-width: ${this.limitWidth}px)` ).matches ) {
this.boundShowButton = event => this.showButton( event );
window.addEventListener( this.promptEvent, this.boundShowButton );
return;
}
// Get cookie values
const promptCookie = Cookies.get( this.cookieName );
const skipCookie = getQueryParam( 'gnca-skip' );
// If it's the first time visiting, show prompt on next visit
if ( ! promptCookie && skipCookie.length < 1 ) {
Cookies.set( this.cookieName, 'showPrompt', { path: '/', expires: 60 });
window.addEventListener( this.promptEvent, event => event.preventDefault() );
return;
}
// Otherwise if the user has dismissed the prompt, don't show again for 2 months
if ( 'showPrompt' !== Cookies.get( this.cookieName ) && skipCookie.length < 1 ) {
window.addEventListener( this.promptEvent, event => event.preventDefault() );
return;
}
// If onesignal prompt is present we should also skip the PWA prompt, show it next apge view
const $onesignalPrompt = document.querySelector( this.onesignalSelector );
if ( $onesignalPrompt && skipCookie.length < 1 ) {
window.addEventListener( this.promptEvent, event => event.preventDefault() );
return;
}
// show snackbar when PWA install conditions are met
this.boundShowSnackbar = event => this.showSnackbar( event );
window.addEventListener( this.promptEvent, this.boundShowSnackbar );
// track completed app installation
window.addEventListener( 'appinstalled', () => {
this.track( 'install' );
});
},
/**
* Fires once the PWA prompt can be shown (typically on `beforeinstallprompt`).
* We'll hide the default prompt and show our own custom snackbar prompt.
*
* @method showSnackbar
* @param {object} event - typically the `beforeinstallprompt` event object.
*/
showSnackbar( event ) {
// stash prompt event
event.preventDefault();
this.deferredPrompt = event;
// trigger custom install button
const snackbar = new Snackbar({
text: {
prompt: 'Get your news faster. Add Global News to your Home Screen.',
dismiss: 'Not Now',
accept: 'Add to Home Screen',
},
});
snackbar.init();
// track show snackbar CTA
this.track( 'display' );
// show prompt if snackbar is accepted
snackbar.$element.addEventListener( customEvent.SNACKBAR_ACCEPTED, () => {
this.showPrompt();
});
// otherwise this will fire again as the user interacts with the prompt
window.removeEventListener( this.promptEvent, this.boundShowSnackbar );
// don't show snackbar prompt again for 60 days
Cookies.set( this.cookieName, 'alreadyPrompted', { path: '/', expires: 60 });
},
/**
* Add a button to the site header to trigger the PWA install prompt on desktop
*
* @method showButton()
* @param {object} event - typically the `beforeinstallprompt` event object.
*/
showButton( event ) {
// stash prompt event
event.preventDefault();
this.deferredPrompt = event;
// bail if button is already added
let $buttonElement = document.querySelector( this.button.selector );
if ( $buttonElement ) {
return;
}
// grab container
const $buttonContainer = document.querySelector( this.button.container );
if ( $buttonContainer ) {
$buttonContainer.classList.add( this.button.modifier );
$buttonContainer.innerHTML = this.button.template + $buttonContainer.innerHTML;
$buttonElement = document.querySelector( this.button.selector );
if ( $buttonElement ) {
$buttonElement.addEventListener( 'click', () => {
this.track( 'add shortcut' );
this.showPrompt();
});
}
}
},
/**
* If the snackbar prompt is accepted, trigger the native PWA install prompt.
*
* @method showPrompt()
*/
showPrompt() {
if ( this.deferredPrompt ) {
this.deferredPrompt.prompt();
if ( this.deferredPrompt.userChoice ) {
this.deferredPrompt.userChoice.then( ( result ) => {
if ( 'accepted' === result.outcome ) {
this.track( 'accepted' );
} else {
this.track( 'cancelled' );
}
});
}
}
this.deferredPrompt = null;
},
/**
* Analytics call for tracking PWA app installation activity
*
* @method track
* @param {string} eventName - event name to track.
*/
track( eventName ) {
/* global gn_analytics */
/* eslint-disable camelcase */
if ( 'undefined' !== typeof ( gn_analytics ) ) {
const data = {};
data['pwa.homebanner'] = eventName;
gn_analytics.Analytics.track(['adobe', 'ga'], {
action: `PWA | ${eventName}`,
data,
});
}
/* eslint-enable camelcase */
},
};
export default PWAInstaller;