Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 105 additions & 23 deletions src/core/components/push_payload.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Payload } from '../types/api';

// --------------------------------------------------------
// ------------------------ Types -------------------------
// --------------------------------------------------------
Expand Down Expand Up @@ -177,24 +179,51 @@ type FCMPayload = {
body?: string;

/**
* Name of the icon file from resource bundle which should be shown on notification.
*/
icon?: string;

/**
* Name of the file from resource bundle which should be played when notification received.
* URL of an image to be displayed in the notification.
*/
sound?: string;

tag?: string;
image?: string;
};

/**
* Configuration of data notification.
*
* Silent notification configuration.
*/
data?: { notification?: FCMPayload['notification'] };
data?: { notification?: FCMPayload['notification'] } & Record<string, Payload | null>;

/**
* Android-specific options for notification delivery.
*/
android?: {
notification?: {
/**
* Name of the icon file from resource bundle which should be shown on notification.
*/
icon?: string;

/**
* Name of the file from resource bundle which should be played when notification received.
*/
sound?: string;

tag?: string;
};
} & Record<string, Payload | null>;

/**
* APNS-specific options for notification delivery.
*/
apns?: Record<string, Payload | null>;

/**
* Web Push-specific options for notification delivery.
*/
webpush?: Record<string, Payload | null>;

/**
* FCM service level options.
*/
fcm_options?: Record<string, Payload | null>;
};
// endregion
// endregion
Expand Down Expand Up @@ -700,7 +729,7 @@ export class FCMNotificationPayload extends BaseNotificationPayload {
set sound(value) {
if (!value || !value.length) return;

this.payload.notification!.sound = value;
this.androidNotification.sound = value;
this._sound = value;
}

Expand All @@ -716,12 +745,12 @@ export class FCMNotificationPayload extends BaseNotificationPayload {
/**
* Update notification icon.
*
* @param value - Name of the icon file which should be shown on notification.
* @param value - Name of the icon file set for `android.notification.icon`.
*/
set icon(value) {
if (!value || !value.length) return;

this.payload.notification!.icon = value;
this.androidNotification.icon = value;
this._icon = value;
}

Expand All @@ -737,12 +766,12 @@ export class FCMNotificationPayload extends BaseNotificationPayload {
/**
* Update notifications grouping tag.
*
* @param value - String which will be used to group similar notifications in notification center.
* @param value - String set for `android.notification.tag` to group similar notifications.
*/
set tag(value) {
if (!value || !value.length) return;

this.payload.notification!.tag = value;
this.androidNotification.tag = value;
this._tag = value;
}

Expand All @@ -767,6 +796,48 @@ export class FCMNotificationPayload extends BaseNotificationPayload {
this.payload.data = {};
}

/**
* Retrieve Android notification payload and initialize required structure.
*
* @returns Android specific notification payload.
*/
private get androidNotification() {
if (!this.payload.android) this.payload.android = {};
if (!this.payload.android.notification) this.payload.android.notification = {};

return this.payload.android.notification;
}

/**
* Move legacy Android-specific notification fields under `android.notification`.
*
* @param notification - Common FCM notification payload.
* @param android - Android-specific payload.
*
* @returns Updated Android payload.
*/
private moveLegacyAndroidNotificationFields(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this one.
notification and android and independent and have different targets:

  • notification: Basic notification template to use across all platforms (because it could be not only for Android).
  • android: Android specific options for messages sent through FCM connection server

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, moveLegacyAndroidNotificationFields is removed as its not needed anymore

notification: NonNullable<FCMPayload['notification']>,
android?: FCMPayload['android'],
): FCMPayload['android'] {
const legacyFields = ['sound', 'icon', 'tag'] as const;
const notificationPayload = notification as Record<string, unknown>;
let androidPayload = android;

legacyFields.forEach((field) => {
const value = notificationPayload[field];
if (typeof value !== 'string' || !value.length) return;

if (!androidPayload) androidPayload = {};
if (!androidPayload.notification) androidPayload.notification = {};

androidPayload.notification[field] = value;
delete notificationPayload[field];
});

return androidPayload;
}

/**
* Translate data object into PubNub push notification payload object.
*
Expand All @@ -775,22 +846,33 @@ export class FCMNotificationPayload extends BaseNotificationPayload {
* @returns Preformatted push notification payload.
*/
public toObject(): FCMPayload | null {
let data = { ...this.payload.data };
let notification = null;
const reservedTopLevelKeys = ['notification', 'data', 'android', 'apns', 'webpush', 'fcm_options'] as const;
let data = { ...(this.payload.data ?? {}) };
const notification = { ...(this.payload.notification ?? {}) };
let android = this.payload.android ? { ...this.payload.android } : undefined;
const payload: FCMPayload = {};
const { apns, webpush, fcm_options } = this.payload;
const additionalData = { ...this.payload } as Record<string, Payload | null>;

// Check whether additional data has been passed outside 'data' object and put it into it if required.
if (Object.keys(this.payload).length > 2) {
const { notification: initialNotification, data: initialData, ...additionalData } = this.payload;
android = this.moveLegacyAndroidNotificationFields(notification, android);

reservedTopLevelKeys.forEach((key) => {
delete additionalData[key];
});

// Check whether additional data has been passed outside 'data' object and put it into it if required.
if (Object.keys(additionalData).length) {
data = { ...data, ...additionalData };
}

if (this._isSilent) data.notification = this.payload.notification;
else notification = this.payload.notification;
if (this._isSilent && Object.keys(notification).length) data.notification = notification;
else if (Object.keys(notification).length) payload.notification = notification;

if (Object.keys(data).length) payload.data = data;
if (notification && Object.keys(notification).length) payload.notification = notification;
if (android && Object.keys(android).length) payload.android = android;
if (apns && Object.keys(apns).length) payload.apns = apns;
if (webpush && Object.keys(webpush).length) payload.webpush = webpush;
if (fcm_options && Object.keys(fcm_options).length) payload.fcm_options = fcm_options;

return Object.keys(payload).length ? payload : null;
}
Expand Down
Loading