fitst commit
This commit is contained in:
399
screens/home/ui/FilterScreen.tsx
Normal file
399
screens/home/ui/FilterScreen.tsx
Normal file
@@ -0,0 +1,399 @@
|
||||
import {
|
||||
ArrowLeft,
|
||||
Briefcase,
|
||||
Building2,
|
||||
CheckCircle2,
|
||||
ChevronRight,
|
||||
Globe,
|
||||
MapPin,
|
||||
Package,
|
||||
Search,
|
||||
SlidersHorizontal,
|
||||
} from 'lucide-react-native';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
FlatList,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
|
||||
// --- TURLAR ---
|
||||
type TabKey = 'products' | 'companies' | 'countries';
|
||||
type FilterStep = 'filter' | 'items' | 'detail';
|
||||
|
||||
const FAKE_ITEMS = [
|
||||
{ id: 1, company_name: 'Artel Electronics', industry: 'Maishiy texnika', country: 'UZ' },
|
||||
{ id: 2, company_name: 'Toshkent City Mall', industry: 'Savdo', country: 'UZ' },
|
||||
{ id: 3, company_name: 'Turkish Airlines', industry: 'Aviatsiya', country: 'TR' },
|
||||
{ id: 4, company_name: 'Siemens AG', industry: 'Muhandislik', country: 'DE' },
|
||||
];
|
||||
|
||||
export default function App() {
|
||||
const [filterVisible, setFilterVisible] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState<TabKey>('products');
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
||||
if (filterVisible) {
|
||||
return <FilterUI back={() => setFilterVisible(false)} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
{/* Search Header */}
|
||||
<View style={styles.header}>
|
||||
<View style={styles.searchContainer}>
|
||||
<Search size={20} color="#94a3b8" style={styles.searchIcon} />
|
||||
<TextInput
|
||||
style={styles.searchInput}
|
||||
placeholder={`${activeTab === 'products' ? 'Mahsulot' : activeTab === 'companies' ? 'Kompaniya' : 'Davlat'} bo'yicha...`}
|
||||
value={searchQuery}
|
||||
onChangeText={setSearchQuery}
|
||||
placeholderTextColor="#94a3b8"
|
||||
/>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.filterButton} onPress={() => setFilterVisible(true)}>
|
||||
<SlidersHorizontal size={22} color="#fff" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Tabs */}
|
||||
<View style={styles.tabWrapper}>
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.tabList}
|
||||
>
|
||||
{[
|
||||
{
|
||||
key: 'products',
|
||||
label: 'Mahsulotlar',
|
||||
icon: <Package size={18} color={activeTab === 'products' ? '#fff' : '#64748b'} />,
|
||||
},
|
||||
{
|
||||
key: 'companies',
|
||||
label: 'Kompaniyalar',
|
||||
icon: <Building2 size={18} color={activeTab === 'companies' ? '#fff' : '#64748b'} />,
|
||||
},
|
||||
{
|
||||
key: 'countries',
|
||||
label: 'Davlatlar',
|
||||
icon: <Globe size={18} color={activeTab === 'countries' ? '#fff' : '#64748b'} />,
|
||||
},
|
||||
].map((tab) => (
|
||||
<TouchableOpacity
|
||||
key={tab.key}
|
||||
onPress={() => setActiveTab(tab.key as TabKey)}
|
||||
style={[styles.tabItem, activeTab === tab.key && styles.activeTabItem]}
|
||||
>
|
||||
{tab.icon}
|
||||
<Text style={[styles.tabText, activeTab === tab.key && styles.activeTabText]}>
|
||||
{tab.label}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
{/* Main List */}
|
||||
<FlatList
|
||||
data={FAKE_ITEMS}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
contentContainerStyle={styles.listContent}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity style={styles.card}>
|
||||
<View style={styles.cardInfo}>
|
||||
<Text style={styles.cardTitle}>{item.company_name}</Text>
|
||||
<Text style={styles.cardSub}>{item.industry}</Text>
|
||||
</View>
|
||||
<ChevronRight size={20} color="#cbd5e1" />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// --- FILTER UI KOMPONENTI ---
|
||||
function FilterUI({ back }: { back: () => void }) {
|
||||
const [step, setStep] = useState<FilterStep>('filter');
|
||||
const [selectedId, setSelectedId] = useState<number | null>(null);
|
||||
|
||||
const handleBack = () => {
|
||||
if (step === 'items') setStep('filter');
|
||||
else if (step === 'detail') setStep('items');
|
||||
else back();
|
||||
};
|
||||
|
||||
const renderFilter = () => (
|
||||
<View style={{ flex: 1 }}>
|
||||
<ScrollView contentContainerStyle={styles.scrollContent}>
|
||||
<View style={styles.section}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<MapPin size={20} color="#3b82f6" />
|
||||
<Text style={styles.sectionLabel}>Hududni tanlang</Text>
|
||||
</View>
|
||||
<View style={styles.selectionCard}>
|
||||
<TouchableOpacity style={styles.selectRow}>
|
||||
<View>
|
||||
<Text style={styles.selectLabel}>Davlat</Text>
|
||||
<Text style={styles.selectValue}>O'zbekiston</Text>
|
||||
</View>
|
||||
<ChevronRight size={20} color="#cbd5e1" />
|
||||
</TouchableOpacity>
|
||||
<View style={styles.divider} />
|
||||
<TouchableOpacity style={styles.selectRow}>
|
||||
<View>
|
||||
<Text style={styles.selectLabel}>Viloyat</Text>
|
||||
<Text style={styles.selectValue}>Barchasi</Text>
|
||||
</View>
|
||||
<ChevronRight size={20} color="#cbd5e1" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<Briefcase size={20} color="#3b82f6" />
|
||||
<Text style={styles.sectionLabel}>Sanoat yo'nalishi</Text>
|
||||
</View>
|
||||
<View style={styles.industryGrid}>
|
||||
{['Texnologiya', 'Tibbiyot', 'Ta’lim', 'Qurilish'].map((item) => (
|
||||
<TouchableOpacity key={item} style={styles.industryTag}>
|
||||
<Text style={styles.industryTagText}>{item}</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
<View style={styles.footer}>
|
||||
<TouchableOpacity onPress={() => setStep('items')} style={styles.applyButton}>
|
||||
<Text style={styles.applyButtonText}>Natijalarni ko'rish ({FAKE_ITEMS.length})</Text>
|
||||
<CheckCircle2 size={20} color="#fff" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const renderItems = () => (
|
||||
<FlatList
|
||||
data={FAKE_ITEMS}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
contentContainerStyle={{ padding: 16 }}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity
|
||||
style={styles.resultCard}
|
||||
onPress={() => {
|
||||
setSelectedId(item.id);
|
||||
setStep('detail');
|
||||
}}
|
||||
>
|
||||
<View style={styles.iconCircle}>
|
||||
<Building2 size={22} color="#3b82f6" />
|
||||
</View>
|
||||
<View style={{ flex: 1, marginLeft: 12 }}>
|
||||
<Text style={styles.companyName}>{item.company_name}</Text>
|
||||
<Text style={styles.industryText}>{item.industry}</Text>
|
||||
</View>
|
||||
<ChevronRight size={20} color="#cbd5e1" />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderDetail = () => {
|
||||
const item = FAKE_ITEMS.find((i) => i.id === selectedId);
|
||||
return (
|
||||
<View style={styles.detailCard}>
|
||||
<Text style={styles.detailTitle}>{item?.company_name}</Text>
|
||||
<View style={styles.badge}>
|
||||
<Text style={styles.badgeText}>{item?.industry}</Text>
|
||||
</View>
|
||||
<Text style={styles.detailDesc}>
|
||||
Bu yerda web-versiyadagi batafsil ma'lumotlar chiqadi.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.navHeader}>
|
||||
<TouchableOpacity onPress={handleBack} style={styles.backButton}>
|
||||
<ArrowLeft size={24} color="#1e293b" />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle}>
|
||||
{step === 'filter' ? 'Filtrlash' : step === 'items' ? 'Natijalar' : 'Batafsil'}
|
||||
</Text>
|
||||
<View style={{ width: 40 }} />
|
||||
</View>
|
||||
{step === 'filter' && renderFilter()}
|
||||
{step === 'items' && renderItems()}
|
||||
{step === 'detail' && renderDetail()}
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// --- STILLAR ---
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: '#f8fafc' },
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
padding: 16,
|
||||
gap: 12,
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
searchContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#f1f5f9',
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 12,
|
||||
height: 48,
|
||||
},
|
||||
searchIcon: { marginRight: 8 },
|
||||
searchInput: { flex: 1, fontSize: 16, color: '#1e293b' },
|
||||
filterButton: {
|
||||
backgroundColor: '#3b82f6',
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 12,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
elevation: 4,
|
||||
},
|
||||
tabWrapper: {
|
||||
backgroundColor: '#fff',
|
||||
paddingBottom: 12,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#f1f5f9',
|
||||
},
|
||||
tabList: { paddingHorizontal: 16, gap: 10 },
|
||||
tabItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 10,
|
||||
borderRadius: 10,
|
||||
backgroundColor: '#f1f5f9',
|
||||
gap: 8,
|
||||
marginRight: 10,
|
||||
},
|
||||
activeTabItem: { backgroundColor: '#3b82f6' },
|
||||
tabText: { fontSize: 14, fontWeight: '600', color: '#64748b' },
|
||||
activeTabText: { color: '#fff' },
|
||||
listContent: { padding: 16 },
|
||||
card: {
|
||||
backgroundColor: '#fff',
|
||||
padding: 16,
|
||||
borderRadius: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: '#f1f5f9',
|
||||
},
|
||||
cardInfo: { flex: 1 },
|
||||
cardTitle: { fontSize: 16, fontWeight: '700', color: '#1e293b' },
|
||||
cardSub: { fontSize: 13, color: '#94a3b8' },
|
||||
navHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 12,
|
||||
backgroundColor: '#fff',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#f1f5f9',
|
||||
},
|
||||
backButton: { padding: 8, borderRadius: 12, backgroundColor: '#f1f5f9' },
|
||||
headerTitle: { fontSize: 18, fontWeight: '700', color: '#1e293b' },
|
||||
scrollContent: { padding: 16, paddingBottom: 100 },
|
||||
section: { marginBottom: 24 },
|
||||
sectionHeader: { flexDirection: 'row', alignItems: 'center', gap: 8, marginBottom: 12 },
|
||||
sectionLabel: { fontSize: 15, fontWeight: '600', color: '#64748b' },
|
||||
selectionCard: {
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: 16,
|
||||
paddingHorizontal: 16,
|
||||
borderWidth: 1,
|
||||
borderColor: '#e2e8f0',
|
||||
},
|
||||
selectRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingVertical: 14,
|
||||
},
|
||||
selectLabel: { fontSize: 12, color: '#94a3b8' },
|
||||
selectValue: { fontSize: 15, fontWeight: '600', color: '#1e293b' },
|
||||
divider: { height: 1, backgroundColor: '#f1f5f9' },
|
||||
industryGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: 10 },
|
||||
industryTag: {
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 10,
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: '#e2e8f0',
|
||||
},
|
||||
industryTagText: { fontSize: 14, color: '#475569' },
|
||||
footer: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
padding: 20,
|
||||
backgroundColor: '#fff',
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: '#f1f5f9',
|
||||
},
|
||||
applyButton: {
|
||||
height: 56,
|
||||
backgroundColor: '#3b82f6',
|
||||
borderRadius: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 10,
|
||||
},
|
||||
applyButtonText: { color: '#fff', fontSize: 16, fontWeight: '700' },
|
||||
resultCard: {
|
||||
backgroundColor: '#fff',
|
||||
padding: 16,
|
||||
borderRadius: 16,
|
||||
marginBottom: 12,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
borderColor: '#f1f5f9',
|
||||
},
|
||||
iconCircle: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '#eff6ff',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
companyName: { fontSize: 16, fontWeight: '700' },
|
||||
industryText: { fontSize: 13, color: '#64748b' },
|
||||
detailCard: { margin: 16, padding: 20, backgroundColor: '#fff', borderRadius: 20 },
|
||||
detailTitle: { fontSize: 22, fontWeight: '800' },
|
||||
badge: {
|
||||
backgroundColor: '#eff6ff',
|
||||
alignSelf: 'flex-start',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 8,
|
||||
marginVertical: 12,
|
||||
},
|
||||
badgeText: { color: '#3b82f6', fontWeight: '600' },
|
||||
detailDesc: { lineHeight: 22, color: '#475569' },
|
||||
});
|
||||
52
screens/home/ui/FilteredItems.tsx
Normal file
52
screens/home/ui/FilteredItems.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { ArrowLeft, ChevronRight } from 'lucide-react-native';
|
||||
import { FlatList, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
export function FilteredItems({ data, back }: any) {
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<View>
|
||||
<TouchableOpacity onPress={back}>
|
||||
<ArrowLeft size={24} color="#1e293b" />
|
||||
</TouchableOpacity>
|
||||
<Text>Natijalar ({data.length})</Text>
|
||||
<View style={{ width: 40 }} />
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
data={data}
|
||||
contentContainerStyle={{ padding: 16 }}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity style={styles.resultCard}>
|
||||
<View style={styles.resultInfo}>
|
||||
<Text style={styles.companyName}>{item.company_name}</Text>
|
||||
<Text style={styles.industryText}>{item.industry || 'Sanoat turi'}</Text>
|
||||
</View>
|
||||
<View style={styles.goIcon}>
|
||||
<ChevronRight size={18} color="#3b82f6" />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// Qo'shimcha stillar resultCard uchun
|
||||
const styles = StyleSheet.create({
|
||||
resultCard: {
|
||||
backgroundColor: '#fff',
|
||||
padding: 16,
|
||||
borderRadius: 16,
|
||||
marginBottom: 12,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
borderColor: '#f1f5f9',
|
||||
},
|
||||
resultInfo: { flex: 1 },
|
||||
companyName: { fontSize: 16, fontWeight: '700', color: '#1e293b' },
|
||||
industryText: { fontSize: 13, color: '#64748b', marginTop: 4 },
|
||||
goIcon: { backgroundColor: '#eff6ff', padding: 8, borderRadius: 10 },
|
||||
});
|
||||
272
screens/home/ui/HomeScreen.tsx
Normal file
272
screens/home/ui/HomeScreen.tsx
Normal file
@@ -0,0 +1,272 @@
|
||||
// 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 { Stack } from 'expo-router';
|
||||
import { Filter, Search } from 'lucide-react-native';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { RefreshControl } from 'react-native-gesture-handler';
|
||||
|
||||
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 [step, setStep] = useState<'filter' | 'items'>('filter');
|
||||
const [query, setQuery] = useState('');
|
||||
const [showFilter, setShowFilter] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [filtered, setFiltered] = useState<{ id: number; company_name: string }[]>([]);
|
||||
const { t } = useTranslation();
|
||||
|
||||
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]);
|
||||
|
||||
if (showFilter && step === 'filter') {
|
||||
return (
|
||||
<FilterUI back={() => setShowFilter(false)} setStep={setStep} setFiltered={setFiltered} />
|
||||
);
|
||||
}
|
||||
|
||||
if (showFilter && step === 'items') {
|
||||
return (
|
||||
<FilteredItems
|
||||
data={filtered}
|
||||
back={() => {
|
||||
setShowFilter(false);
|
||||
setStep('filter');
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
style={[isDark ? styles.darkBg : styles.lightBg]}
|
||||
contentContainerStyle={{ flexGrow: 1, paddingBottom: 60 }}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={['#3b82f6']}
|
||||
tintColor="#3b82f6"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Stack.Screen options={{ headerShown: false }} />
|
||||
|
||||
<View style={styles.content}>
|
||||
{/* Qidiruv va filter */}
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user