@knocklabs/expo 0.1.0 → 0.2.1-rc.0
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 +20 -0
- package/dist/cjs/modules/push/KnockExpoPushNotificationProvider.js +1 -1
- package/dist/cjs/modules/push/KnockExpoPushNotificationProvider.js.map +1 -1
- package/dist/esm/modules/push/KnockExpoPushNotificationProvider.mjs +80 -110
- package/dist/esm/modules/push/KnockExpoPushNotificationProvider.mjs.map +1 -1
- package/dist/types/modules/push/KnockExpoPushNotificationProvider.d.ts +3 -3
- package/dist/types/modules/push/KnockExpoPushNotificationProvider.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/modules/push/KnockExpoPushNotificationProvider.tsx +22 -65
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# @knocklabs/expo
|
2
2
|
|
3
|
+
## 0.2.1-rc.0
|
4
|
+
|
5
|
+
### Patch Changes
|
6
|
+
|
7
|
+
- Updated dependencies [f442962]
|
8
|
+
- @knocklabs/react-core@0.3.0-rc.0
|
9
|
+
- @knocklabs/client@0.11.0-rc.0
|
10
|
+
- @knocklabs/react-native@0.5.1-rc.0
|
11
|
+
|
12
|
+
## 0.2.0
|
13
|
+
|
14
|
+
### Minor Changes
|
15
|
+
|
16
|
+
- 4ac1e67: Add KnockPushNotificationProvider
|
17
|
+
|
18
|
+
### Patch Changes
|
19
|
+
|
20
|
+
- Updated dependencies [4ac1e67]
|
21
|
+
- @knocklabs/react-native@0.5.0
|
22
|
+
|
3
23
|
## 0.1.0
|
4
24
|
|
5
25
|
### Minor Changes
|
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("react/jsx-runtime"),b=require("@knocklabs/react-core"),N=require("@knocklabs/react-native"),w=require("expo-constants"),T=require("expo-device"),j=require("expo-notifications"),i=require("react"),_=t=>t&&typeof t=="object"&&"default"in t?t:{default:t};function x(t){if(t&&typeof t=="object"&&"default"in t)return t;const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const c in t)if(c!=="default"){const a=Object.getOwnPropertyDescriptor(t,c);Object.defineProperty(r,c,a.get?a:{enumerable:!0,get:()=>t[c]})}}return r.default=t,Object.freeze(r)}const d=_(w),q=x(T),s=x(j);s.setNotificationHandler({handleNotification:async()=>({shouldShowAlert:!0,shouldPlaySound:!0,shouldSetBadge:!0})});const R=async t=>({shouldShowAlert:!0,shouldPlaySound:!0,shouldSetBadge:!0}),v=i.createContext(void 0);async function D(){const{status:t}=await s.getPermissionsAsync();if(t!=="granted"){const{status:r}=await s.requestPermissionsAsync();return r}return t}async function A(){try{return!d.default.expoConfig||!d.default.expoConfig.extra||!d.default.expoConfig.extra.eas?(console.error("[Knock] Expo Project ID is not defined in the app configuration."),null):await s.getExpoPushTokenAsync({projectId:d.default.expoConfig.extra.eas.projectId})}catch(t){return console.error("[Knock] Error getting Expo push token:",t),null}}async function H(){return q.isDevice?await D()!=="granted"?(console.warn("[Knock] Push notification permission not granted"),null):A():(console.warn("[Knock] Must use physical device for Push Notifications"),null)}const O=({knockExpoChannelId:t,customNotificationHandler:r,children:c,autoRegister:a=!0})=>{const{registerPushTokenToChannel:h,unregisterPushTokenFromChannel:m}=N.usePushNotifications(),[u,S]=i.useState(null),n=b.useKnockClient(),[g,y]=i.useState(()=>()=>{}),[k,K]=i.useState(()=>()=>{}),C=i.useCallback(e=>{y(()=>e)},[]),E=i.useCallback(e=>{K(()=>e)},[]),f=i.useCallback(async()=>{try{n.log("[Knock] Registering for push notifications");const e=await H();n.log(`[Knock] Token received: ${e==null?void 0:e.data}`),e!=null&&e.data&&(n.log(`[Knock] Setting push token: ${e.data}`),S(e.data))}catch(e){console.error("[Knock] Error registering for push notifications:",e)}},[n]),P=i.useCallback(async(e,l)=>{const o=e.request.content.data.knock_message_id;return n.messages.updateStatus(o,l)},[n]);return i.useEffect(()=>{s.setNotificationHandler({handleNotification:r??R}),a&&f().then(()=>{u&&h(u,t).then(o=>{n.log("[Knock] setChannelData success")}).catch(o=>{console.error("[Knock] Error in setting push token or channel data",o)})}).catch(o=>{console.error("[Knock] Error in setting push token or channel data",o)});const e=s.addNotificationReceivedListener(o=>{n.log("[Knock] Expo Push Notification received in foreground:"),P(o,"interacted"),g(o)}),l=s.addNotificationResponseReceivedListener(o=>{n.log("[Knock] Expo Push Notification was interacted with"),P(o.notification,"interacted"),k(o)});return()=>{s.removeNotificationSubscription(e),s.removeNotificationSubscription(l)}},[f,g,k,r,u,t,n]),p.jsx(v.Provider,{value:{expoPushToken:u,registerForPushNotifications:f,registerPushTokenToChannel:h,unregisterPushTokenFromChannel:m,onNotificationReceived:C,onNotificationTapped:E},children:c})},I=t=>p.jsx(N.KnockPushNotificationProvider,{children:p.jsx(O,{...t})}),M=()=>{const t=i.useContext(v);if(t===void 0)throw new Error("[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider");return t};exports.KnockExpoPushNotificationProvider=I;exports.useExpoPushNotifications=M;
|
2
2
|
//# sourceMappingURL=KnockExpoPushNotificationProvider.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"KnockExpoPushNotificationProvider.js","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"sourcesContent":["import {\n ChannelData,\n Message,\n MessageEngagementStatus,\n} from \"@knocklabs/client\";\nimport { useKnockClient } from \"@knocklabs/react-core\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport * as Notifications from \"expo-notifications\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface KnockExpoPushNotificationContextType {\n expoPushToken: string | null;\n registerForPushNotifications: () => Promise<void>;\n registerPushTokenToChannel(token: string, channelId: string): Promise<void>;\n unregisterPushTokenFromChannel(\n token: string,\n channelId: string,\n ): Promise<void>;\n onNotificationReceived: (\n handler: (notification: Notifications.Notification) => void,\n ) => void;\n onNotificationTapped: (\n handler: (response: Notifications.NotificationResponse) => void,\n ) => void;\n}\n\nNotifications.setNotificationHandler({\n handleNotification: async () => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n };\n },\n});\n\nconst defaultNotificationHandler = async (\n _notification: Notifications.Notification,\n): Promise<Notifications.NotificationBehavior> => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n };\n};\n\nconst KnockExpoPushNotificationContext = createContext<\n KnockExpoPushNotificationContextType | undefined\n>(undefined);\n\nexport interface KnockExpoPushNotificationProviderProps {\n knockExpoChannelId: string;\n customNotificationHandler?: (\n notification: Notifications.Notification,\n ) => Promise<Notifications.NotificationBehavior>;\n children?: React.ReactElement;\n autoRegister?: boolean;\n}\n\nasync function requestPushPermissionIfNeeded(): Promise<string> {\n const { status: existingStatus } = await Notifications.getPermissionsAsync();\n\n if (existingStatus !== \"granted\") {\n const { status } = await Notifications.requestPermissionsAsync();\n return status;\n }\n\n return existingStatus;\n}\n\nasync function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {\n try {\n if (\n !Constants.expoConfig ||\n !Constants.expoConfig.extra ||\n !Constants.expoConfig.extra.eas\n ) {\n console.error(\n \"[Knock] Expo Project ID is not defined in the app configuration.\",\n );\n return null;\n }\n const token = await Notifications.getExpoPushTokenAsync({\n projectId: Constants.expoConfig.extra.eas.projectId,\n });\n return token;\n } catch (error) {\n console.error(\"[Knock] Error getting Expo push token:\", error);\n return null;\n }\n}\n\nasync function requestPermissionAndGetPushToken(): Promise<Notifications.ExpoPushToken | null> {\n // Check for device support\n if (!Device.isDevice) {\n console.warn(\"[Knock] Must use physical device for Push Notifications\");\n return null;\n }\n\n const permissionStatus = await requestPushPermissionIfNeeded();\n\n if (permissionStatus !== \"granted\") {\n console.warn(\"[Knock] Push notification permission not granted\");\n return null;\n }\n\n return getExpoPushToken();\n}\n\nexport const KnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = ({\n knockExpoChannelId,\n customNotificationHandler,\n children,\n autoRegister = true,\n}) => {\n const [expoPushToken, setExpoPushToken] = useState<string | null>(null);\n const knockClient = useKnockClient();\n\n const [notificationReceivedHandler, setNotificationReceivedHandler] =\n useState<(notification: Notifications.Notification) => void>(\n () => () => {},\n );\n\n const [notificationTappedHandler, setNotificationTappedHandler] = useState<\n (response: Notifications.NotificationResponse) => void\n >(() => () => {});\n\n const handleNotificationReceived = useCallback(\n (handler: (notification: Notifications.Notification) => void) => {\n setNotificationReceivedHandler(() => handler);\n },\n [],\n );\n\n const handleNotificationTapped = useCallback(\n (handler: (response: Notifications.NotificationResponse) => void) => {\n setNotificationTappedHandler(() => handler);\n },\n [],\n );\n\n const registerForPushNotifications = useCallback(async (): Promise<void> => {\n try {\n knockClient.log(`[Knock] Registering for push notifications`);\n const token = await requestPermissionAndGetPushToken();\n knockClient.log(`[Knock] Token received: ${token?.data}`);\n if (token?.data) {\n knockClient.log(`[Knock] Setting push token: ${token.data}`);\n setExpoPushToken(token.data);\n }\n } catch (error) {\n console.error(`[Knock] Error registering for push notifications:`, error);\n }\n }, [knockClient]);\n\n const updateKnockMessageStatusFromNotification = useCallback(\n async (\n notification: Notifications.Notification,\n status: MessageEngagementStatus,\n ): Promise<Message> => {\n const messageId = notification.request.content.data[\"knock_message_id\"];\n return knockClient.messages.updateStatus(messageId, status);\n },\n [knockClient],\n );\n\n const registerNewTokenDataOnServer = useCallback(\n async (tokens: string[], channelId: string): Promise<ChannelData> => {\n return knockClient.user.setChannelData({\n channelId: channelId,\n channelData: { tokens: tokens },\n });\n },\n [knockClient],\n );\n\n const registerPushTokenToChannel = useCallback(\n async (token: string, channelId: string): Promise<void> => {\n knockClient.user\n .getChannelData({ channelId: channelId })\n .then((result: ChannelData) => {\n const tokens: string[] = result.data[\"tokens\"];\n if (!tokens.includes(token)) {\n tokens.push(token);\n return registerNewTokenDataOnServer(tokens, channelId);\n }\n knockClient.log(\"[Knock] registerPushTokenToChannel success\");\n })\n .catch((_) => {\n // No data registered on that channel for that user, we'll create a new record\n return registerNewTokenDataOnServer([token], channelId);\n });\n },\n [knockClient, registerNewTokenDataOnServer],\n );\n\n const unregisterPushTokenFromChannel = useCallback(\n async (token: string, channelId: string): Promise<void> => {\n knockClient.user\n .getChannelData({ channelId: channelId })\n .then((result: ChannelData) => {\n const tokens: string[] = result.data[\"tokens\"];\n const updatedTokens = tokens.filter(\n (channelToken) => channelToken !== token,\n );\n knockClient.log(\"unregisterPushTokenFromChannel success\");\n return registerNewTokenDataOnServer(updatedTokens, channelId);\n })\n .catch((error) => {\n console.error(\n `[Knock] Error unregistering push token from channel:`,\n error,\n );\n });\n },\n [knockClient, registerNewTokenDataOnServer],\n );\n\n useEffect(() => {\n Notifications.setNotificationHandler({\n handleNotification:\n customNotificationHandler ?? defaultNotificationHandler,\n });\n\n if (autoRegister) {\n registerForPushNotifications()\n .then(() => {\n if (expoPushToken) {\n registerPushTokenToChannel(expoPushToken, knockExpoChannelId)\n .then((_result) => {\n knockClient.log(\"[Knock] setChannelData success\");\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n\n const notificationReceivedSubscription =\n Notifications.addNotificationReceivedListener((notification) => {\n knockClient.log(\n \"[Knock] Expo Push Notification received in foreground:\",\n );\n updateKnockMessageStatusFromNotification(notification, \"interacted\");\n notificationReceivedHandler(notification);\n });\n\n const notificationResponseSubscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n knockClient.log(\"[Knock] Expo Push Notification was interacted with\");\n updateKnockMessageStatusFromNotification(\n response.notification,\n \"interacted\",\n );\n notificationTappedHandler(response);\n });\n\n return () => {\n Notifications.removeNotificationSubscription(\n notificationReceivedSubscription,\n );\n Notifications.removeNotificationSubscription(\n notificationResponseSubscription,\n );\n };\n\n // TODO: Remove when possible and ensure dependency array is correct\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n registerForPushNotifications,\n notificationReceivedHandler,\n notificationTappedHandler,\n customNotificationHandler,\n expoPushToken,\n knockExpoChannelId,\n knockClient,\n ]);\n\n return (\n <KnockExpoPushNotificationContext.Provider\n value={{\n expoPushToken,\n registerForPushNotifications,\n registerPushTokenToChannel,\n unregisterPushTokenFromChannel,\n onNotificationReceived: handleNotificationReceived,\n onNotificationTapped: handleNotificationTapped,\n }}\n >\n {children}\n </KnockExpoPushNotificationContext.Provider>\n );\n};\n\nexport const useExpoPushNotifications =\n (): KnockExpoPushNotificationContextType => {\n const context = useContext(KnockExpoPushNotificationContext);\n if (context === undefined) {\n throw new Error(\n \"[Knock] useExpoPushNotifications must be used within a PushNotificationProvider\",\n );\n }\n return context;\n };\n"],"names":["Notifications","defaultNotificationHandler","_notification","KnockExpoPushNotificationContext","createContext","requestPushPermissionIfNeeded","existingStatus","status","getExpoPushToken","Constants","error","requestPermissionAndGetPushToken","Device","KnockExpoPushNotificationProvider","knockExpoChannelId","customNotificationHandler","children","autoRegister","expoPushToken","setExpoPushToken","useState","knockClient","useKnockClient","notificationReceivedHandler","setNotificationReceivedHandler","notificationTappedHandler","setNotificationTappedHandler","handleNotificationReceived","useCallback","handler","handleNotificationTapped","registerForPushNotifications","token","updateKnockMessageStatusFromNotification","notification","messageId","registerNewTokenDataOnServer","tokens","channelId","registerPushTokenToChannel","result","_","unregisterPushTokenFromChannel","updatedTokens","channelToken","useEffect","_result","_error","notificationReceivedSubscription","notificationResponseSubscription","response","jsx","useExpoPushNotifications","context","useContext"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"KnockExpoPushNotificationProvider.js","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"sourcesContent":["import { Message, MessageEngagementStatus } from \"@knocklabs/client\";\nimport { useKnockClient } from \"@knocklabs/react-core\";\nimport {\n type KnockPushNotificationContextType,\n KnockPushNotificationProvider,\n usePushNotifications,\n} from \"@knocklabs/react-native\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport * as Notifications from \"expo-notifications\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface KnockExpoPushNotificationContextType\n extends KnockPushNotificationContextType {\n expoPushToken: string | null;\n registerForPushNotifications: () => Promise<void>;\n onNotificationReceived: (\n handler: (notification: Notifications.Notification) => void,\n ) => void;\n onNotificationTapped: (\n handler: (response: Notifications.NotificationResponse) => void,\n ) => void;\n}\n\nNotifications.setNotificationHandler({\n handleNotification: async () => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n };\n },\n});\n\nconst defaultNotificationHandler = async (\n _notification: Notifications.Notification,\n): Promise<Notifications.NotificationBehavior> => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n };\n};\n\nconst KnockExpoPushNotificationContext = createContext<\n KnockExpoPushNotificationContextType | undefined\n>(undefined);\n\nexport interface KnockExpoPushNotificationProviderProps {\n knockExpoChannelId: string;\n customNotificationHandler?: (\n notification: Notifications.Notification,\n ) => Promise<Notifications.NotificationBehavior>;\n children?: React.ReactElement;\n autoRegister?: boolean;\n}\n\nasync function requestPushPermissionIfNeeded(): Promise<string> {\n const { status: existingStatus } = await Notifications.getPermissionsAsync();\n\n if (existingStatus !== \"granted\") {\n const { status } = await Notifications.requestPermissionsAsync();\n return status;\n }\n\n return existingStatus;\n}\n\nasync function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {\n try {\n if (\n !Constants.expoConfig ||\n !Constants.expoConfig.extra ||\n !Constants.expoConfig.extra.eas\n ) {\n console.error(\n \"[Knock] Expo Project ID is not defined in the app configuration.\",\n );\n return null;\n }\n const token = await Notifications.getExpoPushTokenAsync({\n projectId: Constants.expoConfig.extra.eas.projectId,\n });\n return token;\n } catch (error) {\n console.error(\"[Knock] Error getting Expo push token:\", error);\n return null;\n }\n}\n\nasync function requestPermissionAndGetPushToken(): Promise<Notifications.ExpoPushToken | null> {\n // Check for device support\n if (!Device.isDevice) {\n console.warn(\"[Knock] Must use physical device for Push Notifications\");\n return null;\n }\n\n const permissionStatus = await requestPushPermissionIfNeeded();\n\n if (permissionStatus !== \"granted\") {\n console.warn(\"[Knock] Push notification permission not granted\");\n return null;\n }\n\n return getExpoPushToken();\n}\n\nconst InternalKnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = ({\n knockExpoChannelId,\n customNotificationHandler,\n children,\n autoRegister = true,\n}) => {\n const { registerPushTokenToChannel, unregisterPushTokenFromChannel } =\n usePushNotifications();\n const [expoPushToken, setExpoPushToken] = useState<string | null>(null);\n const knockClient = useKnockClient();\n\n const [notificationReceivedHandler, setNotificationReceivedHandler] =\n useState<(notification: Notifications.Notification) => void>(\n () => () => {},\n );\n\n const [notificationTappedHandler, setNotificationTappedHandler] = useState<\n (response: Notifications.NotificationResponse) => void\n >(() => () => {});\n\n const handleNotificationReceived = useCallback(\n (handler: (notification: Notifications.Notification) => void) => {\n setNotificationReceivedHandler(() => handler);\n },\n [],\n );\n\n const handleNotificationTapped = useCallback(\n (handler: (response: Notifications.NotificationResponse) => void) => {\n setNotificationTappedHandler(() => handler);\n },\n [],\n );\n\n const registerForPushNotifications = useCallback(async (): Promise<void> => {\n try {\n knockClient.log(`[Knock] Registering for push notifications`);\n const token = await requestPermissionAndGetPushToken();\n knockClient.log(`[Knock] Token received: ${token?.data}`);\n if (token?.data) {\n knockClient.log(`[Knock] Setting push token: ${token.data}`);\n setExpoPushToken(token.data);\n }\n } catch (error) {\n console.error(`[Knock] Error registering for push notifications:`, error);\n }\n }, [knockClient]);\n\n const updateKnockMessageStatusFromNotification = useCallback(\n async (\n notification: Notifications.Notification,\n status: MessageEngagementStatus,\n ): Promise<Message> => {\n const messageId = notification.request.content.data[\"knock_message_id\"];\n return knockClient.messages.updateStatus(messageId, status);\n },\n [knockClient],\n );\n\n useEffect(() => {\n Notifications.setNotificationHandler({\n handleNotification:\n customNotificationHandler ?? defaultNotificationHandler,\n });\n\n if (autoRegister) {\n registerForPushNotifications()\n .then(() => {\n if (expoPushToken) {\n registerPushTokenToChannel(expoPushToken, knockExpoChannelId)\n .then((_result) => {\n knockClient.log(\"[Knock] setChannelData success\");\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n\n const notificationReceivedSubscription =\n Notifications.addNotificationReceivedListener((notification) => {\n knockClient.log(\n \"[Knock] Expo Push Notification received in foreground:\",\n );\n updateKnockMessageStatusFromNotification(notification, \"interacted\");\n notificationReceivedHandler(notification);\n });\n\n const notificationResponseSubscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n knockClient.log(\"[Knock] Expo Push Notification was interacted with\");\n updateKnockMessageStatusFromNotification(\n response.notification,\n \"interacted\",\n );\n notificationTappedHandler(response);\n });\n\n return () => {\n Notifications.removeNotificationSubscription(\n notificationReceivedSubscription,\n );\n Notifications.removeNotificationSubscription(\n notificationResponseSubscription,\n );\n };\n\n // TODO: Remove when possible and ensure dependency array is correct\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n registerForPushNotifications,\n notificationReceivedHandler,\n notificationTappedHandler,\n customNotificationHandler,\n expoPushToken,\n knockExpoChannelId,\n knockClient,\n ]);\n\n return (\n <KnockExpoPushNotificationContext.Provider\n value={{\n expoPushToken,\n registerForPushNotifications,\n registerPushTokenToChannel,\n unregisterPushTokenFromChannel,\n onNotificationReceived: handleNotificationReceived,\n onNotificationTapped: handleNotificationTapped,\n }}\n >\n {children}\n </KnockExpoPushNotificationContext.Provider>\n );\n};\n\nexport const KnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = (props) => {\n return (\n <KnockPushNotificationProvider>\n <InternalKnockExpoPushNotificationProvider {...props} />\n </KnockPushNotificationProvider>\n );\n};\n\nexport const useExpoPushNotifications =\n (): KnockExpoPushNotificationContextType => {\n const context = useContext(KnockExpoPushNotificationContext);\n if (context === undefined) {\n throw new Error(\n \"[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider\",\n );\n }\n return context;\n };\n"],"names":["Notifications","defaultNotificationHandler","_notification","KnockExpoPushNotificationContext","createContext","requestPushPermissionIfNeeded","existingStatus","status","getExpoPushToken","Constants","error","requestPermissionAndGetPushToken","Device","InternalKnockExpoPushNotificationProvider","knockExpoChannelId","customNotificationHandler","children","autoRegister","registerPushTokenToChannel","unregisterPushTokenFromChannel","usePushNotifications","expoPushToken","setExpoPushToken","useState","knockClient","useKnockClient","notificationReceivedHandler","setNotificationReceivedHandler","notificationTappedHandler","setNotificationTappedHandler","handleNotificationReceived","useCallback","handler","handleNotificationTapped","registerForPushNotifications","token","updateKnockMessageStatusFromNotification","notification","messageId","useEffect","_result","_error","notificationReceivedSubscription","notificationResponseSubscription","response","jsx","KnockExpoPushNotificationProvider","props","KnockPushNotificationProvider","useExpoPushNotifications","context","useContext"],"mappings":"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"}
|
@@ -1,115 +1,85 @@
|
|
1
|
-
import { jsx as
|
2
|
-
import { useKnockClient as
|
3
|
-
import
|
4
|
-
import
|
5
|
-
import * as
|
6
|
-
import
|
7
|
-
|
1
|
+
import { jsx as l } from "react/jsx-runtime";
|
2
|
+
import { useKnockClient as w } from "@knocklabs/react-core";
|
3
|
+
import { KnockPushNotificationProvider as C, usePushNotifications as T } from "@knocklabs/react-native";
|
4
|
+
import c from "expo-constants";
|
5
|
+
import * as R from "expo-device";
|
6
|
+
import * as i from "expo-notifications";
|
7
|
+
import { createContext as b, useContext as A, useState as f, useCallback as a, useEffect as H } from "react";
|
8
|
+
i.setNotificationHandler({
|
8
9
|
handleNotification: async () => ({
|
9
10
|
shouldShowAlert: !0,
|
10
11
|
shouldPlaySound: !0,
|
11
12
|
shouldSetBadge: !0
|
12
13
|
})
|
13
14
|
});
|
14
|
-
const
|
15
|
+
const I = async (t) => ({
|
15
16
|
shouldShowAlert: !0,
|
16
17
|
shouldPlaySound: !0,
|
17
18
|
shouldSetBadge: !0
|
18
|
-
}),
|
19
|
-
async function
|
20
|
-
const { status:
|
21
|
-
if (
|
22
|
-
const { status:
|
23
|
-
return
|
19
|
+
}), P = b(void 0);
|
20
|
+
async function j() {
|
21
|
+
const { status: t } = await i.getPermissionsAsync();
|
22
|
+
if (t !== "granted") {
|
23
|
+
const { status: r } = await i.requestPermissionsAsync();
|
24
|
+
return r;
|
24
25
|
}
|
25
|
-
return
|
26
|
+
return t;
|
26
27
|
}
|
27
|
-
async function
|
28
|
+
async function q() {
|
28
29
|
try {
|
29
|
-
return !
|
30
|
+
return !c.expoConfig || !c.expoConfig.extra || !c.expoConfig.extra.eas ? (console.error(
|
30
31
|
"[Knock] Expo Project ID is not defined in the app configuration."
|
31
|
-
), null) : await
|
32
|
-
projectId:
|
32
|
+
), null) : await i.getExpoPushTokenAsync({
|
33
|
+
projectId: c.expoConfig.extra.eas.projectId
|
33
34
|
});
|
34
|
-
} catch (
|
35
|
-
return console.error("[Knock] Error getting Expo push token:",
|
35
|
+
} catch (t) {
|
36
|
+
return console.error("[Knock] Error getting Expo push token:", t), null;
|
36
37
|
}
|
37
38
|
}
|
38
|
-
async function
|
39
|
-
return
|
39
|
+
async function D() {
|
40
|
+
return R.isDevice ? await j() !== "granted" ? (console.warn("[Knock] Push notification permission not granted"), null) : q() : (console.warn("[Knock] Must use physical device for Push Notifications"), null);
|
40
41
|
}
|
41
|
-
const
|
42
|
-
knockExpoChannelId:
|
43
|
-
customNotificationHandler:
|
42
|
+
const _ = ({
|
43
|
+
knockExpoChannelId: t,
|
44
|
+
customNotificationHandler: r,
|
44
45
|
children: N,
|
45
|
-
autoRegister:
|
46
|
+
autoRegister: m = !0
|
46
47
|
}) => {
|
47
|
-
const [
|
48
|
+
const { registerPushTokenToChannel: h, unregisterPushTokenFromChannel: x } = T(), [s, v] = f(null), n = w(), [p, K] = f(
|
48
49
|
() => () => {
|
49
50
|
}
|
50
|
-
), [g,
|
51
|
-
}),
|
52
|
-
(
|
53
|
-
K(() =>
|
51
|
+
), [g, E] = f(() => () => {
|
52
|
+
}), S = a(
|
53
|
+
(o) => {
|
54
|
+
K(() => o);
|
54
55
|
},
|
55
56
|
[]
|
56
|
-
),
|
57
|
-
(
|
58
|
-
|
57
|
+
), y = a(
|
58
|
+
(o) => {
|
59
|
+
E(() => o);
|
59
60
|
},
|
60
61
|
[]
|
61
|
-
),
|
62
|
+
), u = a(async () => {
|
62
63
|
try {
|
63
|
-
|
64
|
-
const
|
65
|
-
|
66
|
-
} catch (
|
67
|
-
console.error("[Knock] Error registering for push notifications:",
|
64
|
+
n.log("[Knock] Registering for push notifications");
|
65
|
+
const o = await D();
|
66
|
+
n.log(`[Knock] Token received: ${o == null ? void 0 : o.data}`), o != null && o.data && (n.log(`[Knock] Setting push token: ${o.data}`), v(o.data));
|
67
|
+
} catch (o) {
|
68
|
+
console.error("[Knock] Error registering for push notifications:", o);
|
68
69
|
}
|
69
|
-
}, [
|
70
|
-
async (
|
71
|
-
const e =
|
72
|
-
return
|
73
|
-
},
|
74
|
-
[o]
|
75
|
-
), a = r(
|
76
|
-
async (t, i) => o.user.setChannelData({
|
77
|
-
channelId: i,
|
78
|
-
channelData: { tokens: t }
|
79
|
-
}),
|
80
|
-
[o]
|
81
|
-
), P = r(
|
82
|
-
async (t, i) => {
|
83
|
-
o.user.getChannelData({ channelId: i }).then((e) => {
|
84
|
-
const d = e.data.tokens;
|
85
|
-
if (!d.includes(t))
|
86
|
-
return d.push(t), a(d, i);
|
87
|
-
o.log("[Knock] registerPushTokenToChannel success");
|
88
|
-
}).catch((e) => a([t], i));
|
89
|
-
},
|
90
|
-
[o, a]
|
91
|
-
), T = r(
|
92
|
-
async (t, i) => {
|
93
|
-
o.user.getChannelData({ channelId: i }).then((e) => {
|
94
|
-
const E = e.data.tokens.filter(
|
95
|
-
(w) => w !== t
|
96
|
-
);
|
97
|
-
return o.log("unregisterPushTokenFromChannel success"), a(E, i);
|
98
|
-
}).catch((e) => {
|
99
|
-
console.error(
|
100
|
-
"[Knock] Error unregistering push token from channel:",
|
101
|
-
e
|
102
|
-
);
|
103
|
-
});
|
70
|
+
}, [n]), k = a(
|
71
|
+
async (o, d) => {
|
72
|
+
const e = o.request.content.data.knock_message_id;
|
73
|
+
return n.messages.updateStatus(e, d);
|
104
74
|
},
|
105
|
-
[
|
75
|
+
[n]
|
106
76
|
);
|
107
77
|
return H(() => {
|
108
|
-
|
109
|
-
handleNotification:
|
110
|
-
}),
|
111
|
-
|
112
|
-
|
78
|
+
i.setNotificationHandler({
|
79
|
+
handleNotification: r ?? I
|
80
|
+
}), m && u().then(() => {
|
81
|
+
s && h(s, t).then((e) => {
|
82
|
+
n.log("[Knock] setChannelData success");
|
113
83
|
}).catch((e) => {
|
114
84
|
console.error(
|
115
85
|
"[Knock] Error in setting push token or channel data",
|
@@ -122,55 +92,55 @@ const I = ({
|
|
122
92
|
e
|
123
93
|
);
|
124
94
|
});
|
125
|
-
const
|
126
|
-
|
95
|
+
const o = i.addNotificationReceivedListener((e) => {
|
96
|
+
n.log(
|
127
97
|
"[Knock] Expo Push Notification received in foreground:"
|
128
98
|
), k(e, "interacted"), p(e);
|
129
|
-
}),
|
130
|
-
|
99
|
+
}), d = i.addNotificationResponseReceivedListener((e) => {
|
100
|
+
n.log("[Knock] Expo Push Notification was interacted with"), k(
|
131
101
|
e.notification,
|
132
102
|
"interacted"
|
133
103
|
), g(e);
|
134
104
|
});
|
135
105
|
return () => {
|
136
|
-
|
137
|
-
|
138
|
-
),
|
139
|
-
|
106
|
+
i.removeNotificationSubscription(
|
107
|
+
o
|
108
|
+
), i.removeNotificationSubscription(
|
109
|
+
d
|
140
110
|
);
|
141
111
|
};
|
142
112
|
}, [
|
143
|
-
|
113
|
+
u,
|
144
114
|
p,
|
145
115
|
g,
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
]), /* @__PURE__ */
|
151
|
-
|
116
|
+
r,
|
117
|
+
s,
|
118
|
+
t,
|
119
|
+
n
|
120
|
+
]), /* @__PURE__ */ l(
|
121
|
+
P.Provider,
|
152
122
|
{
|
153
123
|
value: {
|
154
|
-
expoPushToken:
|
155
|
-
registerForPushNotifications:
|
156
|
-
registerPushTokenToChannel:
|
157
|
-
unregisterPushTokenFromChannel:
|
158
|
-
onNotificationReceived:
|
159
|
-
onNotificationTapped:
|
124
|
+
expoPushToken: s,
|
125
|
+
registerForPushNotifications: u,
|
126
|
+
registerPushTokenToChannel: h,
|
127
|
+
unregisterPushTokenFromChannel: x,
|
128
|
+
onNotificationReceived: S,
|
129
|
+
onNotificationTapped: y
|
160
130
|
},
|
161
131
|
children: N
|
162
132
|
}
|
163
133
|
);
|
164
|
-
},
|
165
|
-
const
|
166
|
-
if (
|
134
|
+
}, G = (t) => /* @__PURE__ */ l(C, { children: /* @__PURE__ */ l(_, { ...t }) }), z = () => {
|
135
|
+
const t = A(P);
|
136
|
+
if (t === void 0)
|
167
137
|
throw new Error(
|
168
|
-
"[Knock] useExpoPushNotifications must be used within a
|
138
|
+
"[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider"
|
169
139
|
);
|
170
|
-
return
|
140
|
+
return t;
|
171
141
|
};
|
172
142
|
export {
|
173
|
-
|
174
|
-
|
143
|
+
G as KnockExpoPushNotificationProvider,
|
144
|
+
z as useExpoPushNotifications
|
175
145
|
};
|
176
146
|
//# sourceMappingURL=KnockExpoPushNotificationProvider.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"KnockExpoPushNotificationProvider.mjs","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"sourcesContent":["import {\n ChannelData,\n Message,\n MessageEngagementStatus,\n} from \"@knocklabs/client\";\nimport { useKnockClient } from \"@knocklabs/react-core\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport * as Notifications from \"expo-notifications\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface KnockExpoPushNotificationContextType {\n expoPushToken: string | null;\n registerForPushNotifications: () => Promise<void>;\n registerPushTokenToChannel(token: string, channelId: string): Promise<void>;\n unregisterPushTokenFromChannel(\n token: string,\n channelId: string,\n ): Promise<void>;\n onNotificationReceived: (\n handler: (notification: Notifications.Notification) => void,\n ) => void;\n onNotificationTapped: (\n handler: (response: Notifications.NotificationResponse) => void,\n ) => void;\n}\n\nNotifications.setNotificationHandler({\n handleNotification: async () => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n };\n },\n});\n\nconst defaultNotificationHandler = async (\n _notification: Notifications.Notification,\n): Promise<Notifications.NotificationBehavior> => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n };\n};\n\nconst KnockExpoPushNotificationContext = createContext<\n KnockExpoPushNotificationContextType | undefined\n>(undefined);\n\nexport interface KnockExpoPushNotificationProviderProps {\n knockExpoChannelId: string;\n customNotificationHandler?: (\n notification: Notifications.Notification,\n ) => Promise<Notifications.NotificationBehavior>;\n children?: React.ReactElement;\n autoRegister?: boolean;\n}\n\nasync function requestPushPermissionIfNeeded(): Promise<string> {\n const { status: existingStatus } = await Notifications.getPermissionsAsync();\n\n if (existingStatus !== \"granted\") {\n const { status } = await Notifications.requestPermissionsAsync();\n return status;\n }\n\n return existingStatus;\n}\n\nasync function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {\n try {\n if (\n !Constants.expoConfig ||\n !Constants.expoConfig.extra ||\n !Constants.expoConfig.extra.eas\n ) {\n console.error(\n \"[Knock] Expo Project ID is not defined in the app configuration.\",\n );\n return null;\n }\n const token = await Notifications.getExpoPushTokenAsync({\n projectId: Constants.expoConfig.extra.eas.projectId,\n });\n return token;\n } catch (error) {\n console.error(\"[Knock] Error getting Expo push token:\", error);\n return null;\n }\n}\n\nasync function requestPermissionAndGetPushToken(): Promise<Notifications.ExpoPushToken | null> {\n // Check for device support\n if (!Device.isDevice) {\n console.warn(\"[Knock] Must use physical device for Push Notifications\");\n return null;\n }\n\n const permissionStatus = await requestPushPermissionIfNeeded();\n\n if (permissionStatus !== \"granted\") {\n console.warn(\"[Knock] Push notification permission not granted\");\n return null;\n }\n\n return getExpoPushToken();\n}\n\nexport const KnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = ({\n knockExpoChannelId,\n customNotificationHandler,\n children,\n autoRegister = true,\n}) => {\n const [expoPushToken, setExpoPushToken] = useState<string | null>(null);\n const knockClient = useKnockClient();\n\n const [notificationReceivedHandler, setNotificationReceivedHandler] =\n useState<(notification: Notifications.Notification) => void>(\n () => () => {},\n );\n\n const [notificationTappedHandler, setNotificationTappedHandler] = useState<\n (response: Notifications.NotificationResponse) => void\n >(() => () => {});\n\n const handleNotificationReceived = useCallback(\n (handler: (notification: Notifications.Notification) => void) => {\n setNotificationReceivedHandler(() => handler);\n },\n [],\n );\n\n const handleNotificationTapped = useCallback(\n (handler: (response: Notifications.NotificationResponse) => void) => {\n setNotificationTappedHandler(() => handler);\n },\n [],\n );\n\n const registerForPushNotifications = useCallback(async (): Promise<void> => {\n try {\n knockClient.log(`[Knock] Registering for push notifications`);\n const token = await requestPermissionAndGetPushToken();\n knockClient.log(`[Knock] Token received: ${token?.data}`);\n if (token?.data) {\n knockClient.log(`[Knock] Setting push token: ${token.data}`);\n setExpoPushToken(token.data);\n }\n } catch (error) {\n console.error(`[Knock] Error registering for push notifications:`, error);\n }\n }, [knockClient]);\n\n const updateKnockMessageStatusFromNotification = useCallback(\n async (\n notification: Notifications.Notification,\n status: MessageEngagementStatus,\n ): Promise<Message> => {\n const messageId = notification.request.content.data[\"knock_message_id\"];\n return knockClient.messages.updateStatus(messageId, status);\n },\n [knockClient],\n );\n\n const registerNewTokenDataOnServer = useCallback(\n async (tokens: string[], channelId: string): Promise<ChannelData> => {\n return knockClient.user.setChannelData({\n channelId: channelId,\n channelData: { tokens: tokens },\n });\n },\n [knockClient],\n );\n\n const registerPushTokenToChannel = useCallback(\n async (token: string, channelId: string): Promise<void> => {\n knockClient.user\n .getChannelData({ channelId: channelId })\n .then((result: ChannelData) => {\n const tokens: string[] = result.data[\"tokens\"];\n if (!tokens.includes(token)) {\n tokens.push(token);\n return registerNewTokenDataOnServer(tokens, channelId);\n }\n knockClient.log(\"[Knock] registerPushTokenToChannel success\");\n })\n .catch((_) => {\n // No data registered on that channel for that user, we'll create a new record\n return registerNewTokenDataOnServer([token], channelId);\n });\n },\n [knockClient, registerNewTokenDataOnServer],\n );\n\n const unregisterPushTokenFromChannel = useCallback(\n async (token: string, channelId: string): Promise<void> => {\n knockClient.user\n .getChannelData({ channelId: channelId })\n .then((result: ChannelData) => {\n const tokens: string[] = result.data[\"tokens\"];\n const updatedTokens = tokens.filter(\n (channelToken) => channelToken !== token,\n );\n knockClient.log(\"unregisterPushTokenFromChannel success\");\n return registerNewTokenDataOnServer(updatedTokens, channelId);\n })\n .catch((error) => {\n console.error(\n `[Knock] Error unregistering push token from channel:`,\n error,\n );\n });\n },\n [knockClient, registerNewTokenDataOnServer],\n );\n\n useEffect(() => {\n Notifications.setNotificationHandler({\n handleNotification:\n customNotificationHandler ?? defaultNotificationHandler,\n });\n\n if (autoRegister) {\n registerForPushNotifications()\n .then(() => {\n if (expoPushToken) {\n registerPushTokenToChannel(expoPushToken, knockExpoChannelId)\n .then((_result) => {\n knockClient.log(\"[Knock] setChannelData success\");\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n\n const notificationReceivedSubscription =\n Notifications.addNotificationReceivedListener((notification) => {\n knockClient.log(\n \"[Knock] Expo Push Notification received in foreground:\",\n );\n updateKnockMessageStatusFromNotification(notification, \"interacted\");\n notificationReceivedHandler(notification);\n });\n\n const notificationResponseSubscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n knockClient.log(\"[Knock] Expo Push Notification was interacted with\");\n updateKnockMessageStatusFromNotification(\n response.notification,\n \"interacted\",\n );\n notificationTappedHandler(response);\n });\n\n return () => {\n Notifications.removeNotificationSubscription(\n notificationReceivedSubscription,\n );\n Notifications.removeNotificationSubscription(\n notificationResponseSubscription,\n );\n };\n\n // TODO: Remove when possible and ensure dependency array is correct\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n registerForPushNotifications,\n notificationReceivedHandler,\n notificationTappedHandler,\n customNotificationHandler,\n expoPushToken,\n knockExpoChannelId,\n knockClient,\n ]);\n\n return (\n <KnockExpoPushNotificationContext.Provider\n value={{\n expoPushToken,\n registerForPushNotifications,\n registerPushTokenToChannel,\n unregisterPushTokenFromChannel,\n onNotificationReceived: handleNotificationReceived,\n onNotificationTapped: handleNotificationTapped,\n }}\n >\n {children}\n </KnockExpoPushNotificationContext.Provider>\n );\n};\n\nexport const useExpoPushNotifications =\n (): KnockExpoPushNotificationContextType => {\n const context = useContext(KnockExpoPushNotificationContext);\n if (context === undefined) {\n throw new Error(\n \"[Knock] useExpoPushNotifications must be used within a PushNotificationProvider\",\n );\n }\n return context;\n };\n"],"names":["Notifications","defaultNotificationHandler","_notification","KnockExpoPushNotificationContext","createContext","requestPushPermissionIfNeeded","existingStatus","status","getExpoPushToken","Constants","error","requestPermissionAndGetPushToken","Device","KnockExpoPushNotificationProvider","knockExpoChannelId","customNotificationHandler","children","autoRegister","expoPushToken","setExpoPushToken","useState","knockClient","useKnockClient","notificationReceivedHandler","setNotificationReceivedHandler","notificationTappedHandler","setNotificationTappedHandler","handleNotificationReceived","useCallback","handler","handleNotificationTapped","registerForPushNotifications","token","updateKnockMessageStatusFromNotification","notification","messageId","registerNewTokenDataOnServer","tokens","channelId","registerPushTokenToChannel","result","_","unregisterPushTokenFromChannel","updatedTokens","channelToken","useEffect","_result","_error","notificationReceivedSubscription","notificationResponseSubscription","response","jsx","useExpoPushNotifications","context","useContext"],"mappings":";;;;;;AAiCAA,EAAc,uBAAuB;AAAA,EACnC,oBAAoB,aACX;AAAA,IACL,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,EAAA;AAGtB,CAAC;AAED,MAAMC,IAA6B,OACjCC,OAEO;AAAA,EACL,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,IAIdC,IAAmCC,EAEvC,MAAS;AAWX,eAAeC,IAAiD;AAC9D,QAAM,EAAE,QAAQC,EAAA,IAAmB,MAAMN,EAAc,oBAAoB;AAE3E,MAAIM,MAAmB,WAAW;AAChC,UAAM,EAAE,QAAAC,EAAW,IAAA,MAAMP,EAAc,wBAAwB;AACxD,WAAAO;AAAA,EACT;AAEO,SAAAD;AACT;AAEA,eAAeE,IAAgE;AACzE,MAAA;AAEA,WAAA,CAACC,EAAU,cACX,CAACA,EAAU,WAAW,SACtB,CAACA,EAAU,WAAW,MAAM,OAEpB,QAAA;AAAA,MACN;AAAA,IAAA,GAEK,QAEK,MAAMT,EAAc,sBAAsB;AAAA,MACtD,WAAWS,EAAU,WAAW,MAAM,IAAI;AAAA,IAAA,CAC3C;AAAA,WAEMC,GAAO;AACN,mBAAA,MAAM,0CAA0CA,CAAK,GACtD;AAAA,EACT;AACF;AAEA,eAAeC,IAAgF;AAEzF,SAACC,EAAO,WAKa,MAAMP,QAEN,aACvB,QAAQ,KAAK,kDAAkD,GACxD,QAGFG,EAAiB,KAXtB,QAAQ,KAAK,yDAAyD,GAC/D;AAWX;AAEO,MAAMK,IAET,CAAC;AAAA,EACH,oBAAAC;AAAA,EACA,2BAAAC;AAAA,EACA,UAAAC;AAAA,EACA,cAAAC,IAAe;AACjB,MAAM;AACJ,QAAM,CAACC,GAAeC,CAAgB,IAAIC,EAAwB,IAAI,GAChEC,IAAcC,KAEd,CAACC,GAA6BC,CAA8B,IAChEJ;AAAA,IACE,MAAM,MAAM;AAAA,IAAC;AAAA,EAAA,GAGX,CAACK,GAA2BC,CAA4B,IAAIN,EAEhE,MAAM,MAAM;AAAA,EAAA,CAAE,GAEVO,IAA6BC;AAAA,IACjC,CAACC,MAAgE;AAC/D,MAAAL,EAA+B,MAAMK,CAAO;AAAA,IAC9C;AAAA,IACA,CAAC;AAAA,EAAA,GAGGC,IAA2BF;AAAA,IAC/B,CAACC,MAAoE;AACnE,MAAAH,EAA6B,MAAMG,CAAO;AAAA,IAC5C;AAAA,IACA,CAAC;AAAA,EAAA,GAGGE,IAA+BH,EAAY,YAA2B;AACtE,QAAA;AACF,MAAAP,EAAY,IAAI,4CAA4C;AACtD,YAAAW,IAAQ,MAAMrB;AACpB,MAAAU,EAAY,IAAI,2BAA2BW,KAAA,gBAAAA,EAAO,IAAI,EAAE,GACpDA,KAAA,QAAAA,EAAO,SACTX,EAAY,IAAI,+BAA+BW,EAAM,IAAI,EAAE,GAC3Db,EAAiBa,EAAM,IAAI;AAAA,aAEtBtB,GAAO;AACN,cAAA,MAAM,qDAAqDA,CAAK;AAAA,IAC1E;AAAA,EAAA,GACC,CAACW,CAAW,CAAC,GAEVY,IAA2CL;AAAA,IAC/C,OACEM,GACA3B,MACqB;AACrB,YAAM4B,IAAYD,EAAa,QAAQ,QAAQ,KAAK;AACpD,aAAOb,EAAY,SAAS,aAAac,GAAW5B,CAAM;AAAA,IAC5D;AAAA,IACA,CAACc,CAAW;AAAA,EAAA,GAGRe,IAA+BR;AAAA,IACnC,OAAOS,GAAkBC,MAChBjB,EAAY,KAAK,eAAe;AAAA,MACrC,WAAAiB;AAAA,MACA,aAAa,EAAE,QAAAD,EAAe;AAAA,IAAA,CAC/B;AAAA,IAEH,CAAChB,CAAW;AAAA,EAAA,GAGRkB,IAA6BX;AAAA,IACjC,OAAOI,GAAeM,MAAqC;AAC7C,MAAAjB,EAAA,KACT,eAAe,EAAE,WAAAiB,EAAA,CAAsB,EACvC,KAAK,CAACE,MAAwB;AACvB,cAAAH,IAAmBG,EAAO,KAAK;AACrC,YAAI,CAACH,EAAO,SAASL,CAAK;AACxB,iBAAAK,EAAO,KAAKL,CAAK,GACVI,EAA6BC,GAAQC,CAAS;AAEvD,QAAAjB,EAAY,IAAI,4CAA4C;AAAA,MAAA,CAC7D,EACA,MAAM,CAACoB,MAECL,EAA6B,CAACJ,CAAK,GAAGM,CAAS,CACvD;AAAA,IACL;AAAA,IACA,CAACjB,GAAae,CAA4B;AAAA,EAAA,GAGtCM,IAAiCd;AAAA,IACrC,OAAOI,GAAeM,MAAqC;AAC7C,MAAAjB,EAAA,KACT,eAAe,EAAE,WAAAiB,EAAA,CAAsB,EACvC,KAAK,CAACE,MAAwB;AAE7B,cAAMG,IADmBH,EAAO,KAAK,OACR;AAAA,UAC3B,CAACI,MAAiBA,MAAiBZ;AAAA,QAAA;AAErC,eAAAX,EAAY,IAAI,wCAAwC,GACjDe,EAA6BO,GAAeL,CAAS;AAAA,MAAA,CAC7D,EACA,MAAM,CAAC5B,MAAU;AACR,gBAAA;AAAA,UACN;AAAA,UACAA;AAAA,QAAA;AAAA,MACF,CACD;AAAA,IACL;AAAA,IACA,CAACW,GAAae,CAA4B;AAAA,EAAA;AAG5C,SAAAS,EAAU,MAAM;AACd,IAAA7C,EAAc,uBAAuB;AAAA,MACnC,oBACEe,KAA6Bd;AAAA,IAAA,CAChC,GAEGgB,KAC2Bc,EAAA,EAC1B,KAAK,MAAM;AACV,MAAIb,KACFqB,EAA2BrB,GAAeJ,CAAkB,EACzD,KAAK,CAACgC,MAAY;AACjB,QAAAzB,EAAY,IAAI,gCAAgC;AAAA,MAAA,CACjD,EACA,MAAM,CAAC0B,MAAW;AACT,gBAAA;AAAA,UACN;AAAA,UACAA;AAAA,QAAA;AAAA,MACF,CACD;AAAA,IACL,CACD,EACA,MAAM,CAACA,MAAW;AACT,cAAA;AAAA,QACN;AAAA,QACAA;AAAA,MAAA;AAAA,IACF,CACD;AAGL,UAAMC,IACJhD,EAAc,gCAAgC,CAACkC,MAAiB;AAClD,MAAAb,EAAA;AAAA,QACV;AAAA,MAAA,GAEFY,EAAyCC,GAAc,YAAY,GACnEX,EAA4BW,CAAY;AAAA,IAAA,CACzC,GAEGe,IACJjD,EAAc,wCAAwC,CAACkD,MAAa;AAClE,MAAA7B,EAAY,IAAI,oDAAoD,GACpEY;AAAA,QACEiB,EAAS;AAAA,QACT;AAAA,MAAA,GAEFzB,EAA0ByB,CAAQ;AAAA,IAAA,CACnC;AAEH,WAAO,MAAM;AACG,MAAAlD,EAAA;AAAA,QACZgD;AAAA,MAAA,GAEYhD,EAAA;AAAA,QACZiD;AAAA,MAAA;AAAA,IACF;AAAA,EACF,GAIC;AAAA,IACDlB;AAAA,IACAR;AAAA,IACAE;AAAA,IACAV;AAAA,IACAG;AAAA,IACAJ;AAAA,IACAO;AAAA,EAAA,CACD,GAGC,gBAAA8B;AAAA,IAAChD,EAAiC;AAAA,IAAjC;AAAA,MACC,OAAO;AAAA,QACL,eAAAe;AAAA,QACA,8BAAAa;AAAA,QACA,4BAAAQ;AAAA,QACA,gCAAAG;AAAA,QACA,wBAAwBf;AAAA,QACxB,sBAAsBG;AAAA,MACxB;AAAA,MAEC,UAAAd;AAAA,IAAA;AAAA,EAAA;AAGP,GAEaoC,IACX,MAA4C;AACpC,QAAAC,IAAUC,EAAWnD,CAAgC;AAC3D,MAAIkD,MAAY;AACd,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAGG,SAAAA;AACT;"}
|
1
|
+
{"version":3,"file":"KnockExpoPushNotificationProvider.mjs","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"sourcesContent":["import { Message, MessageEngagementStatus } from \"@knocklabs/client\";\nimport { useKnockClient } from \"@knocklabs/react-core\";\nimport {\n type KnockPushNotificationContextType,\n KnockPushNotificationProvider,\n usePushNotifications,\n} from \"@knocklabs/react-native\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport * as Notifications from \"expo-notifications\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface KnockExpoPushNotificationContextType\n extends KnockPushNotificationContextType {\n expoPushToken: string | null;\n registerForPushNotifications: () => Promise<void>;\n onNotificationReceived: (\n handler: (notification: Notifications.Notification) => void,\n ) => void;\n onNotificationTapped: (\n handler: (response: Notifications.NotificationResponse) => void,\n ) => void;\n}\n\nNotifications.setNotificationHandler({\n handleNotification: async () => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n };\n },\n});\n\nconst defaultNotificationHandler = async (\n _notification: Notifications.Notification,\n): Promise<Notifications.NotificationBehavior> => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n };\n};\n\nconst KnockExpoPushNotificationContext = createContext<\n KnockExpoPushNotificationContextType | undefined\n>(undefined);\n\nexport interface KnockExpoPushNotificationProviderProps {\n knockExpoChannelId: string;\n customNotificationHandler?: (\n notification: Notifications.Notification,\n ) => Promise<Notifications.NotificationBehavior>;\n children?: React.ReactElement;\n autoRegister?: boolean;\n}\n\nasync function requestPushPermissionIfNeeded(): Promise<string> {\n const { status: existingStatus } = await Notifications.getPermissionsAsync();\n\n if (existingStatus !== \"granted\") {\n const { status } = await Notifications.requestPermissionsAsync();\n return status;\n }\n\n return existingStatus;\n}\n\nasync function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {\n try {\n if (\n !Constants.expoConfig ||\n !Constants.expoConfig.extra ||\n !Constants.expoConfig.extra.eas\n ) {\n console.error(\n \"[Knock] Expo Project ID is not defined in the app configuration.\",\n );\n return null;\n }\n const token = await Notifications.getExpoPushTokenAsync({\n projectId: Constants.expoConfig.extra.eas.projectId,\n });\n return token;\n } catch (error) {\n console.error(\"[Knock] Error getting Expo push token:\", error);\n return null;\n }\n}\n\nasync function requestPermissionAndGetPushToken(): Promise<Notifications.ExpoPushToken | null> {\n // Check for device support\n if (!Device.isDevice) {\n console.warn(\"[Knock] Must use physical device for Push Notifications\");\n return null;\n }\n\n const permissionStatus = await requestPushPermissionIfNeeded();\n\n if (permissionStatus !== \"granted\") {\n console.warn(\"[Knock] Push notification permission not granted\");\n return null;\n }\n\n return getExpoPushToken();\n}\n\nconst InternalKnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = ({\n knockExpoChannelId,\n customNotificationHandler,\n children,\n autoRegister = true,\n}) => {\n const { registerPushTokenToChannel, unregisterPushTokenFromChannel } =\n usePushNotifications();\n const [expoPushToken, setExpoPushToken] = useState<string | null>(null);\n const knockClient = useKnockClient();\n\n const [notificationReceivedHandler, setNotificationReceivedHandler] =\n useState<(notification: Notifications.Notification) => void>(\n () => () => {},\n );\n\n const [notificationTappedHandler, setNotificationTappedHandler] = useState<\n (response: Notifications.NotificationResponse) => void\n >(() => () => {});\n\n const handleNotificationReceived = useCallback(\n (handler: (notification: Notifications.Notification) => void) => {\n setNotificationReceivedHandler(() => handler);\n },\n [],\n );\n\n const handleNotificationTapped = useCallback(\n (handler: (response: Notifications.NotificationResponse) => void) => {\n setNotificationTappedHandler(() => handler);\n },\n [],\n );\n\n const registerForPushNotifications = useCallback(async (): Promise<void> => {\n try {\n knockClient.log(`[Knock] Registering for push notifications`);\n const token = await requestPermissionAndGetPushToken();\n knockClient.log(`[Knock] Token received: ${token?.data}`);\n if (token?.data) {\n knockClient.log(`[Knock] Setting push token: ${token.data}`);\n setExpoPushToken(token.data);\n }\n } catch (error) {\n console.error(`[Knock] Error registering for push notifications:`, error);\n }\n }, [knockClient]);\n\n const updateKnockMessageStatusFromNotification = useCallback(\n async (\n notification: Notifications.Notification,\n status: MessageEngagementStatus,\n ): Promise<Message> => {\n const messageId = notification.request.content.data[\"knock_message_id\"];\n return knockClient.messages.updateStatus(messageId, status);\n },\n [knockClient],\n );\n\n useEffect(() => {\n Notifications.setNotificationHandler({\n handleNotification:\n customNotificationHandler ?? defaultNotificationHandler,\n });\n\n if (autoRegister) {\n registerForPushNotifications()\n .then(() => {\n if (expoPushToken) {\n registerPushTokenToChannel(expoPushToken, knockExpoChannelId)\n .then((_result) => {\n knockClient.log(\"[Knock] setChannelData success\");\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n\n const notificationReceivedSubscription =\n Notifications.addNotificationReceivedListener((notification) => {\n knockClient.log(\n \"[Knock] Expo Push Notification received in foreground:\",\n );\n updateKnockMessageStatusFromNotification(notification, \"interacted\");\n notificationReceivedHandler(notification);\n });\n\n const notificationResponseSubscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n knockClient.log(\"[Knock] Expo Push Notification was interacted with\");\n updateKnockMessageStatusFromNotification(\n response.notification,\n \"interacted\",\n );\n notificationTappedHandler(response);\n });\n\n return () => {\n Notifications.removeNotificationSubscription(\n notificationReceivedSubscription,\n );\n Notifications.removeNotificationSubscription(\n notificationResponseSubscription,\n );\n };\n\n // TODO: Remove when possible and ensure dependency array is correct\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n registerForPushNotifications,\n notificationReceivedHandler,\n notificationTappedHandler,\n customNotificationHandler,\n expoPushToken,\n knockExpoChannelId,\n knockClient,\n ]);\n\n return (\n <KnockExpoPushNotificationContext.Provider\n value={{\n expoPushToken,\n registerForPushNotifications,\n registerPushTokenToChannel,\n unregisterPushTokenFromChannel,\n onNotificationReceived: handleNotificationReceived,\n onNotificationTapped: handleNotificationTapped,\n }}\n >\n {children}\n </KnockExpoPushNotificationContext.Provider>\n );\n};\n\nexport const KnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = (props) => {\n return (\n <KnockPushNotificationProvider>\n <InternalKnockExpoPushNotificationProvider {...props} />\n </KnockPushNotificationProvider>\n );\n};\n\nexport const useExpoPushNotifications =\n (): KnockExpoPushNotificationContextType => {\n const context = useContext(KnockExpoPushNotificationContext);\n if (context === undefined) {\n throw new Error(\n \"[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider\",\n );\n }\n return context;\n };\n"],"names":["Notifications","defaultNotificationHandler","_notification","KnockExpoPushNotificationContext","createContext","requestPushPermissionIfNeeded","existingStatus","status","getExpoPushToken","Constants","error","requestPermissionAndGetPushToken","Device","InternalKnockExpoPushNotificationProvider","knockExpoChannelId","customNotificationHandler","children","autoRegister","registerPushTokenToChannel","unregisterPushTokenFromChannel","usePushNotifications","expoPushToken","setExpoPushToken","useState","knockClient","useKnockClient","notificationReceivedHandler","setNotificationReceivedHandler","notificationTappedHandler","setNotificationTappedHandler","handleNotificationReceived","useCallback","handler","handleNotificationTapped","registerForPushNotifications","token","updateKnockMessageStatusFromNotification","notification","messageId","useEffect","_result","_error","notificationReceivedSubscription","notificationResponseSubscription","response","jsx","KnockExpoPushNotificationProvider","props","KnockPushNotificationProvider","useExpoPushNotifications","context","useContext"],"mappings":"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"}
|
@@ -1,10 +1,10 @@
|
|
1
|
+
import { KnockPushNotificationContextType } from '@knocklabs/react-native';
|
1
2
|
import { default as React } from 'react';
|
3
|
+
|
2
4
|
import * as Notifications from "expo-notifications";
|
3
|
-
export interface KnockExpoPushNotificationContextType {
|
5
|
+
export interface KnockExpoPushNotificationContextType extends KnockPushNotificationContextType {
|
4
6
|
expoPushToken: string | null;
|
5
7
|
registerForPushNotifications: () => Promise<void>;
|
6
|
-
registerPushTokenToChannel(token: string, channelId: string): Promise<void>;
|
7
|
-
unregisterPushTokenFromChannel(token: string, channelId: string): Promise<void>;
|
8
8
|
onNotificationReceived: (handler: (notification: Notifications.Notification) => void) => void;
|
9
9
|
onNotificationTapped: (handler: (response: Notifications.NotificationResponse) => void) => void;
|
10
10
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"KnockExpoPushNotificationProvider.d.ts","sourceRoot":"","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"KnockExpoPushNotificationProvider.d.ts","sourceRoot":"","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gCAAgC,EAGtC,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAMN,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,oCACf,SAAQ,gCAAgC;IACxC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4BAA4B,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,sBAAsB,EAAE,CACtB,OAAO,EAAE,CAAC,YAAY,EAAE,aAAa,CAAC,YAAY,KAAK,IAAI,KACxD,IAAI,CAAC;IACV,oBAAoB,EAAE,CACpB,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,oBAAoB,KAAK,IAAI,KAC5D,IAAI,CAAC;CACX;AA0BD,MAAM,WAAW,sCAAsC;IACrD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,yBAAyB,CAAC,EAAE,CAC1B,YAAY,EAAE,aAAa,CAAC,YAAY,KACrC,OAAO,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAuMD,eAAO,MAAM,iCAAiC,EAAE,KAAK,CAAC,EAAE,CACtD,sCAAsC,CAOvC,CAAC;AAEF,eAAO,MAAM,wBAAwB,QAC/B,oCAQH,CAAC"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@knocklabs/expo",
|
3
|
-
"version": "0.1.0",
|
3
|
+
"version": "0.2.1-rc.0",
|
4
4
|
"author": "@knocklabs",
|
5
5
|
"license": "MIT",
|
6
6
|
"main": "dist/cjs/index.js",
|
@@ -49,9 +49,9 @@
|
|
49
49
|
"react-native": "*"
|
50
50
|
},
|
51
51
|
"dependencies": {
|
52
|
-
"@knocklabs/client": "^0.
|
53
|
-
"@knocklabs/react-core": "^0.
|
54
|
-
"@knocklabs/react-native": "^0.
|
52
|
+
"@knocklabs/client": "^0.11.0-rc.0",
|
53
|
+
"@knocklabs/react-core": "^0.3.0-rc.0",
|
54
|
+
"@knocklabs/react-native": "^0.5.1-rc.0",
|
55
55
|
"react-native-gesture-handler": "^2.19.0",
|
56
56
|
"react-native-render-html": "^6.3.4",
|
57
57
|
"react-native-svg": "^15.6.0"
|
@@ -1,9 +1,10 @@
|
|
1
|
-
import {
|
2
|
-
ChannelData,
|
3
|
-
Message,
|
4
|
-
MessageEngagementStatus,
|
5
|
-
} from "@knocklabs/client";
|
1
|
+
import { Message, MessageEngagementStatus } from "@knocklabs/client";
|
6
2
|
import { useKnockClient } from "@knocklabs/react-core";
|
3
|
+
import {
|
4
|
+
type KnockPushNotificationContextType,
|
5
|
+
KnockPushNotificationProvider,
|
6
|
+
usePushNotifications,
|
7
|
+
} from "@knocklabs/react-native";
|
7
8
|
import Constants from "expo-constants";
|
8
9
|
import * as Device from "expo-device";
|
9
10
|
import * as Notifications from "expo-notifications";
|
@@ -15,14 +16,10 @@ import React, {
|
|
15
16
|
useState,
|
16
17
|
} from "react";
|
17
18
|
|
18
|
-
export interface KnockExpoPushNotificationContextType
|
19
|
+
export interface KnockExpoPushNotificationContextType
|
20
|
+
extends KnockPushNotificationContextType {
|
19
21
|
expoPushToken: string | null;
|
20
22
|
registerForPushNotifications: () => Promise<void>;
|
21
|
-
registerPushTokenToChannel(token: string, channelId: string): Promise<void>;
|
22
|
-
unregisterPushTokenFromChannel(
|
23
|
-
token: string,
|
24
|
-
channelId: string,
|
25
|
-
): Promise<void>;
|
26
23
|
onNotificationReceived: (
|
27
24
|
handler: (notification: Notifications.Notification) => void,
|
28
25
|
) => void;
|
@@ -114,7 +111,7 @@ async function requestPermissionAndGetPushToken(): Promise<Notifications.ExpoPus
|
|
114
111
|
return getExpoPushToken();
|
115
112
|
}
|
116
113
|
|
117
|
-
|
114
|
+
const InternalKnockExpoPushNotificationProvider: React.FC<
|
118
115
|
KnockExpoPushNotificationProviderProps
|
119
116
|
> = ({
|
120
117
|
knockExpoChannelId,
|
@@ -122,6 +119,8 @@ export const KnockExpoPushNotificationProvider: React.FC<
|
|
122
119
|
children,
|
123
120
|
autoRegister = true,
|
124
121
|
}) => {
|
122
|
+
const { registerPushTokenToChannel, unregisterPushTokenFromChannel } =
|
123
|
+
usePushNotifications();
|
125
124
|
const [expoPushToken, setExpoPushToken] = useState<string | null>(null);
|
126
125
|
const knockClient = useKnockClient();
|
127
126
|
|
@@ -173,58 +172,6 @@ export const KnockExpoPushNotificationProvider: React.FC<
|
|
173
172
|
[knockClient],
|
174
173
|
);
|
175
174
|
|
176
|
-
const registerNewTokenDataOnServer = useCallback(
|
177
|
-
async (tokens: string[], channelId: string): Promise<ChannelData> => {
|
178
|
-
return knockClient.user.setChannelData({
|
179
|
-
channelId: channelId,
|
180
|
-
channelData: { tokens: tokens },
|
181
|
-
});
|
182
|
-
},
|
183
|
-
[knockClient],
|
184
|
-
);
|
185
|
-
|
186
|
-
const registerPushTokenToChannel = useCallback(
|
187
|
-
async (token: string, channelId: string): Promise<void> => {
|
188
|
-
knockClient.user
|
189
|
-
.getChannelData({ channelId: channelId })
|
190
|
-
.then((result: ChannelData) => {
|
191
|
-
const tokens: string[] = result.data["tokens"];
|
192
|
-
if (!tokens.includes(token)) {
|
193
|
-
tokens.push(token);
|
194
|
-
return registerNewTokenDataOnServer(tokens, channelId);
|
195
|
-
}
|
196
|
-
knockClient.log("[Knock] registerPushTokenToChannel success");
|
197
|
-
})
|
198
|
-
.catch((_) => {
|
199
|
-
// No data registered on that channel for that user, we'll create a new record
|
200
|
-
return registerNewTokenDataOnServer([token], channelId);
|
201
|
-
});
|
202
|
-
},
|
203
|
-
[knockClient, registerNewTokenDataOnServer],
|
204
|
-
);
|
205
|
-
|
206
|
-
const unregisterPushTokenFromChannel = useCallback(
|
207
|
-
async (token: string, channelId: string): Promise<void> => {
|
208
|
-
knockClient.user
|
209
|
-
.getChannelData({ channelId: channelId })
|
210
|
-
.then((result: ChannelData) => {
|
211
|
-
const tokens: string[] = result.data["tokens"];
|
212
|
-
const updatedTokens = tokens.filter(
|
213
|
-
(channelToken) => channelToken !== token,
|
214
|
-
);
|
215
|
-
knockClient.log("unregisterPushTokenFromChannel success");
|
216
|
-
return registerNewTokenDataOnServer(updatedTokens, channelId);
|
217
|
-
})
|
218
|
-
.catch((error) => {
|
219
|
-
console.error(
|
220
|
-
`[Knock] Error unregistering push token from channel:`,
|
221
|
-
error,
|
222
|
-
);
|
223
|
-
});
|
224
|
-
},
|
225
|
-
[knockClient, registerNewTokenDataOnServer],
|
226
|
-
);
|
227
|
-
|
228
175
|
useEffect(() => {
|
229
176
|
Notifications.setNotificationHandler({
|
230
177
|
handleNotification:
|
@@ -311,12 +258,22 @@ export const KnockExpoPushNotificationProvider: React.FC<
|
|
311
258
|
);
|
312
259
|
};
|
313
260
|
|
261
|
+
export const KnockExpoPushNotificationProvider: React.FC<
|
262
|
+
KnockExpoPushNotificationProviderProps
|
263
|
+
> = (props) => {
|
264
|
+
return (
|
265
|
+
<KnockPushNotificationProvider>
|
266
|
+
<InternalKnockExpoPushNotificationProvider {...props} />
|
267
|
+
</KnockPushNotificationProvider>
|
268
|
+
);
|
269
|
+
};
|
270
|
+
|
314
271
|
export const useExpoPushNotifications =
|
315
272
|
(): KnockExpoPushNotificationContextType => {
|
316
273
|
const context = useContext(KnockExpoPushNotificationContext);
|
317
274
|
if (context === undefined) {
|
318
275
|
throw new Error(
|
319
|
-
"[Knock] useExpoPushNotifications must be used within a
|
276
|
+
"[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider",
|
320
277
|
);
|
321
278
|
}
|
322
279
|
return context;
|