forked from ZyntariHQ/Invoisio
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathusePushNotifications.ts
More file actions
154 lines (133 loc) · 5 KB
/
Copy pathusePushNotifications.ts
File metadata and controls
154 lines (133 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import { useState, useEffect, useRef } from "react";
import * as Device from "expo-device";
import * as Notifications from "expo-notifications";
import Constants from "expo-constants";
import { Platform } from "react-native";
import { useRouter } from "expo-router";
import { parseDeepLink, navigateToDeepLink } from "../lib/deep-links";
export interface PushNotificationState {
expoPushToken?: Notifications.ExpoPushToken | undefined;
notification?: Notifications.Notification | undefined;
}
export const usePushNotifications = (): PushNotificationState => {
const router = useRouter();
Notifications.setNotificationHandler({
handleNotification: () =>
Promise.resolve({
shouldPlaySound: true,
shouldShowAlert: true,
shouldShowBanner: true,
shouldShowList: true,
shouldSetBadge: false,
}),
});
const [expoPushToken, setExpoPushToken] = useState<
Notifications.ExpoPushToken | undefined
>();
const [notification, setNotification] = useState<
Notifications.Notification | undefined
>();
const notificationListener =
useRef<Notifications.EventSubscription>(undefined);
const responseListener = useRef<Notifications.EventSubscription>(undefined);
async function registerForPushNotificationsAsync() {
let token;
if (Device.isDevice) {
const { status: existingStatus } =
await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== Notifications.PermissionStatus.GRANTED) {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== Notifications.PermissionStatus.GRANTED) {
console.warn("Failed to get push token for push notification");
return;
}
try {
const expoExtra = Constants.expoConfig?.extra as
| Record<string, unknown>
| undefined;
const easObj = expoExtra?.["eas"] as
| Record<string, unknown>
| undefined;
const easProjectId =
typeof easObj?.["projectId"] === "string"
? easObj["projectId"]
: undefined;
const easConfig = Constants.easConfig as Record<string, unknown> | null;
const configProjectId =
typeof easConfig?.["projectId"] === "string"
? easConfig["projectId"]
: undefined;
const projectId = easProjectId ?? configProjectId;
const tokenOptions: Record<string, string> = {};
if (typeof projectId === "string") {
tokenOptions["projectId"] = projectId;
}
token = await Notifications.getExpoPushTokenAsync(tokenOptions);
} catch (e: unknown) {
console.warn("Failed to get expo push token:", e);
}
} else {
console.warn("Must be using a physical device for Push Notifications");
}
if (Platform.OS === "android") {
void Notifications.setNotificationChannelAsync("default", {
name: "default",
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: "#FF231F7C",
});
}
return token;
}
// Handle notification response and navigate
const handleNotificationResponse = (response: Notifications.NotificationResponse) => {
const data = response.notification.request.content.data as Record<string, unknown>;
// Check if notification contains a deep link - using bracket notation for index signature
const deepLinkUrl = (data?.["deepLink"] || data?.["url"] || data?.["link"]) as string | undefined;
if (deepLinkUrl && typeof deepLinkUrl === "string") {
console.log("Notification deep link:", deepLinkUrl);
const parsedData = parseDeepLink(deepLinkUrl);
if (parsedData) {
// If not authenticated, the deep link handler will queue it
navigateToDeepLink(parsedData, router);
return;
}
}
// Fallback: check for invoice ID in notification data - using bracket notation for index signature
const invoiceId = (data?.["invoiceId"] || data?.["invoice_id"]) as string | undefined;
if (invoiceId && typeof invoiceId === "string") {
router.push(`/invoices/${invoiceId}`);
return;
}
console.log("Notification response:", response);
};
useEffect(() => {
void registerForPushNotificationsAsync().then((token) => {
setExpoPushToken(token);
});
notificationListener.current =
Notifications.addNotificationReceivedListener((n) => {
setNotification(n);
});
// Updated: Navigate on notification response
responseListener.current =
Notifications.addNotificationResponseReceivedListener((response) => {
handleNotificationResponse(response);
});
return () => {
if (notificationListener.current) {
notificationListener.current.remove();
}
if (responseListener.current) {
responseListener.current.remove();
}
};
}, []);
return {
expoPushToken,
notification,
};
};