Files
expo-popcore-app/app/templateDetail.tsx
imeepos ae120f24d3 feat: 对接 templateDetail 页面后端接口
- 创建 hooks/use-error.ts 统一错误处理
- 创建 hooks/use-template-detail.ts 获取模板详情
- 创建 hooks/use-template-generations.ts 获取模板生成记录
- 更新 hooks 使用 handleError 统一错误处理
- 优化 SearchResultsGrid 组件,复用 TemplateGeneration 类型
- 删除不必要的类型转换和重复代码

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-16 11:56:38 +08:00

175 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect } from 'react'
import {
View,
Text,
StyleSheet,
Pressable,
StatusBar as RNStatusBar,
ActivityIndicator,
} from 'react-native'
import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useRouter, useLocalSearchParams } from 'expo-router'
import { useTranslation } from 'react-i18next'
import { LeftArrowIcon } from '@/components/icon'
import SearchResultsGrid from '@/components/SearchResultsGrid'
import { useTemplateDetail, useTemplateGenerations, type TemplateGeneration } from '@/hooks'
const CARD_HEIGHTS = [214, 236, 200, 220, 210, 225]
export default function TemplateDetailScreen() {
const { t } = useTranslation()
const router = useRouter()
const params = useLocalSearchParams()
const templateId = typeof params.id === 'string' ? params.id : undefined
const { data: templateDetail, loading: templateLoading, error: templateError, execute: loadTemplateDetail } = useTemplateDetail()
const { generations, loading: generationsLoading, execute: loadGenerations } = useTemplateGenerations()
useEffect(() => {
if (templateId) {
loadTemplateDetail({ id: templateId })
loadGenerations({ templateId, page: 1, limit: 20 })
}
}, [templateId, loadTemplateDetail, loadGenerations])
// 直接使用 TemplateGeneration 数据,只添加必要的 height 字段
const displayData = generations.map((generation, index) => ({
...generation,
height: CARD_HEIGHTS[index % CARD_HEIGHTS.length],
title: generation.template?.title || generation.template?.titleEn || '',
image: generation.resultUrl?.[0] || generation.originalUrl || '',
}))
if (templateLoading && !templateDetail) {
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
<View style={styles.centerContainer}>
<ActivityIndicator size="large" color="#FFE500" />
</View>
</SafeAreaView>
)
}
if (templateError && !templateDetail) {
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
<View style={styles.centerContainer}>
<Text style={styles.errorText}></Text>
<Pressable style={styles.retryButton} onPress={() => router.back()}>
<Text style={styles.retryButtonText}></Text>
</Pressable>
</View>
</SafeAreaView>
)
}
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
{/* 顶部导航栏 */}
<View style={styles.header}>
<Pressable
onPress={() => router.back()}
style={styles.backButton}
>
<LeftArrowIcon />
</Pressable>
</View>
{/* 标题区域 */}
<View style={styles.titleSection}>
<Text style={styles.mainTitle}>
{templateDetail?.title || templateDetail?.titleEn || t('templateDetail.title')}
</Text>
<Text style={styles.subTitle}>
{t('templateDetail.subtitle')}
</Text>
</View>
{/* 加载更多指示器 */}
{generationsLoading && generations.length > 0 && (
<View style={styles.loadingMoreContainer}>
<ActivityIndicator size="small" color="#FFE500" />
<Text style={styles.loadingMoreText}>...</Text>
</View>
)}
<SearchResultsGrid results={displayData} />
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#090A0B',
},
centerContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
gap: 12,
},
header: {
flexDirection: 'row',
alignItems: 'center',
paddingTop: 12,
paddingHorizontal: 12,
paddingBottom: 24,
},
backButton: {
padding: 4,
},
titleSection: {
paddingHorizontal: 12,
paddingBottom: 24,
},
mainTitle: {
color: '#F5F5F5',
fontSize: 20,
fontWeight: '500',
marginBottom: 4,
},
subTitle: {
color: '#ABABAB',
fontSize: 14,
fontWeight: '400',
},
errorText: {
color: '#FFFFFF',
fontSize: 14,
textAlign: 'center',
},
retryButton: {
backgroundColor: '#FF6699',
paddingHorizontal: 24,
paddingVertical: 12,
borderRadius: 8,
},
retryButtonText: {
color: '#FFFFFF',
fontSize: 14,
fontWeight: '600',
},
loadingMoreContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: 8,
paddingVertical: 16,
},
loadingMoreText: {
color: '#ABABAB',
fontSize: 12,
},
})