import { ActivityIndicator, Alert, Linking, ScrollView, Text, TextInput, View, } from 'react-native'; import { useCallback, useState } from 'react'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import * as Haptics from 'expo-haptics'; import { useColors } from '../../lib/theme'; import { FormSheet } from '../FormSheet'; import { RiveAvatar } from '../RiveAvatar'; import { Button } from '../Button'; import { useProtectedDevicesStore } from '../../stores/protectedDevices'; import { useProtectedDevicesRealtime } from '../../hooks/useProtectedDevicesRealtime'; import { useRouter } from 'expo-router'; // TODO lyra-persona: review lyra_intro + step_* body strings for coach tone type Step = 1 | 2 | 3; interface StepItem { titleKey: string; bodyKey: string; icon: React.ComponentProps['name']; } const STEPS: StepItem[] = [ { titleKey: 'devices.step_1_title', bodyKey: 'devices.step_1_body', icon: 'download-outline' }, { titleKey: 'devices.step_2_title', bodyKey: 'devices.step_2_body', icon: 'settings-outline' }, { titleKey: 'devices.step_3_title', bodyKey: 'devices.step_3_body', icon: 'person-outline' }, { titleKey: 'devices.step_4_title', bodyKey: 'devices.step_4_body', icon: 'checkmark-circle-outline' }, ]; export function AddMacSheet({ visible, onClose, }: { visible: boolean; onClose: () => void; }) { const { t } = useTranslation(); const colors = useColors(); const router = useRouter(); const { enroll, enrolling } = useProtectedDevicesStore(); const [step, setStep] = useState(1); const [label, setLabel] = useState('MacBook Pro'); const [labelError, setLabelError] = useState(''); const [enrollResult, setEnrollResult] = useState<{ deviceId: string; downloadUrl: string } | null>(null); const handleActivated = useCallback(() => { Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success).catch(() => {}); setStep(3); }, []); useProtectedDevicesRealtime( step === 2 ? handleActivated : undefined, step === 2, ); function reset() { setStep(1); setLabel('MacBook Pro'); setLabelError(''); setEnrollResult(null); } function handleClose() { reset(); onClose(); } async function handlePrepare() { const trimmed = label.trim(); if (!trimmed) { setLabelError(t('devices.label_question')); return; } if (trimmed.length > 32) { setLabelError(t('devices.label_question')); return; } setLabelError(''); try { const result = await enroll(trimmed, 'mac'); setEnrollResult(result); setStep(2); } catch { Alert.alert(t('common.error'), t('common.unknown_error')); } } function handleDownload() { if (!enrollResult?.downloadUrl) return; Linking.openURL(enrollResult.downloadUrl).catch(() => {}); } function handleNeedHelp() { handleClose(); router.push('/coach'); } const sheetTitle = step === 1 ? t('devices.label_question') : step === 2 ? t('devices.download_button') : t('devices.success_title'); const initialHeightPct = step === 1 ? 0.42 : step === 2 ? 0.74 : 0.52; return ( {step === 1 && ( { handleClose(); router.push('/magic'); }} colors={colors} t={t} /> )} {step === 2 && ( )} {step === 3 && ( )} ); } function Step1LabelContent({ label, setLabel, labelError, onPrepare, enrolling, colors, t, }: { label: string; setLabel: (v: string) => void; labelError: string; onPrepare: () => void; enrolling: boolean; colors: ReturnType; t: (k: string) => string; }) { return ( {labelError ? ( {labelError} ) : null}