expo-duooomi-app/app/templateDetail.tsx

162 lines
4.9 KiB
TypeScript

import { useEffect, useState } 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 { LeftArrowIcon } from '@/components/icon'
import SearchResultsGrid from '@/components/SearchResultsGrid'
import { useTemplateDetail, useTemplates } from '@/hooks/data'
export default function TemplateDetailScreen() {
const router = useRouter()
const params = useLocalSearchParams()
const templateId = params.templateId as string
const { data: templateDetail, loading: detailLoading, error: detailError, execute: fetchDetail } = useTemplateDetail()
const { data: relatedTemplates, loading: relatedLoading, execute: fetchRelated } = useTemplates()
const [gridData, setGridData] = useState<any[]>([])
useEffect(() => {
if (templateId) {
fetchDetail({ id: templateId })
fetchRelated({ limit: 10 })
}
}, [templateId])
useEffect(() => {
if (relatedTemplates?.templates) {
const formattedData = relatedTemplates.templates
.filter((template) => template.id !== templateId)
.map((template, index) => ({
id: Number(template.id) || index,
title: template.title,
image: { uri: template.coverImageUrl },
height: 200,
videoUrl: template.previewUrl,
thumbnailUrl: template.coverImageUrl,
}))
setGridData(formattedData)
}
}, [relatedTemplates, templateId])
if (detailError) {
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.errorContainer}>
<Text style={styles.errorText}></Text>
</View>
</SafeAreaView>
)
}
if (detailLoading) {
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.loadingContainer}>
<ActivityIndicator size="large" color="#FFFFFF" />
</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 || ''}
</Text>
<Text style={styles.subTitle}>
{templateDetail?.description || ''}
</Text>
</View>
{relatedLoading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator size="small" color="#FFFFFF" />
</View>
) : (
<SearchResultsGrid results={gridData} />
)}
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#090A0B',
},
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',
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
errorContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
errorText: {
color: '#ABABAB',
fontSize: 16,
},
})