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.
 
 
 

1896 lines
54 KiB

import React, { useState, useCallback } from "react";
import {
View,
Text,
Image,
StyleSheet,
TouchableOpacity,
ScrollView,
Modal,
TextInput,
Alert,
Platform,
StatusBar,
SafeAreaView,
} from "react-native";
import fontSize from "../utils/fontsizeUtils";
import CircleOutlineIcon from "../components/CircleOutlineIcon";
import {
getCartList,
GetCartList,
updateCartItem,
deleteCartItem,
updateBatchCartSelected,
} from "../services/api/cart";
import widthUtils from "../utils/widthUtils";
import { Swipeable } from "react-native-gesture-handler";
import OrangeCircleIcon from "../components/OrangeCircleIcon";
import { useNavigation } from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { useFocusEffect } from "@react-navigation/native";
import useCreateOrderStore from "../store/createOrder";
import useUserStore from "../store/user";
import { t } from "../i18n";
import { payApi } from "../services/api/payApi";
import IconComponent from "../components/IconComponent";
export const CartScreen = () => {
const [cartList, setCartList] = useState<GetCartList[]>([]);
const {
user: { user_id, currency, vip_discount, country_code },
} = useUserStore();
const [selectedItems, setSelectedItems] = useState<{
[key: string]: boolean;
}>({});
const [allSelected, setAllSelected] = useState(false);
const [totalAmount, setTotalAmount] = useState(0);
const [convertedMinAmount, setConvertedMinAmount] = useState<number | null>(null);
const [deleteModalVisible, setDeleteModalVisible] = useState(false);
const [itemToDelete, setItemToDelete] = useState<{
cartId: number;
cartItemId: number;
cartId1: number;
} | null>(null);
const [quantityInputVisible, setQuantityInputVisible] = useState(false);
const [editingItem, setEditingItem] = useState<{
cartId: number;
cartItemId: number;
currentQuantity: number;
} | null>(null);
const [quantityInput, setQuantityInput] = useState("");
const navigation = useNavigation<NativeStackNavigationProp<any>>();
const { setItems } = useCreateOrderStore();
const [minQuantityModalVisible, setMinQuantityModalVisible] = useState(false);
const [minQuantityMessage, setMinQuantityMessage] = useState("");
// 货币转换函数
const convertCurrency = async () => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
console.log(country_code);
// 如果 country_code 是 255,不需要转换
if (country_code === 225) {
setConvertedMinAmount(null);
return;
}
try {
console.log(`Converting currency for country_code: ${country_code}, from FCFA to ${currency}`);
const data = {
from_currency: "FCFA", // 固定使用 FCFA
to_currency: currency, // 使用用户的货币
amounts: {
total_amount: 50000, // 固定的最低订单金额 50,000 FCFA
},
};
const response = await payApi.convertCurrency(data);
console.log("Currency conversion response:", response);
if (response && response.converted_amounts_list && response.converted_amounts_list.length > 0) {
const convertedTotal = response.converted_amounts_list.find(
(item: any) => item.item_key === "total_amount"
);
if (convertedTotal) {
console.log(`Converted minimum amount: ${convertedTotal.converted_amount} ${currency}`);
setConvertedMinAmount(convertedTotal.converted_amount);
}
} else {
console.warn("No converted amounts found in response");
setConvertedMinAmount(null);
}
} catch (error) {
console.error("货币转换失败:", error);
// 转换失败时不设置转换金额,使用原始逻辑
setConvertedMinAmount(null);
}
};
// 计算选中商品的总金额
const calculateTotalAmount = (list: GetCartList[]) => {
let total = 0;
list.forEach((item) => {
item.skus.forEach((sku) => {
if (sku.selected === 1) {
// 使用 Number.toFixed(2) 保留两位小数,然后转换为数字
total = Number((total + sku.price * sku.quantity).toFixed(2));
}
});
});
setTotalAmount(total);
};
// 在状态更新后计算总金额
const updateCartList = (newList: GetCartList[]) => {
setCartList(newList);
calculateTotalAmount(newList);
// 如果购物车为空,设置全选为false
if (newList.length === 0) {
setAllSelected(false);
}
};
const changeAllSelected = (newList: GetCartList[]) => {
const allSkusSelected = newList.every((item) =>
item.skus.every((sku) => sku.selected === 1)
);
setAllSelected(allSkusSelected);
};
const toggleSelection = async (
cartItemId: string,
index1: number,
index: number | null
) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
if (index != null) {
// 处理子类 SKU 的选择
const data = {
cart_item_id: cartList[index1].skus[index].cart_item_id,
selected: cartList[index1].skus[index].selected === 1 ? 0 : 1,
quantity: cartList[index1].skus[index].quantity,
};
// 立即更新本地状态
setCartList((prev) => {
const newList = prev.map((item, idx) => {
if (idx === index1) {
const newSkus = item.skus.map((sku) => ({
...sku,
selected:
sku.cart_item_id === data.cart_item_id
? data.selected
: sku.selected,
}));
const allSelected = newSkus.every((sku) => sku.selected === 1);
return {
...item,
skus: newSkus,
selected: allSelected ? 1 : 0,
};
}
return item;
});
calculateTotalAmount(newList);
// 在状态更新后检查全选状态
changeAllSelected(newList);
return newList;
});
setSelectedItems((prev) => ({
...prev,
[cartItemId]: !prev[cartItemId],
}));
// 在后台发起网络请求
updateCartItem(cartList[index1].cart_id, data).catch((error) => {
console.error("更新购物车商品状态失败:", error);
// 如果请求失败,回滚本地状态
setCartList((prev) => {
const newList = prev.map((item, idx) => {
if (idx === index1) {
const newSkus = item.skus.map((sku) => ({
...sku,
selected:
sku.cart_item_id === data.cart_item_id
? data.selected === 1
? 0
: 1
: sku.selected,
}));
const allSelected = newSkus.every((sku) => sku.selected === 1);
return {
...item,
skus: newSkus,
selected: allSelected ? 1 : 0,
};
}
return item;
});
calculateTotalAmount(newList);
changeAllSelected(newList);
return newList;
});
});
} else {
// 处理父类商品的选择
const newSelected = cartList[index1].selected === 1 ? 0 : 1;
// 立即更新本地状态
setCartList((prev) => {
const newList = prev.map((item, idx) => {
if (idx === index1) {
return {
...item,
skus: item.skus.map((sku) => ({
...sku,
selected: newSelected,
})),
selected: newSelected,
};
}
return item;
});
calculateTotalAmount(newList);
// 在状态更新后检查全选状态
changeAllSelected(newList);
return newList;
});
// 获取所有子类的 cart_item_id
const cartItemIds = cartList[index1].skus.map((sku) => sku.cart_item_id);
// 在后台发起网络请求
updateBatchCartSelected({
cart_id: cartList[index1].cart_id,
selected: newSelected,
offer_ids: cartItemIds,
}).catch((error) => {
console.error("批量更新购物车商品状态失败:", error);
// 如果请求失败,回滚本地状态
setCartList((prev) => {
const newList = prev.map((item, idx) => {
if (idx === index1) {
return {
...item,
skus: item.skus.map((sku) => ({
...sku,
selected: newSelected === 1 ? 0 : 1,
})),
selected: newSelected === 1 ? 0 : 1,
};
}
return item;
});
calculateTotalAmount(newList);
changeAllSelected(newList);
return newList;
});
});
}
};
const getCart = async () => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
const res = await getCartList();
// 修正父商品的选择状态,确保与子商品状态一致
const correctedItems = res.items.map((item) => {
// 检查该商品下所有子商品是否都被选中
const allSkusSelected = item.skus.every((sku) => sku.selected === 1);
return {
...item,
selected: allSkusSelected ? 1 : 0, // 根据子商品状态设置父商品状态
};
});
setCartList(correctedItems);
calculateTotalAmount(correctedItems);
if (correctedItems.length === 0) {
// 如果购物车为空,直接设置全选为false
setAllSelected(false);
} else {
// 检查所有商品的 skus 数组中的 selected 属性是否都为 1
changeAllSelected(correctedItems);
}
};
const selectAllHandel = () => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
const newAllSelected = !allSelected;
setAllSelected(newAllSelected);
// 立即更新本地状态
setCartList((prev) => {
const newList = prev.map((item) => {
// 获取所有子类的 cart_item_id
const cartItemIds = item.skus.map((sku) => sku.cart_item_id);
// 在后台发起网络请求
updateBatchCartSelected({
cart_id: item.cart_id,
selected: newAllSelected ? 1 : 0,
offer_ids: cartItemIds,
}).catch((error) => {
console.error("批量更新购物车商品状态失败:", error);
// 如果请求失败,回滚本地状态
setCartList((prev) => {
const newList = prev.map((item) => {
return {
...item,
selected: newAllSelected ? 0 : 1,
skus: item.skus.map((sku) => ({
...sku,
selected: newAllSelected ? 0 : 1,
})),
};
});
calculateTotalAmount(newList);
setAllSelected(!newAllSelected);
return newList;
});
});
return {
...item,
selected: newAllSelected ? 1 : 0,
skus: item.skus.map((sku) => {
return { ...sku, selected: newAllSelected ? 1 : 0 };
}),
};
});
calculateTotalAmount(newList);
return newList;
});
};
const handleDeleteSku = (
cartId: number,
cartItemId: number,
cartId1: number
) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
// 设置要删除的商品信息并显示确认对话框
setItemToDelete({ cartId, cartItemId, cartId1 });
setDeleteModalVisible(true);
};
const confirmDelete = () => {
// 如果用户未登录,直接返回
if (!user_id || !itemToDelete) {
return;
}
const { cartId, cartItemId, cartId1 } = itemToDelete;
console.log(itemToDelete);
// 找到要删除的商品,从总价中减去
const itemToRemove = cartList.find((item) => item.cart_id === cartId);
if (itemToRemove) {
const skuToRemove = itemToRemove.skus.find(
(sku) => sku.cart_item_id === cartItemId
);
if (skuToRemove && skuToRemove.selected === 1) {
// 如果商品是已选中状态,从总价中减去
setTotalAmount((prev) =>
Number((prev - skuToRemove.price * skuToRemove.quantity).toFixed(2))
);
}
}
setCartList((prev) => {
// 先找到要删除的商品
const itemToUpdate = prev.find((item) => item.cart_id === cartId);
if (!itemToUpdate) return prev;
// 计算删除后的 SKU 数量
const remainingSkus = itemToUpdate.skus.filter(
(sku) => sku.cart_item_id !== cartItemId
);
// 如果删除后没有 SKU 了,则删除整个商品
if (remainingSkus.length === 0) {
deleteCartItem(cartId1, cartItemId).then((res) => {
console.log(res);
});
const newCartList = prev.filter((item) => item.cart_id !== cartId);
// 检查是否没有商品了,如果没有则将全选设为false
if (newCartList.length === 0) {
setAllSelected(false);
}
return newCartList;
} else {
// 否则只删除特定的 SKU
return prev.map((item) => {
if (item.cart_id === cartId) {
return {
...item,
skus: remainingSkus,
};
}
return item;
});
}
});
deleteCartItem(cartId, cartItemId).then((res) => {
console.log(res);
});
// 关闭确认对话框
setDeleteModalVisible(false);
setItemToDelete(null);
};
const cancelDelete = () => {
// 关闭确认对话框
setDeleteModalVisible(false);
setItemToDelete(null);
};
// useEffect(() => {
// }, []);
useFocusEffect(
useCallback(() => {
// 只有在用户已登录时才执行API调用
if (user_id) {
getCart();
convertCurrency(); // 添加货币转换调用
}
}, [user_id])
);
const gotoOrder = () => {
if (!user_id) {
Alert.alert(t("cart.add_failed"), t("cart.login_required"));
return;
}
// 检查是否有选中的商品
const items: { cart_item_id: number }[] = [];
cartList.forEach((item) => {
item.skus.forEach((sku) => {
if (sku.selected === 1) {
if (sku.cart_item_id) {
items.push({
cart_item_id: sku.cart_item_id,
});
}
}
});
});
if (items.length === 0) {
Alert.alert(t("cart.add_failed"), t("cart.select_products"));
return;
}
// 检查最低订单金额
if (country_code !== 225) {
// 只有当 country_code 不是 255 时才进行最低订单金额检查
if (convertedMinAmount !== null) {
// 如果有转换后的最低金额,检查当前总价是否满足要求
console.log(`Checking converted minimum amount: ${convertedMinAmount} ${currency} vs current total: ${totalAmount}`);
if (totalAmount < convertedMinAmount) {
Alert.alert(
t("cart.notice"),
t("cart.minimum_order_required", {
amount: convertedMinAmount.toFixed(2),
currency: currency
})
);
return;
}
} else {
// 如果转换失败,使用原始的 50,000 FCFA 检查
console.log(`Checking original minimum amount: 50000 FCFA vs current total: ${totalAmount}`);
if (totalAmount < 50000) {
Alert.alert(
t("cart.notice"),
t("cart.minimum_order_required", {
amount: "50,000",
currency: "FCFA"
})
);
return;
}
}
}
// 如果 country_code === 255,则不进行任何最低订单金额检查
setItems(items);
navigation.navigate("PreviewAddress");
};
// 添加更新商品数量的方法
const updateQuantity = async (
cartId: number,
cartItemId: number,
newQuantity: number
) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
try {
// 更新本地状态
setCartList((prev) => {
const newList = prev.map((item) => {
if (item.cart_id === cartId) {
return {
...item,
skus: item.skus.map((sku) => {
if (sku.cart_item_id === cartItemId) {
return { ...sku, quantity: newQuantity };
}
return sku;
}),
};
}
return item;
});
calculateTotalAmount(newList);
return newList;
});
// 调用API更新数量
await updateCartItem(cartId, {
cart_item_id: cartItemId,
quantity: newQuantity,
selected: 1,
});
} catch (error) {
console.error("更新商品数量失败:", error);
// 如果更新失败,回滚本地状态
getCart();
}
};
// 统一的提示函数
const showMinQuantityModal = (message: string) => {
setMinQuantityMessage(message);
setMinQuantityModalVisible(true);
};
// 处理减少数量
const handleDecreaseQuantity = (
cartId: number,
cartItemId: number,
currentQuantity: number,
minOrderQuantity: number
) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
if (currentQuantity > minOrderQuantity) {
updateQuantity(cartId, cartItemId, currentQuantity - 1);
} else {
showMinQuantityModal(`${t("cart.notice")}${t("cart.min_order")}${minOrderQuantity}${t("cart.pieces")}`);
}
};
// 处理增加数量
const handleIncreaseQuantity = (
cartId: number,
cartItemId: number,
currentQuantity: number
) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
updateQuantity(cartId, cartItemId, currentQuantity + 1);
};
// 处理数量输入框确认
const handleQuantityInputConfirm = () => {
// 如果用户未登录,直接返回
if (!user_id || !editingItem) {
return;
}
const newQuantity = parseInt(quantityInput);
if (isNaN(newQuantity) || newQuantity < 1) {
showMinQuantityModal(t("cart.enter_valid_quantity"));
return;
}
const { cartId, cartItemId } = editingItem;
const minOrderQuantity = cartList.find(item => item.cart_id === cartId)?.min_order_quantity || 1;
if (newQuantity < minOrderQuantity) {
showMinQuantityModal(`${t("cart.notice")}${t("cart.min_order")}${minOrderQuantity}${t("cart.pieces")}`);
} else {
updateQuantity(cartId, cartItemId, newQuantity);
setQuantityInputVisible(false);
setEditingItem(null);
setQuantityInput("");
}
};
// 处理点击数量显示
const handleQuantityPress = (
cartId: number,
cartItemId: number,
currentQuantity: number
) => {
// 如果用户未登录,直接返回
if (!user_id) {
return;
}
setEditingItem({ cartId, cartItemId, currentQuantity });
setQuantityInput(currentQuantity.toString());
setQuantityInputVisible(true);
};
// 添加导航到登录页面的函数
const goToLogin = () => {
navigation.navigate("Login"); // 假设登录页面的路由名为 "Login"
};
return (
<SafeAreaView style={styles.safeArea}>
<StatusBar barStyle="dark-content" backgroundColor="#fff" />
<View style={styles.safeAreaContent}>
<View style={styles.container}>
<ScrollView
style={styles.scrollContainer}
contentContainerStyle={styles.scrollContentContainer}
>
<View style={styles.productListingContainer}>
<View style={styles.shoppingCartSection}>
<View style={styles.productCardContainer7}>
<View style={styles.svgContainer}>
{/* Replace SVG with actual icon component or image */}
{/* <BackIcon size={fontSize(18)} /> */}
</View>
{/* <Text style={styles.shoppingCartTitle}>Panier (5)</Text> */}
</View>
{/* <Text style={styles.shoppingCartTitle}>Panier (5)</Text> */}
</View>
{/* <Text style={styles.shoppingCartTitle}>Panier (5)</Text> */}
</View>
{cartList.map((item, index1) => (
<View style={styles.productCardListing} key={item.cart_id}>
<View style={styles.productCardContainer5}>
<View style={styles.svgContainer1}>
<TouchableOpacity
onPress={() =>
toggleSelection(String(item.cart_id), index1, null)
}
disabled={!user_id}
>
<View style={[styles.iconContainer]}>
{item.selected === 1 ? (
<OrangeCircleIcon size={fontSize(24)} />
) : (
<CircleOutlineIcon size={fontSize(24)} />
)}
</View>
</TouchableOpacity>
</View>
<Image
source={{ uri: item.product_image }}
style={styles.imageThumbnail}
/>
<View style={styles.productInfoContainer2}>
<Text style={styles.casualTextSnippet}>
{item.subject}
</Text>
<Text style={styles.productDetailsTextStyle1}>
{t("cart.min_order")}: {item.min_order_quantity}
{t("cart.pieces")}
</Text>
</View>
</View>
{item.skus.map((sku, index) => (
<Swipeable
key={sku.cart_item_id}
enabled={!!user_id}
renderRightActions={() => (
<TouchableOpacity
style={{
backgroundColor: "#ff5217",
justifyContent: "center",
alignItems: "center",
width: 80,
}}
onPress={() =>
handleDeleteSku(
item.cart_id,
sku.cart_item_id,
item.cart_id
)
}
disabled={!user_id}
>
<Text
style={{ color: "white", fontWeight: "bold" }}
>
{t("cart.delete")}
</Text>
</TouchableOpacity>
)}
>
<TouchableOpacity
onPress={() => {
if (user_id) {
navigation.navigate("ProductDetail", {
offer_id: item.offer_id,
searchKeyword: item.subject,
price: sku.price,
});
}
}}
style={[
styles.productCardContainer5,
styles.productCardContainer4,
]}
>
<View style={styles.svgContainer1}>
<TouchableOpacity
onPress={() =>
user_id && toggleSelection(
String(sku.cart_item_id),
index1,
index
)
}
disabled={!user_id}
>
<View style={[styles.iconContainer]}>
{sku.selected === 1 ? (
<OrangeCircleIcon size={fontSize(24)} />
) : (
<CircleOutlineIcon size={fontSize(24)} />
)}
{/* <CircleOutlineIcon size={fontSize(24)} strokeColor={sku.selected === 1 ? "#FF5100" : "#C6C6C6"}/> */}
</View>
</TouchableOpacity>
</View>
<Image
source={{
uri: sku.attributes[0]?.sku_image_url
? sku.attributes[0]?.sku_image_url
: item.product_image,
}}
style={styles.productImageDisplayStyle}
/>
<View style={styles.productCardWidget1}>
{/* 1. SKU attributes at the top */}
{sku.attributes[0]?.value && (
<View style={styles.longLifeRougeStyle}>
<Text
style={styles.longLifeTextSnippet}
numberOfLines={2}
ellipsizeMode="tail"
>
{sku.attributes[0]?.value}{" "}
{sku.attributes[1] ? "/" : ""}{" "}
{sku.attributes[1]?.value}
</Text>
</View>
)}
{/* 2. Price section - discount and actual price close together */}
<View style={styles.priceSection}>
<View style={styles.priceColumnContainer}>
{/* Discount price */}
<View style={styles.productInfoContainer1}>
<View style={styles.priceInfoContainer1}>
<Text style={styles.discountPriceLabel}>
{sku.original_price} {sku.currency}
</Text>
</View>
<View style={styles.vipContainer}>
<Image
source={require("../../assets/img/折扣VIP1 (1).png")}
style={styles.VipImg}
/>
<Text style={styles.discountPercentageTextStyle}>
{((1 - vip_discount) * 100).toFixed(0)}%
</Text>
</View>
</View>
{/* Actual price - right below discount price */}
<View style={styles.productInfoContainer4}>
<Text style={styles.productCodeLabel}>
{sku.price}
</Text>
<Text style={styles.productDetailsTextStyle}>
{sku.currency}
</Text>
</View>
</View>
{/* 3. Quantity controls on the right */}
<View style={styles.orderQuantityContainer}>
<TouchableOpacity
style={[
styles.svgContainer4,
{ borderRightWidth: 0 },
]}
onPress={() =>
user_id && handleDecreaseQuantity(
item.cart_id,
sku.cart_item_id,
sku.quantity,
item.min_order_quantity
)
}
disabled={!user_id}
>
<Text
style={{
fontSize: fontSize(18),
color: "#333",
fontWeight: "500",
}}
>
-
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.quantityLabelContainer}
onPress={() =>
user_id && handleQuantityPress(
item.cart_id,
sku.cart_item_id,
sku.quantity
)
}
disabled={!user_id}
>
<Text style={styles.quantityText}>
{sku.quantity}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.svgContainer4,
{ borderLeftWidth: 0, marginLeft: 0 },
]}
onPress={() =>
user_id && handleIncreaseQuantity(
item.cart_id,
sku.cart_item_id,
sku.quantity
)
}
disabled={!user_id}
>
<Text
style={{
fontSize: fontSize(18),
color: "#333",
fontWeight: "500",
}}
>
+
</Text>
</TouchableOpacity>
</View>
</View>
</View>
</TouchableOpacity>
</Swipeable>
))}
</View>
))}
{/* 商品 */}
</ScrollView>
{/* Fixed Bottom Section */}
<View style={styles.fixedBottomContainer}>
{/* Order Summary */}
{country_code !== 225 && (
<View style={styles.orderSummaryHeader}>
<View style={styles.svgContainer6}>
<Image
source={require("../../assets/img/Vector.png")}
style={{ width: 18, height: 18, tintColor: "#FF5100" }}
/>
</View>
<Text style={styles.orderQuantityInfo}>
<Text>{t("cart.min_order_quantity")} </Text>
<Text style={styles.tiltWarpText}>
{convertedMinAmount !== null
? `${convertedMinAmount.toFixed(2)} ${currency}`
: "50,000FCFA"
}
</Text>
</Text>
</View>
)}
<View style={styles.flexboxContainerWithButton}>
<View style={styles.productInfoContainer}>
<TouchableOpacity onPress={user_id ? selectAllHandel : undefined} disabled={!user_id}>
<View style={styles.svgContainer1}>
{allSelected ? (
<OrangeCircleIcon size={fontSize(24)} />
) : (
<CircleOutlineIcon size={fontSize(24)} />
)}
</View>
</TouchableOpacity>
<Text style={styles.headerTitle}>{t("cart.all")}</Text>
</View>
<View style={styles.productInfoContainer}>
<View style={styles.productInfoContainer}>
<Text style={styles.highlightedText1}>{totalAmount}</Text>
<Text style={styles.priceLabel}>{currency}</Text>
</View>
<TouchableOpacity
style={[styles.submitButtonStyle, !user_id && styles.disabledButton]}
onPress={user_id ? gotoOrder : undefined}
disabled={!user_id}
>
<Text
style={{
color: "white",
fontSize: fontSize(18),
fontWeight: "700",
}}
>
{t("cart.submit")}
</Text>
</TouchableOpacity>
</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>
<Modal
visible={deleteModalVisible && !!user_id}
transparent
animationType="fade"
onRequestClose={cancelDelete}
>
<View style={styles.overlay}>
<View style={styles.popup}>
{/* <Image
source={require("../assets/image_5f59afb0.png")} // 替换成你实际的路径
style={styles.image}
/> */}
<Text style={styles.promptText}>{t("cart.delete_item")}</Text>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.cancelButton1}
onPress={cancelDelete}
>
<Text style={styles.cancelText}>{t("cart.no")}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.confirmButton}
onPress={confirmDelete}
>
<Text style={styles.confirmText}>{t("cart.yes")}</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
{/* 数量输入弹窗 */}
<Modal
visible={quantityInputVisible && !!user_id}
transparent
animationType="fade"
onRequestClose={() => setQuantityInputVisible(false)}
>
<View style={styles.overlay}>
<View style={styles.popup}>
<Text style={styles.promptText}>{t("cart.modify_quantity")}</Text>
<TextInput
style={styles.quantityInput}
value={quantityInput}
onChangeText={setQuantityInput}
keyboardType="number-pad"
maxLength={3}
autoFocus
/>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[styles.cancelButton1, { width: "45%" }]}
onPress={() => {
setQuantityInputVisible(false);
setEditingItem(null);
setQuantityInput("");
}}
>
<Text style={styles.cancelText}>{t("cart.cancel")}</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.confirmButton,
{ width: "45%", backgroundColor: "#ff5100" },
]}
onPress={handleQuantityInputConfirm}
>
<Text style={styles.confirmText}>{t("cart.confirm")}</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
{/* 最小数量提示弹窗 */}
<Modal
visible={minQuantityModalVisible}
transparent
animationType="fade"
onRequestClose={() => setMinQuantityModalVisible(false)}
>
<View style={styles.overlay}>
<View style={[styles.popup, styles.minQuantityPopup]}>
<View style={styles.warningIconContainer}>
<IconComponent name="exclamation" size={28} color="#FF5100" />
</View>
<Text style={[styles.promptText, styles.minQuantityText]}>{minQuantityMessage}</Text>
<TouchableOpacity
style={[styles.confirmButton, styles.minQuantityButton]}
onPress={() => setMinQuantityModalVisible(false)}
>
<Text style={[styles.confirmText, styles.minQuantityButtonText]}>{t("cart.confirm")}</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: "#fff",
},
safeAreaContent: {
flex: 1,
paddingTop: Platform.OS === "android" ? 0 : 0,
},
container: {
flex: 1,
backgroundColor: "#fff",
},
shoppingCartLayout: {
flex: 1,
backgroundColor: "white",
},
scrollContainer: {
flex: 1,
},
scrollContentContainer: {
paddingBottom: widthUtils(100, 100).height,
},
productListingContainer: {
paddingTop: 3,
paddingLeft: 16,
paddingRight: 16,
},
shoppingCartSection: {
marginTop: 14,
},
productCardContainer7: {
flexDirection: "row",
alignItems: "center",
},
svgContainer: {
width: widthUtils(18, 18).width,
height: widthUtils(18, 18).height,
},
shoppingCartTitle: {
marginLeft: 8,
fontSize: fontSize(24),
fontFamily: "Segoe UI",
fontWeight: "600",
color: "black",
},
productCardListing: {
width: "100%",
paddingRight: 4,
paddingLeft: 4,
marginTop: 16,
},
productCardContainer5: {
flexDirection: "row",
gap: 10,
alignItems: "center",
},
svgContainer1: {
width: widthUtils(24, 24).width,
height: widthUtils(24, 24).height,
},
imageThumbnail: {
width: widthUtils(50, 50).width,
height: widthUtils(50, 50).height,
borderRadius: 5,
},
productInfoContainer2: {
flex: 1,
maxWidth: 288,
},
casualTextSnippet: {
width: "100%",
fontSize: fontSize(16),
lineHeight: fontSize(18),
fontFamily: "Segoe UI",
color: "black",
textAlign: "left",
},
productDetailsTextStyle1: {
marginTop: 5,
fontSize: fontSize(12),
fontFamily: "Segoe UI",
color: "#747474",
},
productCardContainer6: {
width: "100%",
marginTop: 11,
},
productCardContainer4: {
marginTop: 12,
marginBottom: 12,
},
productImageDisplayStyle: {
width: widthUtils(80, 80).width,
height: widthUtils(80, 80).height,
borderRadius: 5,
},
productCardWidget1: {
paddingBottom: 5,
flex: 1,
},
longLifeRougeStyle: {
paddingRight: 13,
paddingBottom: 4,
paddingLeft: 13,
paddingTop: 4,
fontFamily: "Segoe UI",
backgroundColor: "#f4f4f4",
borderRadius: 18,
alignSelf: "flex-start",
maxWidth: widthUtils(249, 249).width,
},
longLifeTextSnippet: {
color: "#747474",
fontSize: fontSize(16),
lineHeight: 15,
fontFamily: "Segoe UI",
},
productVariantButton: {
width: widthUtils(24, 80).width,
height: widthUtils(24, 80).height,
fontSize: fontSize(16),
fontFamily: "Segoe UI",
color: "#747474",
backgroundColor: "#f4f4f4",
borderRadius: 12,
justifyContent: "center",
alignItems: "center",
},
productCardContainer3: {
flexDirection: "row",
alignItems: "center",
marginTop: 8,
justifyContent: "flex-start",
},
productInfoContainer4: {
width: widthUtils(76, 76).width,
flexDirection: "row",
alignItems: "center",
marginLeft: 3.75,
},
productInfoContainer: {
flexDirection: "row",
alignItems: "center",
},
productCodeLabel: {
fontSize: fontSize(16),
lineHeight: 22,
fontFamily: "Segoe UI",
fontWeight: "700",
color: "#FF5100",
},
productDetailsTextStyle: {
fontSize: fontSize(10),
fontFamily: "Segoe UI",
fontWeight: "700",
color: "#FF5100",
lineHeight: fontSize(13),
marginLeft: 3,
},
productInfoContainer1: {
flexDirection: "row",
alignItems: "center",
marginLeft: 3.75,
marginBottom: 2,
},
priceInfoContainer1: {
paddingTop: 10,
paddingBottom: 5,
},
discountPriceLabel: {
fontSize: fontSize(12),
fontFamily: "PingFang SC",
fontWeight: "600",
color: "#9a9a9a",
textDecorationLine: 'line-through',
},
vipContainer: {
position: 'relative',
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
},
VipImg: {
width: widthUtils(28, 28).width,
height: widthUtils(28, 28).height,
},
discountPercentageTextStyle: {
position: 'absolute',
fontSize: fontSize(12),
fontFamily: "Segoe UI",
fontWeight: "900",
fontStyle: "italic",
color: "#4e2000",
textAlign: 'center',
},
borderBoxDivider: {
width: "100%",
marginTop: -4.75,
borderTopWidth: 1,
borderTopColor: "#9a9a9a",
},
discountInfoContainer1: {
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
marginLeft: 3.25,
width: widthUtils(22, 22).width,
height: widthUtils(22, 22).height,
},
svgContainer2: {
width: widthUtils(32, 32).width,
height: widthUtils(32, 32).height,
marginTop: -26,
},
priceSection: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
},
orderQuantityContainer: {
flexDirection: "row",
alignItems: "center",
marginLeft: 15,
alignSelf: "flex-end",
},
borderBoxDivider1: {
width: widthUtils(9, 9).width,
borderTopWidth: 1,
borderTopColor: "black",
},
svgContainer3: {
width: widthUtils(12, 12).width,
height: widthUtils(12, 12).height,
},
svgContainer4: {
width: 28,
height: 28,
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 0,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f5f5f5",
},
quantityLabelContainer: {
height: 28,
width: 40,
fontSize: fontSize(14),
fontFamily: "Segoe UI",
color: "black",
backgroundColor: "white",
borderTopWidth: 1,
borderBottomWidth: 1,
borderColor: "#ddd",
justifyContent: "center",
alignItems: "center",
},
flexDivider: {
height: widthUtils(8, 8).height,
width: "120%",
marginLeft: -20,
},
productCardContainer2: {
padding: 12,
paddingLeft: 20,
paddingRight: 20,
paddingBottom: 16,
},
coffeeCupImage: {
width: widthUtils(50, 50).width,
height: widthUtils(50, 50).height,
borderRadius: 5,
marginLeft: 7,
},
coffeeCupDetailsContainer: {
marginLeft: 14,
},
coffeeCupDescriptionTextStyle: {
fontSize: fontSize(16),
lineHeight: fontSize(18),
fontFamily: "Segoe UI",
color: "black",
textAlign: "left",
},
productInfoTextStyle: {
marginTop: 3,
fontSize: fontSize(12),
fontFamily: "Segoe UI",
color: "#747474",
},
productCardWidget: {
flexDirection: "row",
gap: 10,
alignItems: "flex-start",
marginTop: 8,
},
svgContainer5: {
width: widthUtils(24, 24).width,
height: widthUtils(24, 24).height,
alignSelf: "center",
},
productCard: {
paddingBottom: 7,
},
productCardButton: {
width: widthUtils(24, 110).width,
height: widthUtils(24, 110).height,
minWidth: widthUtils(24, 110).width,
fontSize: fontSize(16),
fontFamily: "Segoe UI",
color: "#747474",
backgroundColor: "#f4f4f4",
borderRadius: 12,
justifyContent: "center",
alignItems: "center",
},
productCardDetails: {
flexDirection: "row",
alignItems: "flex-end",
marginTop: 16,
},
priceInfoContainer: {
flexDirection: "row",
alignItems: "flex-end",
},
orangeHighlightedText: {
fontSize: fontSize(20),
lineHeight: fontSize(22),
fontFamily: "Segoe UI",
fontWeight: "700",
color: "#FF5100",
},
highlightedText: {
fontSize: fontSize(11),
fontFamily: "Segoe UI",
fontWeight: "700",
color: "#FF5100",
marginLeft: -1,
},
priceTag: {
width: widthUtils(23, 62).width,
height: widthUtils(23, 62).height,
marginLeft: 4.75,
},
discountInfoContainer: {
flexDirection: "row",
alignItems: "center",
marginLeft: 3,
},
centerContentSvg: {
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
},
emphasizedPercentageText: {
fontSize: fontSize(11),
fontFamily: "Segoe UI",
fontWeight: "900",
fontStyle: "italic",
color: "#4e2000",
},
horizontalTextContainer: {
flexDirection: "row",
alignItems: "center",
marginLeft: 14.5,
},
numericBadge: {
height: widthUtils(24, 24).height,
paddingHorizontal: 15,
marginLeft: 7.5,
fontSize: fontSize(14),
fontFamily: "Segoe UI",
color: "black",
backgroundColor: "#f4f4f4",
borderRadius: 5,
justifyContent: "center",
alignItems: "center",
},
productCardContainer: {
padding: 17,
paddingLeft: 20,
paddingRight: 20,
paddingBottom: 14,
},
textInfoStyle: {
marginTop: 2,
fontSize: fontSize(12),
fontFamily: "Segoe UI",
color: "#747474",
},
productCardContainer1: {
height: widthUtils(80, 80).height,
justifyContent: "center",
},
productDescriptionStyle: {
paddingRight: 13,
paddingBottom: 4,
paddingLeft: 13,
fontSize: fontSize(13),
lineHeight: 15,
fontFamily: "Segoe UI",
color: "#747474",
textAlign: "left",
backgroundColor: "#f4f4f4",
borderRadius: 18,
},
productPriceDiscountBadge: {
flexDirection: "row",
alignItems: "center",
marginTop: 4,
},
priceContainer: {
flexDirection: "row",
alignItems: "stretch",
height: widthUtils(24, 24).height,
},
verticalPriceContainer: {
flexDirection: "column",
alignItems: "stretch",
justifyContent: "center",
marginLeft: 3.75,
},
priceLabel1: {
fontSize: fontSize(12),
fontFamily: "PingFang SC",
fontWeight: "600",
color: "#9a9a9a",
alignSelf: "center",
},
priceDivider: {
marginTop: -4.75,
borderTopWidth: 1,
borderTopColor: "#9a9a9a",
},
discountInfoContainer2: {
flexDirection: "row",
alignItems: "center",
marginLeft: 3.25,
},
orderSummaryHeader: {
flexDirection: "row",
alignItems: "center",
height: widthUtils(33, 33).height,
paddingRight: 20,
paddingLeft: 20,
backgroundColor:
"linear-gradient(90deg, rgba(255, 231, 213, 1) 0%, rgba(255, 218, 218, 1) 98.56%)",
borderRadius: 10,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
},
svgContainer6: {
width: widthUtils(18, 18).width,
height: widthUtils(18, 18).height,
},
orderQuantityInfo: {
marginLeft: 7,
fontSize: fontSize(14),
fontFamily: "Segoe UI",
color: "black",
},
tiltWarpText: {
fontSize: fontSize(14),
fontFamily: "Tilt Warp",
},
flexboxContainerWithButton: {
flexDirection: "row",
gap: 8,
alignItems: "center",
justifyContent: "space-between",
height: widthUtils(70, 70).height,
paddingRight: 20,
paddingLeft: 20,
width: "100%",
},
headerTitle: {
marginLeft: 7,
fontSize: fontSize(14),
fontFamily: "Segoe UI",
fontWeight: "600",
color: "black",
},
highlightedText1: {
fontSize: fontSize(20),
fontFamily: "Segoe UI",
fontWeight: "700",
color: "black",
},
priceLabel: {
fontSize: fontSize(10),
fontFamily: "Segoe UI",
fontWeight: "700",
color: "black",
lineHeight: fontSize(13),
marginTop: fontSize(-8),
},
submitButtonStyle: {
width: widthUtils(50, 160).width,
height: widthUtils(50, 160).height,
minWidth: widthUtils(50, 160).width,
marginLeft: 11.5,
fontSize: fontSize(18),
lineHeight: fontSize(22),
fontFamily: "Segoe UI",
fontWeight: "700",
color: "white",
backgroundColor: "#FF5100",
borderRadius: 30,
justifyContent: "center",
alignItems: "center",
},
fixedBottomContainer: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
backgroundColor: "white",
},
iconContainer: {
width: widthUtils(24, 24).width,
height: widthUtils(24, 24).height,
justifyContent: "center",
alignItems: "center",
borderRadius: 12,
},
selectedIconContainer: {
backgroundColor: "#ff5217",
},
checkmark: {
color: "white",
fontSize: fontSize(16),
fontWeight: "bold",
},
modalOverlay: {
flex: 1,
backgroundColor: "rgba(0, 0, 0, 0.5)",
justifyContent: "center",
alignItems: "center",
},
modalContent: {
backgroundColor: "white",
borderRadius: 10,
padding: 20,
width: "80%",
alignItems: "center",
},
modalTitle: {
fontSize: fontSize(18),
fontWeight: "bold",
marginBottom: 10,
},
modalMessage: {
fontSize: fontSize(16),
marginBottom: 20,
textAlign: "center",
},
modalButtons: {
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
},
modalButton: {
paddingVertical: 10,
paddingHorizontal: 20,
borderRadius: 5,
width: "45%",
alignItems: "center",
},
cancelButton: {
backgroundColor: "#f0f0f0",
},
deleteButton: {
backgroundColor: "#ff5217",
},
cancelButtonText: {
color: "#333",
fontSize: fontSize(16),
fontWeight: "500",
},
deleteButtonText: {
color: "white",
fontSize: fontSize(16),
fontWeight: "500",
},
overlay: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.4)",
justifyContent: "center",
alignItems: "center",
},
popup: {
backgroundColor: "white",
borderRadius: 10,
paddingVertical: 27,
paddingHorizontal: 20,
alignItems: "center",
gap: 21,
width: "80%",
},
image: {
width: 80,
height: 80,
borderRadius: 5,
resizeMode: "cover",
},
promptText: {
fontSize: 20,
fontWeight: "600",
color: "black",
fontFamily: "Segoe UI", // 注意要在项目中配置字体
},
buttonContainer: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
width: "100%",
marginTop: 20,
gap: 20,
},
cancelButton1: {
minWidth: 120,
height: 50,
borderRadius: 30,
backgroundColor: "#f2f3f5",
justifyContent: "center",
alignItems: "center",
},
confirmButton: {
minWidth: 120,
height: 50,
borderRadius: 30,
backgroundColor: "#ff5100",
justifyContent: "center",
alignItems: "center",
marginLeft: 20,
},
cancelText: {
fontSize: 16,
fontWeight: "500",
color: "#333333",
fontFamily: "Source Han Sans CN", // 注意要在项目中配置字体
},
confirmText: {
fontSize: 16,
fontWeight: "500",
color: "#ffffff",
fontFamily: "Source Han Sans CN", // 同上
},
quantityText: {
fontSize: fontSize(16),
color: "#333",
fontWeight: "600",
},
quantityButtonText: {
fontSize: fontSize(18),
color: "#333",
fontWeight: "500",
},
quantityInput: {
width: "100%",
height: 40,
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 5,
paddingHorizontal: 10,
fontSize: fontSize(16),
textAlign: "center",
},
priceColumnContainer: {
flexDirection: "column",
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',
},
warningIconContainer: {
backgroundColor: "#FFF2E9",
borderRadius: 20,
padding: 12,
marginBottom: 16,
alignSelf: 'center',
width: 52,
height: 52,
justifyContent: 'center',
alignItems: 'center',
},
warningIcon: {
width: 32,
height: 32,
},
minQuantityPopup: {
width: '80%',
padding: 24,
},
minQuantityText: {
fontSize: fontSize(16),
color: '#333',
marginVertical: 16,
textAlign: 'center',
lineHeight: fontSize(22),
fontWeight: '500',
},
minQuantityButton: {
width: '100%',
height: 44,
borderRadius: 22,
backgroundColor: '#FF5100',
marginTop: 16,
},
minQuantityButtonText: {
fontSize: fontSize(16),
fontWeight: '600',
},
});