feat(verification): add user identity verification system
Add comprehensive user verification feature including: - VerificationGuideScreen: Guide screen explaining the verification process - VerificationFormScreen: Form for submitting verification applications - VerificationSettingsScreen: Settings page to view verification status - verificationService: API service for verification operations - verificationStore: State management for verification state - DTOs: Types for verification records, status, and admin operations The system supports multiple identity types (student, teacher, staff, alumni, external) and includes both user-facing and admin-facing functionality.
This commit is contained in:
425
src/screens/auth/VerificationFormScreen.tsx
Normal file
425
src/screens/auth/VerificationFormScreen.tsx
Normal file
@@ -0,0 +1,425 @@
|
||||
/**
|
||||
* 身份认证申请表单页面
|
||||
* 用户填写认证信息并提交申请
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
Image,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
Platform,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useRouter, useLocalSearchParams } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
import { useAppColors, type AppColors } from '../../theme';
|
||||
import { useVerificationStore } from '../../stores/verificationStore';
|
||||
import { showPrompt } from '../../services/promptService';
|
||||
import type { UserIdentity } from '../../types/dto';
|
||||
|
||||
const THEME_COLORS = {
|
||||
primary: '#FF6B35',
|
||||
primaryLight: '#FF8C5A',
|
||||
primaryDark: '#E55A2B',
|
||||
};
|
||||
|
||||
const IDENTITY_CONFIG: Record<string, { title: string; idField: string; idLabel: string }> = {
|
||||
student: { title: '在校学生', idField: 'student_id', idLabel: '学号' },
|
||||
teacher: { title: '教职工', idField: 'employee_id', idLabel: '工号' },
|
||||
staff: { title: '工作人员', idField: 'employee_id', idLabel: '工号' },
|
||||
alumni: { title: '校友', idField: 'student_id', idLabel: '学号(原)' },
|
||||
};
|
||||
|
||||
export const VerificationFormScreen: React.FC = () => {
|
||||
const colors = useAppColors();
|
||||
const styles = createStyles(colors);
|
||||
const router = useRouter();
|
||||
const params = useLocalSearchParams<{ identity?: string }>();
|
||||
const { submitVerification, isLoading } = useVerificationStore();
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
real_name: '',
|
||||
student_id: '',
|
||||
employee_id: '',
|
||||
department: '',
|
||||
proof_materials: '',
|
||||
});
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
|
||||
const identity = params.identity as UserIdentity || 'student';
|
||||
const config = IDENTITY_CONFIG[identity] || IDENTITY_CONFIG.student;
|
||||
|
||||
const validateForm = (): boolean => {
|
||||
const newErrors: Record<string, string> = {};
|
||||
|
||||
if (!formData.real_name.trim()) {
|
||||
newErrors.real_name = '请输入真实姓名';
|
||||
}
|
||||
|
||||
if (config.idField === 'student_id' && !formData.student_id.trim()) {
|
||||
newErrors.student_id = `请输入${config.idLabel}`;
|
||||
}
|
||||
|
||||
if (config.idField === 'employee_id' && !formData.employee_id.trim()) {
|
||||
newErrors.employee_id = `请输入${config.idLabel}`;
|
||||
}
|
||||
|
||||
if (!formData.proof_materials) {
|
||||
newErrors.proof_materials = '请上传证明材料';
|
||||
}
|
||||
|
||||
setErrors(newErrors);
|
||||
return Object.keys(newErrors).length === 0;
|
||||
};
|
||||
|
||||
const handlePickImage = async () => {
|
||||
try {
|
||||
const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
||||
if (!permissionResult.granted) {
|
||||
Alert.alert('提示', '需要相册权限才能上传图片');
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
allowsEditing: true,
|
||||
aspect: [4, 3],
|
||||
quality: 0.8,
|
||||
});
|
||||
|
||||
if (!result.canceled && result.assets[0]) {
|
||||
setFormData({ ...formData, proof_materials: result.assets[0].uri });
|
||||
if (errors.proof_materials) {
|
||||
setErrors({ ...errors, proof_materials: '' });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to pick image:', error);
|
||||
Alert.alert('错误', '选择图片失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!validateForm()) return;
|
||||
|
||||
const success = await submitVerification({
|
||||
identity,
|
||||
real_name: formData.real_name.trim(),
|
||||
student_id: formData.student_id.trim() || undefined,
|
||||
employee_id: formData.employee_id.trim() || undefined,
|
||||
department: formData.department.trim() || undefined,
|
||||
proof_materials: formData.proof_materials,
|
||||
});
|
||||
|
||||
if (success) {
|
||||
showPrompt({
|
||||
title: '提交成功',
|
||||
message: '您的认证申请已提交,请等待审核',
|
||||
type: 'success',
|
||||
});
|
||||
router.back();
|
||||
} else {
|
||||
const error = useVerificationStore.getState().error;
|
||||
showPrompt({
|
||||
title: '提交失败',
|
||||
message: error || '请稍后重试',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const renderInput = (
|
||||
field: keyof typeof formData,
|
||||
label: string,
|
||||
placeholder: string,
|
||||
options: {
|
||||
required?: boolean;
|
||||
keyboardType?: 'default' | 'numeric' | 'email-address';
|
||||
maxLength?: number;
|
||||
} = {}
|
||||
) => {
|
||||
const { required, keyboardType = 'default', maxLength } = options;
|
||||
const error = errors[field];
|
||||
|
||||
return (
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.inputLabel}>
|
||||
{label}
|
||||
{required && <Text style={styles.required}> *</Text>}
|
||||
</Text>
|
||||
<View style={[styles.inputWrapper, error && styles.inputWrapperError]}>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder={placeholder}
|
||||
placeholderTextColor={colors.text?.hint || '#999'}
|
||||
value={formData[field]}
|
||||
onChangeText={(text) => {
|
||||
setFormData({ ...formData, [field]: text });
|
||||
if (errors[field]) {
|
||||
setErrors({ ...errors, [field]: '' });
|
||||
}
|
||||
}}
|
||||
keyboardType={keyboardType}
|
||||
maxLength={maxLength}
|
||||
editable={!isLoading}
|
||||
/>
|
||||
</View>
|
||||
{error && <Text style={styles.errorText}>{error}</Text>}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity
|
||||
style={styles.backButton}
|
||||
onPress={() => router.back()}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name="arrow-left"
|
||||
size={24}
|
||||
color={colors.text?.primary || '#333'}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle}>{config.title}认证</Text>
|
||||
<View style={styles.headerRight} />
|
||||
</View>
|
||||
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
>
|
||||
<View style={styles.infoCard}>
|
||||
<MaterialCommunityIcons
|
||||
name="information-outline"
|
||||
size={20}
|
||||
color={THEME_COLORS.primary}
|
||||
/>
|
||||
<Text style={styles.infoText}>
|
||||
请填写真实信息,上传清晰的证明材料照片,审核通过后将获得认证标识
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.formSection}>
|
||||
{renderInput('real_name', '真实姓名', '请输入身份证上的姓名', { required: true })}
|
||||
|
||||
{config.idField === 'student_id' && (
|
||||
renderInput('student_id', config.idLabel, `请输入${config.idLabel}`, {
|
||||
required: true,
|
||||
keyboardType: 'numeric',
|
||||
maxLength: 20,
|
||||
})
|
||||
)}
|
||||
|
||||
{config.idField === 'employee_id' && (
|
||||
renderInput('employee_id', config.idLabel, `请输入${config.idLabel}`, {
|
||||
required: true,
|
||||
keyboardType: 'numeric',
|
||||
maxLength: 20,
|
||||
})
|
||||
)}
|
||||
|
||||
{renderInput('department', '院系/部门', '选填,如:计算机学院', {
|
||||
maxLength: 50,
|
||||
})}
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.inputLabel}>
|
||||
证明材料<Text style={styles.required}> *</Text>
|
||||
</Text>
|
||||
<Text style={styles.hintText}>
|
||||
请上传学生证、工作证、教师资格证等证明材料照片
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
style={[styles.uploadButton, errors.proof_materials && styles.uploadButtonError]}
|
||||
onPress={handlePickImage}
|
||||
activeOpacity={0.8}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{formData.proof_materials ? (
|
||||
<Image
|
||||
source={{ uri: formData.proof_materials }}
|
||||
style={styles.previewImage}
|
||||
resizeMode="cover"
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.uploadPlaceholder}>
|
||||
<MaterialCommunityIcons
|
||||
name="camera-plus-outline"
|
||||
size={40}
|
||||
color={colors.text?.hint || '#999'}
|
||||
/>
|
||||
<Text style={styles.uploadText}>点击上传图片</Text>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
{errors.proof_materials && (
|
||||
<Text style={styles.errorText}>{errors.proof_materials}</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[styles.submitButton, isLoading && styles.submitButtonDisabled]}
|
||||
onPress={handleSubmit}
|
||||
activeOpacity={0.9}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<ActivityIndicator size="small" color="#FFF" />
|
||||
) : (
|
||||
<Text style={styles.submitButtonText}>提交认证申请</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
function createStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 12,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomColor: colors.divider || '#E0E0E0',
|
||||
},
|
||||
backButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: colors.text?.primary || '#333',
|
||||
},
|
||||
headerRight: {
|
||||
width: 40,
|
||||
},
|
||||
scrollContent: {
|
||||
flexGrow: 1,
|
||||
padding: 24,
|
||||
},
|
||||
infoCard: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
backgroundColor: '#FFF5F0',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
marginBottom: 24,
|
||||
},
|
||||
infoText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: colors.text?.secondary || '#666',
|
||||
marginLeft: 8,
|
||||
lineHeight: 20,
|
||||
},
|
||||
formSection: {
|
||||
marginBottom: 24,
|
||||
},
|
||||
inputContainer: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
inputLabel: {
|
||||
fontSize: 15,
|
||||
fontWeight: '500',
|
||||
color: colors.text?.primary || '#333',
|
||||
marginBottom: 8,
|
||||
},
|
||||
required: {
|
||||
color: THEME_COLORS.primary,
|
||||
},
|
||||
hintText: {
|
||||
fontSize: 13,
|
||||
color: colors.text?.hint || '#999',
|
||||
marginBottom: 8,
|
||||
},
|
||||
inputWrapper: {
|
||||
backgroundColor: '#F5F5F7',
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 16,
|
||||
height: 50,
|
||||
borderWidth: 1,
|
||||
borderColor: 'transparent',
|
||||
},
|
||||
inputWrapperError: {
|
||||
borderColor: colors.error?.main || '#FF4444',
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
fontSize: 16,
|
||||
color: colors.text?.primary || '#333',
|
||||
height: 50,
|
||||
},
|
||||
errorText: {
|
||||
fontSize: 12,
|
||||
color: colors.error?.main || '#FF4444',
|
||||
marginTop: 6,
|
||||
},
|
||||
uploadButton: {
|
||||
backgroundColor: '#F5F5F7',
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
minHeight: 200,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
borderColor: 'transparent',
|
||||
},
|
||||
uploadButtonError: {
|
||||
borderColor: colors.error?.main || '#FF4444',
|
||||
},
|
||||
uploadPlaceholder: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 24,
|
||||
},
|
||||
uploadText: {
|
||||
fontSize: 14,
|
||||
color: colors.text?.hint || '#999',
|
||||
marginTop: 12,
|
||||
},
|
||||
previewImage: {
|
||||
width: '100%',
|
||||
height: 200,
|
||||
},
|
||||
submitButton: {
|
||||
height: 56,
|
||||
borderRadius: 14,
|
||||
backgroundColor: THEME_COLORS.primary,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
submitButtonDisabled: {
|
||||
opacity: 0.7,
|
||||
},
|
||||
submitButtonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default VerificationFormScreen;
|
||||
338
src/screens/auth/VerificationGuideScreen.tsx
Normal file
338
src/screens/auth/VerificationGuideScreen.tsx
Normal file
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
* 注册后身份认证引导页面
|
||||
* 可跳过的认证界面,引导用户完成身份认证
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
Image,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { useAppColors, type AppColors } from '../../theme';
|
||||
import * as hrefs from '../../navigation/hrefs';
|
||||
|
||||
const THEME_COLORS = {
|
||||
primary: '#FF6B35',
|
||||
primaryLight: '#FF8C5A',
|
||||
primaryDark: '#E55A2B',
|
||||
};
|
||||
|
||||
// 身份类型选项
|
||||
const IDENTITY_OPTIONS = [
|
||||
{
|
||||
key: 'student',
|
||||
title: '在校学生',
|
||||
description: '需要提交学生证或校园卡照片',
|
||||
icon: 'school-outline',
|
||||
},
|
||||
{
|
||||
key: 'teacher',
|
||||
title: '教职工',
|
||||
description: '需要提交工作证或教师资格证',
|
||||
icon: 'chalkboard-teacher',
|
||||
},
|
||||
{
|
||||
key: 'staff',
|
||||
title: '工作人员',
|
||||
description: '需要提交工作证或在职证明',
|
||||
icon: 'badge-account-outline',
|
||||
},
|
||||
{
|
||||
key: 'alumni',
|
||||
title: '校友',
|
||||
description: '需要提交毕业证或校友卡',
|
||||
icon: 'account-school-outline',
|
||||
},
|
||||
];
|
||||
|
||||
export const VerificationGuideScreen: React.FC = () => {
|
||||
const colors = useAppColors();
|
||||
const styles = createStyles(colors);
|
||||
const router = useRouter();
|
||||
const [selectedIdentity, setSelectedIdentity] = useState<string | null>(null);
|
||||
|
||||
const handleSkip = () => {
|
||||
Alert.alert(
|
||||
'跳过认证',
|
||||
'跳过后您将以普通用户身份使用,部分功能可能受限。您可以在设置中随时完成认证。',
|
||||
[
|
||||
{ text: '继续认证', style: 'cancel' },
|
||||
{
|
||||
text: '跳过',
|
||||
style: 'default',
|
||||
onPress: () => {
|
||||
router.replace(hrefs.hrefHome());
|
||||
},
|
||||
},
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
const handleContinue = () => {
|
||||
if (!selectedIdentity) {
|
||||
Alert.alert('提示', '请选择您的身份类型');
|
||||
return;
|
||||
}
|
||||
// 导航到认证表单页面
|
||||
router.push({
|
||||
pathname: '/auth/verification-form',
|
||||
params: { identity: selectedIdentity },
|
||||
});
|
||||
};
|
||||
|
||||
const renderIdentityCard = (option: typeof IDENTITY_OPTIONS[0]) => {
|
||||
const isSelected = selectedIdentity === option.key;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={option.key}
|
||||
style={[styles.identityCard, isSelected && styles.identityCardSelected]}
|
||||
onPress={() => setSelectedIdentity(option.key)}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<View style={styles.identityIconContainer}>
|
||||
<MaterialCommunityIcons
|
||||
name={option.icon as any}
|
||||
size={32}
|
||||
color={isSelected ? THEME_COLORS.primary : colors.text?.secondary || '#666'}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.identityContent}>
|
||||
<Text style={[styles.identityTitle, isSelected && styles.identityTitleSelected]}>
|
||||
{option.title}
|
||||
</Text>
|
||||
<Text style={styles.identityDescription}>{option.description}</Text>
|
||||
</View>
|
||||
<View style={styles.checkContainer}>
|
||||
{isSelected && (
|
||||
<MaterialCommunityIcons
|
||||
name="check-circle"
|
||||
size={24}
|
||||
color={THEME_COLORS.primary}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
{/* 头部图标 */}
|
||||
<View style={styles.header}>
|
||||
<View style={styles.iconCircle}>
|
||||
<MaterialCommunityIcons
|
||||
name="shield-check-outline"
|
||||
size={48}
|
||||
color={THEME_COLORS.primary}
|
||||
/>
|
||||
</View>
|
||||
<Text style={styles.title}>身份认证</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
完成身份认证,解锁更多专属功能
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* 认证优势 */}
|
||||
<View style={styles.benefitsContainer}>
|
||||
<View style={styles.benefitItem}>
|
||||
<MaterialCommunityIcons
|
||||
name="verified"
|
||||
size={20}
|
||||
color={THEME_COLORS.primary}
|
||||
/>
|
||||
<Text style={styles.benefitText}>获得认证标识</Text>
|
||||
</View>
|
||||
<View style={styles.benefitItem}>
|
||||
<MaterialCommunityIcons
|
||||
name="lock-open-outline"
|
||||
size={20}
|
||||
color={THEME_COLORS.primary}
|
||||
/>
|
||||
<Text style={styles.benefitText}>解锁专属频道</Text>
|
||||
</View>
|
||||
<View style={styles.benefitItem}>
|
||||
<MaterialCommunityIcons
|
||||
name="account-group"
|
||||
size={20}
|
||||
color={THEME_COLORS.primary}
|
||||
/>
|
||||
<Text style={styles.benefitText}>加入社群圈子</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 身份选择 */}
|
||||
<View style={styles.sectionContainer}>
|
||||
<Text style={styles.sectionTitle}>选择您的身份</Text>
|
||||
{IDENTITY_OPTIONS.map(renderIdentityCard)}
|
||||
</View>
|
||||
|
||||
{/* 按钮区域 */}
|
||||
<View style={styles.buttonContainer}>
|
||||
<TouchableOpacity
|
||||
style={[styles.continueButton, !selectedIdentity && styles.continueButtonDisabled]}
|
||||
onPress={handleContinue}
|
||||
activeOpacity={0.9}
|
||||
>
|
||||
<Text style={styles.continueButtonText}>继续认证</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.skipButton} onPress={handleSkip} activeOpacity={0.8}>
|
||||
<Text style={styles.skipButtonText}>暂不认证</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
function createStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
scrollContent: {
|
||||
flexGrow: 1,
|
||||
paddingHorizontal: 24,
|
||||
paddingTop: 40,
|
||||
paddingBottom: 40,
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
marginBottom: 32,
|
||||
},
|
||||
iconCircle: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
borderRadius: 50,
|
||||
backgroundColor: '#FFF5F0',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: 20,
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
fontWeight: '700',
|
||||
color: colors.text?.primary || '#333',
|
||||
marginBottom: 8,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 15,
|
||||
color: colors.text?.secondary || '#666',
|
||||
textAlign: 'center',
|
||||
},
|
||||
benefitsContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
gap: 16,
|
||||
marginBottom: 40,
|
||||
},
|
||||
benefitItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
},
|
||||
benefitText: {
|
||||
fontSize: 13,
|
||||
color: colors.text?.secondary || '#666',
|
||||
},
|
||||
sectionContainer: {
|
||||
marginBottom: 32,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: colors.text?.primary || '#333',
|
||||
marginBottom: 16,
|
||||
},
|
||||
identityCard: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: 16,
|
||||
backgroundColor: '#F5F5F7',
|
||||
borderRadius: 14,
|
||||
marginBottom: 12,
|
||||
borderWidth: 2,
|
||||
borderColor: 'transparent',
|
||||
},
|
||||
identityCardSelected: {
|
||||
backgroundColor: '#FFF5F0',
|
||||
borderColor: THEME_COLORS.primary,
|
||||
},
|
||||
identityIconContainer: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: 16,
|
||||
},
|
||||
identityContent: {
|
||||
flex: 1,
|
||||
},
|
||||
identityTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: colors.text?.primary || '#333',
|
||||
marginBottom: 4,
|
||||
},
|
||||
identityTitleSelected: {
|
||||
color: THEME_COLORS.primary,
|
||||
},
|
||||
identityDescription: {
|
||||
fontSize: 13,
|
||||
color: colors.text?.secondary || '#666',
|
||||
},
|
||||
checkContainer: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
buttonContainer: {
|
||||
gap: 12,
|
||||
},
|
||||
continueButton: {
|
||||
height: 56,
|
||||
borderRadius: 14,
|
||||
backgroundColor: THEME_COLORS.primary,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
continueButtonDisabled: {
|
||||
backgroundColor: '#ccc',
|
||||
},
|
||||
continueButtonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
color: '#fff',
|
||||
},
|
||||
skipButton: {
|
||||
height: 56,
|
||||
borderRadius: 14,
|
||||
backgroundColor: 'transparent',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider || '#E0E0E0',
|
||||
},
|
||||
skipButtonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
color: colors.text?.secondary || '#666',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default VerificationGuideScreen;
|
||||
Reference in New Issue
Block a user