feat: integrate UI components into Home tab

Replace custom loading/error states with reusable components (RefreshControl, LoadingState, ErrorState). Add pull-to-refresh functionality and remove duplicate styles.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
imeepos 2026-01-21 12:03:44 +08:00
parent 9703bb8fce
commit 141ccabe06
1 changed files with 22 additions and 37 deletions

View File

@ -19,7 +19,9 @@ import {
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { DownArrowIcon, PointsIcon, SearchIcon } from '@/components/icon';
import { HomeSkeleton } from '@/components/skeleton/HomeSkeleton';
import ErrorState from '@/components/ErrorState';
import LoadingState from '@/components/LoadingState';
import RefreshControl from '@/components/RefreshControl';
import { useActivates } from '@/hooks/use-activates';
import { useCategories } from '@/hooks/use-categories';
import { CategoryTemplate } from '@repo/sdk';
@ -82,6 +84,7 @@ export default function HomeScreen() {
const params = useLocalSearchParams()
const [activeTab, setActiveTab] = useState(0)
const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(null)
const [refreshing, setRefreshing] = useState(false)
const { load: loadCategories, data: categoriesData, loading: categoriesLoading, error: categoriesError } = useCategories()
const { load, data: activatesData, error } = useActivates()
@ -91,6 +94,12 @@ export default function HomeScreen() {
loadCategories()
}, [])
const handleRefresh = async () => {
setRefreshing(true)
await Promise.all([load(), loadCategories()])
setRefreshing(false)
}
useEffect(() => {
// 当分类数据加载完成后,默认选中第一个分类
if (categoriesData?.categories && categoriesData.categories.length > 0 && !selectedCategoryId) {
@ -280,6 +289,9 @@ export default function HomeScreen() {
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
showsVerticalScrollIndicator={false}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} />
}
onScroll={(event) => {
const scrollY = event.nativeEvent.contentOffset.y
if (scrollY >= tabsPositionRef.current) {
@ -330,26 +342,21 @@ export default function HomeScreen() {
)}
{/* 加载状态 */}
{showLoading && <HomeSkeleton />}
{showLoading && <LoadingState />}
{/* 错误状态 - 分类加载失败 */}
{categoriesError && (
<ErrorState message="加载分类失败" onRetry={() => loadCategories()} />
)}
{/* 空状态 - 分类数据为空 */}
{showEmptyState && (
<View style={styles.emptyState}>
<Text style={styles.emptyStateText}></Text>
<Pressable style={styles.retryButton} onPress={() => loadCategories()}>
<Text style={styles.retryButtonText}></Text>
</Pressable>
</View>
{showEmptyState && !categoriesError && (
<ErrorState message="暂无分类数据" onRetry={() => loadCategories()} />
)}
{/* 空状态 - 当前分类下没有模板 */}
{showEmptyTemplates && (
<View style={styles.emptyState}>
<Text style={styles.emptyStateText}></Text>
<Pressable style={styles.retryButton} onPress={() => loadCategories()}>
<Text style={styles.retryButtonText}></Text>
</Pressable>
</View>
<ErrorState message="该分类暂无模板" onRetry={() => loadCategories()} />
)}
{/* 内容网格 - 使用 FlashList 优化性能 */}
@ -659,26 +666,4 @@ const styles = StyleSheet.create({
color: '#F5F5F5',
lineHeight: 20,
},
emptyState: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingVertical: 60,
gap: 16,
},
emptyStateText: {
color: '#ABABAB',
fontSize: 14,
},
retryButton: {
backgroundColor: '#FF6699',
paddingHorizontal: 24,
paddingVertical: 12,
borderRadius: 8,
},
retryButtonText: {
color: '#FFFFFF',
fontSize: 14,
fontWeight: '600',
},
})