feat(auth): implement multi-step registration process and enhance background services
- Updated RegisterScreen to support a multi-step registration flow with components for email input, verification, and profile setup. - Added new components: VerificationCodeInput, StepIndicator, and corresponding types for step management. - Enhanced background service to check authentication status before executing tasks, improving app reliability. - Updated TypeScript configuration to include module resolution and JSON module support. This update significantly improves the user registration experience and ensures background tasks are only executed for authenticated users.
This commit is contained in:
192
src/screens/auth/RegisterStep1Email.tsx
Normal file
192
src/screens/auth/RegisterStep1Email.tsx
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* 注册步骤1:输入邮箱
|
||||
* 包含邮箱输入框和获取验证码按钮
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { useAppColors, type AppColors } from '../../theme';
|
||||
import { RegisterStepProps } from './types';
|
||||
|
||||
const THEME_COLORS = {
|
||||
primary: '#FF6B35',
|
||||
primaryLight: '#FF8C5A',
|
||||
primaryDark: '#E55A2B',
|
||||
};
|
||||
|
||||
export const RegisterStep1Email: React.FC<RegisterStepProps> = ({
|
||||
formData,
|
||||
updateFormData,
|
||||
onNext,
|
||||
colors: propColors,
|
||||
sendingCode,
|
||||
countdown,
|
||||
onSendCode,
|
||||
}) => {
|
||||
const colors = propColors || useAppColors();
|
||||
const styles = createStyles(colors);
|
||||
|
||||
const [emailError, setEmailError] = useState('');
|
||||
|
||||
const validateEmail = (email: string): boolean => {
|
||||
if (!email.trim()) {
|
||||
setEmailError('请输入邮箱');
|
||||
return false;
|
||||
}
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
setEmailError('请输入正确的邮箱地址');
|
||||
return false;
|
||||
}
|
||||
setEmailError('');
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleSendCode = async () => {
|
||||
if (!validateEmail(formData.email)) {
|
||||
return;
|
||||
}
|
||||
if (onSendCode) {
|
||||
const success = await onSendCode(formData.email);
|
||||
if (success) {
|
||||
onNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.formSection}>
|
||||
{/* 邮箱输入框 */}
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.inputLabel}>邮箱</Text>
|
||||
<View
|
||||
style={[
|
||||
styles.inputWrapper,
|
||||
emailError ? styles.inputWrapperError : null,
|
||||
]}
|
||||
>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="请输入邮箱地址"
|
||||
placeholderTextColor={colors.text?.hint || '#999'}
|
||||
value={formData.email}
|
||||
onChangeText={(text) => {
|
||||
updateFormData({ email: text });
|
||||
if (emailError) setEmailError('');
|
||||
}}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
keyboardType="email-address"
|
||||
editable={!sendingCode}
|
||||
/>
|
||||
{formData.email.length > 0 &&
|
||||
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email) && (
|
||||
<MaterialCommunityIcons
|
||||
name="check-circle"
|
||||
size={20}
|
||||
color={THEME_COLORS.primary}
|
||||
style={styles.checkIcon}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
{emailError ? (
|
||||
<Text style={styles.errorText}>{emailError}</Text>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{/* 获取验证码按钮 */}
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.actionButton,
|
||||
(sendingCode || countdown > 0) && styles.actionButtonDisabled,
|
||||
]}
|
||||
onPress={handleSendCode}
|
||||
disabled={sendingCode || countdown > 0}
|
||||
activeOpacity={0.9}
|
||||
>
|
||||
<Text style={styles.actionButtonText}>
|
||||
{sendingCode
|
||||
? '发送中...'
|
||||
: countdown > 0
|
||||
? `${countdown}秒后重试`
|
||||
: '获取验证码'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function createStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingTop: 20,
|
||||
},
|
||||
formSection: {
|
||||
marginBottom: 24,
|
||||
},
|
||||
inputContainer: {
|
||||
marginBottom: 24,
|
||||
},
|
||||
inputLabel: {
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
color: colors.text?.secondary || '#666',
|
||||
marginBottom: 10,
|
||||
},
|
||||
inputWrapper: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5F5F7',
|
||||
borderRadius: 14,
|
||||
paddingHorizontal: 18,
|
||||
height: 56,
|
||||
borderWidth: 1,
|
||||
borderColor: 'transparent',
|
||||
},
|
||||
inputWrapperError: {
|
||||
borderColor: colors.error?.main || '#FF4444',
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
fontSize: 16,
|
||||
color: colors.text?.primary || '#333',
|
||||
height: 56,
|
||||
},
|
||||
checkIcon: {
|
||||
marginLeft: 8,
|
||||
},
|
||||
errorText: {
|
||||
fontSize: 12,
|
||||
color: colors.error?.main || '#FF4444',
|
||||
marginTop: 6,
|
||||
marginLeft: 4,
|
||||
},
|
||||
actionButton: {
|
||||
height: 56,
|
||||
borderRadius: 14,
|
||||
backgroundColor: '#FF6B35',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 8,
|
||||
},
|
||||
actionButtonDisabled: {
|
||||
opacity: 0.6,
|
||||
},
|
||||
actionButtonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default RegisterStep1Email;
|
||||
Reference in New Issue
Block a user