Files
HouseOrg/src/services/notifications.native.ts
T
2026-06-01 23:16:10 +02:00

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,
});
}
}