import { ActivityIndicator, Alert, Platform, Pressable, ScrollView, Text, View, } from 'react-native'; import { useEffect } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { colors } from '../lib/theme'; import { useDevicesStore, type UserDevice } from '../stores/devices'; import { AppHeader } from '../components/AppHeader'; function platformIcon( platform: string ): React.ComponentProps['name'] { if (platform === 'ios') return 'logo-apple'; if (platform === 'android') return 'logo-android'; return 'phone-portrait-outline'; } function formatLastSeen(iso: string, t: (k: string, o?: any) => string): string { const ms = Date.now() - new Date(iso).getTime(); const min = Math.floor(ms / 60_000); if (min < 1) return t('settings.devices_just_now'); if (min < 60) return t('settings.devices_mins_ago', { count: min }); const hr = Math.floor(min / 60); if (hr < 24) return t('settings.devices_hours_ago', { count: hr }); const day = Math.floor(hr / 24); if (day < 30) return t('settings.devices_days_ago', { count: day }); return new Date(iso).toLocaleDateString(Platform.OS === 'ios' ? undefined : 'de-DE', { day: '2-digit', month: 'short', year: 'numeric', }); } function formatSince(iso: string): string { return new Date(iso).toLocaleDateString(Platform.OS === 'ios' ? undefined : 'de-DE', { day: '2-digit', month: 'short', year: 'numeric', }); } function DeviceRow({ device, onRemove, }: { device: UserDevice; onRemove: (id: string) => void; }) { const { t } = useTranslation(); function confirmRemove() { Alert.alert( t('settings.devices_remove_title'), t('settings.devices_remove_desc'), [ { text: t('common.cancel'), style: 'cancel' }, { text: t('settings.devices_remove_confirm'), style: 'destructive', onPress: () => onRemove(device.id), }, ] ); } return ( {device.name ?? device.model ?? device.platform} {device.isCurrent ? ( {t('settings.devices_this_device')} ) : null} {device.model && device.name && !device.name.includes(device.model) ? ( {device.model} ) : null} {formatLastSeen(device.lastSeenAt, t)} {t('settings.devices_since')} {formatSince(device.createdAt)} {!device.isCurrent ? ( ({ opacity: pressed ? 0.5 : 1 })} > ) : null} ); } export default function DevicesScreen() { const insets = useSafeAreaInsets(); const { t } = useTranslation(); const { devices, maxDevices, plan, loading, loadDevices, removeDevice } = useDevicesStore(); useEffect(() => { loadDevices(); }, []); const atLimit = devices.length >= maxDevices; const fillRatio = Math.min(1, devices.length / Math.max(1, maxDevices)); return ( {/* Slot counter card */} {t('settings.devices_slots')} {devices.length} / {maxDevices} {t('settings.devices_slots_desc', { plan: plan.toUpperCase() })} = 0.8 ? '#f59e0b' : colors.brandOrange, }} /> {/* Device list card */} {loading ? ( ) : devices.length === 0 ? ( {t('settings.devices_empty')} ) : ( devices.map((device, i) => ( )) )} {t('settings.devices_hint')} ); }