import { ActivityIndicator, Alert, Linking, Pressable, Text, TextInput, View, } from 'react-native'; import { useRef, 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 { KeyboardAwareSheet } from '../KeyboardAwareSheet'; import { RiveAvatar } from '../RiveAvatar'; import { useProtectedDevicesStore } from '../../stores/protectedDevices'; 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, confirmInstalled, 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 [confirming, setConfirming] = useState(false); function reset() { setStep(1); setLabel('MacBook Pro'); setLabelError(''); setEnrollResult(null); setConfirming(false); } 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); setEnrollResult(result); setStep(2); } catch { Alert.alert(t('common.error'), t('common.unknown_error')); } } async function handleConfirmInstalled() { if (!enrollResult) return; setConfirming(true); try { await confirmInstalled(enrollResult.deviceId); Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success).catch(() => {}); setStep(3); } catch { Alert.alert(t('common.error'), t('common.unknown_error')); } finally { setConfirming(false); } } function handleDownload() { if (!enrollResult?.downloadUrl) return; Linking.openURL(enrollResult.downloadUrl).catch(() => {}); } function handleNeedHelp() { handleClose(); router.push('/coach'); } const collapsedHeight = step === 1 ? 300 : step === 2 ? 620 : 380; return ( {step === 1 ? t('devices.label_question') : step === 2 ? t('devices.download_button') : t('devices.success_title')} ({ opacity: pressed ? 0.5 : 1 })} > } > {step === 1 && } {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} ({ backgroundColor: colors.brandOrange, borderRadius: 14, paddingVertical: 16, alignItems: 'center', opacity: pressed || enrolling ? 0.7 : 1, })} > {enrolling ? ( ) : ( {t('devices.prepare_profile')} )} ); } function Step2OnboardingContent({ onDownload, onConfirmInstalled, onNeedHelp, confirming, colors, t, }: { onDownload: () => void; onConfirmInstalled: () => void; onNeedHelp: () => void; confirming: boolean; colors: ReturnType; t: (k: string) => string; }) { return ( {/* Lyra intro card */} {t('devices.lyra_intro')} {/* 4-step list */} {STEPS.map((item, idx) => ( {t(item.titleKey)} {t(item.bodyKey)} ))} {/* Download button */} ({ backgroundColor: colors.brandOrange, borderRadius: 14, paddingVertical: 16, alignItems: 'center', flexDirection: 'row', justifyContent: 'center', gap: 8, opacity: pressed ? 0.7 : 1, })} > {t('devices.download_button')} {/* Confirm installed */} ({ borderWidth: 1.5, borderColor: colors.brandOrange, borderRadius: 14, paddingVertical: 14, alignItems: 'center', opacity: pressed || confirming ? 0.7 : 1, })} > {confirming ? ( ) : ( {t('devices.confirm_installed')} )} {/* Need help */} ({ opacity: pressed ? 0.5 : 1, alignItems: 'center' })} > {t('devices.need_help')} ); } function Step3SuccessContent({ onClose, colors, t, }: { onClose: () => void; colors: ReturnType; t: (k: string) => string; }) { return ( {t('devices.success_title')} {t('devices.success_body')} ({ backgroundColor: colors.brandOrange, borderRadius: 14, paddingVertical: 16, paddingHorizontal: 40, alignItems: 'center', opacity: pressed ? 0.7 : 1, alignSelf: 'stretch', })} > {t('common.ok')} ); }