diff --git a/app/screens/address/AddAddress.tsx b/app/screens/address/AddAddress.tsx index 30aa032..a654604 100644 --- a/app/screens/address/AddAddress.tsx +++ b/app/screens/address/AddAddress.tsx @@ -29,6 +29,7 @@ import { settingApi } from "../../services/api/setting"; import flagMap from "../../utils/flagMap"; import { useTranslation } from "react-i18next"; import fontSize from "../../utils/fontsizeUtils"; +import { getCountryTransLanguage } from "../../utils/languageUtils"; type RootStackParamList = { @@ -109,10 +110,10 @@ export const AddAddress = () => { useEffect(() => { settingApi.getCountryList().then((res) => { const formattedCountries = res.map((item) => ({ - label: `${item.name_en} (${item.country})`, + label: `${getCountryTransLanguage(item)} (${item.country})`, value: item.name.toString(), flag: flagMap.get(item.name_en), - name_en: item.name_en, + name_en: getCountryTransLanguage(item), country: item.country })); setItems(formattedCountries); diff --git a/app/screens/address/EditAddress.tsx b/app/screens/address/EditAddress.tsx index 80dfd9e..afdee53 100644 --- a/app/screens/address/EditAddress.tsx +++ b/app/screens/address/EditAddress.tsx @@ -28,6 +28,7 @@ import { settingApi } from "../../services/api/setting"; import flagMap from "../../utils/flagMap"; import { useTranslation } from "react-i18next"; import fontSize from "../../utils/fontsizeUtils"; +import { getCountryTransLanguage } from "../../utils/languageUtils"; type RootStackParamList = { AddRess: { address?: AddressItem }; @@ -50,10 +51,10 @@ export const EditAddress = () => { useNavigation>(); const route = useRoute(); const { t } = useTranslation(); - + const [open, setOpen] = useState(false); const [value, setValue] = useState(null); - const [items, setItems] = useState<{label: string; value: string}[]>([]); + const [items, setItems] = useState<{ label: string; value: string }[]>([]); const [selectedCountryLabel, setSelectedCountryLabel] = useState(""); const [countryList, setCountryList] = useState([]); @@ -91,11 +92,11 @@ export const EditAddress = () => { useEffect(() => { settingApi.getCountryList().then((res) => { const formattedCountries = res.map((item) => ({ - label: `${item.name_en} (${item.country})`, + label: `${getCountryTransLanguage(item)} (${item.country})`, value: item.name.toString(), flag: flagMap.get(item.name_en), - name_en: item.name_en, - country: item.country + name_en: getCountryTransLanguage(item), + country: item.country, })); setItems(formattedCountries); setCountryList(formattedCountries); @@ -108,9 +109,10 @@ export const EditAddress = () => { // 如果有路由参数中的地址 const addressFromRoute = route.params?.address; if (addressFromRoute && addressFromRoute.country) { - const selectedCountry = countryList.find(item => - item.name_en === addressFromRoute.country || - item.value === addressFromRoute.country + const selectedCountry = countryList.find( + (item) => + item.name_en === addressFromRoute.country || + item.value === addressFromRoute.country ); if (selectedCountry) { setSelectedCountryLabel(selectedCountry.label); @@ -155,7 +157,9 @@ export const EditAddress = () => { newErrors.receiver_phone = t("address.errors.phone_required"); } if (!formData.receiver_phone_again) { - newErrors.receiver_phone_again = t("address.errors.confirm_phone_required"); + newErrors.receiver_phone_again = t( + "address.errors.confirm_phone_required" + ); } if (formData.receiver_phone !== formData.receiver_phone_again) { newErrors.receiver_phone_again = t("address.errors.phone_mismatch"); @@ -170,7 +174,9 @@ export const EditAddress = () => { const handleSubmit = async () => { if (validateForm()) { - const selectedCountryObj = countryList.find(item => item.value === value); + const selectedCountryObj = countryList.find( + (item) => item.value === value + ); const submitData = { ...formData, country: selectedCountryObj ? selectedCountryObj.name_en : "", @@ -219,14 +225,18 @@ export const EditAddress = () => { - {t("address.select_recipient")} + + {t("address.select_recipient")} + {/* First Name Field */} - {t("address.first_name")} + + {t("address.first_name")} + * { {/* Last Name Field */} - {t("address.last_name")} + + {t("address.last_name")} + * { placeholder={t("address.placeholder.last_name")} value={formData.receiver_last_name} onChangeText={(text) => - setFormData({ ...formData, receiver_last_name: text }) + setFormData({ + ...formData, + receiver_last_name: text, + }) } /> {errors.receiver_last_name && ( @@ -270,16 +285,22 @@ export const EditAddress = () => { {/* 国家 */} - {t("address.country")} + + {t("address.country")} + setOpen(true)} > {selectedCountryLabel ? ( - {selectedCountryLabel} + + {selectedCountryLabel} + ) : ( - {t("address.placeholder.select_country")} + + {t("address.placeholder.select_country")} + )} @@ -293,11 +314,15 @@ export const EditAddress = () => { {t("address.phone_number")} - * + + * + setFormData({ @@ -317,11 +342,15 @@ export const EditAddress = () => { {t("address.confirm_phone_number")} - * + + * + setFormData({ @@ -347,7 +376,9 @@ export const EditAddress = () => { {/* WhatsApp Field */} - {t("address.whatsapp")} + + {t("address.whatsapp")} + * { }) } trackColor={{ false: "#767577", true: "#81b0ff" }} - thumbColor={formData.is_default ? "#002fa7" : "#f4f3f4"} + thumbColor={ + formData.is_default ? "#002fa7" : "#f4f3f4" + } ios_backgroundColor="#3e3e3e" /> @@ -414,7 +447,9 @@ export const EditAddress = () => { style={styles.primaryButtonStyle} onPress={handleSubmit} > - {t("address.submit")} + + {t("address.submit")} + @@ -431,7 +466,9 @@ export const EditAddress = () => { - {t("address.select_country")} + + {t("address.select_country")} + setOpen(false)}> {t("address.close")} @@ -445,10 +482,7 @@ export const EditAddress = () => { onPress={() => handleCountrySelect(item)} > {item.flag && ( - + )} {item.label} {value === item.value && ( @@ -471,7 +505,7 @@ export const EditAddress = () => { const styles = StyleSheet.create({ safeArea: { flex: 1, - backgroundColor: '#fff', + backgroundColor: "#fff", }, safeAreaContent: { flex: 1, @@ -854,7 +888,7 @@ const styles = StyleSheet.create({ borderTopLeftRadius: 20, borderTopRightRadius: 20, width: "100%", - height: Dimensions.get('window').height * 0.8, + height: Dimensions.get("window").height * 0.8, display: "flex", flexDirection: "column", }, diff --git a/app/screens/loginList/index.tsx b/app/screens/loginList/index.tsx index 2d0bba3..87dcf9a 100644 --- a/app/screens/loginList/index.tsx +++ b/app/screens/loginList/index.tsx @@ -10,7 +10,7 @@ import { Image, Modal, SafeAreaView, - Alert + Alert, } from "react-native"; import { useTranslation } from "react-i18next"; import { useNavigation } from "@react-navigation/native"; @@ -21,31 +21,32 @@ import PhoneLoginModal from "./PhoneLoginModal"; import { loginApi } from "../../services/api/login"; import { userApi } from "../../services"; import useUserStore from "../../store/user"; +import AsyncStorage from "@react-native-async-storage/async-storage"; // 使用标准的ES6模块导入 -// import { -// GoogleSignin, -// statusCodes, -// } from "@react-native-google-signin/google-signin"; +import { + GoogleSignin, + statusCodes, +} from "@react-native-google-signin/google-signin"; -// import { LoginManager, AccessToken, Settings } from "react-native-fbsdk-next"; +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); // 稍微修改了日志信息 -// } +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; @@ -108,122 +109,154 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => { // 处理谷歌登录 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"); - // } - // } + 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 token = res.token_type + " " + res.access_token; + await AsyncStorage.setItem("token", token); + 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(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); - // } - // }); - - // }, []); - + 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); - // } catch (error) { - // console.error('获取 Facebook 用户资料错误:', error); - // Alert.alert("获取资料失败", "无法从 Facebook 获取用户详细资料,请检查网络或权限设置。"); - // } - // }; + 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 用户信息并打印 - // await fetchFacebookProfile(tokenString); - - // // 移除之前的 Alert, 因为 fetchFacebookProfile 内部会处理打印和可能的错误提示 - // // 如果 fetchFacebookProfile 成功,信息已在控制台,如果失败,它会 Alert - // // 可以选择在这里加一个通用成功提示,表明流程已执行 - // 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}`); - // } + 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 token = res.token_type + " " + res.access_token; + await AsyncStorage.setItem("token", token); + // 获取用户信息并更新状态 + 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登录 diff --git a/app/services/api/login.ts b/app/services/api/login.ts index 3c71ef6..ba5f3fc 100644 --- a/app/services/api/login.ts +++ b/app/services/api/login.ts @@ -1,15 +1,22 @@ import apiService from "./apiClient"; +export interface LoginResponse { + access_token: string; + token_type: string; + expires_in: number; + refresh_token: string; + scope: string; +} export const loginApi = { // 谷歌登录 googleLogin: (data: any) => - apiService.post("/api/users/auth/callback/google", data), + apiService.post("/api/users/auth/callback/google", data), // 苹果登录 appleLogin: (data: any) => apiService.post("/api/users/auth/callback/apple", data), // 脸书登录 facebookLogin: (data: any) => - apiService.post("/api/users/auth/callback/facebook", data), + apiService.post("/api/users/auth/callback/facebook", data), };