products
This commit is contained in:
381
app/(tabs)/products/[id].tsx
Normal file
381
app/(tabs)/products/[id].tsx
Normal file
@@ -0,0 +1,381 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
Image,
|
||||
ActivityIndicator,
|
||||
TouchableOpacity,
|
||||
Dimensions,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||
import { useProduct } from '../../../hooks/useProducts';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
|
||||
export default function ProductDetailScreen() {
|
||||
const router = useRouter();
|
||||
const { id } = useLocalSearchParams();
|
||||
const productId = typeof id === 'string' ? parseInt(id) : null;
|
||||
|
||||
const { product, loading, error } = useProduct(productId);
|
||||
|
||||
const formatPrice = (price: number) => {
|
||||
return new Intl.NumberFormat('vi-VN', {
|
||||
style: 'currency',
|
||||
currency: 'VND',
|
||||
}).format(price);
|
||||
};
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
return new Date(dateString).toLocaleDateString('vi-VN', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
});
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color="#007AFF" />
|
||||
<Text style={styles.loadingText}>Đang tải...</Text>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !product) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.errorContainer}>
|
||||
<Ionicons name="alert-circle-outline" size={64} color="#f44336" />
|
||||
<Text style={styles.errorText}>
|
||||
{error || 'Không tìm thấy sản phẩm'}
|
||||
</Text>
|
||||
<TouchableOpacity style={styles.backButton} onPress={() => router.back()}>
|
||||
<Text style={styles.backButtonText}>Quay lại</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container} edges={['top']}>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity style={styles.backBtn} onPress={() => router.back()}>
|
||||
<Ionicons name="arrow-back" size={24} color="#333" />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle} numberOfLines={1}>
|
||||
Chi tiết sản phẩm
|
||||
</Text>
|
||||
<View style={{ width: 40 }} />
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.scrollView} showsVerticalScrollIndicator={false}>
|
||||
{/* Product Image */}
|
||||
<Image
|
||||
source={{ uri: product.imageUrl || 'https://via.placeholder.com/400' }}
|
||||
style={styles.productImage}
|
||||
resizeMode="cover"
|
||||
/>
|
||||
|
||||
{/* Product Info */}
|
||||
<View style={styles.content}>
|
||||
{/* Category Badge */}
|
||||
<View style={styles.categoryBadge}>
|
||||
<Text style={styles.categoryBadgeText}>{product.categoryName}</Text>
|
||||
</View>
|
||||
|
||||
{/* Product Name */}
|
||||
<Text style={styles.productName}>{product.productName}</Text>
|
||||
|
||||
{/* Price & Stock */}
|
||||
<View style={styles.priceStockContainer}>
|
||||
<Text style={styles.price}>{formatPrice(product.price)}</Text>
|
||||
{product.stockQuantity > 0 ? (
|
||||
<View style={styles.stockBadge}>
|
||||
<Ionicons name="checkmark-circle" size={20} color="#4caf50" />
|
||||
<Text style={styles.stockText}>Còn {product.stockQuantity} sản phẩm</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View style={[styles.stockBadge, styles.outOfStockBadge]}>
|
||||
<Ionicons name="close-circle" size={20} color="#f44336" />
|
||||
<Text style={[styles.stockText, styles.outOfStockText]}>Hết hàng</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Divider */}
|
||||
<View style={styles.divider} />
|
||||
|
||||
{/* Description */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Mô tả sản phẩm</Text>
|
||||
<Text style={styles.description}>
|
||||
{product.description || 'Chưa có mô tả cho sản phẩm này.'}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Divider */}
|
||||
<View style={styles.divider} />
|
||||
|
||||
{/* Product Details */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Thông tin chi tiết</Text>
|
||||
|
||||
<View style={styles.detailRow}>
|
||||
<View style={styles.detailLabel}>
|
||||
<Ionicons name="pricetag-outline" size={20} color="#666" />
|
||||
<Text style={styles.detailLabelText}>Mã sản phẩm</Text>
|
||||
</View>
|
||||
<Text style={styles.detailValue}>#{product.productId}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.detailRow}>
|
||||
<View style={styles.detailLabel}>
|
||||
<Ionicons name="cube-outline" size={20} color="#666" />
|
||||
<Text style={styles.detailLabelText}>Danh mục</Text>
|
||||
</View>
|
||||
<Text style={styles.detailValue}>{product.categoryName}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.detailRow}>
|
||||
<View style={styles.detailLabel}>
|
||||
<Ionicons name="calendar-outline" size={20} color="#666" />
|
||||
<Text style={styles.detailLabelText}>Ngày tạo</Text>
|
||||
</View>
|
||||
<Text style={styles.detailValue}>{formatDate(product.createdAt)}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.detailRow}>
|
||||
<View style={styles.detailLabel}>
|
||||
<Ionicons name="time-outline" size={20} color="#666" />
|
||||
<Text style={styles.detailLabelText}>Cập nhật lần cuối</Text>
|
||||
</View>
|
||||
<Text style={styles.detailValue}>{formatDate(product.updatedAt)}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
{/* Bottom Action Buttons */}
|
||||
<View style={styles.bottomActions}>
|
||||
<TouchableOpacity
|
||||
style={[styles.actionButton, styles.addToCartButton]}
|
||||
disabled={product.stockQuantity === 0}
|
||||
>
|
||||
<Ionicons name="cart-outline" size={24} color="#fff" />
|
||||
<Text style={styles.actionButtonText}>
|
||||
{product.stockQuantity > 0 ? 'Thêm vào giỏ' : 'Hết hàng'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={[styles.actionButton, styles.buyNowButton]}>
|
||||
<Ionicons name="flash-outline" size={24} color="#fff" />
|
||||
<Text style={styles.actionButtonText}>Mua ngay</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 12,
|
||||
backgroundColor: '#fff',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#e0e0e0',
|
||||
},
|
||||
backBtn: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
flex: 1,
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
textAlign: 'center',
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
},
|
||||
productImage: {
|
||||
width: width,
|
||||
height: width,
|
||||
backgroundColor: '#f0f0f0',
|
||||
},
|
||||
content: {
|
||||
padding: 16,
|
||||
},
|
||||
categoryBadge: {
|
||||
alignSelf: 'flex-start',
|
||||
backgroundColor: '#e3f2fd',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
borderRadius: 16,
|
||||
marginBottom: 12,
|
||||
},
|
||||
categoryBadgeText: {
|
||||
fontSize: 13,
|
||||
color: '#1976d2',
|
||||
fontWeight: '600',
|
||||
},
|
||||
productName: {
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
color: '#333',
|
||||
marginBottom: 16,
|
||||
lineHeight: 32,
|
||||
},
|
||||
priceStockContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
},
|
||||
price: {
|
||||
fontSize: 28,
|
||||
fontWeight: '700',
|
||||
color: '#e91e63',
|
||||
},
|
||||
stockBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#e8f5e9',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
borderRadius: 8,
|
||||
gap: 6,
|
||||
},
|
||||
stockText: {
|
||||
fontSize: 14,
|
||||
color: '#4caf50',
|
||||
fontWeight: '600',
|
||||
},
|
||||
outOfStockBadge: {
|
||||
backgroundColor: '#ffebee',
|
||||
},
|
||||
outOfStockText: {
|
||||
color: '#f44336',
|
||||
},
|
||||
divider: {
|
||||
height: 1,
|
||||
backgroundColor: '#e0e0e0',
|
||||
marginVertical: 20,
|
||||
},
|
||||
section: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
color: '#333',
|
||||
marginBottom: 12,
|
||||
},
|
||||
description: {
|
||||
fontSize: 15,
|
||||
color: '#666',
|
||||
lineHeight: 24,
|
||||
},
|
||||
detailRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 12,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#f0f0f0',
|
||||
},
|
||||
detailLabel: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
detailLabelText: {
|
||||
fontSize: 15,
|
||||
color: '#666',
|
||||
},
|
||||
detailValue: {
|
||||
fontSize: 15,
|
||||
color: '#333',
|
||||
fontWeight: '600',
|
||||
},
|
||||
bottomActions: {
|
||||
flexDirection: 'row',
|
||||
padding: 16,
|
||||
gap: 12,
|
||||
backgroundColor: '#fff',
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: '#e0e0e0',
|
||||
},
|
||||
actionButton: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 14,
|
||||
borderRadius: 12,
|
||||
gap: 8,
|
||||
},
|
||||
addToCartButton: {
|
||||
backgroundColor: '#ff9800',
|
||||
},
|
||||
buyNowButton: {
|
||||
backgroundColor: '#e91e63',
|
||||
},
|
||||
actionButtonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#fff',
|
||||
},
|
||||
loadingContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
loadingText: {
|
||||
marginTop: 12,
|
||||
fontSize: 16,
|
||||
color: '#666',
|
||||
},
|
||||
errorContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 20,
|
||||
},
|
||||
errorText: {
|
||||
marginTop: 16,
|
||||
fontSize: 16,
|
||||
color: '#f44336',
|
||||
textAlign: 'center',
|
||||
},
|
||||
backButton: {
|
||||
marginTop: 16,
|
||||
backgroundColor: '#007AFF',
|
||||
paddingHorizontal: 24,
|
||||
paddingVertical: 12,
|
||||
borderRadius: 8,
|
||||
},
|
||||
backButtonText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
17
app/(tabs)/products/_layout.tsx
Normal file
17
app/(tabs)/products/_layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Stack } from "expo-router";
|
||||
|
||||
export default function ProductsLayout() {
|
||||
return (
|
||||
<Stack screenOptions={{ headerShown: false }}>
|
||||
<Stack.Screen name="index" />
|
||||
<Stack.Screen
|
||||
name="[id]"
|
||||
options={{
|
||||
presentation: "card",
|
||||
headerShown: false,
|
||||
tabBarStyle: { display: "none" }, // Ẩn tab bar
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
302
app/(tabs)/products/index.tsx
Normal file
302
app/(tabs)/products/index.tsx
Normal file
@@ -0,0 +1,302 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
FlatList,
|
||||
ActivityIndicator,
|
||||
RefreshControl,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useProducts } from '../../../hooks/useProducts';
|
||||
import ProductCard from '../../../components/ProductCard';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
|
||||
export default function ProductsScreen() {
|
||||
const [page, setPage] = useState(0);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [isSearching, setIsSearching] = useState(false);
|
||||
|
||||
const { products, loading, error, refreshing, refresh, hasNext, hasPrevious } = useProducts({
|
||||
page,
|
||||
size: 10,
|
||||
keyword: isSearching ? searchQuery : undefined,
|
||||
});
|
||||
|
||||
const handleSearch = () => {
|
||||
if (searchQuery.trim()) {
|
||||
setIsSearching(true);
|
||||
setPage(0);
|
||||
}
|
||||
};
|
||||
|
||||
const clearSearch = () => {
|
||||
setSearchQuery('');
|
||||
setIsSearching(false);
|
||||
setPage(0);
|
||||
};
|
||||
|
||||
const handleLoadMore = () => {
|
||||
if (hasNext && !loading) {
|
||||
setPage((prev) => prev + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLoadPrevious = () => {
|
||||
if (hasPrevious && !loading && page > 0) {
|
||||
setPage((prev) => prev - 1);
|
||||
}
|
||||
};
|
||||
|
||||
const renderHeader = () => (
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Sản phẩm</Text>
|
||||
<View style={styles.searchContainer}>
|
||||
<View style={styles.searchInputContainer}>
|
||||
<Ionicons name="search" size={20} color="#666" style={styles.searchIcon} />
|
||||
<TextInput
|
||||
style={styles.searchInput}
|
||||
placeholder="Tìm kiếm sản phẩm..."
|
||||
value={searchQuery}
|
||||
onChangeText={setSearchQuery}
|
||||
onSubmitEditing={handleSearch}
|
||||
returnKeyType="search"
|
||||
/>
|
||||
{searchQuery.length > 0 && (
|
||||
<TouchableOpacity onPress={clearSearch} style={styles.clearButton}>
|
||||
<Ionicons name="close-circle" size={20} color="#666" />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
{searchQuery.length > 0 && (
|
||||
<TouchableOpacity style={styles.searchButton} onPress={handleSearch}>
|
||||
<Text style={styles.searchButtonText}>Tìm</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const renderFooter = () => {
|
||||
if (!loading) return null;
|
||||
return (
|
||||
<View style={styles.footer}>
|
||||
<ActivityIndicator size="small" color="#007AFF" />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const renderPagination = () => (
|
||||
<View style={styles.pagination}>
|
||||
<TouchableOpacity
|
||||
style={[styles.pageButton, !hasPrevious && styles.pageButtonDisabled]}
|
||||
onPress={handleLoadPrevious}
|
||||
disabled={!hasPrevious || loading}
|
||||
>
|
||||
<Ionicons name="chevron-back" size={24} color={hasPrevious ? '#007AFF' : '#ccc'} />
|
||||
<Text style={[styles.pageButtonText, !hasPrevious && styles.pageButtonTextDisabled]}>
|
||||
Trước
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<Text style={styles.pageInfo}>Trang {page + 1}</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[styles.pageButton, !hasNext && styles.pageButtonDisabled]}
|
||||
onPress={handleLoadMore}
|
||||
disabled={!hasNext || loading}
|
||||
>
|
||||
<Text style={[styles.pageButtonText, !hasNext && styles.pageButtonTextDisabled]}>
|
||||
Sau
|
||||
</Text>
|
||||
<Ionicons name="chevron-forward" size={24} color={hasNext ? '#007AFF' : '#ccc'} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.errorContainer}>
|
||||
<Ionicons name="alert-circle-outline" size={64} color="#f44336" />
|
||||
<Text style={styles.errorText}>{error}</Text>
|
||||
<TouchableOpacity style={styles.retryButton} onPress={refresh}>
|
||||
<Text style={styles.retryButtonText}>Thử lại</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container} edges={['top']}>
|
||||
<FlatList
|
||||
ListHeaderComponent={renderHeader}
|
||||
data={products}
|
||||
renderItem={({ item }) => <ProductCard product={item} />}
|
||||
keyExtractor={(item) => item.productId.toString()}
|
||||
contentContainerStyle={styles.listContent}
|
||||
ListEmptyComponent={
|
||||
loading ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color="#007AFF" />
|
||||
<Text style={styles.loadingText}>Đang tải...</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.emptyContainer}>
|
||||
<Ionicons name="cube-outline" size={64} color="#ccc" />
|
||||
<Text style={styles.emptyText}>Không có sản phẩm nào</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
ListFooterComponent={
|
||||
<>
|
||||
{renderFooter()}
|
||||
{products.length > 0 && renderPagination()}
|
||||
</>
|
||||
}
|
||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={refresh} />}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#f5f5f5',
|
||||
},
|
||||
header: {
|
||||
backgroundColor: '#fff',
|
||||
padding: 16,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#e0e0e0',
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
fontWeight: 'bold',
|
||||
color: '#333',
|
||||
marginBottom: 12,
|
||||
},
|
||||
searchContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
searchInputContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#f0f0f0',
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
searchIcon: {
|
||||
marginRight: 8,
|
||||
},
|
||||
searchInput: {
|
||||
flex: 1,
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
color: '#333',
|
||||
},
|
||||
clearButton: {
|
||||
padding: 4,
|
||||
},
|
||||
searchButton: {
|
||||
backgroundColor: '#007AFF',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 10,
|
||||
borderRadius: 8,
|
||||
},
|
||||
searchButtonText: {
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
},
|
||||
listContent: {
|
||||
paddingVertical: 8,
|
||||
},
|
||||
loadingContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 40,
|
||||
},
|
||||
loadingText: {
|
||||
marginTop: 12,
|
||||
fontSize: 16,
|
||||
color: '#666',
|
||||
},
|
||||
emptyContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 60,
|
||||
},
|
||||
emptyText: {
|
||||
marginTop: 16,
|
||||
fontSize: 16,
|
||||
color: '#999',
|
||||
},
|
||||
errorContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 20,
|
||||
},
|
||||
errorText: {
|
||||
marginTop: 16,
|
||||
fontSize: 16,
|
||||
color: '#f44336',
|
||||
textAlign: 'center',
|
||||
},
|
||||
retryButton: {
|
||||
marginTop: 16,
|
||||
backgroundColor: '#007AFF',
|
||||
paddingHorizontal: 24,
|
||||
paddingVertical: 12,
|
||||
borderRadius: 8,
|
||||
},
|
||||
retryButtonText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
footer: {
|
||||
paddingVertical: 20,
|
||||
},
|
||||
pagination: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 20,
|
||||
backgroundColor: '#fff',
|
||||
marginTop: 8,
|
||||
},
|
||||
pageButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
},
|
||||
pageButtonDisabled: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
pageButtonText: {
|
||||
fontSize: 16,
|
||||
color: '#007AFF',
|
||||
fontWeight: '600',
|
||||
},
|
||||
pageButtonTextDisabled: {
|
||||
color: '#ccc',
|
||||
},
|
||||
pageInfo: {
|
||||
fontSize: 16,
|
||||
color: '#666',
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user