You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

586 lines
17 KiB

import React, { useEffect, useState, useRef } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
StatusBar,
Platform,
BackHandler,
Image,
Modal,
SafeAreaView,
Alert
} from "react-native";
import { useTranslation } from "react-i18next";
import { useNavigation } from "@react-navigation/native";
import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import fontSize from "../../utils/fontsizeUtils";
import EmailLoginModal from "./EmailLoginModal";
import PhoneLoginModal from "./PhoneLoginModal";
import { loginApi } from "../../services/api/login";
import { userApi } from "../../services";
import useUserStore from "../../store/user";
// 使用标准的ES6模块导入
import {
GoogleSignin,
statusCodes,
} from "@react-native-google-signin/google-signin";
import { LoginManager, AccessToken, Settings } from "react-native-fbsdk-next";
const isDevelopment = __DEV__; // 开发模式检测
// 移出条件块,始终尝试配置 Google 登录
try {
// 配置 Google 登录
GoogleSignin.configure({
iosClientId: "YOUR_IOS_CLIENT_ID_HERE.apps.googleusercontent.com", // iOS CLIENT_ID
webClientId:
"449517618313-av37nffa7rqkefu0ajh5auou3pb0mt51.apps.googleusercontent.com", // <-- 更新为此 Web Client ID
scopes: ["profile", "email"],
offlineAccess: false, // <-- 确保为 false 或移除
forceCodeForRefreshToken: false, // <-- 确保为 false 或移除
});
} catch (error) {
console.log("Google Sign-in模块配置错误:", error); // 稍微修改了日志信息
}
type RootStackParamList = {
Login: undefined;
EmailLogin: undefined;
MainTabs: { screen: string };
Google: undefined;
Home: { screen: string };
};
type LoginScreenProps = {
onClose?: () => void;
isModal?: boolean;
};
export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
const { setUser } = useUserStore();
const { t } = useTranslation();
const navigation =
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
// 全新的状态管理方式
const [emailModalVisible, setEmailModalVisible] = useState(false);
const [phoneModalVisible, setPhoneModalVisible] = useState(false);
// 防止多次触发
const isProcessingEmail = useRef(false);
const isProcessingPhone = useRef(false);
// 处理Android返回按钮
useEffect(() => {
const backAction = () => {
if (emailModalVisible) {
setEmailModalVisible(false);
return true;
}
if (phoneModalVisible) {
setPhoneModalVisible(false);
return true;
}
handleClose();
return true;
};
const backHandler = BackHandler.addEventListener(
"hardwareBackPress",
backAction
);
return () => backHandler.remove();
}, [emailModalVisible, phoneModalVisible]);
// 关闭主屏幕
const handleClose = () => {
if (isModal && onClose) {
onClose();
} else {
navigation.goBack();
}
};
// 处理谷歌登录
const handleGoogleLogin = async () => {
try {
if (!GoogleSignin || typeof GoogleSignin.signIn !== "function") {
console.log("Google Sign-in模块未正确初始化或配置失败");
return;
}
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
console.log("Google 登录成功:", userInfo);
try {
const res = await loginApi.googleLogin(userInfo);
const user = await userApi.getProfile();
setUser(user);
navigation.navigate("MainTabs", { screen: "Home" });
} catch (err) {
console.log("Google 登录失败:", err);
navigation.navigate("Login");
}
// 这里可以处理登录成功后的逻辑
// 比如导航到主页面或保存用户信息
// navigation.navigate("MainTabs", { screen: "Home" });
} catch (error: any) {
console.log("Google 登录错误:", error);
// 开发模式下的错误处理
if (isDevelopment) {
console.log("开发模式:忽略Google登录错误,但已尝试真实登录"); // 修改日志,表明已尝试真实登录
return;
}
if (statusCodes && error.code === statusCodes.SIGN_IN_CANCELLED) {
console.log("用户取消登录");
} else if (statusCodes && error.code === statusCodes.IN_PROGRESS) {
console.log("登录正在进行中");
} else if (
statusCodes &&
error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE
) {
console.log("Play Services 不可用");
} else {
console.log("其他错误:", error.message);
navigation.navigate("Login");
}
}
};
const [userInfo, setUserInfo] = useState<any>(null);
useEffect(() => {
// 确保在 App 启动时初始化 SDK。这通常在您的 App.js 的顶层完成。
// 如果您在 app.json 中配置了 Facebook App ID,这里可以省略 Settings.setAppID 和 Settings.setDisplayName
Settings.initializeSDK();
// 在应用程序启动时检查是否已经登录(可选)
AccessToken.getCurrentAccessToken().then(data => {
if (data) {
console.log("已登录 Facebook,Token:", data.accessToken);
// 可以尝试获取用户信息
// fetchFacebookProfile(data.accessToken);
}
});
}, []);
// 辅助函数:获取 Facebook 用户资料 (可选,需要 'public_profile' 权限)
const fetchFacebookProfile = async (token:string) => {
try {
const response = await fetch(`https://graph.facebook.com/me?fields=id,name,email&access_token=${token}`);
const profile = await response.json();
setUserInfo(profile);
console.log('Facebook User Info:', profile);
return profile;
} catch (error) {
console.error('获取 Facebook 用户资料错误:', error);
Alert.alert("获取资料失败", "无法从 Facebook 获取用户详细资料,请检查网络或权限设置。");
return null;
}
};
// 处理Facebook登录
const handleFacebookLogin = async () => {
try {
// 可选: 先退出登录,确保每次都是全新登录 (主要用于测试)
// await LoginManager.logOut();
const result = await LoginManager.logInWithPermissions([
"public_profile",
"email",
]);
if (result.isCancelled) {
Alert.alert("登录取消", "用户取消了 Facebook 登录。");
return;
}
const data = await AccessToken.getCurrentAccessToken();
// 确保 accessToken 存在且为字符串
if (!data || !data.accessToken) {
Alert.alert("登录失败", "无法获取有效的 Facebook AccessToken。");
return;
}
const tokenString = data.accessToken.toString();
console.log("Facebook Access Token:", tokenString);
// 获取 Facebook 用户信息
const profile = await fetchFacebookProfile(tokenString);
if (profile) {
try {
// 准备发送给后端的数据 - 扁平化格式
const facebookData = {
id: profile.id,
name: profile.name,
email: profile.email,
access_token: tokenString
};
console.log("发送给后端的Facebook数据:", facebookData);
// 调用后端Facebook登录API
const res = await loginApi.facebookLogin(facebookData);
console.log("Facebook 后端登录响应:", res);
// 获取用户信息并更新状态
const user = await userApi.getProfile();
setUser(user);
// 导航到主页面
navigation.navigate("MainTabs", { screen: "Home" });
} catch (err) {
console.log("Facebook 后端登录失败:", err);
Alert.alert("登录失败", "Facebook 登录验证失败,请重试。");
}
} else {
Alert.alert("登录失败", "无法获取 Facebook 用户信息,请重试。");
}
} catch (error: any) {
console.error("Facebook 登录或获取资料时发生错误:", error);
let errorMessage = "发生未知错误";
if (error && typeof error.message === 'string') {
errorMessage = error.message;
}
Alert.alert("登录错误", `Facebook 操作失败:${errorMessage}`);
}
};
// 处理Apple登录
const handleAppleLogin = () => {
// 处理Apple登录
};
// 处理Instagram登录
const handleInstagramLogin = () => {
// 处理Instagram登录
};
// 显示邮箱登录
const showEmailModal = () => {
if (isProcessingEmail.current) return;
isProcessingEmail.current = true;
// 确保手机模态框已关闭
setPhoneModalVisible(false);
// 延迟打开邮箱模态框,避免冲突
setTimeout(() => {
setEmailModalVisible(true);
isProcessingEmail.current = false;
}, 100);
};
// 显示手机登录
const showPhoneModal = () => {
if (isProcessingPhone.current) return;
isProcessingPhone.current = true;
// 确保邮箱模态框已关闭
setEmailModalVisible(false);
// 延迟打开手机模态框,避免冲突
setTimeout(() => {
setPhoneModalVisible(true);
isProcessingPhone.current = false;
}, 100);
};
// 关闭邮箱登录
const hideEmailModal = () => {
console.log("Hiding email modal");
setEmailModalVisible(false);
};
// 关闭手机登录
const hidePhoneModal = () => {
console.log("Hiding phone modal");
setPhoneModalVisible(false);
};
// 处理忘记密码
const handleForgotPassword = () => {
// 处理忘记密码
};
return (
<SafeAreaView style={styles.safeArea}>
<StatusBar barStyle="light-content" backgroundColor="#0066FF" />
<View style={styles.safeAreaContent}>
{/* 顶部蓝色背景区域 */}
<View style={styles.blueHeader}>
<Text style={styles.logo}>brainnel</Text>
<View style={styles.features}>
<View style={styles.featureItem}>
<View style={styles.featureIconContainer}>
<Text style={styles.featureIcon}>💰</Text>
</View>
<Text style={styles.featureText}>{t("wholesalePrice")}</Text>
</View>
<View style={styles.featureItem}>
<View style={styles.featureIconContainer}>
<Text style={styles.featureIcon}>🚚</Text>
</View>
<Text style={styles.featureText}>{t("fastShipping")}</Text>
</View>
</View>
</View>
{/* 登录区域 */}
<View style={styles.loginContainer}>
<TouchableOpacity style={styles.closeButton} onPress={handleClose}>
<Text style={styles.closeButtonText}>×</Text>
</TouchableOpacity>
<View style={styles.titleContainer}>
<Text style={styles.subtitle}>{t("loginSubtitle")}</Text>
</View>
{/* 登录按钮 */}
<TouchableOpacity
style={styles.loginButton}
onPress={handleGoogleLogin}
>
<View style={styles.loginButtonIcon}>
<Image
source={require("../../../assets/img/google.png")}
style={{ width: 20, height: 20 }}
/>
</View>
<Text style={styles.loginButtonText}>
{isDevelopment
? "🧪 " + t("continueWithGoogle") + " (测试模式)"
: t("continueWithGoogle")}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.loginButton}
onPress={handleFacebookLogin}
>
<View style={[styles.loginButtonIcon, styles.facebookIcon]}>
<Text style={{ color: "#fff" }}>f</Text>
</View>
<Text style={styles.loginButtonText}>
{t("continueWithFacebook")}
</Text>
</TouchableOpacity>
{Platform.OS === "ios" && (
<TouchableOpacity
style={styles.loginButton}
onPress={handleAppleLogin}
>
<View style={[styles.loginButtonIcon, styles.appleIconBg]}>
<Text>🍎</Text>
</View>
<Text style={styles.loginButtonText}>
{t("continueWithApple")}
</Text>
</TouchableOpacity>
)}
<TouchableOpacity
style={styles.loginButton}
onPress={handleInstagramLogin}
>
<View style={[styles.loginButtonIcon, styles.instagramIcon]}>
<Text>📷</Text>
</View>
<Text style={styles.loginButtonText}>
{t("continueWithInstagram")}
</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.loginButton} onPress={showEmailModal}>
<View style={styles.loginButtonIcon}>
<Text>✉</Text>
</View>
<Text style={styles.loginButtonText}>{t("continueWithEmail")}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.loginButton} onPress={showPhoneModal}>
<View style={styles.loginButtonIcon}>
<Text>📱</Text>
</View>
<Text style={styles.loginButtonText}>{t("continueWithPhone")}</Text>
</TouchableOpacity>
{/* 忘记密码 */}
<TouchableOpacity
style={styles.forgotPassword}
onPress={handleForgotPassword}
>
<Text style={styles.forgotPasswordText}>{t("forgotPassword")}</Text>
</TouchableOpacity>
{/* 服务条款 */}
<View style={styles.termsContainer}>
<Text style={styles.terms}>
{t("termsText")}{" "}
<Text style={styles.link}>{t("termsOfUse")}</Text>
</Text>
<Text style={styles.terms}>
{t("and")} <Text style={styles.link}>{t("privacyPolicy")}</Text>
</Text>
</View>
</View>
</View>
{/* 邮箱登录模态框 - 直接渲染 */}
<EmailLoginModal visible={emailModalVisible} onClose={hideEmailModal} />
{/* 手机登录模态框 - 直接渲染 */}
<PhoneLoginModal visible={phoneModalVisible} onClose={hidePhoneModal} />
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
},
safeAreaContent: {
flex: 1,
paddingTop: 0,
},
container: {
flex: 1,
backgroundColor: "#FFF",
},
closeButton: {
position: "absolute",
top: 15,
left: 10,
width: 24,
height: 24,
justifyContent: "center",
alignItems: "center",
zIndex: 1,
},
closeButtonText: {
color: "#000",
fontSize: fontSize(24),
fontWeight: "300",
},
blueHeader: {
backgroundColor: "#0066FF",
paddingHorizontal: 20,
paddingBottom: 20,
paddingTop: Platform.OS === "ios" ? 60 : 40,
borderBottomLeftRadius: 24,
borderBottomRightRadius: 24,
},
logo: {
fontSize: fontSize(28),
fontWeight: "bold",
color: "#fff",
marginBottom: 15,
},
features: {
flexDirection: "row",
gap: 16,
},
featureItem: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
featureIconContainer: {
backgroundColor: "rgba(255, 255, 255, 0.2)",
borderRadius: 8,
width: 24,
height: 24,
justifyContent: "center",
alignItems: "center",
},
featureIcon: {
fontSize: fontSize(12),
},
featureText: {
fontSize: fontSize(14),
color: "#fff",
},
loginContainer: {
flex: 1,
paddingHorizontal: 20,
paddingTop: Platform.OS === "ios" ? 40 : 20,
},
titleContainer: {
alignItems: "center",
marginBottom: 30,
paddingTop: 20,
position: "relative",
},
subtitle: {
fontSize: fontSize(14),
color: "#666",
textAlign: "center",
},
loginButton: {
flexDirection: "row",
height: 50,
borderRadius: 25,
borderWidth: 1,
borderColor: "#E1E1E1",
alignItems: "center",
marginBottom: 12,
paddingHorizontal: 16,
backgroundColor: "#fff",
},
loginButtonIcon: {
width: 24,
height: 24,
borderRadius: 12,
justifyContent: "center",
alignItems: "center",
marginRight: 16,
},
facebookIcon: {
backgroundColor: "#3b5998",
},
appleIconBg: {
backgroundColor: "#000",
},
instagramIcon: {
backgroundColor: "#E1306C",
},
loginButtonText: {
flex: 1,
fontSize: fontSize(16),
color: "#000",
textAlign: "center",
marginRight: 16,
},
forgotPassword: {
alignItems: "center",
marginVertical: 20,
},
forgotPasswordText: {
color: "#0066FF",
fontSize: fontSize(14),
},
termsContainer: {
alignItems: "center",
marginTop: 10,
},
terms: {
fontSize: fontSize(12),
color: "#666",
textAlign: "center",
lineHeight: 18,
},
link: {
color: "#0066FF",
},
});
export default LoginScreen;