fix: ust serit tiklaninca donuyordu — Kanban havuzdaki tum ihaleleri (8 bin+ kart) ciziyordu; artik yalnizca takipteki/kolona tasinan ihaleler, sekme gecisi transition ile aninda vurgulaniyor

- KanbanBoard: sunucu her ilana varsayilan 'incelenecek' verdigi icin bos pano 8.372 kart basiyordu; yalnizca takipte veya kolona tasinmis ihaleler kaliyor
- TopNavigation: useTransition + spinner; agir sekmelerde tiklama karsiliksiz kalmiyor
- sunucu: 'yeni liste eskisinden kucukse alma' kurali havuzu 30 Agustos zirvesinde dondurmustu (gunlerce yeni ilan yok); eksiksiz inen liste her zaman devrede
- sunucu: isYeni/bugun eklenen UTC-TR gun farkindan hep 0'di; Europe/Istanbul gunune gore ve her yanitta tazeleniyor (eklenmeZamani da donmuyor)
- ust kartlar: 'bugun eklenenler' tum ilanlari sayiyordu ('once' metnine bakiyordu), 'son giristen beri' sabit 14'tu; sayimlar liste filtresiyle ayni olcut (ihaleTarih.js), arsiv/sonuclanan filtreleri 'sadece acik' kapisina takilmiyor

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 13:02:40 +03:00
co-authored by Claude Fable 5.1
parent 3eb0f91823
commit 920a147126
9 changed files with 226 additions and 56 deletions
+8 -24
View File
@@ -3,19 +3,12 @@ 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');
// "gg.aa.yyyy" → Date. Ayrıştırılamayanı GEÇMİŞ SAYMAYIZ: tarihi belirsiz bir
// ihaleyi sessizce gizlemek, geçmiş bir ihaleyi göstermekten daha kötüdür.
const ihaleGunu = (v) => {
const m = /^(\d{2})\.(\d{2})\.(\d{4})/.exec(String(v || '').trim());
if (!m) return null;
return new Date(Number(m[3]), Number(m[2]) - 1, Number(m[1]));
};
export const TenderList = () => {
const {
tenders,
@@ -28,7 +21,8 @@ export const TenderList = () => {
quickFilter,
onlyValidOnly,
setOnlyValidOnly,
favoriteKurumlar
favoriteKurumlar,
oncekiGiris
} = useApp();
const [sortBy, setSortBy] = useState('newest'); // 'newest', 'urgent', 'distant'
@@ -57,21 +51,11 @@ export const TenderList = () => {
// 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.
if (onlyValidOnly) {
const gun = ihaleGunu(tender.tarih);
if (gun && gun < bugun) return false;
}
// 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;
// Quick Filter
if (quickFilter === 'favori_kurumlar' && !(favoriteKurumlar || []).includes((tender.kurum || '').trim())) return false;
if (quickFilter === 'dogrudan_temin' && tender.alimTuru !== 'Doğrudan Temin') return false;
if (quickFilter === 'bugun_eklenenler' && !((tender.eklenmeZamani || '').includes('önce') || (tender.eklenmeZamani || '').includes('az'))) return false;
if (quickFilter === 'incelenenler' && !tender.incelendi) return false;
if (quickFilter === 'incelenmedi' && tender.incelendi) return false;
if (quickFilter === 'takiptekiler' && !tender.takipte) return false;
if (quickFilter === 'sozlesmeler' && tender.durum !== 'Sözleşme İmzalandı') return false;
if (quickFilter === 'sonuclananlar' && tender.durum !== 'Sonuçlandı') return false;
if (quickFilter === 'iptal' && tender.durum !== 'İptal') return false;
// Hızlı filtre (üst kartlar + sol menü) — ölçütler ihaleTarih.js'de tek yerde
if (!hizliFiltreGecer(tender, quickFilter, { favoriteKurumlar: favoriteKurumlar || [], oncekiGirisMs: oncekiGiris })) return false;
// Dropdown Filters
if (selectedCity && normTr(tender.sehir) !== normTr(selectedCity)) return false;
@@ -87,7 +71,7 @@ export const TenderList = () => {
if (sortBy === 'distant') return b.tarih.localeCompare(a.tarih);
return 0;
});
}, [tenders, searchQuery, selectedCity, selectedAlimTuru, selectedSektorler, selectedCpvler, selectedKurumTipi, quickFilter, sortBy, onlyValidOnly, bugun]);
}, [tenders, searchQuery, selectedCity, selectedAlimTuru, selectedSektorler, selectedCpvler, selectedKurumTipi, quickFilter, sortBy, onlyValidOnly, bugun, favoriteKurumlar, oncekiGiris]);
const gorunenTenders = filteredTenders.slice(0, gosterilen);
const dahaVar = gosterilen < filteredTenders.length;