expo-starter/services/notifications.ts

114 lines
2.4 KiB
TypeScript

import Constants from 'expo-constants';
import * as Device from 'expo-device';
import * as Notifications from 'expo-notifications';
import { httpsCallable } from 'firebase/functions';
import {
arrayUnion,
serverTimestamp,
setDoc,
} from 'firebase/firestore';
import { Platform } from 'react-native';
import { functions } from '@/lib/firebase';
import { userDocRef } from '@/lib/firestore';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldPlaySound: false,
shouldSetBadge: false,
shouldShowBanner: true,
shouldShowList: true,
}),
});
type NotificationSettingsPayload = {
expoPushToken: string | null;
pushEnabled: boolean;
platform: 'android' | 'ios' | 'web' | null;
};
type SendTestPushNotificationResult = {
success: boolean;
};
async function saveExpoPushToken(
uid: string,
expoPushToken: string
) {
await setDoc(
userDocRef(uid),
{
expoPushTokens: arrayUnion(expoPushToken),
updatedAt: serverTimestamp(),
},
{ merge: true }
);
}
function getProjectId() {
const projectId =
Constants.expoConfig?.extra?.eas?.projectId ?? Constants.easConfig?.projectId;
if (!projectId) {
throw new Error('EAS projectId introuvable pour Expo Notifications.');
}
return projectId;
}
export async function registerForPushNotifications(uid: string) {
if (Platform.OS === 'web') {
return null;
}
if (!Device.isDevice) {
return null;
}
const existingPermissions = await Notifications.getPermissionsAsync();
let finalStatus = existingPermissions.status;
if (finalStatus !== 'granted') {
const requestedPermissions = await Notifications.requestPermissionsAsync();
finalStatus = requestedPermissions.status;
}
if (finalStatus !== 'granted') {
return null;
}
const expoPushToken = (
await Notifications.getExpoPushTokenAsync({
projectId: getProjectId(),
})
).data;
await saveExpoPushToken(uid, expoPushToken);
return expoPushToken;
}
export function subscribeToPushTokenRefresh(uid: string) {
if (Platform.OS === 'web') {
return () => undefined;
}
const subscription = Notifications.addPushTokenListener((token) => {
void saveExpoPushToken(uid, token.data);
});
return () => {
subscription.remove();
};
}
export async function sendTestPushNotification() {
const callable = httpsCallable<undefined, SendTestPushNotificationResult>(
functions,
'sendTestPushNotification'
);
await callable();
}