Profile (rebreak-native-ui): - New hook hooks/useProfileData.ts (143 LOC, 4 hooks): useSocialStats, useApprovedDomains, useCooldownHistory, useSosInsights - app/profile/index.tsx: alle DUMMY_* constants entfernt → live data via hooks - PATCH /api/profile/me/demographics nun wired in onChange (war TODO-only) - DELETE /api/profile/me/demographics für revoke-consent - POST /api/profile/me/diga-banner-dismiss Devices (rebreak-native-ui): - New app/devices.tsx push-page: slot-counter, progress-bar, device-list mit trash-button (gesperrt für isCurrent) - New lib/deviceId.ts: persistent device-ID via expo-application (getIosIdForVendorAsync / getAndroidId) mit AsyncStorage-UUID-fallback - New stores/devices.ts: Zustand store (loadDevices, removeDevice, ensureRegistered) - lib/api.ts: x-device-id + x-platform headers bei jedem Backend-Call (skipDeviceHeader option für Bootstrap-register) - app/settings.tsx: Geräte-Row aktiv (push to /devices) statt soon-flagged - locales: 14 neue settings.devices_* keys DE+EN Backend-Status: alle Devices-Endpoints existieren (GET /api/devices, POST /register, DELETE /:id). Pending: GET /api/profile/me/demographics für reload-state-fetch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
51 lines
1.3 KiB
TypeScript
51 lines
1.3 KiB
TypeScript
import { Platform } from 'react-native';
|
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
import * as Application from 'expo-application';
|
|
|
|
const STORAGE_KEY = 'rebreak_device_id';
|
|
|
|
let cached: string | null = null;
|
|
|
|
export async function getDeviceId(): Promise<string> {
|
|
if (cached) return cached;
|
|
|
|
if (Platform.OS === 'ios') {
|
|
const vendor = await Application.getIosIdForVendorAsync();
|
|
if (vendor) {
|
|
cached = vendor;
|
|
return vendor;
|
|
}
|
|
}
|
|
|
|
if (Platform.OS === 'android') {
|
|
const androidId = Application.getAndroidId();
|
|
if (androidId) {
|
|
cached = androidId;
|
|
return androidId;
|
|
}
|
|
}
|
|
|
|
// Fallback: persisted UUID via AsyncStorage (web / simulator edge cases)
|
|
const stored = await AsyncStorage.getItem(STORAGE_KEY).catch(() => null);
|
|
if (stored) {
|
|
cached = stored;
|
|
return stored;
|
|
}
|
|
|
|
const uuid =
|
|
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
const r = (Math.random() * 16) | 0;
|
|
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
|
});
|
|
|
|
await AsyncStorage.setItem(STORAGE_KEY, uuid).catch(() => {});
|
|
cached = uuid;
|
|
return uuid;
|
|
}
|
|
|
|
export function getPlatformName(): string {
|
|
if (Platform.OS === 'ios') return 'ios';
|
|
if (Platform.OS === 'android') return 'android';
|
|
return 'web';
|
|
}
|