KI-AGENT: Mobile Push Registrierung anbinden

This commit is contained in:
2026-05-22 17:34:52 +02:00
parent 5400fd7ad5
commit cacfce4d15
14 changed files with 630 additions and 20 deletions

View File

@@ -150,6 +150,21 @@ export type PrintLabelResponse = {
base64?: string;
};
export type MobilePushRegistrationInput = {
localDeviceId: string;
platform: 'ios' | 'android';
providerToken: string;
deviceLabel?: string | null;
meta?: Record<string, unknown>;
};
export type MobilePushRegistrationResponse = {
success: boolean;
id?: string;
centralDeviceId?: string;
status?: string;
};
export type WikiTreeItem = {
id: string;
parentId?: string | null;
@@ -582,6 +597,24 @@ export async function fetchMe(token: string): Promise<MeResponse> {
});
}
export async function registerMobilePushDevice(
token: string,
payload: MobilePushRegistrationInput
): Promise<MobilePushRegistrationResponse> {
return apiRequest<MobilePushRegistrationResponse>('/api/notifications/push/mobile/register', {
method: 'POST',
token,
body: payload,
});
}
export async function sendMobileTestPush(token: string): Promise<{ accepted: number; rejected: number; deliveryJobId: string }> {
return apiRequest<{ accepted: number; rejected: number; deliveryJobId: string }>('/api/notifications/test-mobile-push', {
method: 'POST',
token,
});
}
export async function switchTenantRequest(tenantId: number, token: string): Promise<string> {
const payload = await apiRequest<{ token?: string }>('/api/tenant/switch', {
method: 'POST',

View File

@@ -0,0 +1,76 @@
import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import * as SecureStore from 'expo-secure-store';
import { Platform } from 'react-native';
import { registerMobilePushDevice } from '@/src/lib/api';
const DEVICE_ID_KEY = 'fedeo.mobilePush.localDeviceId';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldPlaySound: true,
shouldSetBadge: true,
shouldShowBanner: true,
shouldShowList: true,
}),
});
function createLocalDeviceId(): string {
const random = typeof crypto !== 'undefined' && 'randomUUID' in crypto
? crypto.randomUUID()
: `${Date.now()}-${Math.random().toString(36).slice(2)}`;
return `mobile-${random}`;
}
async function getLocalDeviceId() {
const existing = await SecureStore.getItemAsync(DEVICE_ID_KEY);
if (existing) return existing;
const created = createLocalDeviceId();
await SecureStore.setItemAsync(DEVICE_ID_KEY, created);
return created;
}
async function ensurePushPermission() {
const current = await Notifications.getPermissionsAsync();
if (hasPushPermission(current)) return;
const requested = await Notifications.requestPermissionsAsync();
if (!hasPushPermission(requested)) {
throw new Error('Push-Mitteilungen wurden nicht erlaubt.');
}
}
function hasPushPermission(status: unknown): boolean {
const permission = status as { granted?: boolean; status?: string };
return permission.granted === true || permission.status === 'granted';
}
export async function registerDeviceForPush(token: string) {
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
throw new Error('Mobile Push ist nur auf iOS und Android verfügbar.');
}
await ensurePushPermission();
const deviceToken = await Notifications.getDevicePushTokenAsync();
const providerToken = String(deviceToken.data || '');
if (!providerToken) {
throw new Error('Es wurde kein nativer Push-Token zurückgegeben.');
}
return await registerMobilePushDevice(token, {
localDeviceId: await getLocalDeviceId(),
platform: Platform.OS,
providerToken,
deviceLabel: Constants.deviceName || `${Platform.OS} Gerät`,
meta: {
os: Platform.OS,
osVersion: Platform.Version,
expoRuntimeVersion: Constants.expoConfig?.runtimeVersion || null,
appVersion: Constants.expoConfig?.version || null,
},
});
}