PushNotificationContext.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import React, { useEffect, useState, useContext, createContext } from 'react';
  2. import * as Notifications from 'expo-notifications';
  3. import { storage, StoreType } from 'src/storage';
  4. import { Linking, Platform } from 'react-native';
  5. import { CommonActions, useNavigation } from '@react-navigation/native';
  6. import { NAVIGATION_PAGES } from 'src/types';
  7. import { usePostSetSettingsMutation } from '@api/notifications';
  8. const PushNotificationContext = createContext<{
  9. isSubscribed: boolean;
  10. toggleSubscription: () => Promise<void>;
  11. }>({
  12. isSubscribed: false,
  13. toggleSubscription: async () => {}
  14. });
  15. export const usePushNotification = () => useContext(PushNotificationContext);
  16. export const PushNotificationProvider = ({ children }: { children: React.ReactNode }) => {
  17. const token = storage.get('token', StoreType.STRING) as string;
  18. const [isSubscribed, setIsSubscribed] = useState(
  19. (storage.get('subscribed', StoreType.BOOLEAN) as boolean) ?? false
  20. );
  21. const { mutateAsync: setNotificationsSettings } = usePostSetSettingsMutation();
  22. const navigation = useNavigation();
  23. const lastNotificationResponse = Notifications.useLastNotificationResponse();
  24. useEffect(() => {
  25. if (lastNotificationResponse && Platform.OS === 'android') {
  26. console.log(
  27. 'lastNotificationResponse',
  28. lastNotificationResponse.notification.request.content.data
  29. );
  30. const data = lastNotificationResponse.notification.request.content.data;
  31. if (data?.screen && data?.parentScreen) {
  32. if (data?.params) {
  33. const parsedParams = JSON.parse(data.params) ?? {};
  34. navigation.dispatch(
  35. CommonActions.reset({
  36. index: 1,
  37. routes: [
  38. {
  39. name: 'DrawerApp',
  40. state: {
  41. routes: [
  42. {
  43. name: data.parentScreen,
  44. state: {
  45. routes: [
  46. { name: NAVIGATION_PAGES.MAP_TAB },
  47. {
  48. name: data.screen,
  49. params: parsedParams
  50. }
  51. ]
  52. }
  53. }
  54. ]
  55. }
  56. }
  57. ]
  58. })
  59. );
  60. } else {
  61. navigation.dispatch(
  62. CommonActions.reset({
  63. index: 1,
  64. routes: [
  65. {
  66. name: 'DrawerApp',
  67. state: {
  68. routes: [
  69. {
  70. name: data.parentScreen,
  71. state: {
  72. routes: [
  73. { name: NAVIGATION_PAGES.MAP_TAB },
  74. {
  75. name: data.screen
  76. }
  77. ]
  78. }
  79. }
  80. ]
  81. }
  82. }
  83. ]
  84. })
  85. );
  86. }
  87. }
  88. if (data?.url) {
  89. Linking.openURL(data.url);
  90. }
  91. }
  92. }, [lastNotificationResponse]);
  93. useEffect(() => {
  94. if (isSubscribed) {
  95. Notifications.setNotificationHandler({
  96. handleNotification: async () => ({
  97. shouldShowAlert: true,
  98. shouldPlaySound: false,
  99. shouldSetBadge: false
  100. })
  101. });
  102. const notificationListener = Notifications.addNotificationReceivedListener((notification) => {
  103. console.log('Notification received');
  104. });
  105. const responseListener = Notifications.addNotificationResponseReceivedListener((response) => {
  106. console.log('Notification response received');
  107. let screenName;
  108. let url;
  109. let parentScreen;
  110. let params;
  111. if (Platform.OS === 'ios') {
  112. parentScreen = (
  113. response.notification.request.trigger as Notifications.PushNotificationTrigger
  114. )?.payload?.parentScreen;
  115. screenName = (
  116. response.notification.request.trigger as Notifications.PushNotificationTrigger
  117. )?.payload?.screen;
  118. params = (response.notification.request.trigger as Notifications.PushNotificationTrigger)
  119. ?.payload?.params;
  120. url = (response.notification.request.trigger as Notifications.PushNotificationTrigger)
  121. ?.payload?.url;
  122. }
  123. if (screenName && parentScreen) {
  124. if (params) {
  125. const parsedParams = JSON.parse(params as string) ?? {};
  126. navigation.dispatch(
  127. CommonActions.reset({
  128. index: 1,
  129. routes: [
  130. {
  131. name: 'DrawerApp',
  132. state: {
  133. routes: [
  134. {
  135. name: parentScreen as string,
  136. state: {
  137. routes: [
  138. { name: NAVIGATION_PAGES.MAP_TAB },
  139. {
  140. name: screenName as string,
  141. params: parsedParams
  142. }
  143. ]
  144. }
  145. }
  146. ]
  147. }
  148. }
  149. ]
  150. })
  151. );
  152. } else {
  153. navigation.dispatch(
  154. CommonActions.reset({
  155. index: 1,
  156. routes: [
  157. {
  158. name: 'DrawerApp',
  159. state: {
  160. routes: [
  161. {
  162. name: parentScreen as string,
  163. state: {
  164. routes: [
  165. { name: NAVIGATION_PAGES.MAP_TAB },
  166. {
  167. name: screenName as string
  168. }
  169. ]
  170. }
  171. }
  172. ]
  173. }
  174. }
  175. ]
  176. })
  177. );
  178. }
  179. }
  180. if (url) {
  181. Linking.openURL(url as string);
  182. }
  183. });
  184. return () => {
  185. notificationListener.remove();
  186. responseListener.remove();
  187. };
  188. }
  189. }, [isSubscribed]);
  190. const subscribeToNotifications = async () => {
  191. storage.set('subscribed', true);
  192. setIsSubscribed(true);
  193. };
  194. const unsubscribeFromNotifications = async () => {
  195. const settings = {
  196. 'app-ios': 0,
  197. 'app-android': 0,
  198. 'app-friends': 0,
  199. 'email-friends': 0
  200. };
  201. await setNotificationsSettings({
  202. token,
  203. settings: JSON.stringify(settings)
  204. });
  205. storage.remove('deviceToken');
  206. storage.set('subscribed', false);
  207. setIsSubscribed(false);
  208. };
  209. const toggleSubscription = async () => {
  210. if (isSubscribed) {
  211. await unsubscribeFromNotifications();
  212. } else {
  213. await subscribeToNotifications();
  214. }
  215. };
  216. return (
  217. <PushNotificationContext.Provider value={{ isSubscribed, toggleSubscription }}>
  218. {children}
  219. </PushNotificationContext.Provider>
  220. );
  221. };