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.
448 lines
13 KiB
448 lines
13 KiB
import { |
|
View, |
|
StyleSheet, |
|
Text, |
|
ScrollView, |
|
TouchableOpacity, |
|
Image, |
|
ActivityIndicator, |
|
SafeAreaView, |
|
StatusBar, |
|
Platform, |
|
} from "react-native"; |
|
import { useRoute, RouteProp } from "@react-navigation/native"; |
|
import { productStatus } from "../../constants/productStatus"; |
|
import BackIcon from "../../components/BackIcon"; |
|
import MassageIcon from "../../components/MassageIcon"; |
|
import { useEffect, useState, useRef } from "react"; |
|
import fontSize from "../../utils/fontsizeUtils"; |
|
import widthUtils from "../../utils/widthUtils"; |
|
import { useTranslation } from "react-i18next"; |
|
import { |
|
ordersApi, |
|
PaginatedOrderResponse, |
|
PaginatedOrderRequest, |
|
} from "../../services/api/orders"; |
|
import { useNavigation } from "@react-navigation/native"; |
|
import { NativeStackNavigationProp } from "@react-navigation/native-stack"; |
|
import { useOrderListStore } from "../../store/orderList"; |
|
import { getOrderTransLanguage } from "../../utils/languageUtils"; |
|
// import ImageView from "react-native-image-viewing"; |
|
|
|
type StatusScreenRouteProp = RouteProp< |
|
{ |
|
Status: { status: number }; |
|
}, |
|
"Status" |
|
>; |
|
|
|
export function Status() { |
|
const navigation = useNavigation<NativeStackNavigationProp<any>>(); |
|
const route = useRoute<StatusScreenRouteProp>(); |
|
const { t } = useTranslation(); |
|
const [statusList, setStatusList] = useState(() => { |
|
const initialList = [...productStatus]; |
|
initialList.unshift({ |
|
text: t("order.status.all"), |
|
textKey: "order.status.all", |
|
status: null, |
|
icon: BackIcon, |
|
}); |
|
return initialList; |
|
}); |
|
const [status, setStatus] = useState<number | null>(null); |
|
const [page, setPage] = useState(1); |
|
const [pageSize, setPageSize] = useState(10); |
|
const [loading, setLoading] = useState(true); |
|
const [imageViewerVisible, setImageViewerVisible] = useState(false); |
|
const [currentImageIndex, setCurrentImageIndex] = useState(0); |
|
const [images, setImages] = useState<string[]>([]); |
|
const statusScrollViewRef = useRef<ScrollView>(null); |
|
const statusItemRef = useRef<React.ElementRef<typeof TouchableOpacity>>(null); |
|
const { orders, getAllOrders } = useOrderListStore(); |
|
|
|
const getAllOrdersList = async () => { |
|
setLoading(true); |
|
try { |
|
const data = { |
|
page: page, |
|
page_size: pageSize, |
|
status: route.params.status, |
|
}; |
|
await getAllOrders(data, page); |
|
} finally { |
|
setLoading(false); |
|
} |
|
}; |
|
|
|
const scrollToStatus = () => { |
|
const itemIndex = statusList.findIndex( |
|
(item) => item.status === route.params.status |
|
); |
|
console.log(itemIndex); |
|
statusItemRef.current?.measure((x, y, width, height, pageX, pageY) => { |
|
if (width) { |
|
statusScrollViewRef.current?.scrollTo({ |
|
x: width * (itemIndex - 1), |
|
animated: true, |
|
}); |
|
} |
|
}); |
|
}; |
|
useEffect(() => { |
|
setStatus(route.params.status); |
|
scrollToStatus(); |
|
setPage(1); |
|
getAllOrdersList(); |
|
}, []); |
|
|
|
const getStatus = (status: number) => { |
|
switch(status) { |
|
case 0: return t("order.status.waiting_payment"); |
|
case 1: return t("order.status.waiting_shipment"); |
|
case 2: return t("order.status.waiting_receipt"); |
|
case 3: return t("order.status.completed"); |
|
case 4: return t("order.status.cancelled"); |
|
case 5: return t("order.status.refunded"); |
|
case 6: return t("order.status.pay_shipping"); |
|
case 7: return t("order.status.in_transit"); |
|
case 8: return t("order.status.waiting_quote"); |
|
default: return t("order.status.unknown"); |
|
} |
|
}; |
|
|
|
// const handleImagePress = (imageUrl: string) => { |
|
// setImages([imageUrl]); |
|
// setCurrentImageIndex(0); |
|
// setImageViewerVisible(true); |
|
// }; |
|
|
|
const changeStatus = async (status: number) => { |
|
setLoading(true); |
|
setPage(1); |
|
const data: PaginatedOrderRequest = { |
|
page: page, |
|
page_size: pageSize, |
|
}; |
|
if (status) { |
|
data.status = status; |
|
} |
|
if (status === 0) { |
|
data.status = 0; |
|
} |
|
|
|
try { |
|
await getAllOrders(data, page); |
|
// 滚动状态列表到选中项 |
|
} finally { |
|
setLoading(false); |
|
} |
|
}; |
|
|
|
const handleOrderDetailsPress = (orderId: string) => { |
|
navigation.navigate("OrderDetails", { orderId, status }); |
|
}; |
|
|
|
return ( |
|
<SafeAreaView style={styles.safeArea}> |
|
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> |
|
<View style={styles.safeAreaContent}> |
|
<View style={styles.statusHeader}> |
|
<TouchableOpacity onPress={() => navigation.goBack()}> |
|
<BackIcon /> |
|
</TouchableOpacity> |
|
<Text style={styles.statusTitle}>{t("order.status")}</Text> |
|
<MassageIcon size={26} /> |
|
</View> |
|
<View style={styles.statusList}> |
|
<ScrollView |
|
ref={statusScrollViewRef} |
|
style={styles.statusListScr} |
|
horizontal={true} |
|
pagingEnabled={false} |
|
showsHorizontalScrollIndicator={false} |
|
> |
|
{statusList.map((item, index) => ( |
|
<TouchableOpacity |
|
ref={statusItemRef} |
|
style={[ |
|
styles.statusItem, |
|
status === item.status ? styles.statusItemActive : null, |
|
]} |
|
key={index} |
|
onPress={() => { |
|
setStatus(item.status as number); |
|
changeStatus(item.status as number); |
|
}} |
|
> |
|
<Text |
|
style={[ |
|
styles.statusItemText, |
|
status === item.status ? styles.statusItemActiveText : null, |
|
]} |
|
> |
|
{t(item.textKey)} |
|
</Text> |
|
</TouchableOpacity> |
|
))} |
|
</ScrollView> |
|
</View> |
|
|
|
<View style={styles.orderContent}> |
|
{loading && page === 1 ? ( |
|
<View style={styles.loadingContainer}> |
|
<ActivityIndicator size="large" color="#f77f3a" /> |
|
</View> |
|
) : ( |
|
<ScrollView |
|
horizontal={false} |
|
showsVerticalScrollIndicator={false} |
|
scrollEventThrottle={16} |
|
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 - 20; |
|
|
|
if (isAtBottom) { |
|
setLoading(true); |
|
setPage(page + 1); |
|
const data: PaginatedOrderRequest = { |
|
page: page, |
|
page_size: pageSize, |
|
status:status, |
|
}; |
|
getAllOrders(data,page); |
|
} |
|
}} |
|
> |
|
{orders?.items.map((item, index) => ( |
|
<View style={styles.orderItem} key={index}> |
|
<View style={styles.orderStatus}> |
|
<Text style={styles.orderStatusOrderText}> |
|
{item.order_id} |
|
</Text> |
|
<Text style={styles.orderStatusText}> |
|
{getStatus(item.order_status)} |
|
</Text> |
|
</View> |
|
<View style={styles.orderProductList}> |
|
{item.items.map((item, index) => ( |
|
<View style={styles.orderProductItem} key={index}> |
|
<TouchableOpacity style={styles.orderProductItemImage}> |
|
<Image |
|
source={{ uri: item.sku_image }} |
|
style={styles.orderProductItemImage} |
|
/> |
|
</TouchableOpacity> |
|
<View style={styles.orderProductItemInfo}> |
|
<Text style={styles.orderProductItemInfoName}> |
|
{getOrderTransLanguage(item) || item.product_name_fr} |
|
</Text> |
|
{item.sku_attributes?.map((attr, index) => ( |
|
<Text |
|
style={styles.orderProductItemInfoPrice} |
|
key={index} |
|
> |
|
{attr.attribute_name}:{attr.attribute_value} |
|
</Text> |
|
))} |
|
</View> |
|
</View> |
|
))} |
|
</View> |
|
<View style={styles.orderProductPrice}> |
|
<View style={styles.orderProductPriceItem}> |
|
<Text style={styles.orderProductTotalText}>{t("order.total_price")}:</Text> |
|
<Text style={styles.orderProductPriceText}> |
|
{item.actual_amount} {item?.currency} |
|
</Text> |
|
</View> |
|
<TouchableOpacity |
|
style={styles.orderProductView} |
|
onPress={() => handleOrderDetailsPress(item.order_id)} |
|
> |
|
<Text style={styles.orderProductViewText}> |
|
{t("order.view_details")} |
|
</Text> |
|
</TouchableOpacity> |
|
</View> |
|
</View> |
|
))} |
|
{loading && page > 1 && ( |
|
<View style={styles.loadingMoreContainer}> |
|
<ActivityIndicator size="small" color="#f77f3a" /> |
|
</View> |
|
)} |
|
</ScrollView> |
|
)} |
|
</View> |
|
{/* <ImageView |
|
images={images.map(uri => ({ uri }))} |
|
imageIndex={currentImageIndex} |
|
visible={imageViewerVisible} |
|
onRequestClose={() => setImageViewerVisible(false)} |
|
swipeToCloseEnabled={true} |
|
doubleTapToZoomEnabled={true} |
|
/> */} |
|
</View> |
|
</SafeAreaView> |
|
); |
|
} |
|
|
|
const styles = StyleSheet.create({ |
|
safeArea: { |
|
flex: 1, |
|
backgroundColor: '#fff', |
|
}, |
|
safeAreaContent: { |
|
flex: 1, |
|
paddingTop: 0, |
|
}, |
|
statusHeader: { |
|
width: "100%", |
|
backgroundColor: "white", |
|
padding: 16, |
|
justifyContent: "space-between", |
|
flexDirection: "row", |
|
alignItems: "center", |
|
}, |
|
statusTitle: { |
|
fontSize: fontSize(16), |
|
fontWeight: "600", |
|
}, |
|
statusList: { |
|
width: "100%", |
|
borderTopWidth: 1, |
|
borderColor: "#f5f5f5", |
|
}, |
|
statusListScr: { |
|
width: "100%", |
|
}, |
|
statusItem: { |
|
padding: 16, |
|
paddingHorizontal: 20, |
|
backgroundColor: "white", |
|
}, |
|
statusItemText: { |
|
fontSize: fontSize(16), |
|
textAlign: "center", |
|
}, |
|
statusItemTextActive: { |
|
color: "#f77f3a", |
|
borderBottomWidth: 1, |
|
borderColor: "#f77f3a", |
|
}, |
|
statusItemActive: { |
|
borderBottomWidth: 2, |
|
borderColor: "#f77f3a", |
|
}, |
|
statusItemActiveText: { |
|
color: "#f77f3a", |
|
}, |
|
orderContent: { |
|
padding: 20, |
|
flex: 1, |
|
}, |
|
orderItem: { |
|
width: "100%", |
|
backgroundColor: "white", |
|
borderRadius: 10, |
|
marginBottom: 10, |
|
}, |
|
orderStatus: { |
|
width: "100%", |
|
padding: 10, |
|
borderBottomWidth: 1, |
|
flexDirection: "row", |
|
borderColor: "#f5f5f5", |
|
justifyContent: "space-between", |
|
}, |
|
orderStatusOrderText: { |
|
fontSize: fontSize(16), |
|
fontWeight: "600", |
|
width: "70%", |
|
}, |
|
orderStatusText: { |
|
color: "#f77f3a", |
|
width: "30%", |
|
textAlign: "right", |
|
}, |
|
orderProductList: { |
|
width: "100%", |
|
padding: 10, |
|
}, |
|
orderProductItem: { |
|
flexDirection: "row", |
|
paddingBottom: 10, |
|
paddingTop: 10, |
|
borderBottomWidth: 1, |
|
borderColor: "#f5f5f5", |
|
}, |
|
orderProductItemImage: { |
|
width: widthUtils(30, 30).width, |
|
height: widthUtils(30, 30).height, |
|
marginRight: 10, |
|
}, |
|
orderProductItemInfo: { |
|
flex: 1, |
|
}, |
|
orderProductItemInfoName: { |
|
fontSize: fontSize(16), |
|
fontWeight: "600", |
|
}, |
|
orderProductItemInfoPrice: { |
|
fontSize: fontSize(14), |
|
color: "#666", |
|
}, |
|
orderProductPrice: { |
|
padding: 10, |
|
flexDirection: "row", |
|
justifyContent: "space-between", |
|
}, |
|
orderProductView: { |
|
width: "50%", |
|
borderRadius: 8, |
|
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), |
|
fontWeight: "600", |
|
}, |
|
orderProductPriceItem: { |
|
flexDirection: "row", |
|
width: "50%", |
|
}, |
|
loadingContainer: { |
|
flex: 1, |
|
justifyContent: "center", |
|
alignItems: "center", |
|
}, |
|
loadingMoreContainer: { |
|
paddingVertical: 10, |
|
alignItems: "center", |
|
}, |
|
});
|
|
|