Browse Source

购物车和聊天界面未登录不可以使用

main
Mac 2 weeks ago
parent
commit
7b7bfca490
  1. 244
      app/locales/en/translation.json
  2. 27
      app/locales/fr/translation.json
  3. 26
      app/locales/zh/translation.json
  4. 200
      app/screens/CartScreen.tsx
  5. 312
      app/screens/ChatScreen.tsx
  6. 66
      app/screens/loginList/index.tsx

244
app/locales/en/translation.json

@ -96,24 +96,104 @@
"popularCategories": "Popular Categories", "popularCategories": "Popular Categories",
"my":"My", "my":"My",
"categories": "Categories", "categories": "Categories",
"chat": "Chat", "chat": {
"customerServiceChat": "Customer Service", "customer_service": "Customer Service",
"productChat": "Product Support", "product_support": "Product Support",
"notificationChat": "Notifications", "notifications": "Notifications",
"inputMessage": "Type a message...", "input_message": "Type a message...",
"send": "Send", "send": "Send",
"searchProducts": "Search products", "typing_message": "Typing",
"recommendations": "Recommendations", "default_response": "Thank you for your message. Our team will get back to you shortly.",
"sales": "sales", "error_response": "Sorry, there was an error processing your request. Please try again later.",
"productPicture": "Product Picture", "login_required_title": "Please Login First",
"no_stock": "No stock", "login_required_subtitle": "Login to use chat features",
"setting": { "login_now": "Login Now"
"title": "Select Language and Currency", },
"country": "Country", "banner": {
"currency": "Currency", "today": "Today",
"language": "Language", "shipping": {
"fee": "Shipping Fee",
"calculation_result": "Shipping Fee Calculation Result",
"estimated_fee": "Estimated Shipping Fee",
"confirm": "Confirm", "confirm": "Confirm",
"success": "Settings saved successfully" "maritime": "Sea Shipping",
"airway": "Air Shipping",
"select_country": "Select Country",
"parcel_volume": "Parcel Volume",
"enter_parcel_volume": "Please enter parcel volume",
"calculate_shipping": "Calculate Shipping Fee",
"select_country_modal_title": "Select Country",
"close": "Close"
},
"inquiry": {
"title": "Quote Request",
"upload_image": "Upload Image",
"hint": "Please upload an image",
"quantity_required": "Please enter quantity",
"error": "Error",
"submission_failed": "Submission failed, please try again",
"image_inquiry": "Image Inquiry",
"product_name": "Product Name",
"enter_product_name": "Please enter product name",
"quantity": "Quantity",
"enter_quantity": "Please enter quantity",
"material": "Material",
"enter_material": "Please enter material",
"link": "Link",
"enter_link": "Please enter link",
"remark": "Remark",
"enter_remark": "Please enter remark",
"cancel": "Cancel",
"confirm": "Confirm",
"submitting": "Submitting...",
"tab_request": "Request Quote",
"tab_in_progress": "In Progress",
"tab_completed": "Completed",
"loading": "Loading...",
"no_more_data": "No more data",
"no_in_progress": "No inquiries in progress",
"no_completed": "No completed inquiries",
"take_photo": "Take Photo",
"choose_from_gallery": "Choose from Gallery",
"reset_camera": "Reset Camera Function",
"camera_reset": "Reset",
"camera_reset_message": "Now you can use camera function",
"upload_image_get_quote": "Get product quote via image",
"upload_image_get_quote_message": "Upload product images,\nwe will provide you with detailed quotes\nand product information.",
"take_photo_or_upload": "Take Photo or Upload",
"fetch_failed": "Failed to fetch inquiry list",
"item_name": "Item Name",
"none": "None",
"more": "More"
},
"tiktok": {
"store": "Store TikTok",
"live": "Live",
"video": "Video",
"shorts": "Shorts",
"category": "Category"
},
"chat": {
"login_required_title": "Please Login First",
"login_required_subtitle": "Login to use chat features",
"login_now": "Login Now"
}
},
"settings": {
"title": "Settings",
"profile": "My Profile",
"change_password": "Change Password",
"change_phone": "Change Phone Number",
"my_address": "My Address",
"feedback": "Feedback",
"privacy_policy": "Brainnel Privacy Policy",
"terms_of_use": "Terms of Use",
"clear_cache": "Clear Cache",
"language_currency": "Select Language and Currency",
"add_new_address": "Add New Address",
"address_management": "Address Management",
"set_default": "Set Default Address",
"delete": "Delete"
}, },
"login.now": "Login Now", "login.now": "Login Now",
"login.button": "Login", "login.button": "Login",
@ -300,70 +380,6 @@
"submit_order": "Submit Order", "submit_order": "Submit Order",
"select_payment": "Please select payment method" "select_payment": "Please select payment method"
}, },
"settings": {
"title": "Settings",
"profile": "My Profile",
"change_password": "Change Password",
"change_phone": "Change Phone Number",
"my_address": "My Address",
"feedback": "Feedback",
"privacy_policy": "Brainnel Privacy Policy",
"terms_of_use": "Terms of Use",
"clear_cache": "Clear Cache",
"language_currency": "Select Language and Currency",
"add_new_address": "Add New Address",
"address_management": "Address Management",
"set_default": "Set Default Address",
"delete": "Delete"
},
"typingMessage": "Typing",
"defaultResponse": "Thank you for your message. Our team will get back to you shortly.",
"errorResponse": "Sorry, there was an error processing your request. Please try again later.",
"loginRequired": "Login Required",
"loginPrompt": "Please log in to access this feature. Your login will provide a better experience and allow you to track your orders.",
"login": {
"logInOrSignUp": "Log in or sign up",
"phoneNumber": "Phone number",
"enterPassword": "Please re-enter your password",
"passwordIncorrect": "Password incorrect, please confirm your password.",
"verificationCodeInfo": "We will send a verification code on your number to confirm it's you.",
"continue": "Continue",
"pleaseEnterEmail": "Please enter your e-mail address",
"forgotPassword": {
"title": "Forget your password?",
"phoneDescription": "Enter your phone number below, and we'll send you a 6-digit password reset code.",
"emailDescription": "Enter your email address below, and we'll send you a 6-digit password reset code.",
"submit": "Submit",
"invalidPhone": "Invalid phone number",
"requiresDigits": "Requires digits",
"invalidEmail": "Invalid email address"
},
"verification": {
"title": "Enter the verification code",
"description": "Please check your phone now! Enter the 6-digit password reset code sent to",
"expiration": "The code expires after 2 hours.",
"incorrect": "Incorrect verification code",
"resend": "Resend code",
"didntReceive": "Didn't receive the code?",
"helpPoint1": "1. Make sure your phone number is correct.",
"helpPoint2": "2. Please check if your phone can receive SMS messages."
},
"resetPassword": {
"title": "Setting a password",
"enterPassword": "Please enter your password",
"confirmPassword": "Please reconfirm your password",
"required": "Password is required",
"minLength": "Password must be at least 6 characters",
"confirmRequired": "Please confirm your password",
"mismatch": "Passwords do not match",
"failed": "Failed to reset password. Please try again.",
"error": "An error occurred. Please try again.",
"submit": "Submit"
},
"loginRequired": "Login Required",
"loginPrompt": "Please log in to access this feature. Your login will provide a better experience and allow you to track your orders.",
"loginNow": "Login Now"
},
"homePage":{ "homePage":{
"searchPlaceholder": "Search products", "searchPlaceholder": "Search products",
"shipping": "Shipping Calculator", "shipping": "Shipping Calculator",
@ -455,71 +471,9 @@
"yes": "Yes", "yes": "Yes",
"modify_quantity": "Modify Quantity", "modify_quantity": "Modify Quantity",
"cancel": "Cancel", "cancel": "Cancel",
"confirm": "Confirm"
},
"banner": {
"today": "Today",
"shipping": {
"fee": "Shipping Fee",
"calculation_result": "Shipping Fee Calculation Result",
"estimated_fee": "Estimated Shipping Fee",
"confirm": "Confirm", "confirm": "Confirm",
"maritime": "Sea Shipping", "login_required_title": "Please Login First",
"airway": "Air Shipping", "login_required_subtitle": "Login to use cart features",
"select_country": "Select Country", "login_now": "Login Now"
"parcel_volume": "Parcel Volume",
"enter_parcel_volume": "Please enter parcel volume",
"calculate_shipping": "Calculate Shipping Fee",
"select_country_modal_title": "Select Country",
"close": "Close"
},
"inquiry": {
"title": "Quote Request",
"upload_image": "Upload Image",
"hint": "Please upload an image",
"quantity_required": "Please enter quantity",
"error": "Error",
"submission_failed": "Submission failed, please try again",
"image_inquiry": "Image Inquiry",
"product_name": "Product Name",
"enter_product_name": "Please enter product name",
"quantity": "Quantity",
"enter_quantity": "Please enter quantity",
"material": "Material",
"enter_material": "Please enter material",
"link": "Link",
"enter_link": "Please enter link",
"remark": "Remark",
"enter_remark": "Please enter remark",
"cancel": "Cancel",
"confirm": "Confirm",
"submitting": "Submitting...",
"tab_request": "Request Quote",
"tab_in_progress": "In Progress",
"tab_completed": "Completed",
"loading": "Loading...",
"no_more_data": "No more data",
"no_in_progress": "No inquiries in progress",
"no_completed": "No completed inquiries",
"take_photo": "Take Photo",
"choose_from_gallery": "Choose from Gallery",
"reset_camera": "Reset Camera Function",
"camera_reset": "Reset",
"camera_reset_message": "Now you can use camera function",
"upload_image_get_quote": "Get product quote via image",
"upload_image_get_quote_message": "Upload product images,\nwe will provide you with detailed quotes\nand product information.",
"take_photo_or_upload": "Take Photo or Upload",
"fetch_failed": "Failed to fetch inquiry list",
"item_name": "Item Name",
"none": "None",
"more": "More"
},
"tiktok": {
"store": "Store TikTok",
"live": "Live",
"video": "Video",
"shorts": "Shorts",
"category": "Category"
}
} }
} }

27
app/locales/fr/translation.json

@ -96,12 +96,19 @@
"popularCategories": "Catégories populaires", "popularCategories": "Catégories populaires",
"my":"Mon", "my":"Mon",
"categories":"Catégories", "categories":"Catégories",
"chat":"Chat", "chat": {
"customerServiceChat":"Chat client", "customer_service": "Service Client",
"productChat":"Chat produit", "product_support": "Support Produit",
"notificationChat":"Chat notifications", "notifications": "Notifications",
"inputMessage":"Message", "input_message": "Tapez un message...",
"send": "Envoyer", "send": "Envoyer",
"typing_message": "En cours de frappe",
"default_response": "Merci pour votre message. Notre équipe vous répondra sous peu.",
"error_response": "Désolé, une erreur s'est produite lors du traitement de votre demande. Veuillez réessayer plus tard.",
"login_required_title": "Veuillez vous connecter d'abord",
"login_required_subtitle": "Connectez-vous pour utiliser les fonctionnalités de chat",
"login_now": "Se connecter maintenant"
},
"searchProducts":"Rechercher des produits", "searchProducts":"Rechercher des produits",
"recommendations":"Recommandations", "recommendations":"Recommandations",
"sales":"ventes", "sales":"ventes",
@ -392,6 +399,11 @@
}, },
"searchCountry": "Rechercher un pays", "searchCountry": "Rechercher un pays",
"noCountriesFound": "Aucun pays trouvé", "noCountriesFound": "Aucun pays trouvé",
"typingMessage": "En cours de frappe",
"defaultResponse": "Merci pour votre message. Notre équipe vous répondra sous peu.",
"errorResponse": "Désolé, une erreur s'est produite lors du traitement de votre demande. Veuillez réessayer plus tard.",
"loginRequired": "Connexion Requise",
"loginPrompt": "Veuillez vous connecter pour accéder à cette fonctionnalité. Votre connexion vous offrira une meilleure expérience et vous permettra de suivre vos commandes.",
"balance": { "balance": {
"screen": { "screen": {
"title": "Mon Solde", "title": "Mon Solde",
@ -450,7 +462,10 @@
"yes": "Oui", "yes": "Oui",
"modify_quantity": "Modifier la quantité", "modify_quantity": "Modifier la quantité",
"cancel": "Annuler", "cancel": "Annuler",
"confirm": "Confirmer" "confirm": "Confirmer",
"login_required_title": "Veuillez vous connecter d'abord",
"login_required_subtitle": "Connectez-vous pour utiliser les fonctionnalités du panier",
"login_now": "Se connecter maintenant"
}, },
"banner": { "banner": {
"today": "Aujourd'hui", "today": "Aujourd'hui",

26
app/locales/zh/translation.json

@ -93,6 +93,27 @@
"noMoreProducts": "没有更多商品", "noMoreProducts": "没有更多商品",
"chatNow": "立即聊天", "chatNow": "立即聊天",
"popularCategories": "热门分类", "popularCategories": "热门分类",
"my": "我的",
"categories": "分类",
"chat": {
"customer_service": "客服聊天",
"product_support": "产品咨询",
"notifications": "消息通知",
"input_message": "输入消息...",
"send": "发送",
"typing_message": "正在输入",
"default_response": "感谢您的消息。我们的团队会尽快回复您。",
"error_response": "抱歉,处理您的请求时出现错误。请稍后再试。",
"login_required_title": "请先登录",
"login_required_subtitle": "登录后即可使用聊天功能",
"login_now": "立即登录"
},
"recommendations": "推荐",
"sales": "销量",
"productPicture": "商品图片",
"no_stock": "缺货",
"loginRequired": "需要登录",
"loginPrompt": "请登录以访问此功能。登录后您将获得更好的体验并能跟踪您的订单。",
"setting": { "setting": {
"title": "选择语言和货币", "title": "选择语言和货币",
"country": "国家", "country": "国家",
@ -152,6 +173,9 @@
"yes": "是", "yes": "是",
"modify_quantity": "修改数量", "modify_quantity": "修改数量",
"cancel": "取消", "cancel": "取消",
"confirm": "确认" "confirm": "确认",
"login_required_title": "请先登录",
"login_required_subtitle": "登录后即可使用购物车功能",
"login_now": "立即登录"
} }
} }

200
app/screens/CartScreen.tsx

@ -62,6 +62,11 @@ export const CartScreen = () => {
// 货币转换函数 // 货币转换函数
const convertCurrency = async () => { const convertCurrency = async () => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
console.log(country_code); console.log(country_code);
// 如果 country_code 是 255,不需要转换 // 如果 country_code 是 255,不需要转换
@ -140,6 +145,11 @@ export const CartScreen = () => {
index1: number, index1: number,
index: number | null index: number | null
) => { ) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
if (index != null) { if (index != null) {
// 处理子类 SKU 的选择 // 处理子类 SKU 的选择
const data = { const data = {
@ -268,6 +278,11 @@ export const CartScreen = () => {
}; };
const getCart = async () => { const getCart = async () => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
const res = await getCartList(); const res = await getCartList();
// 修正父商品的选择状态,确保与子商品状态一致 // 修正父商品的选择状态,确保与子商品状态一致
@ -293,6 +308,11 @@ export const CartScreen = () => {
}; };
const selectAllHandel = () => { const selectAllHandel = () => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
const newAllSelected = !allSelected; const newAllSelected = !allSelected;
setAllSelected(newAllSelected); setAllSelected(newAllSelected);
@ -345,13 +365,22 @@ export const CartScreen = () => {
cartItemId: number, cartItemId: number,
cartId1: number cartId1: number
) => { ) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
// 设置要删除的商品信息并显示确认对话框 // 设置要删除的商品信息并显示确认对话框
setItemToDelete({ cartId, cartItemId, cartId1 }); setItemToDelete({ cartId, cartItemId, cartId1 });
setDeleteModalVisible(true); setDeleteModalVisible(true);
}; };
const confirmDelete = () => { const confirmDelete = () => {
if (itemToDelete) { // 如果用户未登录,直接返回
if (!user_id || !itemToDelete) {
return;
}
const { cartId, cartItemId, cartId1 } = itemToDelete; const { cartId, cartItemId, cartId1 } = itemToDelete;
console.log(itemToDelete); console.log(itemToDelete);
@ -408,7 +437,6 @@ export const CartScreen = () => {
deleteCartItem(cartId, cartItemId).then((res) => { deleteCartItem(cartId, cartItemId).then((res) => {
console.log(res); console.log(res);
}); });
}
// 关闭确认对话框 // 关闭确认对话框
setDeleteModalVisible(false); setDeleteModalVisible(false);
@ -426,9 +454,12 @@ export const CartScreen = () => {
// }, []); // }, []);
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
// 只有在用户已登录时才执行API调用
if (user_id) {
getCart(); getCart();
convertCurrency(); // 添加货币转换调用 convertCurrency(); // 添加货币转换调用
}, []) }
}, [user_id])
); );
const gotoOrder = () => { const gotoOrder = () => {
@ -498,6 +529,11 @@ export const CartScreen = () => {
cartItemId: number, cartItemId: number,
newQuantity: number newQuantity: number
) => { ) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
try { try {
// 更新本地状态 // 更新本地状态
setCartList((prev) => { setCartList((prev) => {
@ -538,6 +574,11 @@ export const CartScreen = () => {
cartItemId: number, cartItemId: number,
currentQuantity: number currentQuantity: number
) => { ) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
if (currentQuantity > 1) { if (currentQuantity > 1) {
updateQuantity(cartId, cartItemId, currentQuantity - 1); updateQuantity(cartId, cartItemId, currentQuantity - 1);
} }
@ -549,12 +590,20 @@ export const CartScreen = () => {
cartItemId: number, cartItemId: number,
currentQuantity: number currentQuantity: number
) => { ) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
updateQuantity(cartId, cartItemId, currentQuantity + 1); updateQuantity(cartId, cartItemId, currentQuantity + 1);
}; };
// 处理数量输入框确认 // 处理数量输入框确认
const handleQuantityInputConfirm = () => { const handleQuantityInputConfirm = () => {
if (!editingItem) return; // 如果用户未登录,直接返回
if (!user_id || !editingItem) {
return;
}
const newQuantity = parseInt(quantityInput); const newQuantity = parseInt(quantityInput);
if (isNaN(newQuantity) || newQuantity < 1) { if (isNaN(newQuantity) || newQuantity < 1) {
@ -574,11 +623,21 @@ export const CartScreen = () => {
cartItemId: number, cartItemId: number,
currentQuantity: number currentQuantity: number
) => { ) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
setEditingItem({ cartId, cartItemId, currentQuantity }); setEditingItem({ cartId, cartItemId, currentQuantity });
setQuantityInput(currentQuantity.toString()); setQuantityInput(currentQuantity.toString());
setQuantityInputVisible(true); setQuantityInputVisible(true);
}; };
// 添加导航到登录页面的函数
const goToLogin = () => {
navigation.navigate("Login"); // 假设登录页面的路由名为 "Login"
};
return ( return (
<SafeAreaView style={styles.safeArea}> <SafeAreaView style={styles.safeArea}>
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> <StatusBar barStyle="dark-content" backgroundColor="#fff" />
@ -605,6 +664,7 @@ export const CartScreen = () => {
onPress={() => onPress={() =>
toggleSelection(String(item.cart_id), index1, null) toggleSelection(String(item.cart_id), index1, null)
} }
disabled={!user_id}
> >
<View style={[styles.iconContainer]}> <View style={[styles.iconContainer]}>
{item.selected === 1 ? ( {item.selected === 1 ? (
@ -632,6 +692,7 @@ export const CartScreen = () => {
{item.skus.map((sku, index) => ( {item.skus.map((sku, index) => (
<Swipeable <Swipeable
key={sku.cart_item_id} key={sku.cart_item_id}
enabled={!!user_id}
renderRightActions={() => ( renderRightActions={() => (
<TouchableOpacity <TouchableOpacity
style={{ style={{
@ -647,6 +708,7 @@ export const CartScreen = () => {
item.cart_id item.cart_id
) )
} }
disabled={!user_id}
> >
<Text <Text
style={{ color: "white", fontWeight: "bold" }} style={{ color: "white", fontWeight: "bold" }}
@ -658,11 +720,13 @@ export const CartScreen = () => {
> >
<TouchableOpacity <TouchableOpacity
onPress={() => { onPress={() => {
if (user_id) {
navigation.navigate("ProductDetail", { navigation.navigate("ProductDetail", {
offer_id: item.offer_id, offer_id: item.offer_id,
searchKeyword: item.subject, searchKeyword: item.subject,
price: sku.price, price: sku.price,
}); });
}
}} }}
style={[ style={[
styles.productCardContainer5, styles.productCardContainer5,
@ -672,12 +736,13 @@ export const CartScreen = () => {
<View style={styles.svgContainer1}> <View style={styles.svgContainer1}>
<TouchableOpacity <TouchableOpacity
onPress={() => onPress={() =>
toggleSelection( user_id && toggleSelection(
String(sku.cart_item_id), String(sku.cart_item_id),
index1, index1,
index index
) )
} }
disabled={!user_id}
> >
<View style={[styles.iconContainer]}> <View style={[styles.iconContainer]}>
{sku.selected === 1 ? ( {sku.selected === 1 ? (
@ -753,12 +818,13 @@ export const CartScreen = () => {
{ borderRightWidth: 0 }, { borderRightWidth: 0 },
]} ]}
onPress={() => onPress={() =>
handleDecreaseQuantity( user_id && handleDecreaseQuantity(
item.cart_id, item.cart_id,
sku.cart_item_id, sku.cart_item_id,
sku.quantity sku.quantity
) )
} }
disabled={!user_id}
> >
<Text <Text
style={{ style={{
@ -773,12 +839,13 @@ export const CartScreen = () => {
<TouchableOpacity <TouchableOpacity
style={styles.quantityLabelContainer} style={styles.quantityLabelContainer}
onPress={() => onPress={() =>
handleQuantityPress( user_id && handleQuantityPress(
item.cart_id, item.cart_id,
sku.cart_item_id, sku.cart_item_id,
sku.quantity sku.quantity
) )
} }
disabled={!user_id}
> >
<Text style={styles.quantityText}> <Text style={styles.quantityText}>
{sku.quantity} {sku.quantity}
@ -790,12 +857,13 @@ export const CartScreen = () => {
{ borderLeftWidth: 0, marginLeft: 0 }, { borderLeftWidth: 0, marginLeft: 0 },
]} ]}
onPress={() => onPress={() =>
handleIncreaseQuantity( user_id && handleIncreaseQuantity(
item.cart_id, item.cart_id,
sku.cart_item_id, sku.cart_item_id,
sku.quantity sku.quantity
) )
} }
disabled={!user_id}
> >
<Text <Text
style={{ style={{
@ -853,7 +921,7 @@ export const CartScreen = () => {
<View style={styles.flexboxContainerWithButton}> <View style={styles.flexboxContainerWithButton}>
<View style={styles.productInfoContainer}> <View style={styles.productInfoContainer}>
<TouchableOpacity onPress={selectAllHandel}> <TouchableOpacity onPress={user_id ? selectAllHandel : undefined} disabled={!user_id}>
<View style={styles.svgContainer1}> <View style={styles.svgContainer1}>
{allSelected ? ( {allSelected ? (
<OrangeCircleIcon size={fontSize(24)} /> <OrangeCircleIcon size={fontSize(24)} />
@ -872,8 +940,9 @@ export const CartScreen = () => {
<Text style={styles.priceLabel}>{currency}</Text> <Text style={styles.priceLabel}>{currency}</Text>
</View> </View>
<TouchableOpacity <TouchableOpacity
style={styles.submitButtonStyle} style={[styles.submitButtonStyle, !user_id && styles.disabledButton]}
onPress={gotoOrder} onPress={user_id ? gotoOrder : undefined}
disabled={!user_id}
> >
<Text <Text
style={{ style={{
@ -888,11 +957,38 @@ export const CartScreen = () => {
</View> </View>
</View> </View>
</View> </View>
{/* 未登录遮罩 */}
{!user_id && (
<View style={styles.loginOverlay}>
<View style={styles.blurContainer}>
<View style={styles.loginPromptContainer}>
<View style={styles.loginIcon}>
<Text style={styles.loginIconText}>🔒</Text>
</View>
<Text style={styles.loginPromptTitle}>
{t("cart.login_required_title", "请先登录")}
</Text>
<Text style={styles.loginPromptSubtitle}>
{t("cart.login_required_subtitle", "登录后即可使用购物车功能")}
</Text>
<TouchableOpacity
style={styles.loginButton}
onPress={goToLogin}
>
<Text style={styles.loginButtonText}>
{t("cart.login_now", "立即登录")}
</Text>
</TouchableOpacity>
</View>
</View>
</View>
)}
</View> </View>
</View> </View>
<Modal <Modal
visible={deleteModalVisible} visible={deleteModalVisible && !!user_id}
transparent transparent
animationType="fade" animationType="fade"
onRequestClose={cancelDelete} onRequestClose={cancelDelete}
@ -924,7 +1020,7 @@ export const CartScreen = () => {
{/* 数量输入弹窗 */} {/* 数量输入弹窗 */}
<Modal <Modal
visible={quantityInputVisible} visible={quantityInputVisible && !!user_id}
transparent transparent
animationType="fade" animationType="fade"
onRequestClose={() => setQuantityInputVisible(false)} onRequestClose={() => setQuantityInputVisible(false)}
@ -1641,4 +1737,82 @@ const styles = StyleSheet.create({
flexDirection: "column", flexDirection: "column",
justifyContent: "center", justifyContent: "center",
}, },
disabledButton: {
opacity: 0.6,
},
loginOverlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(255, 255, 255, 0.9)',
backdropFilter: 'blur(10px)', // iOS 毛玻璃效果
justifyContent: 'center',
alignItems: 'center',
zIndex: 1000,
},
blurContainer: {
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: Platform.OS === 'android' ? 'rgba(255, 255, 255, 0.95)' : 'transparent',
},
loginPromptContainer: {
backgroundColor: 'white',
borderRadius: 20,
padding: 40,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
maxWidth: '80%',
},
loginIcon: {
width: 80,
height: 80,
marginBottom: 20,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(255, 81, 0, 0.1)',
borderRadius: 40,
},
loginIconText: {
fontSize: 40,
fontWeight: 'bold',
color: '#FF5100',
},
loginPromptTitle: {
fontSize: fontSize(24),
fontWeight: '700',
color: '#333',
marginBottom: 10,
textAlign: 'center',
},
loginPromptSubtitle: {
fontSize: fontSize(16),
color: '#666',
marginBottom: 30,
textAlign: 'center',
lineHeight: fontSize(22),
},
loginButton: {
backgroundColor: '#FF5100',
paddingHorizontal: 40,
paddingVertical: 15,
borderRadius: 25,
minWidth: 160,
},
loginButtonText: {
color: 'white',
fontSize: fontSize(18),
fontWeight: '700',
textAlign: 'center',
},
}); });

312
app/screens/ChatScreen.tsx

@ -7,7 +7,6 @@ import {
TextInput, TextInput,
TouchableOpacity, TouchableOpacity,
FlatList, FlatList,
KeyboardAvoidingView,
Platform, Platform,
ImageBackground, ImageBackground,
StatusBar, StatusBar,
@ -20,7 +19,8 @@ import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { chatService } from "../services/api/chat"; import { chatService } from "../services/api/chat";
import useUserStore from "../store/user"; import useUserStore from "../store/user";
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import { useTranslation } from 'react-i18next'; import { t } from "../i18n";
interface Message { interface Message {
id?: string; id?: string;
mimetype: string; mimetype: string;
@ -33,31 +33,28 @@ interface Message {
isMe?: boolean; isMe?: boolean;
timestamp?: Date; timestamp?: Date;
} }
type TabType = "customer" | "product" | "notification"; type TabType = "customer" | "product" | "notification";
type RootStackParamList = { type RootStackParamList = {
Login: undefined; Login: undefined;
// other screens... // other screens...
}; };
export const ChatScreen = () => { export const ChatScreen = () => {
const [messages, setMessages] = useState<Message[]>([]); const [messages, setMessages] = useState<Message[]>([]);
const [inputText, setInputText] = useState(""); const [inputText, setInputText] = useState("");
const [activeTab, setActiveTab] = useState<TabType>("customer"); const [activeTab, setActiveTab] = useState<TabType>("customer");
const [loginModalVisible, setLoginModalVisible] = useState(false);
const [country, setCountry] = useState<string>(""); // Store the country code const [country, setCountry] = useState<string>(""); // Store the country code
const { t } = useTranslation();
const { user } = useUserStore(); const { user } = useUserStore();
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>(); const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
// Add FlatList ref for auto-scrolling // Add FlatList ref for auto-scrolling
const flatListRef = useRef<FlatList>(null); const flatListRef = useRef<FlatList>(null);
// Add animation values
const [fadeAnim] = useState(new Animated.Value(0));
const [slideAnim] = useState(new Animated.Value(300));
// Auto-scroll to bottom when messages change // Auto-scroll to bottom when messages change
useEffect(() => { useEffect(() => {
if (messages.length > 0) { if (messages.length > 0 && user.user_id) {
setTimeout(() => { setTimeout(() => {
flatListRef.current?.scrollToEnd({ animated: true }); flatListRef.current?.scrollToEnd({ animated: true });
}, 100); }, 100);
@ -78,56 +75,25 @@ export const ChatScreen = () => {
} }
}; };
// Only get country if user is logged in
if (user.user_id) {
getCountry(); getCountry();
}, []);
// Check if user is logged in
useEffect(() => {
if (!user.user_id) {
setLoginModalVisible(true);
// Animate modal appearance
Animated.parallel([
Animated.timing(fadeAnim, {
toValue: 1,
duration: 300,
useNativeDriver: true,
}),
Animated.spring(slideAnim, {
toValue: 0,
tension: 50,
friction: 9,
useNativeDriver: true,
})
]).start();
} else {
setLoginModalVisible(false);
} }
}, [user.user_id]); }, [user.user_id]);
const handleCloseModal = () => {
// Animate modal exit // 添加导航到登录页面的函数
Animated.parallel([ const goToLogin = () => {
Animated.timing(fadeAnim, { navigation.navigate("Login");
toValue: 0,
duration: 200,
useNativeDriver: true,
}),
Animated.timing(slideAnim, {
toValue: 300,
duration: 200,
useNativeDriver: true,
})
]).start(() => {
setLoginModalVisible(false);
});
};
const handleGoToLogin = () => {
handleCloseModal();
// Navigate to login after modal is closed
setTimeout(() => {
navigation.navigate('Login');
}, 200);
}; };
const sendMessage = () => { const sendMessage = () => {
// 如果用户未登录,直接返回
if (!user.user_id) {
return;
}
if (inputText.trim() === "") return; if (inputText.trim() === "") return;
const newMessage: Message = { const newMessage: Message = {
mimetype: "text/plain", mimetype: "text/plain",
userWs: "unknown", userWs: "unknown",
@ -140,6 +106,7 @@ export const ChatScreen = () => {
timestamp: new Date(), timestamp: new Date(),
id: Date.now().toString(), // Add unique id for keyExtractor id: Date.now().toString(), // Add unique id for keyExtractor
}; };
// Extract only the properties that chatService.sendMessage expects // Extract only the properties that chatService.sendMessage expects
const chatServiceMessage = { const chatServiceMessage = {
type: newMessage.type, type: newMessage.type,
@ -150,6 +117,7 @@ export const ChatScreen = () => {
body: newMessage.body, body: newMessage.body,
text: newMessage.text text: newMessage.text
}; };
// Add user message to the chat UI // Add user message to the chat UI
setMessages([...messages, newMessage]); setMessages([...messages, newMessage]);
setInputText(""); setInputText("");
@ -162,7 +130,7 @@ export const ChatScreen = () => {
app_id: "system", app_id: "system",
country: user.country_code, country: user.country_code,
body: "", body: "",
text: `${t('typingMessage')}...`, text: `${t('chat.typing_message')}...`,
type: "chat", type: "chat",
isMe: false, isMe: false,
timestamp: new Date(), timestamp: new Date(),
@ -177,6 +145,7 @@ export const ChatScreen = () => {
const data = { const data = {
newMessage:chatServiceMessage, newMessage:chatServiceMessage,
} }
// Send actual message to API // Send actual message to API
chatService.sendMessage(data) chatService.sendMessage(data)
.then(response => { .then(response => {
@ -192,7 +161,7 @@ export const ChatScreen = () => {
app_id: "system", app_id: "system",
country: user.country_code, country: user.country_code,
body: "", body: "",
text: response?.reply || t('defaultResponse'), text: response?.reply || t('chat.default_response'),
type: "chat", type: "chat",
isMe: false, isMe: false,
timestamp: new Date(), timestamp: new Date(),
@ -214,7 +183,7 @@ export const ChatScreen = () => {
app_id: "system", app_id: "system",
country: user.country_code, country: user.country_code,
body: "", body: "",
text: t('errorResponse'), text: t('chat.error_response'),
type: "chat", type: "chat",
isMe: false, isMe: false,
timestamp: new Date(), timestamp: new Date(),
@ -225,10 +194,12 @@ export const ChatScreen = () => {
}); });
}); });
}; };
// Generate a unique key for each message // Generate a unique key for each message
const keyExtractor = (item: Message, index: number): string => { const keyExtractor = (item: Message, index: number): string => {
return item.id || index.toString(); return item.id || index.toString();
}; };
const renderMessage = ({ item }: { item: Message }) => ( const renderMessage = ({ item }: { item: Message }) => (
<View <View
style={[ style={[
@ -245,6 +216,7 @@ export const ChatScreen = () => {
</Text> </Text>
</View> </View>
); );
const renderTabContent = () => { const renderTabContent = () => {
switch (activeTab) { switch (activeTab) {
case "customer": case "customer":
@ -257,6 +229,7 @@ export const ChatScreen = () => {
keyExtractor={keyExtractor} keyExtractor={keyExtractor}
contentContainerStyle={styles.messageList} contentContainerStyle={styles.messageList}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
scrollEnabled={!!user.user_id}
/> />
</View> </View>
); );
@ -270,6 +243,7 @@ export const ChatScreen = () => {
keyExtractor={keyExtractor} keyExtractor={keyExtractor}
contentContainerStyle={styles.messageList} contentContainerStyle={styles.messageList}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
scrollEnabled={!!user.user_id}
/> />
</View> </View>
); );
@ -283,11 +257,13 @@ export const ChatScreen = () => {
keyExtractor={keyExtractor} keyExtractor={keyExtractor}
contentContainerStyle={styles.messageList} contentContainerStyle={styles.messageList}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
scrollEnabled={!!user.user_id}
/> />
</View> </View>
); );
} }
}; };
return ( return (
<SafeAreaView style={styles.safeArea}> <SafeAreaView style={styles.safeArea}>
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> <StatusBar barStyle="dark-content" backgroundColor="#fff" />
@ -301,7 +277,8 @@ export const ChatScreen = () => {
<View style={styles.tabBar}> <View style={styles.tabBar}>
<TouchableOpacity <TouchableOpacity
style={[styles.tab, activeTab === "customer" && styles.activeTab]} style={[styles.tab, activeTab === "customer" && styles.activeTab]}
onPress={() => setActiveTab("customer")} onPress={() => user.user_id && setActiveTab("customer")}
disabled={!user.user_id}
> >
<Text <Text
style={[ style={[
@ -309,12 +286,13 @@ export const ChatScreen = () => {
activeTab === "customer" && styles.activeTabText, activeTab === "customer" && styles.activeTabText,
]} ]}
> >
{t('customerServiceChat')} {t('chat.customer_service')}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={[styles.tab, activeTab === "product" && styles.activeTab]} style={[styles.tab, activeTab === "product" && styles.activeTab]}
onPress={() => setActiveTab("product")} onPress={() => user.user_id && setActiveTab("product")}
disabled={!user.user_id}
> >
<Text <Text
style={[ style={[
@ -322,12 +300,13 @@ export const ChatScreen = () => {
activeTab === "product" && styles.activeTabText, activeTab === "product" && styles.activeTabText,
]} ]}
> >
{t('productChat')} {t('chat.product_support')}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={[styles.tab, activeTab === "notification" && styles.activeTab]} style={[styles.tab, activeTab === "notification" && styles.activeTab]}
onPress={() => setActiveTab("notification")} onPress={() => user.user_id && setActiveTab("notification")}
disabled={!user.user_id}
> >
<Text <Text
style={[ style={[
@ -335,89 +314,62 @@ export const ChatScreen = () => {
activeTab === "notification" && styles.activeTabText, activeTab === "notification" && styles.activeTabText,
]} ]}
> >
{t('notificationChat')} {t('chat.notifications')}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
{renderTabContent()} {renderTabContent()}
<View style={styles.inputContainer}> <View style={styles.inputContainer}>
<TextInput <TextInput
style={styles.input} style={[styles.input, !user.user_id && styles.disabledInput]}
value={inputText} value={inputText}
onChangeText={setInputText} onChangeText={user.user_id ? setInputText : undefined}
placeholder={t('inputMessage')} placeholder={t('chat.input_message')}
multiline multiline
editable={!!user.user_id}
/> />
<TouchableOpacity style={styles.sendButton} onPress={sendMessage}> <TouchableOpacity
<Text style={styles.sendButtonText}>{t('send')}</Text> style={[styles.sendButton, !user.user_id && styles.disabledButton]}
onPress={user.user_id ? sendMessage : undefined}
disabled={!user.user_id}
>
<Text style={styles.sendButtonText}>{t('chat.send')}</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</ImageBackground> </ImageBackground>
{/* Login Modal */} {/* 未登录遮罩 */}
<Modal {!user.user_id && (
visible={loginModalVisible} <View style={styles.loginOverlay}>
transparent={true} <View style={styles.blurContainer}>
animationType="none" <View style={styles.loginPromptContainer}>
onRequestClose={handleCloseModal} <View style={styles.loginIcon}>
> <Text style={styles.loginIconText}>💬</Text>
<Animated.View
style={[
styles.modalContainer,
{
opacity: fadeAnim,
}
]}
>
<Animated.View
style={[
styles.modalOverlay,
{
opacity: fadeAnim,
}
]}
>
<TouchableOpacity
style={styles.modalOverlayTouch}
activeOpacity={1}
onPress={handleCloseModal}
/>
</Animated.View>
<Animated.View
style={[
styles.modalContent,
{
transform: [{ translateY: slideAnim }],
},
]}
>
<TouchableOpacity
style={styles.closeButton}
onPress={handleCloseModal}
>
<Text style={styles.closeButtonText}></Text>
</TouchableOpacity>
<View style={styles.modalHeader}>
<View style={styles.modalIndicator} />
</View> </View>
<Text style={styles.modalTitle}>{t('loginRequired')}</Text> <Text style={styles.loginPromptTitle}>
<Text style={styles.modalText}> {t("chat.login_required_title", "请先登录")}
{t('pleaseLoginToChat')} </Text>
<Text style={styles.loginPromptSubtitle}>
{t("chat.login_required_subtitle", "登录后即可使用聊天功能")}
</Text> </Text>
<TouchableOpacity <TouchableOpacity
style={styles.modalButton} style={styles.loginButton}
onPress={handleGoToLogin} onPress={goToLogin}
> >
<Text style={styles.modalButtonText}>{t('loginNow')}</Text> <Text style={styles.loginButtonText}>
{t("chat.login_now", "立即登录")}
</Text>
</TouchableOpacity> </TouchableOpacity>
</Animated.View> </View>
</Animated.View> </View>
</Modal> </View>
)}
</View> </View>
</View> </View>
</SafeAreaView> </SafeAreaView>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
safeArea: { safeArea: {
flex: 1, flex: 1,
@ -522,75 +474,85 @@ const styles = StyleSheet.create({
color: "white", color: "white",
fontSize: 16, fontSize: 16,
}, },
// Modal styles loginOverlay: {
modalContainer: {
flex: 1,
justifyContent: 'flex-end',
},
modalOverlay: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
modalOverlayTouch: {
flex: 1,
},
modalContent: {
backgroundColor: '#fff',
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
paddingHorizontal: 20,
paddingBottom: Platform.OS === 'ios' ? 40 : 20,
position: 'relative',
},
closeButton: {
position: 'absolute', position: 'absolute',
top: 20, top: 0,
right: 20, left: 0,
width: 24, right: 0,
height: 24, bottom: 0,
backgroundColor: 'rgba(255, 255, 255, 0.9)',
backdropFilter: 'blur(10px)', // iOS 毛玻璃效果
justifyContent: 'center',
alignItems: 'center',
zIndex: 1000,
},
blurContainer: {
width: '100%',
height: '100%',
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
zIndex: 1, backgroundColor: Platform.OS === 'android' ? 'rgba(255, 255, 255, 0.95)' : 'transparent',
},
loginPromptContainer: {
backgroundColor: 'white',
borderRadius: 20,
padding: 40,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
}, },
closeButtonText: { shadowOpacity: 0.25,
fontSize: 20, shadowRadius: 3.84,
color: '#999', elevation: 5,
maxWidth: '80%',
}, },
modalHeader: { loginIcon: {
width: 80,
height: 80,
marginBottom: 20,
justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
paddingTop: 12, backgroundColor: 'rgba(0, 122, 108, 0.1)',
paddingBottom: 20, borderRadius: 40,
}, },
modalIndicator: { loginIconText: {
width: 40, fontSize: 40,
height: 4, fontWeight: 'bold',
backgroundColor: '#E0E0E0', color: '#007a6c',
borderRadius: 2, },
}, loginPromptTitle: {
modalTitle: { fontSize: 24,
fontSize: 20, fontWeight: '700',
fontWeight: '600', color: '#333',
color: '#000', marginBottom: 10,
textAlign: 'center', textAlign: 'center',
marginBottom: 12,
}, },
modalText: { loginPromptSubtitle: {
fontSize: 16, fontSize: 16,
color: '#666', color: '#666',
marginBottom: 30,
textAlign: 'center', textAlign: 'center',
marginBottom: 24,
lineHeight: 22, lineHeight: 22,
}, },
modalButton: { loginButton: {
backgroundColor: '#007a6c', backgroundColor: '#007a6c',
height: 50, paddingHorizontal: 40,
paddingVertical: 15,
borderRadius: 25, borderRadius: 25,
justifyContent: 'center', minWidth: 160,
alignItems: 'center',
}, },
modalButtonText: { loginButtonText: {
color: '#fff', color: 'white',
fontSize: 16, fontSize: 18,
fontWeight: '600', fontWeight: '700',
textAlign: 'center',
},
disabledInput: {
opacity: 0.6,
},
disabledButton: {
opacity: 0.6,
}, },
}); });

66
app/screens/loginList/index.tsx

@ -15,22 +15,35 @@ import { useTranslation } from "react-i18next";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import type { NativeStackNavigationProp } from "@react-navigation/native-stack"; import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import fontSize from "../../utils/fontsizeUtils"; import fontSize from "../../utils/fontsizeUtils";
import {
GoogleSignin,
GoogleSigninButton,
statusCodes,
} from '@react-native-google-signin/google-signin';
import EmailLoginModal from "./EmailLoginModal"; import EmailLoginModal from "./EmailLoginModal";
import PhoneLoginModal from "./PhoneLoginModal"; import PhoneLoginModal from "./PhoneLoginModal";
// 条件导入Google Sign-in(仅在生产模式)
let GoogleSignin: any = null;
let GoogleSigninButton: any = null;
let statusCodes: any = null;
const isDevelopment = __DEV__; // 开发模式检测
if (!isDevelopment) {
try {
const googleSigninModule = require('@react-native-google-signin/google-signin');
GoogleSignin = googleSigninModule.GoogleSignin;
GoogleSigninButton = googleSigninModule.GoogleSigninButton;
statusCodes = googleSigninModule.statusCodes;
// 配置 Google 登录 // 配置 Google 登录
GoogleSignin.configure({ GoogleSignin.configure({
iosClientId: "YOUR_IOS_CLIENT_ID_HERE.apps.googleusercontent.com", // iOS CLIENT_ID iosClientId: "YOUR_IOS_CLIENT_ID_HERE.apps.googleusercontent.com", // iOS CLIENT_ID
webClientId: "529750832779-d0jpf2493plgm8eutkmk9e9t3rhkta8b.apps.googleusercontent.com", // Web CLIENT_ID (用于Android) webClientId: "529750832779-d0jpf2493plgm8eutkmk9e9t3rhkta8b.apps.googleusercontent.com", // Web CLIENT_ID (用于Android)
scopes: ['profile', 'email'], scopes: ['profile', 'email'],
offlineAccess: true, offlineAccess: true,
forceCodeForRefreshToken: true,
}); });
} catch (error) {
console.log('Google Sign-in模块未安装或配置错误:', error);
}
}
type RootStackParamList = { type RootStackParamList = {
Login: undefined; Login: undefined;
@ -93,6 +106,32 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
// 处理谷歌登录 // 处理谷歌登录
const handleGoogleLogin = async () => { const handleGoogleLogin = async () => {
try { try {
// 开发模式下的模拟登录
if (isDevelopment) {
console.log('开发模式:模拟Google登录成功');
const mockUserInfo = {
user: {
id: 'dev_user_123',
name: 'Test User',
email: 'test@example.com',
photo: null,
},
};
console.log('模拟用户信息:', mockUserInfo);
// 这里可以处理登录成功后的逻辑
// 比如导航到主页面或保存用户信息
// navigation.navigate("MainTabs", { screen: "Home" });
return;
}
// 生产模式下的真实Google登录
if (!GoogleSignin) {
console.log('Google Sign-in模块未配置');
return;
}
await GoogleSignin.hasPlayServices(); await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn(); const userInfo = await GoogleSignin.signIn();
console.log('Google 登录成功:', userInfo); console.log('Google 登录成功:', userInfo);
@ -103,11 +142,18 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
} catch (error: any) { } catch (error: any) {
console.log('Google 登录错误:', error); console.log('Google 登录错误:', error);
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
// 开发模式下的错误处理
if (isDevelopment) {
console.log('开发模式:忽略Google登录错误');
return;
}
if (statusCodes && error.code === statusCodes.SIGN_IN_CANCELLED) {
console.log('用户取消登录'); console.log('用户取消登录');
} else if (error.code === statusCodes.IN_PROGRESS) { } else if (statusCodes && error.code === statusCodes.IN_PROGRESS) {
console.log('登录正在进行中'); console.log('登录正在进行中');
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) { } else if (statusCodes && error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
console.log('Play Services 不可用'); console.log('Play Services 不可用');
} else { } else {
console.log('其他错误:', error.message); console.log('其他错误:', error.message);
@ -222,7 +268,7 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
/> />
</View> </View>
<Text style={styles.loginButtonText}> <Text style={styles.loginButtonText}>
{t("continueWithGoogle")} {isDevelopment ? '🧪 ' + t("continueWithGoogle") + ' (测试模式)' : t("continueWithGoogle")}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>

Loading…
Cancel
Save