import { ActivityIndicator, Platform, TouchableOpacity, Text, View } from 'react-native'; import { useEffect, useRef, useState } from 'react'; import { TrueSheet, type SheetDetent } from '@lodev09/react-native-true-sheet'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { useColors } from '../lib/theme'; import { apiFetch } from '../lib/api'; import { useDeviceLimitStore, type DeviceLimitDevice } from '../stores/deviceLimit'; 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 DeviceLimitRow({ device, removing, onRemove, }: { device: DeviceLimitDevice; removing: boolean; onRemove: (id: string) => void; }) { const { t } = useTranslation(); const colors = useColors(); return ( {device.name ?? device.model ?? device.platform} {device.model && device.name && !device.name.includes(device.model) ? ( {device.model} ) : null} {formatLastSeen(device.lastSeenAt, t)} {removing ? ( ) : ( onRemove(device.id)} hitSlop={8} activeOpacity={0.5} > )} ); } export function DeviceLimitReachedSheet() { const { t } = useTranslation(); const colors = useColors(); const sheetRef = useRef(null); const { visible, devices, max, plan, hide, removeDevice } = useDeviceLimitStore(); const [removingId, setRemovingId] = useState(null); useEffect(() => { if (visible) { sheetRef.current?.present(); } }, [visible]); async function handleRemove(id: string) { setRemovingId(id); try { await apiFetch(`/api/devices/${id}`, { method: 'DELETE', skipDeviceHeader: true, }); removeDevice(id); const remaining = useDeviceLimitStore.getState().devices; if (remaining.length < max) { sheetRef.current?.dismiss(); hide(); } } finally { setRemovingId(null); } } return ( {t('device_limit.title')} {t('device_limit.subtitle', { count: devices.length, max, plan: plan.toUpperCase() })} {devices.map((device, i) => ( ))} {t('device_limit.hint')} ); }