Last active
September 19, 2019 10:09
-
-
Save efstathiosntonas/0c4fcd97360fb8f0a20fe43f0963b0b1 to your computer and use it in GitHub Desktop.
OneSignal React Native Notifications Handler and AsyncStorage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import AsyncStorage from '@react-native-community/async-storage'; | |
import {Navigation} from 'react-native-navigation'; | |
import {uniqBy} from 'lodash'; | |
// using uuid/v4 to generate unique keys for each notification for FlatList etc. | |
import uuidv4 from 'uuid/v4'; | |
// AsyncStorage.clear(); | |
export const handleNotifications = async (notification, condition, ref) => { | |
console.log('COMING FROM ', ref); | |
// Delete a single Notification | |
if (condition === 'delete') { | |
let notifs = await getNotificationsFromStorage('delete'); | |
const index = notifs.findIndex( | |
item => | |
item.payload.notificationID === notification.payload.notificationID | |
); | |
if (index > -1) { | |
notifs.splice(index, 1); | |
} | |
await saveNotificationsToStorage(notifs, 'delete single notification'); | |
await setTabBadgeCounter(notifs); | |
} | |
// Mark single Notification as seen | |
if (condition === 'seen') { | |
let notifs = await getNotificationsFromStorage('seen'); | |
const index = notifs.findIndex( | |
item => | |
item.payload.notificationID === notification.payload.notificationID | |
); | |
notifs[index].seen = true; | |
await saveNotificationsToStorage(notifs, 'seen single notification'); | |
await setTabBadgeCounter(notifs); | |
} | |
// Mark Notification as visited | |
if (condition === 'visited') { | |
const notifications = await getNotificationsFromStorage('visited'); | |
const index = notifications.findIndex( | |
/* notification._id is coming from mongo database, it has nothing to do with OneSignal, | |
we check if the notification is been seen/opened by user in notifications view screen */ | |
item => item.payload.additionalData.id === notification._id | |
); | |
if (index > -1) { | |
console.log('found visited', notification); | |
notifications[index].seen = true; | |
notifications[index].key = uuidv4(); | |
await saveNotificationsToStorage( | |
notifications, | |
'mark notification visited' | |
); | |
await setTabBadgeCounter(notifications); | |
} | |
} | |
let notifications = await getNotificationsFromStorage( | |
'if all conditions fails, we reach normal notification procedure' | |
); | |
// We already have notifs in storage | |
if (notifications !== null) { | |
await setTabBadgeCounter(notifications); | |
notification.key = uuidv4(); | |
if (condition === 'open') { | |
const {notification: extractedNotification} = notification; | |
if (!extractedNotification.isAppInFocus) { | |
extractedNotification.key = uuidv4(); | |
await setNotificationNotOpened( | |
extractedNotification, | |
'opened & extracted, not in focus, we have notifications in storage' | |
); | |
} | |
await goToNotificationView( | |
extractedNotification, | |
'going to notification view, opened & extracted, we have notifications in storage' | |
); | |
} else if (condition === 'receive') { | |
notification.seen = false; | |
const storedNotifications = await unshiftNotificationInStorage( | |
notification, | |
'receive, storage has notifs' | |
); | |
await setTabBadgeCounter(storedNotifications); | |
} | |
} else { | |
// We don't have notifs in storage | |
if (condition === 'open') { | |
/* when opening notification from `opened` OneSignal event it has different | |
format than the `receive` OneSignal event */ | |
const {notification: extractedNotification} = notification; | |
/* set notification as seen since we are going directly | |
in notification view screen, not in notification list view */ | |
extractedNotification.seen = true; | |
extractedNotification.key = uuidv4(); | |
if (!extractedNotification.isAppInFocus) { | |
await setNotificationNotOpened( | |
extractedNotification, | |
'opened & extracted, app NOT focused, we dont have notifications in storage' | |
); | |
} | |
const storedNotifications = await pushNotificationInStorage( | |
extractedNotification, | |
'opened & extracted, app IN focus, we dont have notifications in storage' | |
); | |
await setTabBadgeCounter(storedNotifications); | |
await goToNotificationView(extractedNotification); | |
} else if (condition === 'receive') { | |
notification.seen = false; | |
notification.key = uuidv4(); | |
const storedNotifications = await pushNotificationInStorage( | |
notification, | |
'receive, we dont have notifications in storage' | |
); | |
await setTabBadgeCounter(storedNotifications); | |
} | |
} | |
}; | |
/* Helpers for managing notifications */ | |
export const setTabBadgeCounter = async notifications => { | |
const unseenNotifications = notifications.reduce((sum, item) => { | |
if (item.seen === false) { | |
return sum + 1; | |
} else { | |
return sum; | |
} | |
}, 0); | |
// using wix's react native navigation v3 | |
Navigation.mergeOptions('NotificationsScreen', { | |
bottomTab: { | |
badge: unseenNotifications === 0 ? '' : unseenNotifications.toString(), | |
badgeColor: 'red' | |
} | |
}); | |
}; | |
export const goToNotificationView = async (notification, ref) => { | |
/* | |
using wix's react native navigation v3 | |
first we need to navigate to Notification tab, in my case it was fourth in my tabs so index is 3 | |
then we push to the notification view/screen passing the notification data as props | |
*/ | |
console.log('GOING TO NOTIFICATION VIEW ', ref); | |
Navigation.mergeOptions('notificationStack', { | |
bottomTabs: { | |
currentTabIndex: 3 | |
} | |
}); | |
await Navigation.push('notificationStack', { | |
component: { | |
name: 'NotificationScreen', | |
passProps: { | |
item: notification, | |
mode: 'notifications', | |
id: notification.payload.additionalData.id | |
} | |
} | |
}); | |
}; | |
export const unshiftNotificationInStorage = async (notification, ref) => { | |
console.log('UNSHIFT NOTIFICATION FROM STORAGE ', ref); | |
const parsedNotifications = await getNotificationsFromStorage(); | |
parsedNotifications.unshift(notification); | |
/* | |
check if we have duplicate notifications | |
and remove them from notification array by checking notificationID | |
from notification's payload | |
*/ | |
const uniqueNotifications = uniqBy( | |
parsedNotifications, | |
'payload.notificationID' | |
); | |
await saveNotificationsToStorage( | |
uniqueNotifications, | |
'unshift notification and save' | |
); | |
console.log('RESULT - UNSHIFT NOTIFICATION ', ref, uniqueNotifications); | |
return uniqueNotifications; | |
}; | |
export const pushNotificationInStorage = async (notification, ref) => { | |
console.log('PUSHING NOTIFICATION TO STORAGE ', ref); | |
let parsedNotifications = await getNotificationsFromStorage(); | |
if (parsedNotifications) { | |
parsedNotifications.push(notification); | |
} else { | |
parsedNotifications = []; | |
parsedNotifications.push(notification); | |
} | |
await saveNotificationsToStorage( | |
parsedNotifications, | |
'push notification and save' | |
); | |
console.log('RESULT - PUSHING NOTIFICATION ', ref, parsedNotifications); | |
return parsedNotifications; | |
}; | |
/* | |
the following 2 functions are almost a hack, set notification in localStorage as not opened | |
so when app is killed and opened, navigate to notification view screen. | |
In my case i have 2 navigation roots, 1 root is splash screen and the other root is bottom Tabs, | |
when my app loads for first time (from killed state) when a user taps the notification shadow then | |
navigator cannot 'see' Tabs root. In my Home screen i have this in order to send user to notification screen: | |
const fromNotificationOpen = await AsyncStorage.getItem('notificationNotOpened'); | |
if (fromNotificationOpen) { | |
await goToNotificationView(JSON.parse(fromNotificationOpen)); | |
} | |
After visiting the notification view, in componentDidMount simply call await AsyncStorage.removeItem('notificationNotOpened') | |
to get rid of the unopened notification, | |
*/ | |
export const setNotificationNotOpened = async (notification, ref) => { | |
console.log('EXTRACTED & NOT OPENED BUT COMING FROM OPENED EVENT ', ref); | |
await AsyncStorage.setItem( | |
'notificationNotOpened', | |
JSON.stringify(notification) | |
); | |
const result = await AsyncStorage.getItem('notificationNotOpened'); | |
console.log( | |
'RESULT - EXTRACTED & NOT OPENED BUT COMING FROM OPENED EVENT ', | |
ref, | |
JSON.parse(result) | |
); | |
}; | |
export const getNotificationsFromStorage = async ref => { | |
console.log('GETTING NOTIFICATION FROM STORAGE ', ref); | |
const notifications = await AsyncStorage.getItem('notifications'); | |
console.log( | |
'RESULT - GETTING NOTIFICATION FROM STORAGE ', | |
ref, | |
notifications | |
? JSON.parse(notifications) | |
: ', STORAGE HAS NO NOTIFICATIONS OR WHATSSOEVER' | |
); | |
return JSON.parse(notifications); | |
}; | |
export const saveNotificationsToStorage = async (notifications, ref) => { | |
console.log('SAVING NOTIFICATION TO STORAGE ', ref); | |
await AsyncStorage.setItem('notifications', JSON.stringify(notifications)); | |
const storedNotifications = await AsyncStorage.getItem('notifications'); | |
console.log( | |
'RESULT - SAVING NOTIFICATION TO STORAGE ', | |
ref, | |
JSON.parse(storedNotifications) | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment