import React, { useState, useMemo, useEffect, useRef, useCallback } from 'react'; import { useApp } from '../context/AppContext'; import { TenderCard } from './TenderCard'; import { Download, SlidersHorizontal, Layers, Loader2 } from 'lucide-react'; import confetti from 'canvas-confetti'; import { acikIhale, hizliFiltreGecer, GECMIS_FILTRELER } from '../services/ihaleTarih'; // İl adları kaynaklar arasında farklı yazılabiliyor (Ankara / ANKARA); // filtre büyük-küçük harf ve Türkçe karakter duyarlılığına takılmasın. const normTr = (v) => String(v || '').trim().toLocaleUpperCase('tr-TR'); export const TenderList = () => { const { tenders, searchQuery, kalemEslesen, uyumEsigi, selectedCity, selectedAlimTuru, selectedSektorler, selectedCpvler, selectedKurumTipi, quickFilter, onlyValidOnly, setOnlyValidOnly, favoriteKurumlar, oncekiGiris } = useApp(); const [sortBy, setSortBy] = useState('newest'); // 'newest', 'urgent', 'distant' // Sonsuz kaydırma: sayfa yerine aşağı indikçe liste büyür. // (Sayfalama 10 bin kayıtta 1000+ sayfa düğmesi basıyordu.) const SAYFA_ADIM = 20; const [gosterilen, setGosterilen] = useState(SAYFA_ADIM); const dipRef = useRef(null); // Bugünün başlangıcı — "bugün ihalesi olan" listede kalsın. const bugun = useMemo(() => { const d = new Date(); d.setHours(0, 0, 0, 0); return d; }, []); // Filter logic const filteredTenders = useMemo(() => { return tenders.filter(tender => { // Search Query if (searchQuery) { const q = searchQuery.toLowerCase(); const matchTitle = (tender.baslik || '').toLowerCase().includes(q); const matchKurum = (tender.kurum || '').toLowerCase().includes(q); const matchIkn = (tender.ikn || '').toLowerCase().includes(q); const matchItems = tender.items && tender.items.some(i => (i.ad || '').toLowerCase().includes(q)); // Kartta taşınan ilk kalemler + sunucudaki tam kalem araması const matchKalem = tender.kalemler && tender.kalemler.some(a => (a || '').toLowerCase().includes(q)); const matchHavuz = kalemEslesen && tender.ikn && kalemEslesen.has(tender.ikn); if (!matchTitle && !matchKurum && !matchIkn && !matchItems && !matchKalem && !matchHavuz) return false; } // Geçmiş ihaleler: varsayılan olarak GİZLİ. Kullanıcı "geçmişi de göster" // derse (onlyValidOnly=false) hepsi gelir. Tarihi okunamayan kayıt gizlenmez. // Arşiv / sonuçlananlar gibi geçmişi hedefleyen hızlı filtrelerde kapı kapalı. if (onlyValidOnly && !GECMIS_FILTRELER.has(quickFilter) && !acikIhale(tender, bugun)) return false; // Hızlı filtre (üst kartlar + sol menü) — ölçütler ihaleTarih.js'de tek yerde if (!hizliFiltreGecer(tender, quickFilter, { favoriteKurumlar: favoriteKurumlar || [], oncekiGirisMs: oncekiGiris, uyumEsigi })) return false; // Dropdown Filters if (selectedCity && normTr(tender.sehir) !== normTr(selectedCity)) return false; if (selectedAlimTuru && tender.alimTuru !== selectedAlimTuru) return false; if (selectedSektorler.length && !selectedSektorler.includes(tender.sektor)) return false; if (selectedCpvler.length && !(tender.cpvBolum || []).some(b => selectedCpvler.includes(b))) return false; if (selectedKurumTipi && tender.kurumTipi !== selectedKurumTipi) return false; return true; }).sort((a, b) => { if (sortBy === 'uyum') return (b.aiMatchScore ?? -1) - (a.aiMatchScore ?? -1) || b.id.localeCompare(a.id); if (sortBy === 'newest') return b.id.localeCompare(a.id); if (sortBy === 'urgent') return a.tarih.localeCompare(b.tarih); if (sortBy === 'distant') return b.tarih.localeCompare(a.tarih); return 0; }); }, [tenders, searchQuery, kalemEslesen, uyumEsigi, selectedCity, selectedAlimTuru, selectedSektorler, selectedCpvler, selectedKurumTipi, quickFilter, sortBy, onlyValidOnly, bugun, favoriteKurumlar, oncekiGiris]); const gorunenTenders = filteredTenders.slice(0, gosterilen); const dahaVar = gosterilen < filteredTenders.length; // Baştan başlama YALNIZCA filtre/sıralama değişiminde olmalı. filteredTenders // dizisine bağlansaydı havuz her yenilendiğinde (10 dk) kullanıcı listenin // başına fırlardı. useEffect(() => { setGosterilen(SAYFA_ADIM); }, [ searchQuery, selectedCity, selectedAlimTuru, selectedSektorler, selectedCpvler, selectedKurumTipi, quickFilter, sortBy, onlyValidOnly, ]); const dahaGoster = useCallback(() => { setGosterilen((n) => Math.min(n + SAYFA_ADIM, filteredTenders.length)); }, [filteredTenders.length]); // Dipteki işaretçi görünür olunca yükle. IntersectionObserver yoksa // (eski tarayıcı) aşağıdaki "Daha fazla göster" düğmesi devreye girer. useEffect(() => { const el = dipRef.current; if (!el || !dahaVar || typeof IntersectionObserver === 'undefined') return; const gozlemci = new IntersectionObserver( (girisler) => { if (girisler[0]?.isIntersecting) dahaGoster(); }, { rootMargin: '600px 0px' }, // ekrana girmeden önce yükle ); gozlemci.observe(el); return () => gozlemci.disconnect(); }, [dahaVar, dahaGoster]); const handleExportExcel = () => { confetti({ particleCount: 80, spread: 60, origin: { y: 0.6 } }); const headers = ['IKN', 'Baslik', 'Kurum', 'Sehir', 'Tarih', 'Alim Turu', 'Sektor', 'CPV']; const rows = filteredTenders.map(t => [ t.ikn, `"${t.baslik.replace(/"/g, '""')}"`, `"${t.kurum.replace(/"/g, '""')}"`, t.sehir, t.tarih, t.alimTuru, t.sektor, `"${(t.cpvLabel || (t.cpv || []).join(', ') || '').replace(/"/g, '""')}"` ]); const csvContent = 'data:text/csv;charset=utf-8,\uFEFF' + [headers.join(','), ...rows.map(r => r.join(','))].join('\n'); const encodedUri = encodeURI(csvContent); const link = document.createElement('a'); link.setAttribute('href', encodedUri); link.setAttribute('download', `ihaleist_ihale_listesi_${Date.now()}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); }; return (
{/* Header bar above list */}

İhale Listesi ({filteredTenders.length.toLocaleString('tr-TR')} Sonuç)

{/* Varsayılan: yalnızca ihale tarihi geçmemiş ilanlar */}
{/* Tender Cards List */} {gorunenTenders.length === 0 ? (

Arama kriterlerine uygun ihale bulunamadı

Lütfen arama kelimenizi değiştirin veya filtreleri temizleyin.

) : (
{gorunenTenders.map(tender => ( ))}
)} {/* Sonsuz kaydırma dibi — sayfa yok, aşağı indikçe dolar */} {filteredTenders.length > 0 && (
{dahaVar ? ( <>
{gorunenTenders.length.toLocaleString('tr-TR')} / {filteredTenders.length.toLocaleString('tr-TR')} ihale gösteriliyor
{/* Gözlemci çalışmazsa elle yükleme yolu açık kalsın */} ) : (

Tüm kayıtlar gösterildi — {filteredTenders.length.toLocaleString('tr-TR')} ihale

)}
)}
); };