Files
info-target-mobile/screens/home/ui/HomeScreen.tsx
Samandar Turgunboyev d747c72c8d complated
2026-02-17 10:46:57 +05:00

290 lines
7.8 KiB
TypeScript

// pages/home/ui/HomeScreen.tsx
import { useTheme } from '@/components/ThemeContext';
import CompanyList from '@/components/ui/CompanyList';
import CountriesList from '@/components/ui/CountriesList';
import FilteredItems from '@/components/ui/FilteredItems';
import FilterUI from '@/components/ui/FilterUI';
import ProductList from '@/components/ui/ProductList';
import SearchTabs from '@/components/ui/SearchTabs';
import { useTabSearch } from '@/hooks/useSearch';
import { TabKey } from '@/types';
import { useQueryClient } from '@tanstack/react-query';
import { StatusBar } from 'expo-status-bar';
import { Filter, Search } from 'lucide-react-native';
import React, { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
Modal,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import { GestureHandlerRootView, RefreshControl } from 'react-native-gesture-handler';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import { useHomeStore } from '../lib/hook';
function Loading() {
return (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#3b82f6" />
</View>
);
}
export default function HomeScreen() {
const { isDark } = useTheme();
const [activeTab, setActiveTab] = useState<TabKey>('products');
const [query, setQuery] = useState('');
const [refreshing, setRefreshing] = useState(false);
const [filtered, setFiltered] = useState<{ id: number; company_name: string }[]>([]);
const { t } = useTranslation();
const { showFilter, setShowFilter, step, setStep } = useHomeStore();
const queryClient = useQueryClient();
const { isLoading, error } = useTabSearch(activeTab, query);
const onRefresh = useCallback(async () => {
setRefreshing(true);
try {
if (activeTab === 'products') {
await queryClient.invalidateQueries({ queryKey: ['products-list'] });
}
await queryClient.refetchQueries();
} catch (err) {
console.error('Refresh error:', err);
} finally {
setRefreshing(false);
}
}, [queryClient, activeTab]);
const placeholderText = useMemo(() => {
switch (activeTab) {
case 'products':
return 'Mahsulot qidirish...';
case 'companies':
return 'Korxona qidirish...';
case 'countries':
return 'Davlat qidirish...';
default:
return 'Qidiruv...';
}
}, [activeTab]);
const RenderedView = useMemo(() => {
switch (activeTab) {
case 'products':
return <ProductList query={query} />;
case 'companies':
return <CompanyList query={query} />;
case 'countries':
return <CountriesList search={query} />;
}
}, [activeTab, query]);
const handleCloseFilter = () => {
setShowFilter(false);
setStep('filter');
};
// Show filtered items if filter was applied
if (showFilter && step === 'items') {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<FilteredItems data={filtered} back={handleCloseFilter} />
</GestureHandlerRootView>
);
}
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<ScrollView
style={[isDark ? styles.darkBg : styles.lightBg]}
contentContainerStyle={{ flexGrow: 1 }}
keyboardShouldPersistTaps="handled"
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={['#3b82f6']}
tintColor="#3b82f6"
/>
}
>
<View style={styles.content}>
<View style={styles.searchSection}>
<View
style={[
styles.searchInputContainer,
isDark ? styles.darkSearchInput : styles.lightSearchInput,
]}
>
<Search size={20} color={isDark ? '#64748b' : '#94a3b8'} style={styles.searchIcon} />
<TextInput
style={[styles.searchInput, isDark ? styles.darkInputText : styles.lightInputText]}
placeholder={t(placeholderText)}
value={query}
onChangeText={setQuery}
placeholderTextColor={isDark ? '#64748b' : '#94a3b8'}
/>
</View>
<TouchableOpacity
style={styles.filterButton}
onPress={() => setShowFilter(true)}
activeOpacity={0.7}
>
<Filter size={20} color="#fff" />
</TouchableOpacity>
</View>
<SearchTabs value={activeTab} onChange={setActiveTab} />
{error && (
<View style={[styles.errorContainer, isDark ? styles.darkError : styles.lightError]}>
<Text style={styles.errorText}>{t("Ma'lumot yuklashda xatolik")}</Text>
<TouchableOpacity onPress={onRefresh} style={styles.retryButton}>
<Text style={styles.retryButtonText}>{t('Qayta urinish')}</Text>
</TouchableOpacity>
</View>
)}
{isLoading && !refreshing && <Loading />}
{!isLoading && RenderedView}
</View>
</ScrollView>
{/* Filter Modal */}
<Modal
visible={showFilter && step === 'filter'}
animationType="slide"
presentationStyle="pageSheet"
onRequestClose={handleCloseFilter}
>
<SafeAreaProvider style={{ flex: 1 }}>
<SafeAreaView style={{ flex: 1, backgroundColor: isDark ? '#0f172a' : '#fff' }}>
<StatusBar
style={isDark ? 'light' : 'dark'}
backgroundColor={isDark ? '#0f172a' : '#fff'}
/>
<FilterUI back={handleCloseFilter} setStep={setStep} setFiltered={setFiltered} />
</SafeAreaView>
</SafeAreaProvider>
</Modal>
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
darkBg: {
flex: 1,
backgroundColor: '#0f172a',
},
lightBg: {
flex: 1,
backgroundColor: '#f8fafc',
},
content: {
padding: 16,
maxWidth: 768,
width: '100%',
alignSelf: 'center',
gap: 20,
},
searchSection: {
flexDirection: 'row',
gap: 12,
alignItems: 'center',
},
searchInputContainer: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
borderRadius: 16,
borderWidth: 1.5,
paddingHorizontal: 16,
shadowColor: '#3b82f6',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.05,
shadowRadius: 8,
elevation: 2,
},
darkSearchInput: {
backgroundColor: '#1e293b',
borderColor: '#334155',
},
lightSearchInput: {
backgroundColor: '#ffffff',
borderColor: '#e2e8f0',
},
searchIcon: {
marginRight: 10,
},
searchInput: {
flex: 1,
paddingVertical: 14,
fontSize: 15,
fontWeight: '500',
},
darkInputText: {
color: '#f1f5f9',
},
lightInputText: {
color: '#0f172a',
},
filterButton: {
backgroundColor: '#3b82f6',
width: 48,
height: 48,
borderRadius: 16,
alignItems: 'center',
justifyContent: 'center',
shadowColor: '#3b82f6',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 4,
},
loadingContainer: {
padding: 60,
alignItems: 'center',
justifyContent: 'center',
},
errorContainer: {
padding: 32,
alignItems: 'center',
borderRadius: 16,
},
darkError: {
backgroundColor: '#1e293b',
},
lightError: {
backgroundColor: '#ffffff',
borderWidth: 1,
borderColor: '#fee2e2',
},
errorText: {
fontSize: 16,
fontWeight: '600',
color: '#f87171',
marginBottom: 12,
},
retryButton: {
backgroundColor: '#3b82f6',
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 10,
},
retryButtonText: {
color: '#ffffff',
fontWeight: '700',
fontSize: 14,
},
});