initial
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { FlatList, ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { api, DocCategory } from '@/api';
|
||||
import { useT } from '@/i18n';
|
||||
import { AppBar } from '@/components/AppBar';
|
||||
import { Chip, EmptyState, Loading, TextField } from '@/components/ui';
|
||||
import { DocumentRow } from '@/components/domain';
|
||||
import { DocWithProperty, fetchAllDocuments } from '@/lib/allDocuments';
|
||||
import { colors, fontSize, spacing } from '@/theme';
|
||||
|
||||
export default function SearchScreen() {
|
||||
const router = useRouter();
|
||||
const t = useT();
|
||||
const [query, setQuery] = useState('');
|
||||
const [category, setCategory] = useState<string>('all');
|
||||
|
||||
const docsQuery = useQuery({ queryKey: ['all-documents'], queryFn: fetchAllDocuments });
|
||||
const catsQuery = useQuery({ queryKey: ['categories'], queryFn: () => api.reference.categories() });
|
||||
|
||||
const categories: DocCategory[] = catsQuery.data ?? [];
|
||||
const catName = (slug: string) => categories.find((c) => c.slug === slug)?.name ?? slug;
|
||||
|
||||
const results = useMemo(() => {
|
||||
const docs: DocWithProperty[] = docsQuery.data ?? [];
|
||||
const q = query.trim().toLowerCase();
|
||||
return docs.filter((d) => {
|
||||
const matchesCat = category === 'all' || d.category === category;
|
||||
const matchesQuery =
|
||||
!q || d.name.toLowerCase().includes(q) || catName(d.category).toLowerCase().includes(q);
|
||||
return matchesCat && matchesQuery;
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [docsQuery.data, query, category, categories]);
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: colors.bgApp }}>
|
||||
<AppBar title={t('tabs.search')} large />
|
||||
|
||||
<View style={styles.controls}>
|
||||
<TextField
|
||||
icon="search"
|
||||
value={query}
|
||||
onChangeText={setQuery}
|
||||
placeholder={t('properties.searchPlaceholder')}
|
||||
autoCapitalize="none"
|
||||
autoFocus
|
||||
/>
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.chips}
|
||||
>
|
||||
<Chip label={t('common.all')} active={category === 'all'} onPress={() => setCategory('all')} />
|
||||
{categories.map((c) => (
|
||||
<Chip
|
||||
key={c.slug}
|
||||
label={c.name}
|
||||
active={category === c.slug}
|
||||
onPress={() => setCategory(c.slug)}
|
||||
/>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
{docsQuery.isLoading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<FlatList
|
||||
data={results}
|
||||
keyExtractor={(d) => String(d.id)}
|
||||
contentContainerStyle={styles.list}
|
||||
ListHeaderComponent={
|
||||
<Text style={styles.count}>
|
||||
{t('properties.docCount', { count: results.length })}
|
||||
</Text>
|
||||
}
|
||||
renderItem={({ item }) => (
|
||||
<View style={{ marginBottom: spacing[3] }}>
|
||||
<DocumentRow
|
||||
document={item}
|
||||
subtitle={`${item.propertyName} · ${catName(item.category)}`}
|
||||
onPress={() => router.push(`/document/${item.id}?propertyId=${item.propertyId}`)}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
<EmptyState
|
||||
icon="search-outline"
|
||||
title={t('documents.emptyTitle')}
|
||||
subtitle={t('documents.emptySubtitle')}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
controls: { paddingHorizontal: spacing[4], gap: spacing[3], paddingBottom: spacing[2] },
|
||||
chips: { gap: 8, paddingVertical: spacing[1], paddingRight: spacing[4] },
|
||||
list: { padding: spacing[4], paddingTop: spacing[2], paddingBottom: spacing[9] },
|
||||
count: { fontSize: fontSize.sm, color: colors.slate500, marginBottom: spacing[3], fontWeight: '600' },
|
||||
});
|
||||
Reference in New Issue
Block a user