@janiscommerce/app-push-notification 0.0.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ [Unreleased]
4
+
5
+ ### Added
6
+
7
+ - Added NotificationProvider (HOC) to receive notifications at background and foreground.\
8
+ - Added github actions to deploy to npm
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # @janiscommerce/app-push-notification
2
+
3
+ ![janis-logo](brand-logo.png)
4
+
5
+ Library for receiving notifications issued from firebase/janis.
6
+
7
+
8
+ ## PeerDependencies installation:
9
+
10
+ In order to receive notifications it is necessary to include the dependency
11
+
12
+
13
+ ```javascript
14
+ npm install @react-native-firebase/messaging
15
+ ```
16
+
17
+ ## Installation:
18
+
19
+
20
+ ```javascript
21
+ npm install @janis-commerce/app-push-notification
22
+ ```
23
+
24
+
25
+ ## What is received from firebase?
26
+
27
+ What is received is an object called RemoteMessage, which contains the data emitted from Firebase and is what triggers the notification listeners.
28
+ Inside remoteMessage you get the notifications object that contains the information that we could use to render a component with the application in the foreground
29
+
30
+ For more information about this, read https://rnfirebase.io/reference/messaging/remotemessage
31
+
32
+ This library provides the following components and methods:
33
+
34
+ ## Functions
35
+
36
+ <dl>
37
+ <dt><a href="#useNotification">useNotification()</a> ⇒ <code>object</code></dt>
38
+ <dd><p>is a hook, which returns the elements contained within the notifications context. Returns an object containing:</p>
39
+ <table>
40
+ <thead>
41
+ <tr>
42
+ <th>name</th>
43
+ <th>description</th>
44
+ </tr>
45
+ </thead>
46
+ <tbody><tr>
47
+ <td>deviceToken</td>
48
+ <td>is the token linked to the device, which we use to subscribe it to notifications.</td>
49
+ </tr>
50
+ </tbody></table>
51
+ </dd>
52
+ <dt><a href="#NotificationProvider">NotificationProvider(children, foregroundCallback, backgroundCallback, config, events, environment)</a> ⇒ <code>null</code> | <code>React.element</code></dt>
53
+ <dd><p>It is the main component of the package, it is a HOC that is responsible for handling the logic of subscribing to notifications and receiving messages from the Firebase console. The HOC contains listeners to listen to notifications in the foreground and background, so (unless we cancel the subscription), we will receive notifications from the app even when it is closed.</p>
54
+ </dd>
55
+ </dl>
56
+
57
+ <a name="useNotification"></a>
58
+
59
+ ## useNotification() ⇒ <code>object</code>
60
+ is a hook, which returns the elements contained within the notifications context. Returns an object containing:
61
+ | name | description |
62
+ |----------|----------|
63
+ | deviceToken | is the token linked to the device, which we use to subscribe it to notifications. |
64
+
65
+ **Kind**: global function
66
+ **Example**
67
+ ```js
68
+ import {useNotification} from '@janiscommerce/app-push-notification'
69
+
70
+ const {} = useNotification()
71
+ ```
72
+ <a name="NotificationProvider"></a>
73
+
74
+ ## NotificationProvider(children, foregroundCallback, backgroundCallback, config, events, environment) ⇒ <code>null</code> \| <code>React.element</code>
75
+ It is the main component of the package, it is a HOC that is responsible for handling the logic of subscribing to notifications and receiving messages from the Firebase console. The HOC contains listeners to listen to notifications in the foreground and background, so (unless we cancel the subscription), we will receive notifications from the app even when it is closed.
76
+
77
+ **Kind**: global function
78
+ **Throws**:
79
+
80
+ - null when not receive a children argument
81
+
82
+
83
+ | Param | Type | Description |
84
+ | --- | --- | --- |
85
+ | children | <code>React.element</code> | Component that will be rendered within the HOC, and about which the notification will be displayed |
86
+ | foregroundCallback | <code>function</code> | function that will be executed when a foreground notification is received. |
87
+ | backgroundCallback | <code>function</code> | function that will be executed when a background notification is received. |
88
+ | config | <code>object</code> | It is an object that contains the user's data, which will be used to subscribe the user to notifications. |
89
+ | config.appName | <code>string</code> | name of the aplication |
90
+ | config.accessToken | <code>string</code> | accessToken provided by janis |
91
+ | config.client | <code>string</code> | client provided by janis |
92
+ | events | <code>Array.&lt;string&gt;</code> | is an array that will contain the events to which the user wants to subscribe |
93
+ | environment | <code>string</code> | The environment is necessary for the API that we are going to use to subscribe the device to notifications. |
94
+
95
+ **Example**
96
+ ```js
97
+ import NotificationProvider from '@janiscommerce/app-push-notification'
98
+
99
+
100
+ //...
101
+
102
+ const foregroundCallback = (remoteMessage) => console.log('a new FCM:',remoteMessage)
103
+ const backgrounCallback = (remoteMessage) => {
104
+ console.log('a new FCM was received in background', remoteMessage)
105
+ }
106
+
107
+ return (
108
+ <NotificationProvider
109
+ foregroundCallback={foregroundCallback}
110
+ backgroundCallback={backgroundCallback}
111
+ config={client:'fizzmod', accessToken:'access_token_push', appName:'janisAppName'}
112
+ events={['Notification','events','janis']}
113
+ environment='beta'
114
+ >
115
+ <MyComponent/>
116
+ </NotificationProvider>
117
+ )
118
+ ```
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+
3
+ export const NotificationContext = React.createContext(null);
4
+
5
+ /**
6
+ * @function useNotification
7
+ * @description is a hook, which returns the elements contained within the notifications context. Returns an object containing:
8
+ * | name | description |
9
+ * |----------|----------|
10
+ * | deviceToken | is the token linked to the device, which we use to subscribe it to notifications. |
11
+ * @returns {object}
12
+ * @example
13
+ * import {useNotification} from '@janiscommerce/app-push-notification'
14
+ *
15
+ * const {} = useNotification()
16
+ */
17
+
18
+ export const useNotification = () => React.useContext(NotificationContext);
@@ -0,0 +1,116 @@
1
+ import React, {useEffect, useState} from 'react';
2
+ import {NotificationContext} from '../NotificationContext';
3
+ import {
4
+ getFCMToken,
5
+ setupBackgroundMessageHandler,
6
+ setupForegroundMessageHandler,
7
+ DefaultAlert,
8
+ isFunction,
9
+ isString,
10
+ isObject,
11
+ isArray,
12
+ topicsSubscription,
13
+ } from '../utils';
14
+
15
+ /**
16
+ * @function NotificationProvider
17
+ * @description It is the main component of the package, it is a HOC that is responsible for handling the logic of subscribing to notifications and receiving messages from the Firebase console. The HOC contains listeners to listen to notifications in the foreground and background, so (unless we cancel the subscription), we will receive notifications from the app even when it is closed.
18
+ * @param {React.element} children Component that will be rendered within the HOC, and about which the notification will be displayed
19
+ * @param {function} foregroundCallback function that will be executed when a foreground notification is received.
20
+ * @param {function} backgroundCallback function that will be executed when a background notification is received.
21
+ * @param {object} config It is an object that contains the user's data, which will be used to subscribe the user to notifications.
22
+ * @param {string} config.appName name of the aplication
23
+ * @param {string} config.accessToken accessToken provided by janis
24
+ * @param {string} config.client client provided by janis
25
+ * @param {Array<string>} events is an array that will contain the events to which the user wants to subscribe
26
+ * @param {string} environment The environment is necessary for the API that we are going to use to subscribe the device to notifications.
27
+ * @throws null when not receive a children argument
28
+ * @returns {null | React.element}
29
+ * @example
30
+ *
31
+ * import NotificationProvider from '@janiscommerce/app-push-notification'
32
+ *
33
+ *
34
+ * //...
35
+ *
36
+ * const foregroundCallback = (remoteMessage) => console.log('a new FCM:',remoteMessage)
37
+ * const backgrounCallback = (remoteMessage) => {
38
+ * console.log('a new FCM was received in background', remoteMessage)
39
+ * }
40
+ *
41
+ * return (
42
+ * <NotificationProvider
43
+ * foregroundCallback={foregroundCallback}
44
+ * backgroundCallback={backgroundCallback}
45
+ * config={client:'fizzmod', accessToken:'access_token_push', appName:'janisAppName'}
46
+ * events={['Notification','events','janis']}
47
+ * environment='beta'
48
+ * >
49
+ * <MyComponent/>
50
+ * </NotificationProvider>
51
+ * )
52
+ */
53
+
54
+ const NotificationProvider = ({
55
+ children,
56
+ foregroundCallback,
57
+ backgroundCallback,
58
+ config,
59
+ events,
60
+ environment,
61
+ }) => {
62
+ if (!children) return null;
63
+
64
+ const [deviceToken, setDeviceToken] = useState(null);
65
+ const validForegroundCallback = isFunction(foregroundCallback)
66
+ ? foregroundCallback
67
+ : DefaultAlert;
68
+ const validBackgroundCallback = isFunction(backgroundCallback)
69
+ ? backgroundCallback
70
+ : /* istanbul ignore next */ (remoteMessage) => remoteMessage;
71
+ const validConfig = config && isObject(config) ? config : {};
72
+ const validEvents = events && isArray(events) ? events : [];
73
+
74
+ // eslint-disable-next-line no-unused-vars
75
+ const parsedConfig = {...validConfig, environment, events: validEvents};
76
+
77
+ const getDeviceToken = async () => {
78
+ const fcmToken = await getFCMToken();
79
+ if (!fcmToken || !isString(fcmToken)) return null;
80
+
81
+ setDeviceToken(fcmToken)
82
+ return fcmToken;
83
+ };
84
+
85
+ // eslint-disable-next-line
86
+ const registerDevice = async () => {
87
+ const newDeviceToken = await getDeviceToken();
88
+
89
+ if (!newDeviceToken) return null;
90
+ // eslint-disable-next-line
91
+ validEvents.forEach(async (event) => {
92
+ if (!event || !isString(event)) return null;
93
+ await topicsSubscription(event);
94
+ });
95
+ };
96
+
97
+ useEffect(() => {
98
+ registerDevice();
99
+ const foregroundMessageHandler = setupForegroundMessageHandler(
100
+ validForegroundCallback,
101
+ );
102
+
103
+ return () => {
104
+ foregroundMessageHandler();
105
+ setupBackgroundMessageHandler(validBackgroundCallback);
106
+ };
107
+ }, []);
108
+
109
+ return (
110
+ <NotificationContext.Provider value={{deviceToken}}>
111
+ {children}
112
+ </NotificationContext.Provider>
113
+ );
114
+ };
115
+
116
+ export default NotificationProvider;
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import NotificationProvider from './NotificationProvider';
2
+ import {useNotification} from './NotificationContext';
3
+ import {topicsSubscription, topicsUnsubscription} from './utils';
4
+
5
+ export {useNotification, topicsSubscription, topicsUnsubscription};
6
+ export default NotificationProvider;
@@ -0,0 +1,43 @@
1
+ import axios from 'axios';
2
+ import {isString, isArray, validateOauthData, getHeaders} from '../../index';
3
+
4
+ const SubscribeNotifications = async (params = {}) => {
5
+ try {
6
+ if (!params || !Object.keys(params).length)
7
+ throw new Error('params is not a valid object');
8
+
9
+ const {client, accessToken, deviceToken, events, appName, environment} =
10
+ params;
11
+
12
+ if (!validateOauthData(accessToken, client))
13
+ throw new Error('accessToken and client are required');
14
+ if (!deviceToken || !isString(deviceToken))
15
+ throw new Error('device token is invalid or null');
16
+ if (!events || !isArray(events))
17
+ throw new Error('events to be subscribed to are null');
18
+ if (!appName || !isString(appName))
19
+ throw new Error('application name are invalid or null');
20
+ if (!environment || !isString(environment))
21
+ throw new Error('environment is invalid or null');
22
+
23
+ const parsedEvents = events.filter((event) => !!event && isString(event));
24
+ if (!parsedEvents.length)
25
+ throw new Error('events to be suscribed are invalids');
26
+
27
+ const headers = getHeaders({client, accessToken});
28
+ const validUrl = `https://notifications.${environment}.in/api/push/register`;
29
+ const body = {
30
+ deviceToken,
31
+ events: parsedEvents,
32
+ platformApplicationName: appName,
33
+ };
34
+
35
+ const {data} = await axios.post(validUrl, body, {headers});
36
+
37
+ return data;
38
+ } catch (error) {
39
+ return Promise.reject(error?.response?.data?.message || error);
40
+ }
41
+ };
42
+
43
+ export default SubscribeNotifications;
@@ -0,0 +1,366 @@
1
+ import {Alert} from 'react-native';
2
+ import messaging from '@react-native-firebase/messaging';
3
+ import AsyncStorage from '@react-native-async-storage/async-storage';
4
+ import DeviceInfo from 'react-native-device-info';
5
+
6
+ // Helpers
7
+
8
+ /**
9
+ * @function isFunction
10
+ * @param {function} fn
11
+ * @description return true or false if arg is a valid function
12
+ * @returns {bool}
13
+ * @example
14
+ * import {isFunction} from '@janiscommerce/apps-helpers'
15
+ * isFunction(() => true) // true
16
+ */
17
+ export const isFunction = (fn) =>
18
+ !!({}.toString.call(fn) === '[object Function]');
19
+
20
+ /**
21
+ * @function isString
22
+ * @param {string} str - String to validate.
23
+ * @description If the type of the argument is a string, return true, otherwise return false.
24
+ * @returns {bool}
25
+ * @example
26
+ * import {isString} from '@janiscommerce/apps-helpers'
27
+ * isString('Janis') // true
28
+ */
29
+
30
+ export const isString = (str) => !!(typeof str === 'string');
31
+
32
+ /**
33
+ * @function isObject
34
+ * @param {object} obj
35
+ * @description return true or false if arg is a valid object
36
+ * @returns {bool}
37
+ * @example
38
+ * import {isObject} from '@janiscommerce/apps-helpers'
39
+ * isObject('Janis') // false
40
+ */
41
+ export const isObject = (obj) => !!(obj && obj.constructor === Object);
42
+
43
+ /**
44
+ * @function isNumber
45
+ * @param {number} num
46
+ * @description return true or false if arg is a valid number
47
+ * @returns {bool}
48
+ * @example
49
+ * import {isNumber} from '@janiscommerce/apps-helpers'
50
+ * isNumber('Janis') // false
51
+ */
52
+ export const isNumber = (num) =>
53
+ typeof num === 'number' && !Number.isNaN(Number(num));
54
+
55
+ /**
56
+ * @function isBoolean
57
+ * @param {boolean} fn
58
+ * @description return true or false if arg is a valid boolean
59
+ * @returns {bool}
60
+ * @example
61
+ * import {isBoolean} from '@janiscommerce/apps-helpers'
62
+ * isBoolean((true) // true
63
+ */
64
+ export const isBoolean = (bool) => typeof bool === 'boolean';
65
+
66
+ /**
67
+ * @function isArray
68
+ * @param {array} arr
69
+ * @description return true or false if arg is a valid array
70
+ * @returns {bool}
71
+ * @example
72
+ * import {isArray} from '@janiscommerce/apps-helpers'
73
+ * isArray(['Janis']) // true
74
+ */
75
+ export const isArray = (arr) => !!(arr instanceof Array);
76
+
77
+ /**
78
+ * @function validateOauthData
79
+ * @param {string} accessToken
80
+ * @param {string} client
81
+ * @returns {boolean} - true or false
82
+ * @example validateOauthData([], 'fizzmodarg') => false
83
+ * @example validateOauthData('34234sdfrdf', 'fizzmodarg') => true
84
+ */
85
+ export const validateOauthData = (accessToken, client) => {
86
+ if (!accessToken || !client) return false;
87
+ if (!isString(accessToken) || !isString(client)) return false;
88
+ return true;
89
+ };
90
+
91
+ export const formatDeviceDataForUserAgent = (deviceData) => {
92
+ if (!isObject(deviceData) || !Object.keys(deviceData).length) return {};
93
+
94
+ const keysToCheck = [
95
+ 'janis-app-package-name',
96
+ 'janis-app-version',
97
+ 'janis-app-name',
98
+ 'janis-app-build',
99
+ 'janis-app-device-os-name',
100
+ 'janis-app-device-os-version',
101
+ 'janis-app-device-id',
102
+ 'janis-app-device-name',
103
+ ];
104
+
105
+ const hasSomeValidValues = keysToCheck.some(
106
+ (key) => isString(deviceData[key]) && !!deviceData[key],
107
+ );
108
+
109
+ if (!hasSomeValidValues) return {};
110
+
111
+ const userAgentParts = [];
112
+
113
+ keysToCheck.forEach((key) => {
114
+ const value =
115
+ !deviceData[key] || !isString(deviceData[key])
116
+ ? `unknown ${key}`
117
+ : deviceData[key];
118
+ userAgentParts.push(value);
119
+ });
120
+
121
+ return {
122
+ 'user-agent': `${userAgentParts[0]}/${userAgentParts[1]} (${userAgentParts[2]}; ${userAgentParts[3]}) ${userAgentParts[4]}/${userAgentParts[5]} (${userAgentParts[6]}; ${userAgentParts[7]})`,
123
+ };
124
+ };
125
+
126
+ /**
127
+ * @function getDeviceData
128
+ * @description return data from device user
129
+ * @returns {{
130
+ * 'application-name': string,
131
+ * 'build-number': string,
132
+ * 'app-version': string,
133
+ * 'bundle-id': string,
134
+ * 'os-name': string,
135
+ * 'device-id': string,
136
+ * 'device-name': string
137
+ * }} - Object with device data
138
+ * @example getDeviceData() => {applicationName: 'AppName', buildNumber: '434', appVersion: '1.5.0', bundleId: 'com.janis.appname', osName: 'android', osVersion: '11', deviceId: '34hf83hf89ahfjo', deviceName: 'Pixel 2'}
139
+ */
140
+
141
+ export const getDeviceData = () => {
142
+ const applicationName = DeviceInfo.getApplicationName() || '';
143
+ const buildNumber = DeviceInfo.getBuildNumber() || '';
144
+ const appVersion = DeviceInfo.getVersion() || '';
145
+ const bundleId = DeviceInfo.getBundleId() || '';
146
+ const osName = DeviceInfo.getSystemName() || '';
147
+ const osVersion = DeviceInfo.getSystemVersion() || '';
148
+ const deviceId = DeviceInfo.getUniqueId() || '';
149
+ const deviceName = DeviceInfo.getModel() || '';
150
+
151
+ return {
152
+ 'janis-app-name': applicationName,
153
+ 'janis-app-build': buildNumber,
154
+ 'janis-app-version': appVersion,
155
+ 'janis-app-package-name': bundleId,
156
+ 'janis-app-device-os-name': osName,
157
+ 'janis-app-device-os-version': osVersion,
158
+ 'janis-app-device-id': deviceId,
159
+ 'janis-app-device-name': deviceName,
160
+ };
161
+ };
162
+
163
+ const filterValidHeaders = (headers) => {
164
+ if (!headers || !isObject(headers) || !Object.keys(headers).length) return {};
165
+
166
+ return Object.fromEntries(
167
+ Object.entries(headers).filter(([, value]) => !!value && !!isString(value)),
168
+ );
169
+ };
170
+
171
+ /**
172
+ * @function getHeaders
173
+ * @param {object} [params={}] - object with params
174
+ * @param {object} [deviceDataHeaders={}] - headers with the device info
175
+ * @param {object} [customHeaders={}] - extra custom headers
176
+ * @param {string} params.client - client name for janis api
177
+ * @param {string} params.accessToken - access token for janis api
178
+ * @param {number} params.page - number of page
179
+ * @param {number} params.pageSize - quantity per page
180
+ * @param {boolean} params.getTotals - request api totals
181
+ * @param {boolean} params.getOnlyTotals - request api totals without body response
182
+ * @description get correct headers for janis api
183
+ * @returns {object}
184
+ * @example
185
+ * const params = {
186
+ * client: 'my-client',
187
+ * accessToken: 'my-access-token',
188
+ * page: 1,
189
+ * pageSize: 10,
190
+ * getTotals: true,
191
+ * getOnlyTotals: false
192
+ * };
193
+ * const deviceDataHeaders = {
194
+ * 'janis-app-name': 'MyApp',
195
+ * 'janis-app-version': '1.0.0',
196
+ * 'janis-app-device-os-name': 'iOS',
197
+ * 'janis-app-device-os-version': '14.5',
198
+ * 'janis-app-device-name': 'iPhone 12',
199
+ * 'janis-app-device-id': '123456789'
200
+ * };
201
+ * const customHeaders = {
202
+ * 'custom-header': 'custom-value'
203
+ * };
204
+ * const headers = getHeaders(params, deviceDataHeaders, customHeaders);
205
+ * // {
206
+ * // 'content-Type': 'application/json',
207
+ * // 'janis-api-key': 'Bearer',
208
+ * // 'janis-client': 'my-client',
209
+ * // 'janis-api-secret': 'my-access-token',
210
+ * // 'x-janis-page': 1,
211
+ * // 'x-janis-page-size': 10,
212
+ * // 'x-janis-totals': true,
213
+ * // 'x-janis-only-totals': false,
214
+ * // 'user-agent': 'MyApp/1.0.0 (iOS 14.5; iPhone 12; 123456789)',
215
+ * // 'custom-header': 'custom-value'
216
+ * // }
217
+ */
218
+
219
+ export const getHeaders = (params = {}, customHeaders = {}) => {
220
+ const deviceDataHeaders = getDeviceData();
221
+
222
+ const validCustomHeaders = filterValidHeaders(customHeaders);
223
+ const validDeviceDataHeaders = filterValidHeaders(deviceDataHeaders);
224
+ const validUserAgentHeader = formatDeviceDataForUserAgent(
225
+ validDeviceDataHeaders,
226
+ );
227
+
228
+ const baseHeaders = {
229
+ 'content-Type': 'application/json',
230
+ 'janis-api-key': 'Bearer',
231
+ ...validUserAgentHeader,
232
+ ...validDeviceDataHeaders,
233
+ ...validCustomHeaders,
234
+ };
235
+
236
+ if (!isObject(params)) return baseHeaders;
237
+ const {client, accessToken, page, pageSize, getTotals, getOnlyTotals} =
238
+ params;
239
+
240
+ return {
241
+ ...baseHeaders,
242
+ ...(isString(client) && client && {'janis-client': client}),
243
+ ...(isString(accessToken) &&
244
+ accessToken && {'janis-api-secret': accessToken}),
245
+ ...(isNumber(page) && page && {'x-janis-page': page}),
246
+ ...(isNumber(pageSize) && pageSize && {'x-janis-page-size': pageSize}),
247
+ ...(isBoolean(getTotals) && getTotals && {'x-janis-totals': getTotals}),
248
+ ...(isBoolean(getOnlyTotals) &&
249
+ getOnlyTotals && {'x-janis-only-totals': getOnlyTotals}),
250
+ };
251
+ };
252
+
253
+ // MESSAGING UTILS
254
+
255
+ /**
256
+ * @function getFCMToken
257
+ * @description This function is responsible for generating an fmc token or obtaining it from storage if one already exists. If it cannot be obtained, it will return an empty string
258
+ * @returns {Promise<string>}
259
+ * @example
260
+ *
261
+ * getFCMToken() => JDF6GJS364uhaGGe384gJHIQs23nbRNFG2859gJSD9gBivajeSJD
262
+ */
263
+
264
+ export const getFCMToken = async () => {
265
+ try {
266
+ const fcmToken = await AsyncStorage.getItem('fcmtoken');
267
+
268
+ if (!fcmToken) {
269
+ const newFcmToken = await messaging().getToken();
270
+
271
+ if (newFcmToken) {
272
+ await AsyncStorage.setItem('fcmtoken', newFcmToken);
273
+ return newFcmToken;
274
+ }
275
+ }
276
+
277
+ return fcmToken || '';
278
+ } catch (error) {
279
+ console.error('error', error.message);
280
+
281
+ return '';
282
+ }
283
+ };
284
+
285
+ // esto actualmente no funciona con la versión RN de picking. Pero será necesario eventualemnte.
286
+ // A partir de la versión 13 (api >= 33 ) de android el usuario tiene que otorgar los permisos manualmente.
287
+ // por lo que deberemos agregarlo dentro del package futuro y sumarlo a picking una vez que esté actualizado.
288
+
289
+ // export const requestUserPermission = async () => {
290
+ // const permission = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
291
+
292
+ // return permission;
293
+ // };
294
+
295
+ /** *
296
+ * @function setupForegroundMessageHandler
297
+ * @description This function is responsible for handling any callbacks from Firebase cloud messaging in the foreground and rendering them using a callback
298
+ * @param {Function} callback is the function that will receive the payload and render it as appropriate
299
+ */
300
+
301
+ export const setupForegroundMessageHandler = (callback) =>
302
+ messaging().onMessage(async (remoteMessage) => {
303
+ callback(remoteMessage);
304
+ });
305
+
306
+ /** *
307
+ * @function setupBackgroundMessageHandler
308
+ * @description This function is responsible for handling any callbacks from Firebase cloud messaging in the background or with the application closed
309
+ * @param {Function} callback is the function that will receive the payload and render it as appropriate
310
+ */
311
+
312
+ export const setupBackgroundMessageHandler = (callback) =>
313
+ messaging().setBackgroundMessageHandler(async (remoteMessage) => {
314
+ callback(remoteMessage);
315
+ });
316
+
317
+ /** *
318
+ * @name DefaultAlert
319
+ * @description a default alert component to be used when a foregroundCallback function is not passed by parameters
320
+ * @param {object} remoteMessage the object that was received from fcm
321
+ * @throws null when not receive a valid object as remoteMessage
322
+ * @returns an alert with title and body received from FCM remoteMessage
323
+ *
324
+ */
325
+
326
+ export const DefaultAlert = (remoteMessage = {}) => {
327
+ if (!remoteMessage || !Object.keys(remoteMessage).length) return null;
328
+
329
+ const {notification = {}} = remoteMessage;
330
+ const {title, body} = notification;
331
+
332
+ const validTitle = isString(title) ? title : 'A new FCM message arrived!';
333
+ const validateBody = isString(body) ? body : undefined;
334
+
335
+ return Alert.alert(validTitle, validateBody);
336
+ };
337
+
338
+ /* istanbul ignore next */
339
+ export const topicsSubscription = async (topics) => {
340
+ try {
341
+ if (!topics || !isString(topics)) return null;
342
+
343
+ await messaging().subscribeToTopic(topics);
344
+
345
+ return {message: `suscribed to ${topics} topic!`};
346
+ } catch (reason) {
347
+ console.error(reason?.message);
348
+
349
+ return Promise.reject(reason?.message);
350
+ }
351
+ };
352
+
353
+ /* istanbul ignore next */
354
+ export const topicsUnsubscription = async (topic) => {
355
+ try {
356
+ if (!topic || !isString(topic)) return null;
357
+
358
+ await messaging().unsubscribeFromTopic(topic);
359
+
360
+ return {message: `unsuscribed to ${topic} topic!`};
361
+ } catch (reason) {
362
+ console.error(reason?.message);
363
+
364
+ return Promise.reject(reason?.message);
365
+ }
366
+ };
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@janiscommerce/app-push-notification",
3
+ "version": "0.0.1-beta.1",
4
+ "type": "commonjs",
5
+ "description": "This package will take care of performing the main actions for registration to receive notifications in the foreground and background.",
6
+ "main": "lib/index.js",
7
+ "scripts": {
8
+ "test": "jest",
9
+ "lint": "eslint .",
10
+ "build-docs": "jsdoc2md --template template-readme.hbs --files lib/*.js lib/NotificationProvider/*.js > README.md",
11
+ "test:coverage": "jest --collectCoverage",
12
+ "validate:code": "npm run lint -- --fix && jest --collectCoverage"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/janis-commerce/app-push-notification.git"
17
+ },
18
+ "files": [
19
+ "lib/"
20
+ ],
21
+ "keywords": [
22
+ "janis",
23
+ "janiscommerce",
24
+ "app",
25
+ "pushnotification"
26
+ ],
27
+ "author": "Janis",
28
+ "license": "ISC",
29
+ "dependencies": {
30
+ "@react-native-async-storage/async-storage": "^1.18.1",
31
+ "@react-native-firebase/app": "^18.3.1",
32
+ "@react-native-firebase/messaging": "^18.3.1",
33
+ "axios": "^1.3.6",
34
+ "react-native-device-info": "^10.12.0"
35
+ },
36
+ "peerDependencies": {
37
+ "react": ">=17.0.2 <=18.2.0",
38
+ "react-native": ">=0.67.5 <=0.72.0"
39
+ },
40
+ "devDependencies": {
41
+ "@babel/core": "^7.23.6",
42
+ "@babel/eslint-parser": "^7.5.4",
43
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
44
+ "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
45
+ "@babel/preset-env": "^7.22.10",
46
+ "@babel/runtime": "^7.12.5",
47
+ "@react-native-community/eslint-config": "^2.0.0",
48
+ "@react-native-firebase/app": "^18.3.1",
49
+ "@react-native-firebase/messaging": "^18.3.1",
50
+ "@testing-library/react-native": "^12.0.1",
51
+ "babel-jest": "^28.0.0",
52
+ "babel-loader": "8.2.4",
53
+ "eslint": "^8.56.0",
54
+ "eslint-config-airbnb": "^18.2.1",
55
+ "eslint-config-prettier": "^8.1.0",
56
+ "eslint-plugin-import": "^2.22.1",
57
+ "eslint-plugin-jsx-a11y": "^6.4.1",
58
+ "eslint-plugin-prettier": "^3.3.1",
59
+ "eslint-plugin-react": "^7.22.0",
60
+ "eslint-plugin-react-hooks": "^4.2.0",
61
+ "husky": "^4.3.8",
62
+ "jest": "^28.0.0",
63
+ "jsdoc-babel": "^0.5.0",
64
+ "jsdoc-to-markdown": "^8.0.0",
65
+ "lint-staged": "^10.5.4",
66
+ "metro-react-native-babel-preset": "^0.66.2",
67
+ "nock": "^13.0.11",
68
+ "prettier": "^2.4.1",
69
+ "react": "^17.0.2",
70
+ "react-native": "^0.67.5",
71
+ "react-test-renderer": "^17.0.2"
72
+ },
73
+ "bugs": {
74
+ "url": "https://github.com/janis-commerce/app-push-notification/issues"
75
+ },
76
+ "homepage": "https://github.com/janis-commerce/app-push-notification#readme"
77
+ }