expo-popcore-app/app/searchResults.tsx

176 lines
6.0 KiB
TypeScript

import { useState, useEffect } from 'react'
import {
View,
StyleSheet,
StatusBar as RNStatusBar,
ScrollView,
} from 'react-native'
import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useRouter, useLocalSearchParams } from 'expo-router'
import SearchResultsGrid from '@/components/SearchResultsGrid'
import SearchBar from '@/components/SearchBar'
import LoadingState from '@/components/LoadingState'
import ErrorState from '@/components/ErrorState'
import PaginationLoader from '@/components/PaginationLoader'
import { useTemplates, useSearchHistory } from '@/hooks'
export default function SearchResultsScreen() {
const router = useRouter()
const params = useLocalSearchParams()
const [searchText, setSearchText] = useState((params.q as string) || '')
const { templates, loading, loadingMore, error, execute, refetch, loadMore, hasMore } = useTemplates()
const { addToHistory } = useSearchHistory()
useEffect(() => {
if (params.q && typeof params.q === 'string') {
const query = params.q.trim()
setSearchText(query)
if (query) {
execute({ search: query, limit: 20, sortBy: 'createdAt', sortOrder: 'desc', page: 1 })
addToHistory(query)
}
}
}, [params.q, execute, addToHistory])
const handleRefresh = async () => {
if (searchText) {
await refetch()
}
}
const handleLoadMore = () => {
if (hasMore && !loadingMore) {
loadMore()
}
}
const searchResults = templates.map(template => ({
id: template.id,
title: template.title || template.titleEn || '',
image: { uri: template.previewUrl || template.coverImageUrl || '' },
previewUrl: template.previewUrl,
coverImageUrl: template.coverImageUrl,
aspectRatio: template.aspectRatio ? parseFloat(template.aspectRatio as string) : undefined,
}))
if (loading) {
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
<SearchBar
searchText={searchText}
onSearchTextChange={setSearchText}
onSearch={(text) => {
router.push({
pathname: '/searchTemplate',
params: { q: text, focus: 'true' },
})
}}
onBack={() => router.back()}
readOnly={true}
onInputPress={() => {
router.push({
pathname: '/searchTemplate',
params: { q: searchText, focus: 'true' },
})
}}
onClearPress={() => {
router.push({
pathname: '/searchTemplate',
params: { q: '', focus: 'true' },
})
}}
marginBottom={12}
/>
<LoadingState />
</SafeAreaView>
)
}
if (error) {
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
<SearchBar
searchText={searchText}
onSearchTextChange={setSearchText}
onSearch={(text) => {
router.push({
pathname: '/searchTemplate',
params: { q: text, focus: 'true' },
})
}}
onBack={() => router.back()}
readOnly={true}
onInputPress={() => {
router.push({
pathname: '/searchTemplate',
params: { q: searchText, focus: 'true' },
})
}}
onClearPress={() => {
router.push({
pathname: '/searchTemplate',
params: { q: '', focus: 'true' },
})
}}
marginBottom={12}
/>
<ErrorState message={error.message} onRetry={refetch} />
</SafeAreaView>
)
}
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
<SearchBar
searchText={searchText}
onSearchTextChange={setSearchText}
onSearch={(text) => {
router.push({
pathname: '/searchTemplate',
params: { q: text, focus: 'true' },
})
}}
onBack={() => router.back()}
readOnly={true}
onInputPress={() => {
router.push({
pathname: '/searchTemplate',
params: { q: searchText, focus: 'true' },
})
}}
onClearPress={() => {
router.push({
pathname: '/searchTemplate',
params: { q: '', focus: 'true' },
})
}}
marginBottom={12}
/>
<SearchResultsGrid
results={searchResults}
loading={false}
onEndReached={handleLoadMore}
ListFooterComponent={loadingMore ? <PaginationLoader /> : null}
/>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#090A0B',
},
})