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.
801 lines
23 KiB
801 lines
23 KiB
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 <Icon name={name} size={size} color={color} />; |
|
}); |
|
|
|
// 路由参数类型 |
|
type ProductDetailRouteParams = { |
|
offer_id: string; |
|
searchKeyword?: string; |
|
price: number; |
|
}; |
|
|
|
// 颜色选项组件 |
|
const ColorOption = React.memo(({ color, selected, onSelect }: { color: string; selected: boolean; onSelect: () => void }) => ( |
|
<TouchableOpacity |
|
style={[styles.colorOption, selected && styles.colorOptionSelected]} |
|
onPress={onSelect} |
|
> |
|
<View style={[styles.colorCircle, { backgroundColor: color }]} /> |
|
<Text style={styles.colorName}>{color}</Text> |
|
</TouchableOpacity> |
|
)); |
|
|
|
// 尺寸选项组件 |
|
const SizeOption = React.memo(({ size, selected, onSelect }: { size: string; selected: boolean; onSelect: () => void }) => ( |
|
<TouchableOpacity |
|
style={[styles.sizeOption, selected && styles.sizeOptionSelected]} |
|
onPress={onSelect} |
|
> |
|
<Text style={[styles.sizeText, selected && styles.sizeTextSelected]}>{size}</Text> |
|
</TouchableOpacity> |
|
)); |
|
|
|
// 相关商品组件 |
|
const RelatedProductItem = React.memo(({ product, onPress }: { product: any; onPress: () => void }) => ( |
|
<TouchableOpacity style={styles.relatedProductItem} onPress={onPress}> |
|
<Image source={{ uri: product.image }} style={styles.relatedProductImage} /> |
|
<Text style={styles.relatedProductPrice}>${product.price}</Text> |
|
</TouchableOpacity> |
|
)); |
|
|
|
export const ProductDetailScreen = () => { |
|
const { t } = useTranslation(); |
|
const navigation = useNavigation<NativeStackNavigationProp<any>>(); |
|
const route = useRoute<RouteProp<Record<string, ProductDetailRouteParams>, string>>(); |
|
const [product, setProduct] = useState<ProductDetailParams | null>(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 ( |
|
<SafeAreaView style={styles.container}> |
|
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> |
|
<View style={styles.header}> |
|
<TouchableOpacity style={styles.backButton} onPress={goBack}> |
|
<IconComponent name="arrow-back" size={24} color="#333" /> |
|
</TouchableOpacity> |
|
<Text style={styles.headerTitle}>{t('productDetail')}</Text> |
|
<View style={styles.headerRight}> |
|
<IconComponent name="ellipsis-vertical" size={20} color="#333" /> |
|
</View> |
|
</View> |
|
<View style={styles.loadingContainer}> |
|
<ActivityIndicator size="large" color="#ff6600" /> |
|
<Text style={styles.loadingText}>{t('loadingProductInfo')}</Text> |
|
</View> |
|
</SafeAreaView> |
|
); |
|
} |
|
|
|
if (!product) { |
|
return ( |
|
<SafeAreaView style={styles.container}> |
|
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> |
|
<View style={styles.header}> |
|
<TouchableOpacity style={styles.backButton} onPress={goBack}> |
|
<IconComponent name="arrow-back" size={24} color="#333" /> |
|
</TouchableOpacity> |
|
<Text style={styles.headerTitle}>{t('productDetail')}</Text> |
|
<View style={styles.headerRight}> |
|
<IconComponent name="ellipsis-vertical" size={20} color="#333" /> |
|
</View> |
|
</View> |
|
<View style={styles.errorContainer}> |
|
<IconComponent name="alert-circle-outline" size={48} color="#ff6600" /> |
|
<Text style={styles.errorText}>{t('productNotAvailable')}</Text> |
|
</View> |
|
</SafeAreaView> |
|
); |
|
} |
|
|
|
return ( |
|
<SafeAreaView style={styles.container}> |
|
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> |
|
|
|
{/* 头部导航 */} |
|
<View style={styles.header}> |
|
<TouchableOpacity style={styles.backButton} onPress={goBack}> |
|
<IconComponent name="arrow-back" size={24} color="#333" /> |
|
</TouchableOpacity> |
|
<Text style={styles.headerTitle} numberOfLines={1}> |
|
{t('productDetail')} |
|
</Text> |
|
<View style={styles.headerRight}> |
|
<TouchableOpacity style={styles.headerIconButton}> |
|
<IconComponent name="ellipsis-vertical" size={20} color="#333" /> |
|
</TouchableOpacity> |
|
</View> |
|
</View> |
|
|
|
<ScrollView |
|
style={styles.scrollContainer} |
|
showsVerticalScrollIndicator={false} |
|
onScroll={({ nativeEvent }) => { |
|
const { layoutMeasurement, contentOffset, contentSize } = nativeEvent; |
|
const paddingToBottom = 20; |
|
if (layoutMeasurement.height + contentOffset.y >= |
|
contentSize.height - paddingToBottom) { |
|
handleLoadMore(); |
|
} |
|
}} |
|
scrollEventThrottle={400} |
|
> |
|
{/* 产品图片轮播 */} |
|
<View style={styles.imageContainer}> |
|
{product.product_image_urls && product.product_image_urls.length > 0 ? ( |
|
<> |
|
<FlatList |
|
data={product.product_image_urls} |
|
horizontal |
|
pagingEnabled |
|
showsHorizontalScrollIndicator={false} |
|
keyExtractor={(_, index) => `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 }) => ( |
|
<View style={[styles.imageContainer, { width: screenWidth }]}> |
|
<Image |
|
source={{ uri: item }} |
|
style={{ width: '100%', height: '100%' }} |
|
resizeMode="contain" |
|
/> |
|
</View> |
|
)} |
|
/> |
|
{/* 指示器 */} |
|
{product.product_image_urls.length > 1 && ( |
|
<View style={styles.paginationContainer}> |
|
{product.product_image_urls.map((_, index) => ( |
|
<View |
|
key={`dot-${index}`} |
|
style={[ |
|
styles.paginationDot, |
|
index === activeImageIndex ? styles.paginationDotActive : {} |
|
]} |
|
/> |
|
))} |
|
</View> |
|
)} |
|
</> |
|
) : ( |
|
<View style={styles.imagePlaceholder}> |
|
<Text style={styles.imagePlaceholderText}>{t('productDetail')}</Text> |
|
</View> |
|
)} |
|
</View> |
|
|
|
{/* 产品基本信息 */} |
|
<View style={styles.infoSection}> |
|
<View style={styles.priceContainer}> |
|
<Text style={styles.productPrice}> |
|
${product.price?.toFixed(2) || '29.99'} |
|
</Text> |
|
<Text style={styles.originalPrice}>${(product.price * 1.4).toFixed(2) || '49.99'}</Text> |
|
<View style={styles.discountBadge}> |
|
<Text style={styles.discountText}>-40%</Text> |
|
</View> |
|
<View style={styles.vipBadge}> |
|
<Text style={styles.vipText}>VIP</Text> |
|
</View> |
|
</View> |
|
|
|
<Text style={styles.productTitle}>{product.subject || 'Product Name'}</Text> |
|
<Text style={styles.productSales}>{t('monthlySales')} {product.sold_out || 2458}</Text> |
|
|
|
{/* 颜色选择 */} |
|
<View style={styles.optionSection}> |
|
<Text style={styles.optionTitle}>{t('color')}</Text> |
|
<View style={styles.colorOptions}> |
|
{colorOptions.map((color, index) => ( |
|
<ColorOption |
|
key={`color-${index}`} |
|
color={color} |
|
selected={selectedColor === color} |
|
onSelect={() => setSelectedColor(color)} |
|
/> |
|
))} |
|
<TouchableOpacity style={styles.moreColorsButton}> |
|
<Text style={styles.moreColorsText}>+2</Text> |
|
</TouchableOpacity> |
|
</View> |
|
</View> |
|
|
|
{/* 尺寸选择 */} |
|
<View style={styles.optionSection}> |
|
<Text style={styles.optionTitle}>{t('size')}</Text> |
|
<View style={styles.sizeOptions}> |
|
{sizeOptions.map((size, index) => ( |
|
<SizeOption |
|
key={`size-${index}`} |
|
size={size} |
|
selected={selectedSize === size} |
|
onSelect={() => setSelectedSize(size)} |
|
/> |
|
))} |
|
</View> |
|
</View> |
|
</View> |
|
|
|
{/* 相关商品 */} |
|
<View style={styles.relatedProductsSection}> |
|
<View style={styles.sectionHeader}> |
|
<Text style={styles.sectionTitle}>{t('moreFromStore')}</Text> |
|
<TouchableOpacity style={styles.viewAllButton}> |
|
<Text style={styles.viewAllText}>{t('viewAll')}</Text> |
|
<IconComponent name="chevron-forward" size={16} color="#0066ff" /> |
|
</TouchableOpacity> |
|
</View> |
|
|
|
<View style={styles.relatedProductsContainer}> |
|
{relatedProducts.map((product, index) => ( |
|
<RelatedProductItem |
|
key={`related-${product.id}`} |
|
product={product} |
|
onPress={() => handleRelatedProductPress(product)} |
|
/> |
|
))} |
|
</View> |
|
|
|
{loadingMore && ( |
|
<View style={styles.loadMoreIndicator}> |
|
<ActivityIndicator size="small" color="#ff6600" /> |
|
<Text style={styles.loadMoreText}>{t('loadingMoreProducts')}</Text> |
|
</View> |
|
)} |
|
|
|
{!hasMoreProducts && relatedProducts.length > 0 && ( |
|
<Text style={styles.noMoreProductsText}>{t('noMoreProducts')}</Text> |
|
)} |
|
</View> |
|
|
|
{/* 商品详情 */} |
|
<View style={styles.detailsSection}> |
|
<Text style={styles.sectionTitle}>{t('productDetails')}</Text> |
|
<View style={styles.productDetails}> |
|
<View style={styles.productDetailItem}> |
|
<View style={styles.detailPlaceholder}> |
|
<Text style={styles.detailPlaceholderText}>{t('productDetails')} 1</Text> |
|
</View> |
|
</View> |
|
<View style={styles.productDetailItem}> |
|
<View style={styles.detailPlaceholder}> |
|
<Text style={styles.detailPlaceholderText}>{t('productDetails')} 2</Text> |
|
</View> |
|
</View> |
|
<View style={styles.productDetailItem}> |
|
<View style={styles.detailPlaceholder}> |
|
<Text style={styles.detailPlaceholderText}>{t('productDetails')} 3</Text> |
|
</View> |
|
</View> |
|
</View> |
|
</View> |
|
|
|
{/* 底部空间,确保内容不被底部操作栏遮挡 */} |
|
<View style={styles.bottomSpace} /> |
|
</ScrollView> |
|
|
|
{/* 底部操作栏 */} |
|
<View style={styles.bottomBar}> |
|
<TouchableOpacity style={styles.chatButton}> |
|
<IconComponent name="chatbubble-outline" size={22} color="#666" /> |
|
<Text style={styles.chatButtonText}>{t('customerService')}</Text> |
|
</TouchableOpacity> |
|
<TouchableOpacity style={styles.addToCartButton} onPress={handleAddToCart}> |
|
<IconComponent name="cart-outline" size={20} color="#fff" /> |
|
<Text style={styles.addToCartText}>{t('addToCart')}</Text> |
|
</TouchableOpacity> |
|
<TouchableOpacity style={styles.buyNowButton} onPress={handleBuyNow}> |
|
<Text style={styles.buyNowText}>{t('buyNow')}</Text> |
|
</TouchableOpacity> |
|
</View> |
|
</SafeAreaView> |
|
); |
|
}; |
|
|
|
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, |
|
}, |
|
});
|