fix: il adları kaynaklar arasında bölünüyordu (Ankara / ANKARA)

Sorun: ilan.gov.tr illeri 'Ankara' biçiminde, EKAP arşivi/DT 'ANKARA' biçiminde
veriyordu. İl filtresi birebir string karşılaştırdığı için kullanıcı 'Ankara'
seçtiğinde 161 'ANKARA' kaydı görünmüyordu. 81 ilin hepsi çift kayıtlıydı
(162 farklı il değeri).

- server/tr-text.mjs: Türkçe duyarlı titleCaseTr / normTr yardımcıları
- history-store + dt-store: il adı okunurken tek biçime indiriliyor
  (mevcut kayıtlar için de geçerli, yeniden tarama gerekmiyor)
- TenderList: il filtresi normalize karşılaştırma yapıyor (savunma katmanı)
This commit is contained in:
2026-08-29 02:40:22 +03:00
parent 03d5a04c91
commit c701083642
4 changed files with 30 additions and 3 deletions
+2 -1
View File
@@ -6,6 +6,7 @@
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { titleCaseTr } from './tr-text.mjs';
// node:sqlite bazı Node sürümlerinde deneysel/flag'li. Yoksa DT devre dışı kalır, // node:sqlite bazı Node sürümlerinde deneysel/flag'li. Yoksa DT devre dışı kalır,
// ilan.gov.tr canlı verisi yine de çalışır. // ilan.gov.tr canlı verisi yine de çalışır.
@@ -66,7 +67,7 @@ function mapDtRow(row) {
ikn: row.dtn || '', ikn: row.dtn || '',
baslik: row.isin_adi || '', baslik: row.isin_adi || '',
kurum, kurum,
sehir: row.ili && !row.ili.startsWith('Plaka') ? row.ili : '', sehir: row.ili && !row.ili.startsWith('Plaka') ? titleCaseTr(row.ili) : '',
bolge: '', bolge: '',
tarih: row.dt_tarihi || '', tarih: row.dt_tarihi || '',
saat: '', saat: '',
+2 -1
View File
@@ -8,6 +8,7 @@
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { titleCaseTr } from './tr-text.mjs';
let DatabaseSync = null; let DatabaseSync = null;
try { try {
@@ -148,7 +149,7 @@ function rowToTender(r) {
ikn: r.ikn, ikn: r.ikn,
baslik: r.ihale_adi || 'İhale', baslik: r.ihale_adi || 'İhale',
kurum: r.idare_adi || '—', kurum: r.idare_adi || '—',
sehir: r.il || '', sehir: titleCaseTr(r.il),
tarih: r.ihale_tarihi || '', tarih: r.ihale_tarihi || '',
alimTuru: r.ihale_tipi || 'İhale', alimTuru: r.ihale_tipi || 'İhale',
sektor: r.ihale_tipi || 'Genel', sektor: r.ihale_tipi || 'Genel',
+21
View File
@@ -0,0 +1,21 @@
/**
* Türkçe metin yardımcıları.
* Kaynaklar il adını farklı yazıyor (ilan.gov.tr "Ankara", EKAP "ANKARA");
* tek biçime indirgemezsek il filtresi ve gruplamalar bölünüyor.
*/
/** "İSTANBUL" → "İstanbul", "şanlıurfa" → "Şanlıurfa" (Türkçe i/ı duyarlı) */
export function titleCaseTr(s) {
if (!s) return '';
return String(s)
.trim()
.toLocaleLowerCase('tr-TR')
.split(/(\s+|-)/)
.map((w) => (/^[\s-]*$/.test(w) ? w : w.charAt(0).toLocaleUpperCase('tr-TR') + w.slice(1)))
.join('');
}
/** Karşılaştırma için normalize (büyük harf, Türkçe duyarlı) */
export function normTr(s) {
return String(s || '').trim().toLocaleUpperCase('tr-TR');
}
+5 -1
View File
@@ -4,6 +4,10 @@ import { TenderCard } from './TenderCard';
import { Download, SlidersHorizontal, Layers, ChevronLeft, ChevronRight } from 'lucide-react'; import { Download, SlidersHorizontal, Layers, ChevronLeft, ChevronRight } from 'lucide-react';
import confetti from 'canvas-confetti'; import confetti from 'canvas-confetti';
// İ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 = () => { export const TenderList = () => {
const { const {
tenders, tenders,
@@ -46,7 +50,7 @@ export const TenderList = () => {
if (quickFilter === 'iptal' && tender.durum !== 'İptal') return false; if (quickFilter === 'iptal' && tender.durum !== 'İptal') return false;
// Dropdown Filters // Dropdown Filters
if (selectedCity && tender.sehir !== selectedCity) return false; if (selectedCity && normTr(tender.sehir) !== normTr(selectedCity)) return false;
if (selectedAlimTuru && tender.alimTuru !== selectedAlimTuru) return false; if (selectedAlimTuru && tender.alimTuru !== selectedAlimTuru) return false;
if (selectedSektor && tender.sektor !== selectedSektor) return false; if (selectedSektor && tender.sektor !== selectedSektor) return false;
if (selectedKurumTipi && tender.kurumTipi !== selectedKurumTipi) return false; if (selectedKurumTipi && tender.kurumTipi !== selectedKurumTipi) return false;