import { useMemo } from 'react'; import { Image, type ImageSourcePropType, Text, View } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { useColors } from '../../lib/theme'; import { FormSheet } from '../FormSheet'; import { HalfDonut } from '../common/HalfDonut'; import { useProtectionCoverage } from '../../hooks/useProfileData'; const PROTECTED_COLOR = '#22c55e'; const UNPROTECTED_COLOR = '#e5e5e5'; const DONUT_WIDTH = 200; const DAY_MS = 86_400_000; export type DeviceDetail = { name: string; icon: ImageSourcePropType; platform: string; /** ISO — Bindungs-/Verbindungsdatum */ createdAt: string; lastSeenAt?: string | null; statusLabel: string; statusColor: string; }; function fmtDate(iso: string): string { return new Date(iso).toLocaleDateString(undefined, { day: '2-digit', month: 'short', year: 'numeric', }); } function fmtLastSeen(iso: string, t: (k: string, o?: any) => string): string { const min = Math.floor((Date.now() - new Date(iso).getTime()) / 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 fmtDate(iso); } /** * DeviceDetailSheet — Detail-Ansicht beim Tap auf eine Geräte-Row. * * Zeigt Verbindungsstatus, Bindungs-Datum und den Schutz-Verlauf als * HalfDonut (geschützt vs. ungeschützt) — gleiche Visualisierung wie auf der * Profile-Page. Per-Gerät-Split wird client-side berechnet: * geschützt = volle Tage seit Bindung dieses Geräts * ungeschützt = Account-Schutzalter, das VOR der Bindung lag * → echte gerätespezifische Verteilung + Progress, ohne neuen Backend-Endpoint. */ export function DeviceDetailSheet({ visible, device, onClose, }: { visible: boolean; device: DeviceDetail | null; onClose: () => void; }) { const { t } = useTranslation(); const colors = useColors(); const { coverage } = useProtectionCoverage(); const { protectedDays, unprotectedDays } = useMemo(() => { if (!device) return { protectedDays: 0, unprotectedDays: 0 }; const boundAt = new Date(device.createdAt).getTime(); const devProtected = Math.max(0, Math.floor((Date.now() - boundAt) / DAY_MS)); const accountSpan = coverage ? coverage.protectedDays + coverage.unprotectedDays : devProtected; const before = Math.max(0, accountSpan - devProtected); return { protectedDays: devProtected, unprotectedDays: before }; }, [device, coverage]); const segments = useMemo( () => [ { value: Math.max(protectedDays, 1), color: PROTECTED_COLOR }, { value: Math.max(unprotectedDays, 0), color: UNPROTECTED_COLOR }, ], [protectedDays, unprotectedDays], ); return ( {device && ( {/* Identität */} {device.name} {device.statusLabel} {/* Schutz-Verlauf (HalfDonut, wie Profile) */} {t('devices.detail_coverage_label')} {protectedDays} {t('devices.detail_this_device_protected')} {unprotectedDays} {t('devices.detail_before_binding')} {/* Meta-Infos */} {device.lastSeenAt ? ( ) : null} )} ); } function InfoRow({ label, value, valueColor, colors, divider, }: { label: string; value: string; valueColor?: string; colors: ReturnType; divider?: boolean; }) { return ( {label} {value} ); }