import { Ionicons } from '@expo/vector-icons'; import { useRouter } from 'expo-router'; import { useEffect, useState } from 'react'; import { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, TextInput, View, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { colors } from '../src/theme'; import { useAuth } from '../src/context/AuthContext'; import { useJobPreference } from '../src/hooks'; import { EXPECTED_CITY_OPTIONS, EXPECTED_SALARY_OPTIONS, JOB_STATUS_OPTIONS, WORK_TYPE_OPTIONS, } from '../src/constants'; import { withCurrentOption } from '../src/utils'; import type { JobPreference } from '../src/types'; /* ===================== 子组件:单选项 chips ===================== */ function ChipGroup({ title, options, value, onSelect, }: { title: string; options: string[]; value: string; onSelect: (v: string) => void; }) { return ( {title} {options.map((opt) => { const selected = opt === value; return ( onSelect(opt)} > {opt} ); })} ); } /* ===================== 子组件:四态 ===================== */ function Loading() { return ( 正在加载求职意向… ); } function ErrorState({ onRetry }: { onRetry: () => void }) { return ( 加载失败 点击重试 ); } /* ===================== 页面 ===================== */ export default function JobPreferenceScreen() { const router = useRouter(); const { completeCandidateSetup } = useAuth(); const { preference, loading, error, refresh, save } = useJobPreference(); const [form, setForm] = useState(null); const [saving, setSaving] = useState(false); useEffect(() => { if (preference && !form) setForm(preference); }, [preference, form]); if (loading || !form) { return ( ); } if (error) { return ( ); } const canSave = form.position.trim().length > 0; const update = (field: K, value: JobPreference[K]) => { setForm((prev) => (prev ? { ...prev, [field]: value } : prev)); }; const handleSave = async () => { if (!canSave || saving) return; setSaving(true); try { await save(form); completeCandidateSetup(); router.replace('/(tabs)/jobs'); } finally { setSaving(false); } }; const handleSkip = () => { router.replace('/(tabs)/jobs'); }; return ( 设置求职意向 告诉我们你的期望,才能推荐更匹配的岗位 期望职位 update('position', v)} placeholder="如:前端开发工程师" placeholderTextColor={colors.textHint} /> update('city', v)} /> update('salary', v)} /> update('workType', v)} /> update('status', v)} /> {saving ? '保存中…' : '保存并进入求职端'} 稍后设置 ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: colors.pageBg }, body: { padding: 20, paddingBottom: 24 }, center: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 12 }, tip: { fontSize: 14, color: colors.textSecondary }, retryBtn: { paddingHorizontal: 18, paddingVertical: 8, borderRadius: 16, backgroundColor: colors.primaryLight, }, retryText: { fontSize: 13, fontWeight: '600', color: colors.primaryText }, header: { marginBottom: 20 }, headerTitle: { fontSize: 22, fontWeight: '800', color: colors.textPrimary }, headerDesc: { fontSize: 13, color: colors.textSecondary, marginTop: 6 }, section: { marginBottom: 20 }, sectionTitle: { fontSize: 15, fontWeight: '700', color: colors.textPrimary, marginBottom: 10 }, input: { height: 50, borderRadius: 12, borderWidth: 1, borderColor: colors.border, backgroundColor: colors.white, paddingHorizontal: 14, fontSize: 16, color: colors.textPrimary, }, chips: { flexDirection: 'row', flexWrap: 'wrap', gap: 10 }, chip: { paddingHorizontal: 14, paddingVertical: 9, borderRadius: 18, backgroundColor: colors.white, borderWidth: 1, borderColor: colors.border, }, chipSelected: { backgroundColor: colors.primaryLight, borderColor: colors.primary }, chipText: { fontSize: 13, color: colors.textSecondary }, chipTextSelected: { color: colors.primaryText, fontWeight: '600' }, footer: { paddingHorizontal: 20, paddingVertical: 14, backgroundColor: colors.white, borderTopWidth: 1, borderTopColor: colors.borderLight, }, saveBtn: { height: 50, borderRadius: 25, backgroundColor: colors.primaryBtn, alignItems: 'center', justifyContent: 'center', }, saveBtnDisabled: { backgroundColor: colors.border, opacity: 0.7 }, saveText: { fontSize: 16, fontWeight: '700', color: colors.textInverse }, skipBtn: { alignItems: 'center', paddingVertical: 14 }, skipText: { fontSize: 14, color: colors.textHint }, });