import { useMemo, useState } from 'react'; import { useRouter } from 'expo-router'; import * as Notifications from 'expo-notifications'; import { useTranslation } from 'react-i18next'; import { OnboardingLayout } from '@/components/onboarding/OnboardingLayout'; import { NameInputStep } from '@/components/onboarding/NameInputStep'; import { SelectionStep } from '@/components/onboarding/SelectionStep'; import { ReminderStep } from '@/components/onboarding/ReminderStep'; import { buildUserProfileFromQuestionnaire, mapOnboardingSelectionsToQuestionnaireAnswers } from '@/src/features/userProfileScoring'; import { fetchRecoFeed } from '@/src/services/recoApi'; import { recordRecoFeedServed, setOnboardingCompleted, setUserProfile, setDailyReminderSettings, setUserProfileScoring, setRecoFeedCache, } from '@/src/storage/appStorage'; type Step = | { id: 'name'; type: 'name' } | { id: 'status' | 'emotion' | 'influence' | 'support'; type: 'selection'; optionIds: string[] } | { id: 'reminder'; type: 'reminder' }; const STEPS: Step[] = [ { id: 'name', type: 'name' }, { id: 'status', type: 'selection', optionIds: ['pregnant', 'has_kids', 'no_fill'] }, { id: 'emotion', type: 'selection', optionIds: ['happy', 'calm', 'stressed', 'low'] }, { id: 'influence', type: 'selection', optionIds: ['family', 'work', 'relationship', 'friends', 'health'] }, { id: 'support', type: 'selection', optionIds: ['emotional', 'parenting', 'self_worth', 'anxiety', 'balance'] }, { id: 'reminder', type: 'reminder' }, ]; export default function OnboardingScreen() { const router = useRouter(); const { t, i18n } = useTranslation(); const [stepIndex, setStepIndex] = useState(0); const [name, setName] = useState(''); const [selections, setSelections] = useState>({}); const [reminderTimes, setReminderTimes] = useState(3); const currentStep = STEPS[stepIndex]; const currentTitle = useMemo(() => t(`onboardingSurvey.steps.${currentStep.id}.title`), [t, currentStep.id]); const currentOptions = useMemo(() => { if (currentStep.type !== 'selection') return []; return currentStep.optionIds.map((optId) => ({ id: optId, label: t(`onboardingSurvey.steps.${currentStep.id}.options.${optId}`), })); }, [t, currentStep]); async function onFinish() { // 请求推送权限 const { status } = await Notifications.requestPermissionsAsync(); const pushEnabled = status === 'granted'; // 将 Onboarding 选择映射为标准问卷枚举(允许跳过) const answers = mapOnboardingSelectionsToQuestionnaireAnswers(selections); // 生成用户画像(供推荐/Push/Widget 复用) const scoringProfile = buildUserProfileFromQuestionnaire(answers); await setUserProfileScoring(scoringProfile); // Onboarding 结束后预拉取一次 Feed 文案(失败不阻塞进入首页) try { const lang = i18n.language?.toLowerCase().startsWith('zh') ? 'tc' : 'en'; const { items, meta } = await fetchRecoFeed({ k: 30, user_profile: { profile_version: scoringProfile.profile_version, profile_source: scoringProfile.profile_source, profile_generated_at: scoringProfile.profile_generated_at, profile_confidence: scoringProfile.profile_confidence, profile_answered: scoringProfile.profile_answered, stage: scoringProfile.stage, emotion_score: scoringProfile.emotion_score, context: scoringProfile.context, need: scoringProfile.need, }, }); await setRecoFeedCache({ saved_at: new Date().toISOString(), lang, items: items.map((x) => ({ content_id: x.content_id, text: x.text })), meta: meta as Record, }); await recordRecoFeedServed(items.map((x) => x.content_id)); } catch { // 网络失败时使用首页本地 mock 兜底 } await setUserProfile({ name, intents: Object.values(selections).flat() }); await setDailyReminderSettings({ timesPerDay: reminderTimes, pushEnabled: pushEnabled }); await setOnboardingCompleted(true); router.replace('/(app)/home'); } const onNext = () => { if (stepIndex < STEPS.length - 1) { setStepIndex(stepIndex + 1); } else { onFinish(); } }; const onBack = () => { if (stepIndex > 0) { setStepIndex(stepIndex - 1); } }; const onSkip = async () => { // 跳过整个 Onboarding:仍生成一个“全跳过”的最小画像,保证下游可用 const scoringProfile = buildUserProfileFromQuestionnaire({}); await setUserProfileScoring(scoringProfile); // 标记已完成,避免下次启动再次进入 Onboarding await setOnboardingCompleted(true); router.replace('/(app)/home'); }; // 题目为多选:点击切换选中状态 const handleToggleSelection = (id: string) => { setSelections(prev => { const currentIds = prev[currentStep.id] || []; const nextIds = currentIds.includes(id) ? currentIds.filter(i => i !== id) : [...currentIds, id]; return { ...prev, [currentStep.id]: nextIds }; }); }; const handleSkipStep = () => { setSelections((prev) => ({ ...prev, [currentStep.id]: [] })); onNext(); }; return ( 0} > {currentStep.type === 'name' && ( )} {currentStep.type === 'selection' && ( )} {currentStep.type === 'reminder' && ( )} ); }