import React, { useEffect, useState, useCallback, useRef } from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
Image,
TouchableOpacity,
SafeAreaView,
StatusBar,
ActivityIndicator,
Dimensions,
FlatList
} from 'react-native';
import Ionicons from '@expo/vector-icons/Ionicons';
import { useNavigation, useRoute } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { RouteProp } from '@react-navigation/native';
import { productApi, ProductDetailParams } from '../services/api/productApi';
// 获取屏幕宽度
const { width: screenWidth } = Dimensions.get('window');
// 图标组件 - 使用React.memo优化渲染
const IconComponent = React.memo(({ name, size, color }: { name: string; size: number; color: string }) => {
const Icon = Ionicons as any;
return ;
});
// 产品类型定义
interface Product {
id: string;
title: string;
price: number;
image: string;
currency: string;
sales: number;
description: string;
specifications: Record;
}
// 路由参数类型
type ProductDetailRouteParams = {
offer_id: string;
searchKeyword?: string;
price:number;
};
export const ProductDetailScreen = () => {
const navigation = useNavigation>();
const route = useRoute, string>>();
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const [activeImageIndex, setActiveImageIndex] = useState(0);
// 获取产品详情
useEffect(() => {
fetchProductDetails();
}, []);
// 模拟获取产品详情的API调用
const fetchProductDetails = async () => {
if (!route.params?.offer_id) return;
setLoading(true);
try {
const res = await productApi.getProductDetail(route.params.offer_id);
console.log(res);
res.price = route.params.price;
// 模拟返回的数据
const searchKeyword = route.params.searchKeyword || 'Product';
console.log(searchKeyword);
setProduct(res);
} catch (error) {
console.error('Error fetching product details:', error);
// 在实际应用中应该显示错误消息
} finally {
setLoading(false);
}
};
// 返回上一页
const goBack = useCallback(() => {
navigation.goBack();
}, [navigation]);
// 返回到搜索结果页
const goBackToSearch = useCallback(() => {
if (route.params?.searchKeyword) {
navigation.navigate('SearchResult', { keyword: route.params.searchKeyword });
} else {
navigation.goBack();
}
}, [navigation, route.params?.searchKeyword]);
if (loading) {
return (
Product Details
Loading product details...
);
}
if (!product) {
return (
Product Details
Product not found
Back to Search Results
);
}
return (
{/* 头部导航 */}
{product.subject}
{/* 产品图片轮播 */}
{product.product_image_urls && product.product_image_urls.length > 0 ? (
<>
`image-${index}`}
onScroll={(event) => {
const slideSize = event.nativeEvent.layoutMeasurement.width;
const index = Math.floor(event.nativeEvent.contentOffset.x / slideSize);
setActiveImageIndex(index);
}}
scrollEventThrottle={16}
renderItem={({ item }) => (
)}
/>
{/* 指示器 */}
{product.product_image_urls.length > 1 && (
{product.product_image_urls.map((_, index) => (
))}
)}
>
) : (
Product Image
)}
{/* 产品基本信息 */}
{product.subject}
{product.price}
{product.subject_trans}
{/* 如果是从搜索结果跳转来的,显示匹配的关键词 */}
{route.params?.searchKeyword && (
Matched Search:
{route.params.searchKeyword}
)}
{/* 产品描述 */}
{/*
Description
{product.description}
*/}
{/* 产品规格 */}
{/*
Specifications
{Object.entries(product.specifications).map(([key, value], index) => (
{key}
{value}
))}
*/}
{/* 返回搜索结果按钮 */}
Back to Search Results
{/* 底部空间,确保内容不被底部操作栏遮挡 */}
{/* 底部操作栏 */}
Add to Cart
Buy Now
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 15,
paddingVertical: 10,
borderBottomWidth: 1,
borderBottomColor: '#f0f0f0',
backgroundColor: '#fff',
},
backButton: {
padding: 5,
},
headerTitle: {
flex: 1,
fontSize: 16,
fontWeight: 'bold',
color: '#333',
textAlign: 'center',
marginHorizontal: 10,
},
headerRight: {
width: 24,
},
scrollContainer: {
flex: 1,
},
imageContainer: {
height: 300,
backgroundColor: '#f9f9f9',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
},
productImage: {
width: '100%',
height: '100%',
},
imagePlaceholder: {
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
},
imagePlaceholderText: {
fontSize: 16,
color: '#999',
},
infoSection: {
padding: 15,
borderBottomWidth: 8,
borderBottomColor: '#f5f5f5',
},
productTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#333',
marginBottom: 10,
},
productPrice: {
fontSize: 24,
fontWeight: 'bold',
color: '#ff6600',
marginBottom: 5,
},
productSales: {
fontSize: 14,
color: '#999',
marginBottom: 10,
},
keywordContainer: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#f0f8ff',
paddingVertical: 5,
paddingHorizontal: 10,
borderRadius: 5,
marginTop: 5,
},
keywordLabel: {
fontSize: 14,
color: '#666',
},
keywordValue: {
fontSize: 14,
fontWeight: 'bold',
color: '#0066ff',
},
section: {
padding: 15,
borderBottomWidth: 8,
borderBottomColor: '#f5f5f5',
},
sectionTitle: {
fontSize: 16,
fontWeight: 'bold',
color: '#333',
marginBottom: 10,
},
descriptionText: {
fontSize: 14,
color: '#666',
lineHeight: 20,
},
specRow: {
flexDirection: 'row',
paddingVertical: 8,
borderBottomWidth: 1,
borderBottomColor: '#f0f0f0',
},
specKey: {
flex: 1,
fontSize: 14,
color: '#666',
},
specValue: {
flex: 2,
fontSize: 14,
color: '#333',
},
backToSearchButton: {
alignItems: 'center',
paddingVertical: 15,
margin: 15,
},
backToSearchText: {
fontSize: 14,
color: '#0066ff',
},
bottomSpace: {
height: 60,
},
bottomBar: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
flexDirection: 'row',
height: 60,
backgroundColor: '#fff',
borderTopWidth: 1,
borderTopColor: '#f0f0f0',
paddingHorizontal: 15,
paddingVertical: 10,
},
addToCartButton: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ff9500',
borderRadius: 25,
marginRight: 10,
},
addToCartText: {
color: '#fff',
fontWeight: 'bold',
marginLeft: 5,
},
buyNowButton: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ff6600',
borderRadius: 25,
},
buyNowText: {
color: '#fff',
fontWeight: 'bold',
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
loadingText: {
fontSize: 16,
color: '#666',
marginTop: 10,
},
errorContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
errorText: {
fontSize: 18,
fontWeight: 'bold',
color: '#333',
marginTop: 15,
marginBottom: 20,
},
paginationContainer: {
position: 'absolute',
bottom: 15,
flexDirection: 'row',
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
paginationDot: {
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: 'rgba(0, 0, 0, 0.2)',
marginHorizontal: 4,
},
paginationDotActive: {
backgroundColor: '#ff6600',
width: 10,
height: 10,
borderRadius: 5,
},
});