import { useTheme } from '@/components/ThemeContext'; import { products_api } from '@/screens/home/lib/api'; import { ProductResponse } from '@/screens/home/lib/types'; import { BottomSheetBackdrop, BottomSheetModal, BottomSheetScrollView } from '@gorhom/bottom-sheet'; import { useInfiniteQuery } from '@tanstack/react-query'; import { ResizeMode, Video } from 'expo-av'; import { Info, Package, PlayCircle } from 'lucide-react-native'; import React, { useCallback, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ActivityIndicator, Dimensions, Image, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import { FlatList } from 'react-native-gesture-handler'; const { width: SCREEN_WIDTH } = Dimensions.get('window'); const IMAGE_WIDTH = SCREEN_WIDTH - 40; const PAGE_SIZE = 10; type Props = { query: string }; export default function ProductList({ query }: Props) { const { t } = useTranslation(); const { isDark } = useTheme(); const trimmedQuery = query.trim(); const [selectedProduct, setSelectedProduct] = useState(null); const [currentImageIndex, setCurrentImageIndex] = useState(0); const bottomSheetModalRef = useRef(null); const { data, isLoading, isError, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({ queryKey: ['products-list', trimmedQuery], queryFn: async ({ pageParam = 1 }) => { const response = await products_api.getProducts({ page: pageParam, page_size: PAGE_SIZE, search: trimmedQuery, }); return response.data.data; }, getNextPageParam: (lastPage) => lastPage.current_page < lastPage.total_pages ? lastPage.current_page + 1 : undefined, initialPageParam: 1, }); const allProducts = data?.pages.flatMap((p) => p.results) ?? []; const handlePresentModalPress = useCallback((product: ProductResponse) => { setSelectedProduct(product); setCurrentImageIndex(0); bottomSheetModalRef.current?.present(); }, []); const renderBackdrop = useCallback( (props: any) => ( ), [] ); const isVideoFile = (url?: string) => url?.toLowerCase().match(/\.(mp4|mov|avi|mkv|webm)$/i); const renderItem = ({ item }: { item: ProductResponse }) => { const mainFile = item.files?.[0]?.file; const isVideo = isVideoFile(mainFile); return ( handlePresentModalPress(item)} > {mainFile ? ( <> {isVideo && ( )} ) : ( )} {item.title} {item.company} ); }; const renderCarouselItem = ({ item }: { item: { id: number; file: string } }) => { const isVideo = isVideoFile(item.file); return ( {isVideo ? ( ); }; if (isLoading && !data) return ( ); if (isError) return ( {t('Xatolik yuz berdi')} ); return ( <> item.id.toString()} renderItem={renderItem} numColumns={2} columnWrapperStyle={{ justifyContent: 'space-between', marginBottom: 20 }} contentContainerStyle={{ paddingBottom: 60 }} onEndReached={() => hasNextPage && !isFetchingNextPage && fetchNextPage()} onEndReachedThreshold={0.4} ListFooterComponent={ isFetchingNextPage ? ( ) : null } ListEmptyComponent={ data ? ( {t('Natija topilmadi')} ) : null } /> {selectedProduct && ( <> item.id.toString()} horizontal pagingEnabled showsHorizontalScrollIndicator={false} onMomentumScrollEnd={(e) => { const index = Math.round(e.nativeEvent.contentOffset.x / IMAGE_WIDTH); setCurrentImageIndex(index); }} /> {selectedProduct.files.length > 1 && ( {selectedProduct.files.map((_, i) => ( ))} )} {selectedProduct.title} {selectedProduct.company} {t("Batafsil ma'lumot")} {selectedProduct.description || "Ma'lumot mavjud emas."} )} ); } const styles = StyleSheet.create({ listContainer: { gap: 0, paddingBottom: 20 }, card: { borderRadius: 16, overflow: 'hidden', width: (SCREEN_WIDTH - 40) / 2, marginLeft: 2, shadowColor: '#000', shadowOpacity: 0.15, shadowOffset: { width: 0, height: 4 }, shadowRadius: 50, elevation: 4, }, darkCard: { backgroundColor: '#1e293b', }, lightCard: { backgroundColor: '#ffffff', }, imageContainer: { width: '100%', height: 160, }, darkImageBg: { backgroundColor: '#0f172a', }, lightImageBg: { backgroundColor: '#f1f5f9', }, image: { width: '100%', height: '100%' }, videoIconOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.25)', }, placeholder: { flex: 1, alignItems: 'center', justifyContent: 'center' }, info: { padding: 12 }, title: { fontSize: 16, fontWeight: '700', marginBottom: 4, }, darkText: { color: '#f1f5f9', }, lightText: { color: '#0f172a', }, companyRow: { flexDirection: 'row', alignItems: 'center', gap: 6 }, companyText: { fontSize: 13, }, darkSubText: { color: '#64748b', }, lightSubText: { color: '#94a3b8', }, // Bottom Sheet sheetContent: { flex: 1 }, sheetContentContainer: { paddingHorizontal: 20, paddingBottom: 40 }, carouselWrapper: { width: IMAGE_WIDTH, height: 280, marginBottom: 20, borderRadius: 16, overflow: 'hidden', alignSelf: 'center', }, carouselImageContainer: { width: IMAGE_WIDTH, height: 280, backgroundColor: '#e2e8f0' }, carouselImage: { width: '100%', height: '100%' }, pagination: { position: 'absolute', bottom: 12, flexDirection: 'row', width: '100%', justifyContent: 'center', alignItems: 'center', gap: 8, }, paginationDot: { width: 8, height: 8, borderRadius: 4, backgroundColor: 'rgba(255,255,255,0.4)' }, paginationDotActive: { backgroundColor: '#3b82f6', width: 20 }, sheetHeader: { marginBottom: 16 }, sheetTitle: { fontSize: 20, fontWeight: '800', marginBottom: 8, }, sheetCompanyBadge: { flexDirection: 'row', alignItems: 'center', gap: 6, backgroundColor: '#3b82f6', alignSelf: 'flex-start', paddingHorizontal: 10, paddingVertical: 5, borderRadius: 12, }, sheetCompanyText: { fontSize: 13, color: '#ffffff', fontWeight: '700' }, divider: { height: 1, marginBottom: 20, }, darkDivider: { backgroundColor: '#334155', }, lightDivider: { backgroundColor: '#e2e8f0', }, section: { marginBottom: 20 }, sectionTitleRow: { flexDirection: 'row', alignItems: 'center', gap: 8, marginBottom: 8 }, sectionLabel: { fontSize: 16, fontWeight: '700', }, sheetDescription: { fontSize: 15, lineHeight: 22, }, center: { flex: 1, justifyContent: 'center', alignItems: 'center' }, footerLoader: { paddingVertical: 20, alignItems: 'center' }, });