Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User model/notification events #1028

Merged
merged 13 commits into from
May 5, 2023
7 changes: 7 additions & 0 deletions __test__/unit/events/eventsUnique.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ONESIGNAL_EVENTS } from "../../../src/onesignal/OneSignalEvents";

test('Test uniqueness of OneSignal event names', () => {
const events = Object.values(ONESIGNAL_EVENTS);
const uniqueEvents = [...new Set(events)];
expect(events.length).toEqual(uniqueEvents.length);
});
14 changes: 7 additions & 7 deletions src/onesignal/NotificationsNamespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import OneSignalError from "../../src/shared/errors/OneSignalError";
import OneSignal from "./OneSignal";
import { EventListenerBase } from "../page/userModel/EventListenerBase";
import NotificationEventName from "../page/models/NotificationEventName";
import { NotificationClicked } from "../../src/shared/models/Notification";
import { NotificationClickResult, NotificationForegroundWillDisplayEvent } from "../page/models/NotificationEvent";

export default class NotificationsNamespace extends EventListenerBase {
constructor(private _permissionNative?: NotificationPermission) {
Expand Down Expand Up @@ -149,9 +149,9 @@ export default class NotificationsNamespace extends EventListenerBase {
}

/* Function overloads */
addEventListener(event: NotificationEventName.Click, listener: (obj: NotificationClicked) => void): void;
addEventListener(event: NotificationEventName.WillDisplay, listener: (obj: StructuredNotification) => void): void;
addEventListener(event: NotificationEventName.Dismiss, listener: (obj: StructuredNotification) => void): void;
addEventListener(event: NotificationEventName.Click, listener: (obj: NotificationClickResult) => void): void;
addEventListener(event: NotificationEventName.ForegroundWillDisplay, listener: (obj: NotificationForegroundWillDisplayEvent) => void): void;
addEventListener(event: NotificationEventName.Dismiss, listener: (obj: OSNotificationDataPayload) => void): void;
addEventListener(event: NotificationEventName.PermissionChange,
listener: (permission: boolean) => void): void;
addEventListener(event: NotificationEventName.PermissionPromptDisplay, listener: () => void): void;
Expand All @@ -161,9 +161,9 @@ export default class NotificationsNamespace extends EventListenerBase {
}

/* Function overloads */
removeEventListener(event: NotificationEventName.Click, listener: (event: NotificationClicked) => void): void;
removeEventListener(event: NotificationEventName.WillDisplay, listener: (obj: StructuredNotification) => void): void;
removeEventListener(event: NotificationEventName.Dismiss, listener: (obj: StructuredNotification) => void): void;
removeEventListener(event: NotificationEventName.Click, listener: (event: NotificationClickResult) => void): void;
removeEventListener(event: NotificationEventName.ForegroundWillDisplay, listener: (obj: OSNotificationDataPayload) => void): void;
removeEventListener(event: NotificationEventName.Dismiss, listener: (obj: OSNotificationDataPayload) => void): void;
removeEventListener(event: NotificationEventName.PermissionChange,
listener: (permission: boolean) => void): void;
removeEventListener(event: NotificationEventName.PermissionPromptDisplay, listener: () => void): void;
Expand Down
4 changes: 2 additions & 2 deletions src/onesignal/OneSignalEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const ONESIGNAL_EVENTS = {
* Occurs after the user is officially subscribed to push notifications. The service worker is fully registered
* and activated and the user is eligible to receive push notifications at any point after this.
*/
SUBSCRIPTION_CHANGED: 'subscriptionChange',
SUBSCRIPTION_CHANGED: 'change',
/**
* Occurs after a POST call to OneSignal's server to send the welcome notification has completed. The actual
* notification arrives shortly after.
Expand All @@ -24,7 +24,7 @@ export const ONESIGNAL_EVENTS = {
/**
* Occurs when a notification is displayed.
*/
NOTIFICATION_WILL_DISPLAY: 'willDisplay',
NOTIFICATION_WILL_DISPLAY: 'foregroundWillDisplay',
/**
* Occurs when a notification is dismissed by the user either clicking 'X' or clearing all notifications
* (available in Android). This event is NOT called if the user clicks the notification's body or any of the
Expand Down
4 changes: 2 additions & 2 deletions src/onesignal/PushSubscriptionNamespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ export default class PushSubscriptionNamespace extends EventListenerBase {
await this._enable(false);
}

addEventListener(event: "subscriptionChange", listener: (change: SubscriptionChangeEvent) => void): void {
addEventListener(event: "change", listener: (change: SubscriptionChangeEvent) => void): void {
OneSignal.emitter.on(event, listener);
}

removeEventListener(event: "subscriptionChange", listener: (change: SubscriptionChangeEvent) => void): void {
removeEventListener(event: "change", listener: (change: SubscriptionChangeEvent) => void): void {
OneSignal.emitter.off(event, listener);
}

Expand Down
17 changes: 17 additions & 0 deletions src/page/models/NotificationEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { OSNotification } from "../../shared/models/OSNotification";

// post-user-model
export interface NotificationClickEvent {
notification: OSNotification;
result: NotificationClickResult;
}

export type NotificationClickResult = {
actionId?: string;
url?: string;
}

export interface NotificationForegroundWillDisplayEvent {
notification: OSNotification;
preventDefault(): void;
}
2 changes: 1 addition & 1 deletion src/page/models/NotificationEventName.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
enum NotificationEventName {
Click = "click",
WillDisplay = "willDisplay",
ForegroundWillDisplay = "foregroundWillDisplay",
Dismiss = "dismiss",
PermissionChange = "permissionChange",
PermissionPromptDisplay = "permissionPromptDisplay"
Expand Down
2 changes: 1 addition & 1 deletion src/shared/helpers/OutcomesHelper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { OutcomesConfig, OutcomeAttribution, OutcomeAttributionType, SentUniqueOutcome } from '../models/Outcomes';
import { NotificationClicked, NotificationReceived } from '../models/Notification';
import { NotificationClicked, NotificationReceived } from '../models/OSNotification';
import Database from "../services/Database";
import Log from '../libraries/Log';
import { Utils } from "../../shared/context/Utils";
Expand Down
2 changes: 1 addition & 1 deletion src/shared/helpers/ServiceWorkerHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { cancelableTimeout, CancelableTimeoutPromise } from '../../sw/helpers/Ca
import Utils from "../context/Utils";
import OutcomesHelper from "./OutcomesHelper";
import { OSServiceWorkerFields } from "../../sw/serviceWorker/types";
import { NotificationClicked } from "../models/Notification";
import { NotificationClicked } from "../models/OSNotification";
import { SessionOrigin, initializeNewSession, SessionStatus, Session } from "../models/Session";
import OneSignalApiSW from "../api/OneSignalApiSW";
import Path from "../models/Path";
Expand Down
2 changes: 1 addition & 1 deletion src/shared/managers/ServiceWorkerManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export class ServiceWorkerManager {
// Least likely to modify, since modifying this property changes the page's URL
url = location.href;
}
await Database.put('NotificationOpened', { url: url, data: data, timestamp: Date.now() });
await Database.put('NotificationOpened', { url, data, timestamp: Date.now() });
}
else
await OneSignalEvent.trigger(OneSignal.EVENTS.NOTIFICATION_CLICKED, data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Utils from '../context/Utils';
import { InvalidArgumentError, InvalidArgumentReason } from '../errors/InvalidArgumentError';
import { NotificationActionButton } from '../../page/models/NotificationActionButton';

export class Notification {
export class OSNotification {
public id?: string;
public title?: string;
public body?: string;
Expand All @@ -15,7 +15,7 @@ export class Notification {
public renotify?: true;
public actions?: Array<NotificationActionButton>;

constructor(title: string, options?: Notification) {
constructor(title: string, options?: OSNotification) {
this.title = title;
if (options) {
this.id = options.id;
Expand All @@ -38,19 +38,19 @@ export class Notification {
icon = "https://onesignal.com/images/notification_logo.png",
data = {}
} = {}) {
return new Notification(title, {
return new OSNotification(title, {
icon: icon,
body: body,
url: url,
data: data
});
}

static createFromPushPayload(payload: any): Notification {
static createFromPushPayload(payload: any): OSNotification {
if (!payload) {
throw new InvalidArgumentError('payload', InvalidArgumentReason.Empty);
}
const notification = new Notification(payload.title, {
const notification = new OSNotification(payload.title, {
id: payload.custom.i,
title: payload.title,
body: payload.alert,
Expand Down Expand Up @@ -83,6 +83,7 @@ export interface NotificationReceived {
timestamp: number;
}

// used to store click info in IndexedDB
export interface NotificationClicked {
notificationId: string;
action: string;
Expand Down
34 changes: 34 additions & 0 deletions src/shared/models/OSNotificationDataPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* the data payload on the notification event notification object
* @see https://developer.mozilla.org/en-US/docs/Web/API/NotificationEvent
*
* @example
* NotificationEvent {
* action: "action"
* notification: Notification {
* actions: (2) [{…}, {…}]
* badge: ""
* body: "Test Message"
* data: {…} <------ this is the OSNotificationDataPayload payload
* }
* }
*/

type OSNotificationDataPayload = {
id: string;
content: string;
heading?: string;
url?: string;
data?: object;
rr?: string;
icon?: string;
image?: string;
tag?: string;
badge?: string;
vibrate?: VibratePattern;
buttons?: NotificationButtonData[];
};

interface NotificationButtonData extends NotificationAction {
url: string;
};
18 changes: 18 additions & 0 deletions src/shared/models/RawNotificationPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export interface RawNotificationPayload {
title: string; // heading
alert: string; // content
custom: ICustomNotificationPayload;
icon: string;
image: string;
tag: string;
badge: string;
vibrate: string;
o: any[];
}

interface ICustomNotificationPayload {
a: any;
i: string;
u: string;
rr: string;
}
21 changes: 0 additions & 21 deletions src/shared/models/StructuredNotification.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/shared/services/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import IndexedDb from "./IndexedDb";

import { AppConfig } from "../models/AppConfig";
import { AppState, ClickedNotifications } from "../models/AppState";
import { NotificationReceived, NotificationClicked } from "../models/Notification";
import { NotificationReceived, NotificationClicked } from "../models/OSNotification";
import { ServiceWorkerState } from "../models/ServiceWorkerState";
import { Subscription } from "../models/Subscription";
import { TestEnvironmentKind } from "../models/TestEnvironmentKind";
Expand Down
2 changes: 1 addition & 1 deletion src/shared/services/IndexedDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default class IndexedDb {
if (event.oldVersion < 2) {
db.createObjectStore("Sessions", { keyPath: "sessionKey" });
db.createObjectStore("NotificationReceived", { keyPath: "notificationId" });
db.createObjectStore("NotificationClicked", { keyPath: "notificationId" });
db.createObjectStore("NotificationClicked", { keyPath: "notification.id" });
}
if (event.oldVersion < 3) {
db.createObjectStore("SentUniqueOutcome", { keyPath: "outcomeName" });
Expand Down
Loading