UNPKG

onesignal-web-sdk

Version:

Web push notifications from OneSignal.

206 lines (186 loc) 9.23 kB
import Event from '../Event'; import LimitStore from '../LimitStore'; import OneSignalApiShared from '../OneSignalApiShared'; import Database from '../services/Database'; import { ContextSWInterface } from "../models/ContextSW"; import Log from '../libraries/Log'; import { CustomLink } from "../CustomLink"; import { OneSignalUtils } from "../utils/OneSignalUtils"; import { BrowserUtils } from "../utils/BrowserUtils"; export default class EventHelper { static onNotificationPermissionChange() { EventHelper.checkAndTriggerSubscriptionChanged(); } static async onInternalSubscriptionSet(optedOut: boolean) { LimitStore.put('subscription.optedOut', optedOut); } static async checkAndTriggerSubscriptionChanged() { OneSignalUtils.logMethodCall('checkAndTriggerSubscriptionChanged'); const context: ContextSWInterface = OneSignal.context; const subscriptionState = await context.subscriptionManager.getSubscriptionState(); const isPushEnabled = await OneSignal.privateIsPushNotificationsEnabled(); const appState = await Database.getAppState(); const { lastKnownPushEnabled } = appState; const didStateChange = ( lastKnownPushEnabled === null || isPushEnabled !== lastKnownPushEnabled ); if (!didStateChange) return; Log.info( `The user's subscription state changed from ` + `${lastKnownPushEnabled === null ? '(not stored)' : lastKnownPushEnabled}${subscriptionState.subscribed}` ); appState.lastKnownPushEnabled = isPushEnabled; await Database.setAppState(appState); EventHelper.triggerSubscriptionChanged(isPushEnabled); } static async _onSubscriptionChanged(newSubscriptionState: boolean | undefined) { EventHelper.onSubscriptionChanged_showWelcomeNotification(newSubscriptionState); EventHelper.onSubscriptionChanged_evaluateNotifyButtonDisplayPredicate(); EventHelper.onSubscriptionChanged_updateCustomLink(); } private static async onSubscriptionChanged_showWelcomeNotification(isSubscribed: boolean | undefined) { if (OneSignal.__doNotShowWelcomeNotification) { Log.debug('Not showing welcome notification because user has previously subscribed.'); return; } if (isSubscribed === true) { const { deviceId } = await Database.getSubscription(); const { appId } = await Database.getAppConfig(); let welcome_notification_opts = OneSignal.config.userConfig.welcomeNotification; let welcome_notification_disabled = welcome_notification_opts !== undefined && welcome_notification_opts['disable'] === true; let title = welcome_notification_opts !== undefined && welcome_notification_opts['title'] !== undefined && welcome_notification_opts['title'] !== null ? welcome_notification_opts['title'] : ''; let message = welcome_notification_opts !== undefined && welcome_notification_opts['message'] !== undefined && welcome_notification_opts['message'] !== null && welcome_notification_opts['message'].length > 0 ? welcome_notification_opts['message'] : 'Thanks for subscribing!'; let unopenableWelcomeNotificationUrl = new URL(location.href).origin + '?_osp=do_not_open'; let url = welcome_notification_opts && welcome_notification_opts['url'] && welcome_notification_opts['url'].length > 0 ? welcome_notification_opts['url'] : unopenableWelcomeNotificationUrl; title = BrowserUtils.decodeHtmlEntities(title); message = BrowserUtils.decodeHtmlEntities(message); if (!welcome_notification_disabled) { Log.debug('Sending welcome notification.'); OneSignalApiShared.sendNotification( appId, [deviceId], { en: title }, { en: message }, url, null, { __isOneSignalWelcomeNotification: true }, undefined ); Event.trigger(OneSignal.EVENTS.WELCOME_NOTIFICATION_SENT, { title: title, message: message, url: url }); } } } private static async onSubscriptionChanged_evaluateNotifyButtonDisplayPredicate() { if (!OneSignal.config.userConfig.notifyButton) return; const displayPredicate = OneSignal.config.userConfig.notifyButton.displayPredicate; if (displayPredicate && typeof displayPredicate === "function" && OneSignal.notifyButton) { const predicateResult = await displayPredicate(); if (predicateResult !== false) { Log.debug('Showing notify button because display predicate returned true.'); OneSignal.notifyButton.launcher.show(); } else { Log.debug('Hiding notify button because display predicate returned false.'); OneSignal.notifyButton.launcher.hide(); } } } private static async onSubscriptionChanged_updateCustomLink() { if (OneSignal.config.userConfig.promptOptions) { await CustomLink.initialize(OneSignal.config.userConfig.promptOptions.customlink); } } static triggerSubscriptionChanged(to) { Event.trigger(OneSignal.EVENTS.SUBSCRIPTION_CHANGED, to); } /** * When notifications are clicked, because the site isn't open, the notification is stored in the database. The next * time the page opens, the event is triggered if its less than 5 minutes (usually page opens instantly from click). * * This method is fired for both HTTPS and HTTP sites, so for HTTP sites, the host URL needs to be used, not the * subdomain.onesignal.com URL. */ static async fireStoredNotificationClicks(url: string = document.URL) { async function fireEventWithNotification(clickedNotificationInfo) { // Remove the notification from the recently clicked list // Once this page processes this retroactively provided clicked event, nothing should get the same event const appState = await Database.getAppState(); appState.clickedNotifications[clickedNotificationInfo.url] = null; await Database.setAppState(appState); /* Clicked notifications look like: { "url": "https://notify.tech", "data": { "id": "f44dfcc7-e8cd-47c6-af7e-e2b7ac68afca", "heading": "Example Notification", "content": "This is an example notification.", "icon": "https://onesignal.com/images/notification_logo.png" (there would be a URL field here if it was set) }, "timestamp": 1490998270607 } */ const { data: notification, timestamp } = clickedNotificationInfo; if (timestamp) { const minutesSinceNotificationClicked = (Date.now() - timestamp) / 1000 / 60; if (minutesSinceNotificationClicked > 5) return; } Event.trigger(OneSignal.EVENTS.NOTIFICATION_CLICKED, notification); } const appState = await Database.getAppState(); /* Is the flag notificationClickHandlerMatch: origin enabled? If so, this means we should provide a retroactive notification.clicked event as long as there exists any recently clicked notification that matches this site's origin. Otherwise, the default behavior is to only provide a retroactive notification.clicked event if this page's URL exactly matches the notification's URL. */ const notificationClickHandlerMatch = await Database.get<string>('Options', 'notificationClickHandlerMatch'); if (notificationClickHandlerMatch === 'origin') { for (const clickedNotificationUrl of Object.keys(appState.clickedNotifications)) { // Using notificationClickHandlerMatch: 'origin', as long as the notification's URL's origin matches our current tab's origin, // fire the clicked event if (new URL(clickedNotificationUrl).origin === location.origin) { const clickedNotification = appState.clickedNotifications[clickedNotificationUrl]; await fireEventWithNotification(clickedNotification); } } } else { /* If a user is on https://site.com, document.URL and location.href both report the page's URL as https://site.com/. This causes checking for notifications for the current URL to fail, since there is a notification for https://site.com, but there is no notification for https://site.com/. As a workaround, if there are no notifications for https://site.com/, we'll do a check for https://site.com. */ var pageClickedNotifications = appState.clickedNotifications[url]; if (pageClickedNotifications) { await fireEventWithNotification(pageClickedNotifications); } else if (!pageClickedNotifications && url.endsWith('/')) { var urlWithoutTrailingSlash = url.substring(0, url.length - 1); pageClickedNotifications = appState.clickedNotifications[urlWithoutTrailingSlash]; if (pageClickedNotifications) { await fireEventWithNotification(pageClickedNotifications); } } } } }