chahinebrini 7fae4539ae diag(calls): add VoIP+push-token+ring-target logs; fix /call mount race
- AppDelegate: NSLog for didUpdate token, didInvalidate, didReceiveIncomingPush
- backend/push: log [push-token] register, [call-ring] receiver token-counts +
  expo-push-fanout for android-fallback
- app/call.tsx: 250ms grace window before closeScreen on initial idle (fixes
  'foreground call flashes briefly then disappears' race when dm.tsx
  startCall set() hasn't propagated through useCallStore selector yet)
2026-06-04 20:37:43 +02:00

87 lines
3.0 KiB
TypeScript

import { create } from 'zustand';
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as Notifications from 'expo-notifications';
const STORAGE_KEY = '@rebreak/notifications-prefs';
type NotificationPrefsState = {
pushEnabled: boolean;
streakReminderEnabled: boolean;
streakReminderTime: { hour: number; minute: number };
/** iOS-CallKit: ReBreak-Calls in nat. "Anrufe"-App + iCloud-Sync.
* Default false (DSGVO/Art.9 — Sucht-Zielgruppe). Opt-in via Settings.
* Änderung wird erst nach App-Neustart wirksam. */
callsInRecents: boolean;
init: () => Promise<void>;
setPushEnabled: (value: boolean) => Promise<void>;
setStreakReminderEnabled: (value: boolean) => Promise<void>;
setStreakReminderTime: (hour: number, minute: number) => Promise<void>;
setCallsInRecents: (value: boolean) => Promise<void>;
reset: () => Promise<void>;
};
async function persist(patch: Partial<Pick<NotificationPrefsState, 'pushEnabled' | 'streakReminderEnabled' | 'streakReminderTime' | 'callsInRecents'>>) {
const existing = await AsyncStorage.getItem(STORAGE_KEY);
const current = existing ? JSON.parse(existing) : {};
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify({ ...current, ...patch }));
}
export const useNotificationPrefsStore = create<NotificationPrefsState>((set, get) => ({
pushEnabled: true,
streakReminderEnabled: false,
streakReminderTime: { hour: 9, minute: 0 },
callsInRecents: false,
init: async () => {
const stored = await AsyncStorage.getItem(STORAGE_KEY);
if (!stored) {
await persist({ pushEnabled: true });
return;
}
const parsed = JSON.parse(stored);
set({
pushEnabled: parsed.pushEnabled ?? true,
streakReminderEnabled: parsed.streakReminderEnabled ?? false,
streakReminderTime: parsed.streakReminderTime ?? { hour: 9, minute: 0 },
callsInRecents: parsed.callsInRecents ?? false,
});
},
// TODO: wire up expo-notifications requestPermissionsAsync + scheduleNotificationAsync
// once the streak reminder backend endpoint exists. Currently persists user intent only.
setPushEnabled: async (value) => {
if (value) {
const { status } = await Notifications.requestPermissionsAsync();
if (status !== 'granted') {
return;
}
}
set({ pushEnabled: value });
await persist({ pushEnabled: value });
},
setStreakReminderEnabled: async (value) => {
set({ streakReminderEnabled: value });
await persist({ streakReminderEnabled: value });
},
setStreakReminderTime: async (hour, minute) => {
const streakReminderTime = { hour, minute };
set({ streakReminderTime });
await persist({ streakReminderTime });
},
setCallsInRecents: async (value) => {
set({ callsInRecents: value });
await persist({ callsInRecents: value });
},
reset: async () => {
set({ pushEnabled: false, streakReminderEnabled: false, streakReminderTime: { hour: 9, minute: 0 }, callsInRecents: false });
try {
await AsyncStorage.removeItem(STORAGE_KEY);
} catch {}
},
}));