2025-08-08 18:55:18 +08:00

232 lines
7.1 KiB
TypeScript

import { Fonts } from "@/constants/Fonts";
import { router } from "expo-router";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { StyleSheet, TouchableOpacity, View } from "react-native";
import { useAuth } from "../../contexts/auth-context";
import { fetchApi } from "../../lib/server-api-util";
import { User } from "../../types/user";
import { ThemedText } from "../ThemedText";
import Button from "./ui/Button";
import TextInput from "./ui/TextInput";
interface LoginProps {
updateUrlParam: (status: string, value: string) => void;
setError: (error: string) => void;
setShowPassword: (showPassword: boolean) => void;
showPassword: boolean;
}
const Login = ({ updateUrlParam, setError, setShowPassword, showPassword }: LoginProps) => {
const { t } = useTranslation();
const { login } = useAuth();
const [isLoading, setIsLoading] = useState(false);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleLogin = async () => {
if (!email) {
setError(t('auth.login.emailPlaceholder', { ns: 'login' }));
return;
};
if (!password) {
setError(t('auth.login.passwordPlaceholder', { ns: 'login' }));
return;
}
setIsLoading(true);
try {
const body = {
account: email,
password: password,
};
const res = await fetchApi<User>('/iam/login/password-login', {
method: 'POST',
body: JSON.stringify(body),
}, true, false);
login({ ...res, email: res?.account }, res.access_token || '');
const userInfo = await fetchApi<User>("/iam/user-info");
if (userInfo?.nickname) {
router.replace('/ask');
} else {
router.replace('/user-message');
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : t('auth.login.loginError', { ns: 'login' });
setError(errorMessage);
} finally {
setIsLoading(false);
}
};
const handleForgotPassword = () => {
updateUrlParam('status', 'forgetPwd');
};
const handleSignUp = () => {
updateUrlParam('status', 'signUp');
};
return (
<View style={styles.container}>
{/* 邮箱 */}
<TextInput
label={t('auth.login.email', { ns: 'login' })}
placeholder={t('auth.login.accountPlaceholder', { ns: 'login' })}
onChangeText={(text) => {
setEmail(text);
setError('123');
}}
autoCapitalize="none"
value={email}
/>
{/* 密码 */}
<TextInput
label={t('auth.login.password', { ns: 'login' })}
placeholder={t('auth.login.passwordPlaceholder', { ns: 'login' })}
onChangeText={(text) => {
setPassword(text);
setError('123');
}}
autoCapitalize="none"
value={password}
type="password"
setShowPassword={setShowPassword}
showPassword={showPassword}
containerStyle={{ marginBottom: 0 }}
/>
{/* 忘记密码 */}
<TouchableOpacity
style={styles.forgotPassword}
onPress={handleForgotPassword}
>
<ThemedText style={styles.forgotPasswordText} color="textPrimary" type="inter">
{t('auth.login.forgotPassword', { ns: 'login' })}
</ThemedText>
</TouchableOpacity>
{/* 登录按钮 */}
<Button isLoading={isLoading} handleLogin={handleLogin} text={t('auth.login.loginButton', { ns: 'login' })} />
{/* 注册 */}
<View style={styles.signupContainer}>
<ThemedText style={styles.signupText} type="sfPro">
{t('auth.login.signUpMessage', { ns: 'login' })}
</ThemedText>
<TouchableOpacity onPress={handleSignUp}>
<ThemedText style={styles.signupLink} type="sfPro">
{t('auth.login.signUp', { ns: 'login' })}
</ThemedText>
</TouchableOpacity>
</View>
{/* 第三方登录 */}
<View style={{ width: "100%", alignItems: "center", opacity: 0 }}>
<View style={styles.loginTypeContainer}>
<ThemedText>
OR
</ThemedText>
<View style={{ flexDirection: 'row', justifyContent: "space-between", width: "100%" }}>
<ThemedText style={styles.loginType} />
<ThemedText style={styles.loginType} />
<ThemedText style={styles.loginType} />
</View>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
loginTypeContainer: {
display: "flex",
flexDirection: "column",
justifyContent: 'center',
alignItems: 'center',
gap: 16,
width: "70%"
},
loginType: {
borderRadius: 12,
width: 42,
height: 42,
textAlign: 'center',
backgroundColor: '#FADBA1'
},
inputContainer: {
marginBottom: 20,
},
inputLabel: {
fontSize: Fonts['base'],
color: Fonts['textPrimary'],
fontWeight: Fonts['bold'],
fontFamily: Fonts['sfPro'],
marginBottom: 8,
marginLeft: 8,
},
textInput: {
borderRadius: Fonts['xs'],
paddingHorizontal: Fonts['base'],
paddingVertical: Fonts['xs'],
fontSize: Fonts['sm'],
lineHeight: Fonts['base'],
textAlignVertical: 'center',
backgroundColor: Fonts['bgInput'],
color: Fonts['textSecondary'],
fontFamily: Fonts['inter'],
paddingRight: Fonts['5xl'],
},
passwordInputContainer: {
position: 'relative',
},
eyeIcon: {
position: 'absolute',
right: 12,
top: 14,
},
forgotPassword: {
alignSelf: 'flex-end',
marginBottom: 24,
},
forgotPasswordText: {
color: '#AC7E35',
fontSize: 11,
},
loginButton: {
width: '100%',
backgroundColor: '#E2793F',
borderRadius: 28,
padding: 16,
alignItems: 'center',
marginBottom: 24,
},
loginButtonText: {
color: '#FFFFFF',
fontWeight: '600',
fontSize: 18,
},
signupContainer: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 8,
},
signupText: {
color: '#AC7E35',
fontSize: Fonts['sm'],
},
signupLink: {
color: '#E2793F',
fontSize: Fonts['sm'],
fontWeight: '600',
marginLeft: 4,
textDecorationLine: 'underline',
},
});
export default Login;