Files
paseo/packages/app/src/utils/os-notifications.ts
T
Mohamed Boudra 868f9fb571 WIP: Large refactor checkpoint
- Refactored daemon client and RPC layer
- Added new client package structure in server
- Removed legacy hooks (use-daemon-request, use-session-rpc, use-websocket)
- Added use-daemon-client hook
- Added e2e test infrastructure with Playwright
- Updated agent providers and session handling
- Removed codex-sdk patches
2026-01-12 13:30:20 +07:00

131 lines
3.4 KiB
TypeScript

import { Platform } from "react-native";
import * as Notifications from "expo-notifications";
type OsNotificationPayload = {
title: string;
body?: string;
data?: Record<string, unknown>;
};
let isNativeConfigured = false;
let permissionState: "unknown" | "granted" | "denied" = "unknown";
let permissionRequest: Promise<boolean> | null = null;
function getWebNotificationConstructor(): {
permission: string;
requestPermission?: () => Promise<string>;
new (title: string, options?: { body?: string; data?: Record<string, unknown> }): unknown;
} | null {
const NotificationConstructor = (globalThis as { Notification?: any }).Notification;
return NotificationConstructor ?? null;
}
async function configureNativeNotifications(): Promise<void> {
if (isNativeConfigured || Platform.OS === "web") {
return;
}
isNativeConfigured = true;
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldShowBanner: true,
shouldShowList: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
}
async function ensureNotificationPermission(): Promise<boolean> {
if (Platform.OS === "web") {
const NotificationConstructor = getWebNotificationConstructor();
if (!NotificationConstructor) {
return false;
}
if (NotificationConstructor.permission === "granted") {
return true;
}
if (NotificationConstructor.permission === "denied") {
return false;
}
if (permissionRequest) {
return permissionRequest;
}
permissionRequest = Promise.resolve(
NotificationConstructor.requestPermission
? NotificationConstructor.requestPermission()
: "denied"
).then((permission) => permission === "granted");
const result = await permissionRequest;
permissionRequest = null;
return result;
}
if (permissionState === "granted") {
return true;
}
if (permissionState === "denied") {
return false;
}
if (permissionRequest) {
return permissionRequest;
}
permissionRequest = (async () => {
const existing = await Notifications.getPermissionsAsync();
if (existing.status === "granted") {
permissionState = "granted";
return true;
}
if (!existing.canAskAgain) {
permissionState = "denied";
return false;
}
const requested = await Notifications.requestPermissionsAsync();
permissionState = requested.status === "granted" ? "granted" : "denied";
return permissionState === "granted";
})();
const result = await permissionRequest;
permissionRequest = null;
return result;
}
export async function sendOsNotification(
payload: OsNotificationPayload
): Promise<boolean> {
if (Platform.OS === "web") {
const NotificationConstructor = getWebNotificationConstructor();
if (!NotificationConstructor) {
return false;
}
const granted = await ensureNotificationPermission();
if (!granted) {
return false;
}
new NotificationConstructor(payload.title, {
body: payload.body,
data: payload.data,
});
return true;
}
await configureNativeNotifications();
const granted = await ensureNotificationPermission();
if (!granted) {
return false;
}
await Notifications.scheduleNotificationAsync({
content: {
title: payload.title,
body: payload.body,
data: payload.data,
},
trigger: null,
});
return true;
}