fix: EKAP dokümanları açılmıyor — yeni sekme tıklama anında açılıyor, boşluklu İKN'ler düzeltildi

İki ayrı neden vardı:

1) window.open sunucu yanıtından SONRA çağrılıyordu; Safari, PWA ve sıkı ayarlı
   Chrome bunu açılır-pencere sayıp sessizce engelliyordu — düğme "çalışmıyor"
   görünüyordu. Sekme artık tıklamanın hemen içinde boş açılır, adres gelince
   yönlendirilir. Engellenirse gerçek bir bağlantı (a href) gösterilir; bağlantı
   tıklaması hiçbir tarayıcıda engellenmez.

2) ilan.gov.tr bazı kayıtlarda İKN'yi başta/sonda boşluk ve kesme boşluğu (nbsp)
   ile veriyor (" 2026/1622878"). Bu 50 kayıtta panel "EKAP formatında değil"
   deyip düğmeyi hiç göstermiyordu. İKN artık alınırken boşluksuz saklanıyor;
   panel ve doküman araması da savunma amaçlı temizliyor.

Ayrıca: "EKAP'ta 0 doküman kayıtlı" yanıltıcı metni kaldırıldı (EKAP arama
kaydı sayıyı vermiyor), EKAP'ın önce güvenlik doğrulaması istediği açıklandı.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-05 23:53:43 +03:00
co-authored by Claude Fable 5.1
parent 8e9dff6833
commit 2271883be4
3 changed files with 46 additions and 7 deletions
+41 -5
View File
@@ -16,8 +16,13 @@ export const TenderDocuments = ({ tender }) => {
const [error, setError] = useState(null);
const [bilgi, setBilgi] = useState(null);
const [ilerleme, setIlerleme] = useState('');
// Son üretilen EKAP doküman adresi — yeni sekme engellenirse kullanıcı
// gerçek bir bağlantıya tıklayarak açabilsin (bağlantı tıklaması engellenmez).
const [ekapUrl, setEkapUrl] = useState(null);
const ikn = tender?.ikn;
// Eski kayıtlarda İKN boşluklu gelebiliyor (" 2026/1622878"); EKAP tespiti
// ve sunucu çağrıları boşluksuz değerle yapılır.
const ikn = String(tender?.ikn || '').replace(/[\s\u00a0]+/g, '') || undefined;
const [belgeler, setBelgeler] = useState([]);
const [yukleniyor, setYukleniyor] = useState(false);
const dosyaRef = useRef(null);
@@ -106,13 +111,28 @@ export const TenderDocuments = ({ tender }) => {
const dokumaniAc = async () => {
setBusy('url'); setError(null);
// Açılır pencere engelleyici: yeni sekme, tıklamanın HEMEN içinde
// (await'ten önce) açılmalı. Sunucu yanıtından sonra çağrılan window.open
// Safari, PWA ve sıkı ayarlı Chrome'da sessizce engelleniyor — kullanıcı
// "düğme çalışmıyor / dokümanlar açılmıyor" görüyordu. Sekme boş açılır,
// adres gelince yönlendirilir; engellenirse aşağıda gerçek bağlantı çıkar.
let sekme = null;
try { sekme = window.open('', '_blank'); } catch { sekme = null; }
if (sekme) {
try {
sekme.opener = null;
sekme.document.write('<p style="font-family:sans-serif;padding:24px;color:#334155">EKAP doküman sayfasına yönlendiriliyor…</p>');
} catch { /* yazılamazsa da yönlendirme çalışır */ }
}
try {
const r = await fetch(`/api/documents/url?ikn=${encodeURIComponent(ikn)}`);
const d = await r.json();
if (!d.success) throw new Error(d.error);
setBilgi({ dokumanSayisi: d.dokumanSayisi });
window.open(d.url, '_blank', 'noopener,noreferrer');
setEkapUrl(d.url);
setBilgi({ dokumanSayisi: d.dokumanSayisi, ekapSekme: sekme ? 'acildi' : 'engellendi' });
if (sekme) sekme.location.href = d.url;
} catch (e) {
if (sekme) { try { sekme.close(); } catch { /* yoksay */ } }
setError(e.message);
} finally { setBusy(null); }
};
@@ -217,7 +237,8 @@ export const TenderDocuments = ({ tender }) => {
<>
<p className="text-xs text-slate-500 leading-relaxed">
İhale dokümanları EKAP üzerinde tutulur. Aşağıdaki bağlantı sizi doğrudan bu ihalenin
EKAP doküman sayfasına götürür; ilan metnini ise analiz için buradan çekebilirsiniz.
EKAP doküman sayfasına götürür; EKAP önce kısa bir <strong>güvenlik doğrulaması</strong> (resim seçme)
ister, ardından şartname ve ekleri listelenir. İlan metnini ise analiz için buradan çekebilirsiniz.
</p>
<div className="flex gap-2 flex-wrap">
@@ -240,9 +261,24 @@ export const TenderDocuments = ({ tender }) => {
</button>
</div>
{ekapUrl && (
<div className={`rounded-lg p-2.5 flex gap-2 border ${bilgi?.ekapSekme === 'engellendi' ? 'bg-amber-50 border-amber-200' : 'bg-slate-50 border-slate-200'}`}>
<ExternalLink className="w-3.5 h-3.5 text-blue-600 shrink-0 mt-0.5" />
<p className="text-[11px] text-slate-700 leading-relaxed">
{bilgi?.ekapSekme === 'engellendi'
? <>Tarayıcınız yeni sekmeyi engelledi. </>
: <>EKAP doküman sayfası yeni sekmede açıldı. Açılmadıysa: </>}
<a href={ekapUrl} target="_blank" rel="noopener noreferrer" className="text-blue-600 font-bold hover:underline">
EKAP doküman sayfasını aç
</a>
{' '}· Bağlantı bir süre sonra geçerliliğini yitirebilir; açılmazsa düğmeye yeniden basın.
</p>
</div>
)}
{bilgi && !bilgi.derin && (
<p className="text-[11px] text-slate-500">
{bilgi.dokumanSayisi != null && <>EKAP'ta {bilgi.dokumanSayisi} doküman kayıtlı. </>}
{bilgi.dokumanSayisi > 0 && <>EKAP'ta {bilgi.dokumanSayisi} doküman kayıtlı. </>}
{bilgi.karakter != null && <>{bilgi.ilanSayisi} ilan · {bilgi.okasSayisi} kalem · {bilgi.karakter.toLocaleString('tr-TR')} karakter metin analize gönderildi. </>}
{bilgi.yuklendi && (
<>