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';
import { useTranslation } from 'react-i18next';
// 获取屏幕宽度
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 ;
});
// 路由参数类型
type ProductDetailRouteParams = {
offer_id: string;
searchKeyword?: string;
price: number;
};
// 颜色选项组件
const ColorOption = React.memo(({ color, selected, onSelect }: { color: string; selected: boolean; onSelect: () => void }) => (
{color}
));
// 尺寸选项组件
const SizeOption = React.memo(({ size, selected, onSelect }: { size: string; selected: boolean; onSelect: () => void }) => (
{size}
));
// 相关商品组件
const RelatedProductItem = React.memo(({ product, onPress }: { product: any; onPress: () => void }) => (
${product.price}
));
export const ProductDetailScreen = () => {
const { t } = useTranslation();
const navigation = useNavigation>();
const route = useRoute, string>>();
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const [activeImageIndex, setActiveImageIndex] = useState(0);
const [selectedColor, setSelectedColor] = useState('Black');
const [selectedSize, setSelectedSize] = useState('M');
const [relatedProducts, setRelatedProducts] = useState([
{ id: 1, name: 'Related Product 1', price: 19.99, image: 'https://via.placeholder.com/150' },
{ id: 2, name: 'Related Product 2', price: 24.99, image: 'https://via.placeholder.com/150' },
{ id: 3, name: 'Related Product 3', price: 14.99, image: 'https://via.placeholder.com/150' },
{ id: 4, name: 'Related Product 4', price: 34.99, image: 'https://via.placeholder.com/150' },
]);
const [page, setPage] = useState(1);
const [loadingMore, setLoadingMore] = useState(false);
const [hasMoreProducts, setHasMoreProducts] = useState(true);
// 颜色和尺寸选项
const colorOptions = ['Black', 'White', 'Blue', 'Red'];
const sizeOptions = ['S', 'M', 'L', 'XL', 'XXL'];
// 获取产品详情
useEffect(() => {
fetchProductDetails();
}, []);
// 获取产品详情的API调用
const fetchProductDetails = async () => {
if (!route.params?.offer_id) return;
setLoading(true);
try {
const res = await productApi.getProductDetail(route.params.offer_id);
res.price = route.params.price;
setProduct(res);
} catch (error) {
console.error('Error fetching product details:', error);
} finally {
setLoading(false);
}
};
// 返回上一页
const goBack = useCallback(() => {
navigation.goBack();
}, [navigation]);
// 处理相关商品点击
const handleRelatedProductPress = useCallback((product: any) => {
// 这里可以导航到对应的商品详情页
console.log('Navigate to related product:', product.id);
}, []);
// 处理添加到购物车
const handleAddToCart = useCallback(() => {
// 添加到购物车的逻辑
console.log('Add to cart with color:', selectedColor, 'and size:', selectedSize);
}, [selectedColor, selectedSize]);
// 处理立即购买
const handleBuyNow = useCallback(() => {
// 立即购买的逻辑
console.log('Buy now with color:', selectedColor, 'and size:', selectedSize);
}, [selectedColor, selectedSize]);
// 获取相关商品
const fetchRelatedProducts = useCallback(async (pageNumber = 1) => {
if (!hasMoreProducts && pageNumber > 1) return;
try {
setLoadingMore(true);
// 模拟网络请求延迟
await new Promise(resolve => setTimeout(resolve, 1000));
// 模拟新数据
const newProducts = Array(4).fill(0).map((_, index) => ({
id: pageNumber * 10 + index,
name: `Related Product ${pageNumber * 10 + index}`,
price: Number((Math.random() * 30 + 10).toFixed(2)),
image: 'https://via.placeholder.com/150'
}));
if (pageNumber === 1) {
setRelatedProducts(newProducts);
} else {
setRelatedProducts(prev => [...prev, ...newProducts]);
}
// 模拟数据加载完毕的情况
if (pageNumber >= 3) {
setHasMoreProducts(false);
} else {
setPage(pageNumber);
}
} catch (error) {
console.error('Error fetching related products:', error);
} finally {
setLoadingMore(false);
}
}, [hasMoreProducts]);
// 初始加载相关商品
useEffect(() => {
fetchRelatedProducts(1);
}, [fetchRelatedProducts]);
// 处理滚动到底部加载更多
const handleLoadMore = useCallback(() => {
if (!loadingMore && hasMoreProducts) {
fetchRelatedProducts(page + 1);
}
}, [fetchRelatedProducts, loadingMore, hasMoreProducts, page]);
if (loading) {
return (
{t('productDetail')}
{t('loadingProductInfo')}
);
}
if (!product) {
return (
{t('productDetail')}
{t('productNotAvailable')}
);
}
return (
{/* 头部导航 */}
{t('productDetail')}
{
const { layoutMeasurement, contentOffset, contentSize } = nativeEvent;
const paddingToBottom = 20;
if (layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom) {
handleLoadMore();
}
}}
scrollEventThrottle={400}
>
{/* 产品图片轮播 */}
{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) => (
))}
)}
>
) : (
{t('productDetail')}
)}
{/* 产品基本信息 */}
${product.price?.toFixed(2) || '29.99'}
${(product.price * 1.4).toFixed(2) || '49.99'}
-40%
VIP
{product.subject || 'Product Name'}
{t('monthlySales')} {product.sold_out || 2458}
{/* 颜色选择 */}
{t('color')}
{colorOptions.map((color, index) => (
setSelectedColor(color)}
/>
))}
+2
{/* 尺寸选择 */}
{t('size')}
{sizeOptions.map((size, index) => (
setSelectedSize(size)}
/>
))}
{/* 相关商品 */}
{t('moreFromStore')}
{t('viewAll')}
{relatedProducts.map((product, index) => (
handleRelatedProductPress(product)}
/>
))}
{loadingMore && (
{t('loadingMoreProducts')}
)}
{!hasMoreProducts && relatedProducts.length > 0 && (
{t('noMoreProducts')}
)}
{/* 商品详情 */}
{t('productDetails')}
{t('productDetails')} 1
{t('productDetails')} 2
{t('productDetails')} 3
{/* 底部空间,确保内容不被底部操作栏遮挡 */}
{/* 底部操作栏 */}
{t('customerService')}
{t('addToCart')}
{t('buyNow')}
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 15,
paddingVertical: 10,
backgroundColor: '#fff',
borderBottomWidth: 1,
borderBottomColor: '#f0f0f0',
},
backButton: {
padding: 5,
},
headerTitle: {
flex: 1,
fontSize: 16,
fontWeight: 'bold',
color: '#333',
textAlign: 'center',
marginHorizontal: 10,
},
headerRight: {
flexDirection: 'row',
alignItems: 'center',
},
headerIconButton: {
padding: 5,
},
scrollContainer: {
flex: 1,
},
imageContainer: {
height: 300,
backgroundColor: '#f9f9f9',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
},
imagePlaceholder: {
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
},
imagePlaceholderText: {
fontSize: 16,
color: '#999',
},
paginationContainer: {
position: 'absolute',
bottom: 15,
flexDirection: 'row',
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
paginationDot: {
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: 'rgba(255, 255, 255, 0.4)',
marginHorizontal: 4,
},
paginationDotActive: {
backgroundColor: '#fff',
width: 10,
height: 10,
borderRadius: 5,
},
infoSection: {
padding: 15,
backgroundColor: '#fff',
marginBottom: 10,
},
priceContainer: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 10,
},
productPrice: {
fontSize: 24,
fontWeight: 'bold',
color: '#ff6600',
},
originalPrice: {
fontSize: 16,
color: '#999',
textDecorationLine: 'line-through',
marginLeft: 8,
},
discountBadge: {
backgroundColor: '#ff6600',
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 3,
marginLeft: 8,
},
discountText: {
color: '#fff',
fontSize: 12,
fontWeight: 'bold',
},
vipBadge: {
backgroundColor: '#f1c40f',
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 3,
marginLeft: 6,
},
vipText: {
color: '#fff',
fontSize: 12,
fontWeight: 'bold',
},
productTitle: {
fontSize: 16,
color: '#333',
marginBottom: 8,
},
productSales: {
fontSize: 12,
color: '#999',
marginBottom: 15,
},
optionSection: {
marginTop: 15,
},
optionTitle: {
fontSize: 14,
fontWeight: 'bold',
color: '#333',
marginBottom: 10,
},
colorOptions: {
flexDirection: 'row',
flexWrap: 'wrap',
},
colorOption: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 10,
paddingVertical: 6,
borderRadius: 4,
marginRight: 10,
marginBottom: 10,
borderWidth: 1,
borderColor: '#e0e0e0',
},
colorOptionSelected: {
borderColor: '#ff6600',
backgroundColor: '#fff8f5',
},
colorCircle: {
width: 16,
height: 16,
borderRadius: 8,
marginRight: 6,
},
colorName: {
fontSize: 12,
color: '#333',
},
moreColorsButton: {
width: 35,
height: 35,
borderRadius: 4,
backgroundColor: '#f5f5f5',
justifyContent: 'center',
alignItems: 'center',
marginRight: 10,
marginBottom: 10,
},
moreColorsText: {
fontSize: 12,
color: '#333',
},
sizeOptions: {
flexDirection: 'row',
flexWrap: 'wrap',
},
sizeOption: {
paddingHorizontal: 15,
paddingVertical: 6,
borderRadius: 4,
marginRight: 10,
marginBottom: 10,
borderWidth: 1,
borderColor: '#e0e0e0',
},
sizeOptionSelected: {
borderColor: '#ff6600',
backgroundColor: '#fff8f5',
},
sizeText: {
fontSize: 12,
color: '#333',
},
sizeTextSelected: {
color: '#ff6600',
fontWeight: 'bold',
},
relatedProductsSection: {
backgroundColor: '#fff',
padding: 15,
marginBottom: 10,
},
sectionHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 15,
},
sectionTitle: {
fontSize: 16,
fontWeight: 'bold',
color: '#333',
},
viewAllButton: {
flexDirection: 'row',
alignItems: 'center',
},
viewAllText: {
fontSize: 12,
color: '#0066ff',
},
relatedProductsContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
marginTop: 10,
},
relatedProductItem: {
width: screenWidth / 2 - 25,
marginBottom: 15,
},
relatedProductImage: {
width: '100%',
height: 120,
borderRadius: 4,
marginBottom: 5,
},
relatedProductPrice: {
fontSize: 14,
fontWeight: 'bold',
color: '#ff6600',
},
loadMoreIndicator: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingVertical: 10,
},
loadMoreText: {
fontSize: 12,
color: '#666',
marginLeft: 8,
},
noMoreProductsText: {
textAlign: 'center',
fontSize: 12,
color: '#999',
paddingVertical: 10,
},
detailsSection: {
backgroundColor: '#fff',
padding: 15,
},
productDetails: {
marginTop: 10,
},
productDetailItem: {
marginBottom: 10,
},
productDetailImage: {
width: '100%',
height: 200,
borderRadius: 4,
},
detailPlaceholder: {
width: '100%',
height: 200,
borderRadius: 4,
backgroundColor: '#f0f0f0',
justifyContent: 'center',
alignItems: 'center',
},
detailPlaceholderText: {
fontSize: 16,
color: '#999',
},
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,
},
chatButton: {
alignItems: 'center',
justifyContent: 'center',
marginRight: 15,
},
chatButtonText: {
fontSize: 10,
color: '#666',
marginTop: 2,
},
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,
},
});