109 lines
3.0 KiB
TypeScript
109 lines
3.0 KiB
TypeScript
import * as Notifications from 'expo-notifications';
|
|
import Constants from 'expo-constants';
|
|
import { pb } from './pocketbase';
|
|
import { getOrCreateDeviceId } from './household';
|
|
|
|
Notifications.setNotificationHandler({
|
|
handleNotification: async () => ({
|
|
shouldShowAlert: true,
|
|
shouldPlaySound: true,
|
|
shouldSetBadge: false,
|
|
shouldShowBanner: true,
|
|
shouldShowList: true,
|
|
}),
|
|
});
|
|
|
|
export async function requestNotificationPermission(): Promise<boolean> {
|
|
const { status } = await Notifications.requestPermissionsAsync();
|
|
return status === 'granted';
|
|
}
|
|
|
|
export async function getFcmToken(): Promise<string | null> {
|
|
try {
|
|
const projectId =
|
|
Constants.expoConfig?.extra?.eas?.projectId ??
|
|
(Constants as any).easConfig?.projectId;
|
|
const token = await Notifications.getExpoPushTokenAsync(
|
|
projectId ? { projectId } : {}
|
|
);
|
|
return token.data;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function updateFcmToken(householdId: string, enabled: boolean): Promise<void> {
|
|
const deviceId = await getOrCreateDeviceId();
|
|
const token = enabled ? await getFcmToken() : null;
|
|
|
|
const existing = await pb.collection('members').getFullList({
|
|
filter: `device_id = "${deviceId}" && household = "${householdId}"`,
|
|
});
|
|
if (existing.length === 0) return;
|
|
|
|
await pb.collection('members').update(existing[0].id, {
|
|
fcm_token: token,
|
|
notifications_enabled: enabled,
|
|
});
|
|
}
|
|
|
|
export async function sendShoppingListPush(
|
|
householdId: string,
|
|
itemName: string
|
|
): Promise<void> {
|
|
try {
|
|
const deviceId = await getOrCreateDeviceId();
|
|
const members = await pb.collection('members').getFullList({
|
|
filter: `household = "${householdId}" && notifications_enabled = true && fcm_token != ""`,
|
|
});
|
|
const tokens = members
|
|
.filter((m) => m.device_id !== deviceId)
|
|
.map((m) => m.fcm_token as string)
|
|
.filter((t) => t?.startsWith('ExponentPushToken'));
|
|
|
|
if (tokens.length === 0) return;
|
|
|
|
await fetch('https://exp.host/--/api/v2/push/send', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
body: JSON.stringify(
|
|
tokens.map((to) => ({
|
|
to,
|
|
title: 'Einkaufsliste',
|
|
body: `${itemName} wurde hinzugefügt`,
|
|
sound: 'default',
|
|
}))
|
|
),
|
|
});
|
|
} catch (e) {
|
|
console.warn('sendShoppingListPush failed:', e);
|
|
}
|
|
}
|
|
|
|
export async function scheduleExpiryCheck(
|
|
items: Array<{ name: string; expiryDate: Date | null }>
|
|
) {
|
|
await Notifications.cancelAllScheduledNotificationsAsync();
|
|
|
|
const now = new Date();
|
|
const threeDays = 3 * 24 * 60 * 60 * 1000;
|
|
|
|
const expiringSoon = items.filter(
|
|
(item) =>
|
|
item.expiryDate &&
|
|
item.expiryDate.getTime() - now.getTime() <= threeDays &&
|
|
item.expiryDate.getTime() > now.getTime()
|
|
);
|
|
|
|
for (const item of expiringSoon) {
|
|
await Notifications.scheduleNotificationAsync({
|
|
content: {
|
|
title: 'MHD läuft ab',
|
|
body: `${item.name} läuft in ≤ 3 Tagen ab!`,
|
|
data: {},
|
|
},
|
|
trigger: null,
|
|
});
|
|
}
|
|
}
|