diff --git a/app/components/AddressIcon.tsx b/app/components/AddressIcon.tsx index 1158688..6000189 100644 --- a/app/components/AddressIcon.tsx +++ b/app/components/AddressIcon.tsx @@ -1,7 +1,7 @@ import React from 'react'; import Svg, { Path } from 'react-native-svg'; -const AddressIcon = ({size = 18}) => ( +const AddressIcon = ({size = 18, color = "#FB553C"}) => ( ( > ); diff --git a/app/components/BrightnessIcon.tsx b/app/components/BrightnessIcon.tsx new file mode 100644 index 0000000..650ec19 --- /dev/null +++ b/app/components/BrightnessIcon.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import Svg, { Path } from 'react-native-svg'; + +const BrightnessIcon = ({size = 20,color = '#3d3d3d'}:{size:number,color:string}) => ( + + + +); + +export default BrightnessIcon; \ No newline at end of file diff --git a/app/components/InfoIcon.tsx b/app/components/InfoIcon.tsx new file mode 100644 index 0000000..fac207e --- /dev/null +++ b/app/components/InfoIcon.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import Svg, { Path, Circle } from 'react-native-svg'; + +const InfoIcon = ({size = 20,color = "#3D3D3D"}:{size:number,color:string }) => ( + + {/* Outer circle */} + + + {/* Info line (i) */} + + + {/* Info dot (i) */} + + +); + +export default InfoIcon; \ No newline at end of file diff --git a/app/components/MyFavoriteIcon.tsx b/app/components/MyFavoriteIcon.tsx index e6df19d..b565252 100644 --- a/app/components/MyFavoriteIcon.tsx +++ b/app/components/MyFavoriteIcon.tsx @@ -1,7 +1,7 @@ import React from'react'; import { Svg, Path } from'react-native-svg'; -const MyFavoriteIcon = ({size}:{size:number}) => { +const MyFavoriteIcon = ({size,color}:{size:number,color:string}) => { return ( { > ); diff --git a/app/components/OrderIcon.tsx b/app/components/OrderIcon.tsx new file mode 100644 index 0000000..a1a2b8e --- /dev/null +++ b/app/components/OrderIcon.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import Svg, { Path } from 'react-native-svg'; + +const OrderIcon = ({size = 20,color = "#3D3D3D"}:{size:number,color:string}) => ( + + + +); + +export default OrderIcon; \ No newline at end of file diff --git a/app/components/PhoneIcon.tsx b/app/components/PhoneIcon.tsx new file mode 100644 index 0000000..566b015 --- /dev/null +++ b/app/components/PhoneIcon.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import Svg, { Path } from 'react-native-svg'; + +const PhoneIcon = ({size = 20,color = '#3d3d3d'}:{size:number,color:string}) => ( + + + +); + +export default PhoneIcon; \ No newline at end of file diff --git a/app/components/PowerIcon.tsx b/app/components/PowerIcon.tsx new file mode 100644 index 0000000..a8cbd09 --- /dev/null +++ b/app/components/PowerIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import Svg, { Path } from 'react-native-svg'; + +const PowerIcon = ({size, color}:{size: number, color: string}) => ( + + {/* Outer circle */} + + + {/* Power symbol */} + + +); + +export default PowerIcon; \ No newline at end of file diff --git a/app/components/ShareIcon.tsx b/app/components/ShareIcon.tsx new file mode 100644 index 0000000..bdf888b --- /dev/null +++ b/app/components/ShareIcon.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import Svg, { Path } from 'react-native-svg'; + +const ShareIcon = ({ size = 24, fill = '#373737' }) => ( + + + +); + +export default ShareIcon; \ No newline at end of file diff --git a/app/components/ShoppingBagIcon.tsx b/app/components/ShoppingBagIcon.tsx index c8c82d7..2df27ff 100644 --- a/app/components/ShoppingBagIcon.tsx +++ b/app/components/ShoppingBagIcon.tsx @@ -1,27 +1,21 @@ import React from 'react'; -import { Svg, Path, G, ClipPath, Rect, Defs } from 'react-native-svg'; +import { Svg, Path} from 'react-native-svg'; const ShoppingBagIcon = ({ - size = 18, + size = 16, color = "#FF5100", - strokeColor = "transparent", - strokeWidth = 0 + }) => ( - - - - - - - - - - + + + ); export default ShoppingBagIcon; \ No newline at end of file diff --git a/app/components/WatchAppIcon.tsx b/app/components/WatchAppIcon.tsx new file mode 100644 index 0000000..257de4c --- /dev/null +++ b/app/components/WatchAppIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import Svg, { Path } from 'react-native-svg'; + +const WatchAppIcon = ({size = 20,color = '#6ED65B'}:{size:number,color?:string}) => ( + + {/* Speech bubble tail */} + + + {/* Speech bubble body */} + + +); + +export default WatchAppIcon; \ No newline at end of file diff --git a/app/constants/productStatus.ts b/app/constants/productStatus.ts index a2f4653..30be0f5 100644 --- a/app/constants/productStatus.ts +++ b/app/constants/productStatus.ts @@ -7,12 +7,13 @@ interface ProductStatus { status: number | null; } export const productStatus: ProductStatus[] = [ - { icon: DocumentApprovedIcon, text: '待报价', status: 5 }, + { icon: DocumentApprovedIcon, text: '待报价', status: 8 }, { icon: PdfDocumentIcon, text: '待付款', status: 0 }, { icon: DocumentClockIcon, text: '付运费', status: 6 }, { icon: DocumentClockIcon, text: '待发货', status: 1 }, { icon: DocumentApprovedIcon, text: '运输中', status: 7 }, { icon: DocumentApprovedIcon, text: '代收货', status: 2 }, { icon: PdfDocumentIcon, text: '已完成', status: 3 }, - { icon: DocumentClockIcon, text: '已取消', status: 4 } + { icon: DocumentClockIcon, text: '已取消', status: 4 }, + { icon: DocumentClockIcon, text: '已退款', status: 5 } ] \ No newline at end of file diff --git a/app/screens/HomeScreen.tsx b/app/screens/HomeScreen.tsx index b6ddb67..68f0c7c 100644 --- a/app/screens/HomeScreen.tsx +++ b/app/screens/HomeScreen.tsx @@ -24,7 +24,6 @@ import Ionicons from "@expo/vector-icons/Ionicons"; import { useNavigation } from "@react-navigation/native"; import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { useTranslation } from "react-i18next"; -import Swiper from "react-native-swiper"; import widthUtils from "../utils/widthUtils"; import DownArrowIcon from "../components/DownArrowIcon"; import { LinearGradient } from "expo-linear-gradient"; @@ -91,13 +90,15 @@ export const HomeScreen = () => { } }; - const handleProductPress = (item: Product) => { - navigation.navigate("ProductDetail", { - offer_id: item.offer_id, - searchKeyword: searchParams.keyword, - price: item.min_price, + const handleProductPress = useCallback((item: Product) => { + InteractionManager.runAfterInteractions(() => { + navigation.navigate("ProductDetail", { + offer_id: item.offer_id, + searchKeyword: searchParams.keyword, + price: item.min_price, + }); }); - }; + }, [navigation]); const onRefresh = useCallback(async () => { setRefreshing(true); @@ -164,6 +165,18 @@ export const HomeScreen = () => { }); }, [navigation]); + const navigateToShippingDetails = useCallback(() => { + InteractionManager.runAfterInteractions(() => { + navigation.navigate("ShippingDetailsSection"); + }); + }, [navigation]); + + const navigateToInquiry = useCallback(() => { + InteractionManager.runAfterInteractions(() => { + navigation.navigate("InquiryScreen"); + }); + }, [navigation]); + const scrollToCategory = (category: string) => { const categoryIndex = categories.findIndex((c) => c === category); if (categoryIndex !== -1 && horizontalScrollRef.current) { @@ -297,7 +310,7 @@ export const HomeScreen = () => { navigation.navigate("ShippingDetailsSection")} + onPress={navigateToShippingDetails} > { {/* 右侧区域 - 一个 */} navigation.navigate("InquiryScreen")} + onPress={navigateToInquiry} > = ({ // 关闭确认对话框 setDeleteModalVisible(false); }; + + const handleNavigateToCart = useCallback(() => { + setDeleteModalVisible(false); + InteractionManager.runAfterInteractions(() => { + navigation.navigate("MainTabs", { screen: "Cart" }); + }); + }, [navigation]); + return ( @@ -901,7 +910,7 @@ const ProductCard: React.FC = ({ Non - navigation.navigate("MainTabs", { screen: "Cart" })}> + Voir le panier diff --git a/app/screens/ProductDetailScreen.tsx b/app/screens/ProductDetailScreen.tsx index 372a95d..c7da772 100644 --- a/app/screens/ProductDetailScreen.tsx +++ b/app/screens/ProductDetailScreen.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useCallback } from "react"; import { View, Text, @@ -11,6 +11,8 @@ import { Animated, BackHandler, ActivityIndicator, + Alert, + InteractionManager, } from "react-native"; import fontSize from "../utils/fontsizeUtils"; import widthUtils from "../utils/widthUtils"; @@ -18,13 +20,17 @@ import DiagonalArrowIcon from "../components/DiagonalArrowIcon"; import Carousel from "react-native-reanimated-carousel"; import WhiteCircleIcon from "../components/WhiteCircleIconIcon"; import ShoppingCartIcon from "../components/ShoppingCartIcon"; +import HeartIcon from "../components/HeartIcon"; +import HeartRedIcon from "../components/HeartIconRed"; +import ShareIcon from "../components/ShareIcon"; import { useState } from "react"; import { productApi, ProductDetailParams, Similars, SkuAttribute, - ProductGroupList + ProductGroupList, + similar, } from "../services/api/productApi"; import { useNavigation, useRoute } from "@react-navigation/native"; import { NativeStackNavigationProp } from "@react-navigation/native-stack"; @@ -38,8 +44,6 @@ type ProductDetailRouteParams = { price: number; }; - - export const ProductDetailScreen = () => { const { width } = useWindowDimensions(); // 移动到组件内部 const navigation = useNavigation>(); @@ -50,6 +54,7 @@ export const ProductDetailScreen = () => { const [expandedGroups, setExpandedGroups] = useState<{ [key: string]: boolean; }>({}); + const [isHeartRed, setIsHeartRed] = useState(false); const [product, setProduct] = useState(); const [groupList, setGroupList] = useState([]); @@ -58,11 +63,16 @@ export const ProductDetailScreen = () => { const [similars, setSimilars] = useState(); const [isSimilarsFlag, setIsSimilarsFlag] = useState(false); const [imageUrls, setImageUrls] = useState([]); - const [imageHeights, setImageHeights] = useState<{ [key: string]: number }>({}); + const [imageHeights, setImageHeights] = useState<{ [key: string]: number }>( + {} + ); const [priceSelectedSku, setPriceSelectedSku] = useState(); const [showBottomSheet, setShowBottomSheet] = useState(false); - const groupData = (res: ProductDetailParams,priceSelectedSku:SkuAttribute[]) => { + const groupData = ( + res: ProductDetailParams, + priceSelectedSku: SkuAttribute[] + ) => { let result = {} as any; // 遍历数据 res.skus.forEach((item) => { @@ -72,7 +82,7 @@ export const ProductDetailScreen = () => { if (!result[attribute_name]) { result[attribute_name] = []; } - + // 如果当前属性的值(value)已经存在于该组内,跳过 if ( !result[attribute_name].some( @@ -83,14 +93,14 @@ export const ProductDetailScreen = () => { } }); }); - + const list: ProductGroupList[] = []; - + // Iterate over each attribute and transform the data for (const [attributeName, attributes] of Object.entries(result)) { const withImage: any[] = []; const withoutImage: any[] = []; - + // @ts-ignore attributes.forEach((attribute) => { attribute.has_color = false; @@ -98,7 +108,7 @@ export const ProductDetailScreen = () => { const hasImage = attribute.sku_image_url !== null && attribute.sku_image_url !== undefined; - + // Push the attribute to the appropriate array if (hasImage) { withImage.push(attribute); @@ -106,7 +116,7 @@ export const ProductDetailScreen = () => { withoutImage.push(attribute); } }); - + // Add has_image to the list item list.push({ attribute_name: attributeName, @@ -115,28 +125,28 @@ export const ProductDetailScreen = () => { }); } - if(!priceSelectedSku){ - list.forEach(item => { + if (!priceSelectedSku) { + list.forEach((item) => { item.attributes[0].has_color = true; - }) + }); return list; } - - if(priceSelectedSku.length >= 1){ - priceSelectedSku.forEach(item => { - list.forEach(item1 => { - item1.attributes.forEach(attribute => { - if(attribute.value === item.value){ + + if (priceSelectedSku.length >= 1) { + priceSelectedSku.forEach((item) => { + list.forEach((item1) => { + item1.attributes.forEach((attribute) => { + if (attribute.value === item.value) { attribute.has_color = true; } - }) - }) - }) + }); + }); + }); return list; } return list; }; - + // 处理展开/收起 const toggleExpand = (attributeName: string) => { setExpandedGroups((prev) => ({ @@ -170,32 +180,35 @@ export const ProductDetailScreen = () => { ); setGroupList(newGroupList); } - const selectedSku:SkuAttribute[] = [] - groupList.forEach(item => { - item.attributes.forEach(attribute => { - if(attribute.has_color){ + const selectedSku: SkuAttribute[] = []; + groupList.forEach((item) => { + item.attributes.forEach((attribute) => { + if (attribute.has_color) { selectedSku.push(attribute); } - }) - }) - - let price = 0 - product?.skus.forEach(item => { - const values1 = item.attributes.map(item => item.value).sort(); - const values2 = selectedSku.map(item => item.value).sort(); - if(values1.every((val, index) => val === values2[index])){ - if(item.offer_price){ - price = item.offer_price - }else{ - price = product.sale_info.price_range_list[product.sale_info.price_range_list.length - 1].price + }); + }); + + let price = 0; + product?.skus.forEach((item) => { + const values1 = item.attributes.map((item) => item.value).sort(); + const values2 = selectedSku.map((item) => item.value).sort(); + if (values1.every((val, index) => val === values2[index])) { + if (item.offer_price) { + price = item.offer_price; + } else { + price = + product.sale_info.price_range_list[ + product.sale_info.price_range_list.length - 1 + ].price; } } - }) - if(product) { + }); + if (product) { setProduct({ ...product, - price: price === 0 ? '无货' : price - }) + price: price === 0 ? "无货" : price, + }); } }; @@ -216,34 +229,37 @@ export const ProductDetailScreen = () => { ); setGroupList(newGroupList); } - - const selectedSku:SkuAttribute[] = [] - groupList.forEach(item => { - item.attributes.forEach(attribute => { - if(attribute.has_color){ + + const selectedSku: SkuAttribute[] = []; + groupList.forEach((item) => { + item.attributes.forEach((attribute) => { + if (attribute.has_color) { selectedSku.push(attribute); } - }) - }) - - let price = 0 - product?.skus.forEach(item => { - const values1 = item.attributes.map(item => item.value).sort(); - const values2 = selectedSku.map(item => item.value).sort(); - - if(values1.every((val, index) => val === values2[index])){ - if(item.offer_price){ - price = item.offer_price - }else{ - price = product?.sale_info?.price_range_list[product?.sale_info?.price_range_list?.length - 1]?.price + }); + }); + + let price = 0; + product?.skus.forEach((item) => { + const values1 = item.attributes.map((item) => item.value).sort(); + const values2 = selectedSku.map((item) => item.value).sort(); + + if (values1.every((val, index) => val === values2[index])) { + if (item.offer_price) { + price = item.offer_price; + } else { + price = + product?.sale_info?.price_range_list[ + product?.sale_info?.price_range_list?.length - 1 + ]?.price; } } - }) - if(product) { + }); + if (product) { setProduct({ ...product, - price: price === 0 ? '无货' : price - }) + price: price === 0 ? "无货" : price, + }); } }; @@ -259,26 +275,31 @@ export const ProductDetailScreen = () => { if (priceSelectedSku) { res.price = priceSelectedSku.offer_price; } else { - res.price = res?.sale_info?.price_range_list[res?.sale_info?.price_range_list?.length - 1]?.price; + res.price = + res?.sale_info?.price_range_list[ + res?.sale_info?.price_range_list?.length - 1 + ]?.price; } - }else{ - res.price = route.params.price + } else { + res.price = route.params.price; } if (res.skus != null) { - const priceSelectedSku = res.skus.find(item => item.offer_price === route.params.price) - if (priceSelectedSku) { - setPriceSelectedSku({ - price:route.params.price, - }) - } - } - setPriceSelectedSku(priceSelectedSku) + const priceSelectedSku = res.skus.find( + (item) => item.offer_price === route.params.price + ); + if (priceSelectedSku) { + setPriceSelectedSku({ + price: route.params.price, + }); + } + } + setPriceSelectedSku(priceSelectedSku); setProduct(res); - let list:ProductGroupList[] = [] - if(res.skus != null){ - list = groupData(res,priceSelectedSku?.attributes as SkuAttribute[]); - }else{ - list = [] + let list: ProductGroupList[] = []; + if (res.skus != null) { + list = groupData(res, priceSelectedSku?.attributes as SkuAttribute[]); + } else { + list = []; } const imageUrls = []; const regex = /]+src="([^"]+)"/g; @@ -307,13 +328,16 @@ export const ProductDetailScreen = () => { }, []); useEffect(() => { - const backHandler = BackHandler.addEventListener('hardwareBackPress', () => { - if (showBottomSheet) { - setShowBottomSheet(false); - return true; + const backHandler = BackHandler.addEventListener( + "hardwareBackPress", + () => { + if (showBottomSheet) { + setShowBottomSheet(false); + return true; + } + return false; } - return false; - }); + ); return () => backHandler.remove(); }, [showBottomSheet]); @@ -322,12 +346,30 @@ export const ProductDetailScreen = () => { const { width: imageWidth, height: imageHeight } = event.nativeEvent.source; const aspectRatio = imageHeight / imageWidth; const calculatedHeight = width * aspectRatio; - setImageHeights(prev => ({ + setImageHeights((prev) => ({ ...prev, - [src]: calculatedHeight + [src]: calculatedHeight, })); }; + const handleSearchPress = useCallback(() => { + InteractionManager.runAfterInteractions(() => { + navigation.navigate("Search"); + }); + }, [navigation]); + + const handleProductPress = useCallback( + (item: similar) => { + InteractionManager.runAfterInteractions(() => { + navigation.push("ProductDetail", { + offer_id: item.offer_id, + price: item.min_price, + }); + }); + }, + [navigation] + ); + return ( {isLoading ? ( @@ -337,42 +379,26 @@ export const ProductDetailScreen = () => { ) : ( <> + + + + + + 搜索 + + + { + navigation.navigate('MainTabs', { screen: 'Cart' }) + }}> + + + + - - - { - if (showBottomSheet) { - setShowBottomSheet(false); - } else { - navigation.goBack(); - } - }}> - - - - - - - Recherche - - - {/* Replace with your SVG component or icon */} - - - - - {/* Replace with your SVG component or icon */} - - - {/* Replace with your SVG component or icon */} - - - - { )} /> + + { + setIsHeartRed(!isHeartRed); + Alert.alert("收藏成功", "是否我的查看收藏", [ + { + text: "取消", + onPress: () => console.log("取消 pressed"), + style: "cancel", + }, + { + text: "确定", + onPress: () => console.log("确定 pressed"), + }, + ]); + }} + > + {isHeartRed ? ( + + ) : ( + + )} + + + {/* 底部指示灯 - 固定在右下角 */} { - {product?.price} + + {product?.price} + FCFA 3000FCFA @@ -468,7 +533,11 @@ export const ProductDetailScreen = () => { item.has_image ? ( - {item.attribute_name} : {item.attributes.find(item => item.has_color)?.value} + {item.attribute_name} :{" "} + { + item.attributes.find((item) => item.has_color) + ?.value + } {getDisplayAttributes( @@ -502,7 +571,7 @@ export const ProductDetailScreen = () => { } > - 更多 + +{item.attributes.length - 6} )} @@ -510,31 +579,37 @@ export const ProductDetailScreen = () => { {expandedGroups[item.attribute_name] && ( toggleExpand(item.attribute_name)} + onPress={() => + toggleExpand(item.attribute_name) + } > - 收起 + + 收起 + )} - - { - groupList.length > 1 && index === 0 && ( - setShowBottomSheet(true)}> - - - - - ) - } - { - groupList.length === 1 && index === 0 && ( - setShowBottomSheet(true)}> - - - - - ) - } + + {groupList.length > 1 && index === 0 && ( + setShowBottomSheet(true)} + > + + + + + )} + {groupList.length === 1 && index === 0 && ( + setShowBottomSheet(true)} + > + + + + + )} ) : ( @@ -587,31 +662,37 @@ export const ProductDetailScreen = () => { {expandedGroups[item.attribute_name] && ( toggleExpand(item.attribute_name)} + onPress={() => + toggleExpand(item.attribute_name) + } > - 收起 + + 收起 + )} - { - groupList.length === 1 && ( - setShowBottomSheet(true)}> - - - - - ) - } + {groupList.length === 1 && ( + setShowBottomSheet(true)} + > + + + + + )} - { - groupList.length === 2 && index === 0 && ( - setShowBottomSheet(true)}> - - - - - ) - } + {groupList.length === 2 && index === 0 && ( + setShowBottomSheet(true)} + > + + + + + )} ) )} @@ -623,7 +704,7 @@ export const ProductDetailScreen = () => { More from this store - View All + {/* View All */} { > {isSimilarsFlag && similars?.map((item) => ( - + handleProductPress(item)} + > { FCFA - + ))} @@ -678,7 +763,7 @@ export const ProductDetailScreen = () => { setShowBottomSheet(true)} + onPress={() => setShowBottomSheet(true)} > addToCart @@ -686,15 +771,15 @@ export const ProductDetailScreen = () => { {showBottomSheet && product && ( - - - setShowBottomSheet(false)} product={product} groupList={groupList}> - - + + + setShowBottomSheet(false)} + product={product} + groupList={groupList} + > + + )} )} @@ -707,8 +792,41 @@ const styles = StyleSheet.create({ flex: 1, backgroundColor: "white", }, + headerBox: { + width: "100%", + padding: 10, + justifyContent: "space-between", + flexDirection: "row", + alignItems:'center', + backgroundColor:'#fff' + }, + backIcon:{ + width:'5%', + alignItems:'flex-end' + }, + search:{ + width:'70%', + padding:15, + backgroundColor:'#f4f4f4', + borderWidth:1, + borderColor:'#eeeeee', + borderRadius:25, + flexDirection:'row', + alignItems:'center', + justifyContent:'space-between' + }, + searchText:{ + fontSize:fontSize(16), + color:'#747474', + fontWeight:'600' + }, + searchIcon:{ + alignItems:'center', + justifyContent:'space-between', + flexDirection:'row', + width:'15%' + }, scrollViewContent: { - flexGrow: 1, }, productDetailsContainer3: { flexDirection: "column", @@ -740,53 +858,59 @@ const styles = StyleSheet.create({ textAlign: "center", }, timeDisplayContainer: { - width: widthUtils(54,154).width, - height: widthUtils(54,54).height, + width: widthUtils(54, 154).width, + height: widthUtils(54, 54).height, }, searchContainer1: { flexDirection: "row", alignItems: "center", - justifyContent: "flex-start", + justifyContent: "space-between", marginTop: 2, + width: "100%", }, - svgContainer: { - width: widthUtils(18,18).width, - height: widthUtils(18,18).height, + backButtonContainer: { + width: "10%", + alignItems: "flex-start", }, searchContainer2: { - flex: 1, + width: "70%", flexDirection: "row", - gap: 8, alignItems: "center", - justifyContent: "space-between", - height: widthUtils(50,50).height, - paddingRight: 20, - paddingLeft: 16, - marginLeft: 4, + height: widthUtils(50, 50).height, + paddingRight: 10, + paddingLeft: 10, backgroundColor: "#f4f4f4", borderWidth: 1, borderColor: "#eeeeee", borderRadius: 25, + marginRight: 10, }, - searchTitleTextStyle: { - fontWeight: "600", - fontSize: fontSize(16), - color: "#747474", + iconsContainer: { + width: "20%", + flexDirection: "row", + alignItems: "center", + justifyContent: "flex-start", + }, + svgContainer: { + width: widthUtils(18, 18).width, + height: widthUtils(18, 18).height, }, svgContainer1: { - width: widthUtils(24,24).width, - height: widthUtils(24,24).height, + width: widthUtils(24, 24).width, + height: widthUtils(24, 24).height, color: "#373737", - }, - searchContainer: { - flexDirection: "row", + justifyContent: "center", alignItems: "center", - justifyContent: "flex-start", - marginLeft: 9, + }, + searchTitleTextStyle: { + fontWeight: "600", + fontSize: fontSize(16), + color: "#747474", + flex: 1, }, svgContainer2: { - width: widthUtils(24,24).width, - height: widthUtils(24,24).height, + width: widthUtils(24, 24).width, + height: widthUtils(24, 24).height, marginLeft: 11, color: "#373737", }, @@ -812,8 +936,8 @@ const styles = StyleSheet.create({ flexDirection: "column", alignItems: "center", justifyContent: "center", - width: widthUtils(40,40).width, - height: widthUtils(40,40).height, + width: widthUtils(40, 40).width, + height: widthUtils(40, 40).height, backgroundColor: "#efefef", borderRadius: 25, }, @@ -821,8 +945,8 @@ const styles = StyleSheet.create({ flexDirection: "column", alignItems: "center", justifyContent: "center", - width: widthUtils(60,60).width, - height: widthUtils(60,60).height, + width: widthUtils(60, 60).width, + height: widthUtils(60, 60).height, marginTop: 125, backgroundColor: "rgba(92, 92, 92, 0.6)", borderWidth: 1, @@ -830,14 +954,14 @@ const styles = StyleSheet.create({ borderRadius: 35, }, svgContainer3: { - width: widthUtils(20,20).width, - height: widthUtils(20,20).height, + width: widthUtils(20, 20).width, + height: widthUtils(20, 20).height, color: "#ffffff", }, darkButton: { alignSelf: "flex-end", - width: widthUtils(26,50).width, - height: widthUtils(26,50).height, + width: widthUtils(26, 50).width, + height: widthUtils(26, 50).height, minWidth: 50, marginTop: 147, @@ -924,8 +1048,8 @@ const styles = StyleSheet.create({ color: "#4e2000", }, svgContainer4: { - width: widthUtils(32,32).width, - height: widthUtils(32,32).height, + width: widthUtils(32, 32).width, + height: widthUtils(32, 32).height, marginTop: -26, }, specialHighlightedSection: { @@ -933,8 +1057,8 @@ const styles = StyleSheet.create({ marginLeft: -1.75, }, svgContainer5: { - width: widthUtils(10,10).width, - height: widthUtils(10,10).height, + width: widthUtils(10, 10).width, + height: widthUtils(10, 10).height, color: "#3b3b3b", }, vipStatusContainer: { @@ -1000,25 +1124,25 @@ const styles = StyleSheet.create({ marginTop: 8, }, imageContainer: { - width: widthUtils(40,40).width, - height: widthUtils(40,40).height, + width: widthUtils(40, 40).width, + height: widthUtils(40, 40).height, borderRadius: 5, }, centerBox: { flexDirection: "column", alignItems: "stretch", justifyContent: "center", - width: widthUtils(40,40).width, + width: widthUtils(40, 40).width, backgroundColor: "#e0e0e0", borderRadius: 5, }, imageContainerStyles: { - height: widthUtils(40,40).height, + height: widthUtils(40, 40).height, }, svgContainer6: { alignSelf: "flex-end", - width: widthUtils(18,18).width, - height: widthUtils(18,18).height, + width: widthUtils(18, 18).width, + height: widthUtils(18, 18).height, }, sizeSelector: { marginTop: 0, @@ -1076,20 +1200,18 @@ const styles = StyleSheet.create({ expandButton: { alignItems: "center", justifyContent: "center", - height: widthUtils(30, 40).height, + height: widthUtils(38, 38).height, paddingHorizontal: 11, fontWeight: "600", fontSize: fontSize(14), color: "#ff5100", - backgroundColor: "#fff5f0", borderRadius: 5, lineHeight: widthUtils(40, 40).height, marginBottom: 10, - borderWidth: 1, - borderColor: "#ff5100", + backgroundColor: "#efefef", }, expandButtonText: { - color: "#ff5100", + color: "#b7b7b7", fontWeight: "600", }, storeRecommendationsContainer: { @@ -1126,8 +1248,8 @@ const styles = StyleSheet.create({ paddingRight: 10, }, productCard: { - width: widthUtils(115,90).width, - height: widthUtils(115,90).height, + width: widthUtils(115, 90).width, + height: widthUtils(115, 90).height, marginRight: 10, }, cardContainerWithPrice: { @@ -1139,8 +1261,8 @@ const styles = StyleSheet.create({ borderRadius: 5, }, imageContainerCompact: { - height: widthUtils(90,90).height, - width: widthUtils(90,90).width, + height: widthUtils(90, 90).height, + width: widthUtils(90, 90).width, }, priceContainerFlex: { flexDirection: "row", @@ -1162,13 +1284,13 @@ const styles = StyleSheet.create({ }, productImageContainer: { width: "100%", - height: widthUtils(90,90).height, + height: widthUtils(90, 90).height, borderRadius: 5, }, orangeHighlightTextStyle: { fontWeight: "700", fontSize: fontSize(16), - lineHeight: widthUtils(20,20).height, + lineHeight: widthUtils(20, 20).height, marginTop: 2, color: "#ff5100", }, @@ -1190,7 +1312,7 @@ const styles = StyleSheet.create({ marginTop: 8, fontWeight: "400", fontSize: fontSize(14), - lineHeight: widthUtils(20,20).height, + lineHeight: widthUtils(20, 20).height, color: "#373737", textAlign: "left", }, @@ -1200,14 +1322,14 @@ const styles = StyleSheet.create({ marginLeft: 20, }, imageContainerStyles1: { - width: widthUtils(229,390).width, - height: widthUtils(229,390).height, + width: widthUtils(229, 390).width, + height: widthUtils(229, 390).height, }, flexCenterButtons: { flexDirection: "row", alignItems: "center", justifyContent: "center", - height: widthUtils(64,64).height, + height: widthUtils(64, 64).height, paddingRight: 20, paddingLeft: 20, marginTop: -64, @@ -1218,8 +1340,8 @@ const styles = StyleSheet.create({ alignItems: "center", justifyContent: "center", gap: 4, - width: widthUtils(50,160).width, - height: widthUtils(50,160).height, + width: widthUtils(50, 160).width, + height: widthUtils(50, 160).height, minWidth: 160, fontWeight: "700", fontSize: fontSize(18), @@ -1230,8 +1352,8 @@ const styles = StyleSheet.create({ borderRadius: 30, }, svgContainer7: { - width: widthUtils(24,24).width, - height: widthUtils(24,24).height, + width: widthUtils(24, 24).width, + height: widthUtils(24, 24).height, color: "#ffffff", }, orangeGradientButton: { @@ -1239,8 +1361,8 @@ const styles = StyleSheet.create({ alignItems: "center", justifyContent: "center", gap: 7, - width: widthUtils(50,220).width, - height: widthUtils(50,220).height, + width: widthUtils(50, 220).width, + height: widthUtils(50, 220).height, minWidth: 220, marginLeft: 10, fontWeight: "700", @@ -1279,7 +1401,7 @@ const styles = StyleSheet.create({ paddingHorizontal: 15, backgroundColor: "transparent", zIndex: 100, - height: widthUtils(60,60).height, + height: widthUtils(60, 60).height, }, chatNowButton: { width: "40%", @@ -1305,7 +1427,7 @@ const styles = StyleSheet.create({ }, addToCartButton: { width: "60%", - height: widthUtils(50,50).height, + height: widthUtils(50, 50).height, flexDirection: "row", alignItems: "center", justifyContent: "center", @@ -1326,23 +1448,23 @@ const styles = StyleSheet.create({ marginLeft: 8, }, modalContainer: { - backgroundColor: 'rgba(0, 0, 0, 0.5)', - justifyContent: 'flex-end', + backgroundColor: "rgba(0, 0, 0, 0.5)", + justifyContent: "flex-end", }, modalContent: { - height: '90%', - backgroundColor: 'white', + height: "90%", + backgroundColor: "white", borderTopLeftRadius: 20, borderTopRightRadius: 20, padding: 20, }, closeButton: { - alignSelf: 'flex-end', + alignSelf: "flex-end", padding: 10, }, closeButtonText: { fontSize: fontSize(16), - color: '#333', + color: "#333", }, bottomSheetOverlay: { position: "absolute", @@ -1362,13 +1484,13 @@ const styles = StyleSheet.create({ }, loadingContainer: { flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: 'white', + justifyContent: "center", + alignItems: "center", + backgroundColor: "white", }, loadingText: { marginTop: 10, fontSize: fontSize(16), - color: '#666', + color: "#666", }, }); diff --git a/app/screens/productStatus/OrderDatails.tsx b/app/screens/productStatus/OrderDatails.tsx index a505e3f..41176c2 100644 --- a/app/screens/productStatus/OrderDatails.tsx +++ b/app/screens/productStatus/OrderDatails.tsx @@ -1,13 +1,690 @@ -import React from 'react'; -import { View, Text, StyleSheet } from 'react-native'; - +import React, { useEffect, useState } from "react"; +import { + View, + Text, + StyleSheet, + TouchableOpacity, + ActivityIndicator, + ScrollView, + Image, + Alert, + Linking, +} from "react-native"; +import BackIcon from "../../components/BackIcon"; +import MassageIcon from "../../components/MassageIcon"; +import fontSize from "../../utils/fontsizeUtils"; +import { useNavigation } from "@react-navigation/native"; +import { NativeStackNavigationProp } from "@react-navigation/native-stack"; +import { useRoute, RouteProp } from "@react-navigation/native"; +import { ordersApi, OrderDetailsType } from "../../services/api/orders"; +import OrderIcon from "../../components/OrderIcon"; +import InfoIcon from "../../components/InfoIcon"; +import Progress from "./Progress"; +import AddressIcon from "../../components/AddressIcon"; +import EditIcon from "../../components/ColorfulEditIcon"; +import BrightnessIcon from "../../components/BrightnessIcon"; +import PhoneIcon from "../../components/PhoneIcon"; +import WatchAppIcon from "../../components/watchAppIcon"; +import ShoppingBagIcon from "../../components/ShoppingBagIcon"; +import PowerIcon from "../../components/PowerIcon"; +import CardIcon from "../../components/ShoppingCartIcon"; +import { useOrderListStore } from "../../store/orderList"; export const OrderDetails = () => { + const navigation = useNavigation>(); + const route = useRoute< + RouteProp< + { + OrderDetails: { + orderId: string; + }; + }, + "OrderDetails" + > + >(); + const [orderDetails, setOrderDetails] = useState(); + const [isLoading, setIsLoading] = useState(true); + const { deleteOrder, changeOrder,updateOrderShippingInfo } = useOrderListStore(); + const getOrderDetails = async () => { + try { + setIsLoading(true); + const response = await ordersApi.getOrderDetails(route.params.orderId); + setOrderDetails(response); + } catch (error) { + console.error("Error fetching order details:", error); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + getOrderDetails(); + }, []); + //拨打电话 + const callPhone = async (phoneNumber: string) => { + const url = `tel:${phoneNumber}`; + + try { + await Linking.openURL(url); // 直接尝试打开拨号界面 + } catch (error) { + Alert.alert("错误", "无法打开拨号界面"); + console.error("拨号失败:", error); + } + }; + return ( - - OrderDetails + + + navigation.goBack()}> + + + 订单详情 + + + {isLoading ? ( + + + + ) : orderDetails ? ( + + + + + + + 订单状态 + + + + + + + + {/* 订单信息 */} + + + + + 订单信息 + + + + Order ID + + {orderDetails.order_id} + + + + Order Date + + {orderDetails.create_time} + + + + Shipping Method + + {orderDetails.shipping_fee} + + + + + + {/* 配送信息 */} + + + + + 配送信息 + + + + + + + Warehouse + + + + + + + {orderDetails.receiver_address} + + + + + + + + + 付款后联系方式 + + + + + + + + + + Recipient + + + + + + {/* 姓名 */} + + + {orderDetails.receiver_name} + + + + {/* 电话 */} + + + + + {orderDetails.receiver_phone} + + + + {/* watchApp */} + + + + WhatsApp: + + {orderDetails.receiver_phone} + + + + + + + + + {/* 商品信息 */} + + + + + + 商品信息 ({orderDetails.items.length}) + + + + {orderDetails.items.map((item, index) => ( + + + + + + + + {item.product_name} + + + + {item.sku_attributes.map((sku, index) => ( + + {sku.attribute_name}:{sku.attribute_value} + + ))} + {/* {item.product_name} */} + + + + {item.total_price} + + + + + + x{item.quantity} + + + + ))} + + + + + + + + Add All to Card + + + + + + {/* 价格信息 */} + + + + + 价格详情 + + + + Subtotal + + {orderDetails.total_amount} + + + + + Platform Shipping Fee + + + {orderDetails.shipping_fee} + + + + + International Shipping Fee + + + {orderDetails.shipping_fee} + + + + + Total + + {orderDetails.total_amount} + + + + + + ${orderDetails.shipping_fee} estimated international fee + (COD) + + + + + + + {/* 代付款 */} + {orderDetails.order_status === 0 && ( + + { + deleteOrder(route.params.orderId); + }} + > + 取消订单 + + { + navigation.navigate("Pay", { + order_id: route.params.orderId, + }); + }} + > + 付款 + + + )} + {/* 待发货 */} + {orderDetails.order_status === 1 && ( + + { + callPhone("15903995548"); + }} + > + 联系货代中心 + + { + changeOrder(route.params.orderId, 2); + navigation.goBack(); + }} + > + 取消订单 + + + )} + {/* 代收货 */} + {orderDetails.order_status === 2 && ( + + {}}> + 查询物流 + + { + updateOrderShippingInfo(route.params.orderId,{ + shipping_status: 0, + shipping_info: { + shipping_company: "string", + shipping_no: "string", + shipping_info: {} + } + }); + navigation.goBack(); + }} + > + 确认收货 + + + )} + {/* 已完成 */} + {orderDetails.order_status === 3 && ( + + { + deleteOrder(route.params.orderId); + navigation.goBack(); + }} + > + Cancel Order + + + Pay Now + + + )} + {/* 已取消 */} + {orderDetails.order_status === 4 && ( + + {}}> + 添加到购物车 + + + 重新下单 + + + )} + + ) : ( + 无法加载订单状态 + )} ); }; +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#f8f9fa", + }, + header: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + padding: 16, + backgroundColor: "#fff", + shadowColor: "#000", + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.1, + shadowRadius: 3, + elevation: 3, + }, + title: { + fontSize: fontSize(16), + fontWeight: "600", + }, + orderStatus: { + paddingInline: 16, + marginTop: 10, + }, + orderStatusContent: { + backgroundColor: "#fff", + borderRadius: 16, + }, + orderStatusTitle: { + flexDirection: "row", + alignItems: "center", + borderBottomWidth: 1, + borderColor: "#f5f5f5", + padding: 10, + }, + orderStatusTitleText: { + fontSize: fontSize(16), + fontWeight: "600", + marginLeft: 10, + }, + orderStatusContentPreview: { + padding: 10, + justifyContent: "center", + }, + productItem: { + flexDirection: "row", + width: "100%", + borderBottomWidth: 1, + borderColor: "#f5f5f5", + padding: 10, + }, + productItemImage: { + width: "15%", + height: 50, + borderRadius: 10, + }, + productItemInfo: { + width: "75%", + justifyContent: "space-between", + paddingLeft: 10, + }, + productItemNum: { + width: "10%", + alignItems: "center", + justifyContent: "flex-end", + }, + productItemNumText: { + fontSize: fontSize(16), + color: "#999", + }, + productItemInfoName: { + width: "100%", + paddingVertical: 5, + }, + productItemInfoNameText: { + fontSize: fontSize(13), + fontWeight: "600", + }, + productItemInfoSkuText: { + fontSize: fontSize(13), + color: "#999", + }, + productItemInfoSku: { + width: "100%", + paddingVertical: 5, + }, + productItemInfoPrice: { + width: "100%", + paddingVertical: 5, + }, + orderStatusContentPreviewInformation: { + flexDirection: "row", + justifyContent: "space-between", + width: "100%", + }, - + loadingContainer: { + flex: 1, + justifyContent: "center", + alignItems: "center", + }, + orderId: { + flexDirection: "row", + justifyContent: "space-between", + paddingVertical: 10, + width: "100%", + }, + orderIdText: { + color: "#999", + width: "50%", + }, + orderIdText1: { + width: "50%", + textAlign: "right", + }, + TotalText: { + color: "#f77f3a", + fontSize: fontSize(18), + fontWeight: "600", + width: "50%", + }, + TotalPrice: { + color: "#f77f3a", + fontSize: fontSize(18), + fontWeight: "600", + width: "50%", + textAlign: "right", + }, + warehouse: { + width: "50%", + }, + recipientTitle: { + paddingVertical: 5, + }, + recipientPhoneContainer: { + flexDirection: "row", + alignItems: "center", + }, + recipient: { + width: "50%", + }, + orderStatusContentPreviewInformationText: { + fontSize: fontSize(16), + fontWeight: "600", + }, + warehousePhone: { + padding: 5, + backgroundColor: "#f9f9f9", + borderRadius: 10, + width: "90%", + flexDirection: "row", + alignItems: "center", + }, + warehousePhoneText: { + fontSize: fontSize(14), + fontWeight: "400", + color: "#3D3D3D", + }, + warehousePhoneTextContainer: { + paddingRight: 5, + }, + recipientName: { + fontSize: fontSize(16), + fontWeight: "600", + }, + recipientPhone: { + fontSize: fontSize(14), + fontWeight: "400", + color: "#3D3D3D", + }, + dottedLine: { + width: "100%", + borderBottomWidth: 2, + borderColor: "#f5f5f5", + borderStyle: "dashed", + }, + orderRemakeText: { + fontSize: fontSize(14), + fontWeight: "400", + color: "#999", + }, + addCard: { + width: "100%", + justifyContent: "center", + alignItems: "center", + }, + addCardBox: { + padding: 10, + borderWidth: 1, + borderColor: "#0098ef", + borderRadius: 10, + backgroundColor: "#e2f2fd", + opacity: 0.5, + flexDirection: "row", + alignItems: "center", + }, + addCardText: { + fontSize: fontSize(16), + fontWeight: "600", + color: "#0098ef", + marginLeft: 5, + }, + bottomButtons: { + position: "absolute", + bottom: 0, + width: "100%", + flexDirection: "row", + justifyContent: "center", + alignItems: "center", + padding: 10, + backgroundColor: "#fff", + shadowColor: "#000", + shadowOffset: { + width: 0, + height: -4, + }, + shadowOpacity: 0.1, + shadowRadius: 3, + elevation: 3, + }, + bottomButton1: { + padding: 10, + marginHorizontal: 10, + alignItems: "center", + backgroundColor: "#f0f0f0", + borderRadius: 5, + flex: 1, + }, + bottomButton: { + padding: 10, + marginHorizontal: 10, + alignItems: "center", + backgroundColor: "#fe7f42", + borderRadius: 5, + flex: 1, + }, + bottomButtonText: { + fontSize: fontSize(18), + fontWeight: "600", + color: "#fff", + }, + bottomButtonText1: { + fontSize: fontSize(18), + fontWeight: "600", + color: "#999", + }, +}); diff --git a/app/screens/productStatus/Progress.tsx b/app/screens/productStatus/Progress.tsx new file mode 100644 index 0000000..1b1b782 --- /dev/null +++ b/app/screens/productStatus/Progress.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { View, StyleSheet } from 'react-native'; +import { Text } from 'react-native-paper'; + + +interface ProgressProps { + statuses: number; + labels?: string[]; +} + +const Progress: React.FC = ({ statuses , labels = [] }) => { + return ( + + + {labels.map((_, index) => ( + + + {index < labels.length - 1 && ( + + )} + + ))} + + + {labels.map((label, index) => ( + {label} + ))} + + + ); +}; + +const styles = StyleSheet.create({ + mainContainer: { + alignItems: 'center', + }, + progressContainer: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + marginBottom: 10, + }, + node: { + width: 20, + height: 20, + borderRadius: 10, + backgroundColor: '#E0E0E0', + }, + completedNode: { + backgroundColor: '#4CAF50', + }, + line: { + height: 2, + width: 40, + backgroundColor: '#E0E0E0', + }, + completedLine: { + backgroundColor: '#4CAF50', + }, + labelsContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + width: '100%', + paddingHorizontal: 10, + }, + label: { + fontSize: 12, + color: '#666', + textAlign: 'center', + width: 60, + }, +}); + +export default Progress; diff --git a/app/screens/productStatus/Status.tsx b/app/screens/productStatus/Status.tsx index 8a14b1f..9d5eaca 100644 --- a/app/screens/productStatus/Status.tsx +++ b/app/screens/productStatus/Status.tsx @@ -21,6 +21,7 @@ import { } from "../../services/api/orders"; import { useNavigation } from "@react-navigation/native"; import { NativeStackNavigationProp } from "@react-navigation/native-stack"; +import { useOrderListStore } from "../../store/orderList"; // import ImageView from "react-native-image-viewing"; type StatusScreenRouteProp = RouteProp< @@ -43,33 +44,25 @@ export function Status() { return initialList; }); const [status, setStatus] = useState(null); - const [orderList, setOrderList] = useState(); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(10); - const [total, setTotal] = useState(0); - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(true); const [imageViewerVisible, setImageViewerVisible] = useState(false); const [currentImageIndex, setCurrentImageIndex] = useState(0); const [images, setImages] = useState([]); const statusScrollViewRef = useRef(null); const statusItemRef = useRef>(null); + const { orders, getAllOrders } = useOrderListStore(); - const getAllOrders = async () => { + const getAllOrdersList = async () => { setLoading(true); try { const data = { page: page, page_size: pageSize, + status: route.params.status, }; - const response = await ordersApi.getAllOrders(data); - setOrderList((prev) => ({ - ...response, - items: - page === 1 - ? response.items - : [...(prev?.items || []), ...response.items], - })); - setTotal(response.total); + await getAllOrders(data, page); } finally { setLoading(false); } @@ -93,7 +86,7 @@ export function Status() { setStatus(route.params.status); scrollToStatus(); setPage(1); - getAllOrders(); + getAllOrdersList(); }, []); const getStatus = (status: number) => { @@ -128,22 +121,19 @@ export function Status() { if (status) { data.status = status; } + if (status === 0) { + data.status = 0; + } + try { - const response = await ordersApi.getAllOrders(data); - setOrderList((prev) => ({ - ...response, - items: - page === 1 - ? response.items - : [...(prev?.items || []), ...response.items], - })); + await getAllOrders(data, page); // 滚动状态列表到选中项 } finally { setLoading(false); } }; - const handleOrderDetailsPress = (orderId: number) => { + const handleOrderDetailsPress = (orderId: string) => { navigation.navigate("OrderDetails", { orderId }); }; @@ -203,18 +193,29 @@ export function Status() { onMomentumScrollEnd={(event) => { const { contentOffset, contentSize, layoutMeasurement } = event.nativeEvent; + console.log('Scroll values:', { + contentOffsetY: contentOffset.y, + layoutHeight: layoutMeasurement.height, + contentHeight: contentSize.height, + sum: contentOffset.y + layoutMeasurement.height + }); const isAtBottom = contentOffset.y + layoutMeasurement.height >= - contentSize.height; - + contentSize.height - 20; + if (isAtBottom) { setLoading(true); setPage(page + 1); - getAllOrders(); + const data: PaginatedOrderRequest = { + page: page, + page_size: pageSize, + status:status, + }; + getAllOrders(data,page); } }} > - {orderList?.items.map((item, index) => ( + {orders?.items.map((item, index) => ( @@ -313,7 +314,7 @@ const styles = StyleSheet.create({ width: "100%", }, statusItem: { - width: widthUtils(100,100).width, + width: widthUtils(100, 100).width, padding: 16, backgroundColor: "white", }, @@ -354,9 +355,12 @@ const styles = StyleSheet.create({ orderStatusOrderText: { fontSize: fontSize(16), fontWeight: "600", + width: "70%", }, orderStatusText: { color: "#f77f3a", + width: "30%", + textAlign: "right", }, orderProductList: { width: "100%", @@ -370,8 +374,8 @@ const styles = StyleSheet.create({ borderColor: "#f5f5f5", }, orderProductItemImage: { - width: widthUtils(30,30).width, - height: widthUtils(30,30).height, + width: widthUtils(30, 30).width, + height: widthUtils(30, 30).height, marginRight: 10, }, orderProductItemInfo: { @@ -391,19 +395,25 @@ const styles = StyleSheet.create({ justifyContent: "space-between", }, orderProductView: { - padding: 5, + width: "50%", borderRadius: 8, - borderWidth: 1, - borderColor: "#f77f3a", + alignItems: "flex-end", }, orderProductViewText: { color: "#f77f3a", fontSize: fontSize(14), + borderWidth: 1, + borderColor: "#f77f3a", + width: "50%", + borderRadius: 8, + padding: 5, + textAlign: "center", }, orderProductPriceText: { fontSize: fontSize(16), fontWeight: "600", color: "#f77f3a", + textAlign: "right", }, orderProductTotalText: { fontSize: fontSize(16), @@ -411,6 +421,7 @@ const styles = StyleSheet.create({ }, orderProductPriceItem: { flexDirection: "row", + width: "50%", }, loadingContainer: { flex: 1, diff --git a/app/services/api/orders.ts b/app/services/api/orders.ts index 1bd47f5..88fd72c 100644 --- a/app/services/api/orders.ts +++ b/app/services/api/orders.ts @@ -257,7 +257,7 @@ interface Address { pay_status: number; order_status: number; shipping_status: number; - order_id: number; + order_id: string; order_no: string; items: OrderItem[]; create_time: string; // or Date @@ -280,6 +280,64 @@ interface Address { page_size: number; } + + interface SkuAttributesDetails { + attribute_name: string; + attribute_value: string; + } + + interface OrderItemDetails { + offer_id: number; + cart_item_id: number | null; + sku_id: number; + product_name: string; + product_name_en: string; + product_name_ar: string; + product_name_fr: string; + product_image: string; + sku_attributes: SkuAttributesDetails[]; + quantity: number; + unit_price: number; + total_price: number; + order_item_id: string; + order_id: string; + create_time: string; // or Date + update_time: string; // or Date + } + + export interface OrderDetailsType { + user_id: number; + total_amount: number; + actual_amount: number; + discount_amount: number; + shipping_fee: number; + address_id: number; + receiver_name: string; + receiver_phone: string; + receiver_address: string; + buyer_message: string; + pay_status: number; + order_status: number; + shipping_status: number; + order_id: string; + order_no: string; + items: OrderItemDetails[]; + create_time: string; // or Date + transport_type: number; + payment_method: string; + pay_time: string | null; // or Date | null + shipping_time: string | null; // or Date | null + complete_time: string | null; // or Date | null + update_time: string; // or Date + } + export interface UpdateOrderShippingInfo { + "shipping_status": number, + "shipping_info": { + "shipping_company": string, + "shipping_no": string, + "shipping_info": {} + } + } export const ordersApi = { getOrders: (data:OrderPreviewData) => apiService.post("/api/orders/preview",data), @@ -304,8 +362,20 @@ interface Address { apiService.get(`/api/orders`,data), // 获取订单指定信息 - getOrderDetails: (order_id:number) => - apiService.get(`/api/orders/${order_id}`), + getOrderDetails: (order_id:string) => + apiService.get(`/api/orders/${order_id}`), + + // 删除订单 + deleteOrder: (order_id:string) => + apiService.delete(`/api/orders/${order_id}`), + + // 修改订单 + changeOrder: (order_id:string,status:number) => + apiService.patch(`/api/orders/${order_id}/status?status=${status}`), + + // 修改物流信息 + updateOrderShippingInfo: (order_id:string,data:UpdateOrderShippingInfo) => + apiService.patch(`/api/orders/${order_id}/shipping`,data), }; \ No newline at end of file diff --git a/app/store/orderList.ts b/app/store/orderList.ts new file mode 100644 index 0000000..0c90da9 --- /dev/null +++ b/app/store/orderList.ts @@ -0,0 +1,65 @@ +import { create } from 'zustand'; +import { ordersApi, PaginatedOrderResponse, PaginatedOrderRequest,UpdateOrderShippingInfo} from '../services/api/orders'; + +interface OrderListState { + orders: PaginatedOrderResponse, + getAllOrders: (data: PaginatedOrderRequest,page:number) => Promise, + deleteOrder: (orderId: string) => Promise, + changeOrder: (orderId: string,status:number) => Promise, + updateOrderShippingInfo: (orderId: string,data:UpdateOrderShippingInfo) => Promise, +} + +export const useOrderListStore = create((set, get) => ({ + orders: { + items: [], + total: 0, + page: 1, + page_size: 10, + }, + + getAllOrders: async (data: PaginatedOrderRequest,page:number) => { + const response = await ordersApi.getAllOrders(data); + set((state) => ({ + orders: { + ...response, + items: page === 1 + ? response.items + : [...state.orders.items, ...response.items], + } + })); + }, + + deleteOrder: async (orderId: string) => { + await ordersApi.deleteOrder(orderId); + set((state) => ({ + orders: { + ...state.orders, + items: state.orders.items.filter(item => item.order_id !== orderId), + total: state.orders.total - 1 + } + })); + }, + + changeOrder: async (orderId: string,status:number) => { + await ordersApi.changeOrder(orderId,status); + set((state) => ({ + orders: { + ...state.orders, + items: state.orders.items.filter(item => item.order_id !== orderId), + total: state.orders.total - 1 + } + })); + }, + + updateOrderShippingInfo: async (orderId: string,data:UpdateOrderShippingInfo) => { + await ordersApi.updateOrderShippingInfo(orderId,data); + set((state) => ({ + orders: { + ...state.orders, + items: state.orders.items.filter(item => item.order_id !== orderId), + total: state.orders.total - 1 + } + })); + }, +})); +