fix: guide EKAP human verification
This commit is contained in:
@@ -177,6 +177,12 @@ const TenderDocumentSession = ({ tender }) => {
|
||||
try {
|
||||
const r = await fetch(`/api/documents/url?ikn=${encodeURIComponent(ikn)}`);
|
||||
const d = await r.json();
|
||||
if (!d.success && d.code === 'HUMAN_VERIFICATION_REQUIRED' && d.manualAction && d.manualUrl) {
|
||||
setEkapUrl(d.manualUrl);
|
||||
setBilgi({ manualAction: true, ekapSekme: sekme ? 'acildi' : 'engellendi' });
|
||||
if (sekme) sekme.location.href = d.manualUrl;
|
||||
return;
|
||||
}
|
||||
if (!d.success) throw new Error(d.error);
|
||||
setEkapUrl(d.url);
|
||||
setBilgi({ dokumanSayisi: d.dokumanSayisi, ekapSekme: sekme ? 'acildi' : 'engellendi' });
|
||||
@@ -326,16 +332,20 @@ const TenderDocumentSession = ({ tender }) => {
|
||||
</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'}`}>
|
||||
<div className={`rounded-lg p-2.5 flex gap-2 border ${bilgi?.ekapSekme === 'engellendi' || bilgi?.manualAction ? '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'
|
||||
{bilgi?.manualAction
|
||||
? <>EKAP güvenlik doğrulaması istedi. Kendi oturumunuzda EKAP’ı açıp İKN ile arayın: </>
|
||||
: 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.
|
||||
{bilgi?.manualAction
|
||||
? <> · Doğrulamadan sonra dosyaları indirin ve aşağıdaki yükleme alanına ekleyin.</>
|
||||
: <> · Bağlantı bir süre sonra geçerliliğini yitirebilir; açılmazsa düğmeye yeniden basın.</>}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -4,11 +4,20 @@
|
||||
* Dev'de Vite proxy'si /api isteklerini localhost:3001'e yönlendirir.
|
||||
*/
|
||||
|
||||
function sourceError(data, temporaryMessage) {
|
||||
if (data.code === 'HUMAN_VERIFICATION_REQUIRED' && data.manualAction) {
|
||||
return new Error(data.error || 'EKAP güvenlik doğrulaması gerekiyor. EKAP’ı kendi tarayıcınızda açın.');
|
||||
}
|
||||
if (data.code === 'SOURCE_UNAVAILABLE' && data.retryable) return new Error(temporaryMessage);
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function fetchLiveTenders({ refresh = false } = {}) {
|
||||
const res = await fetch(`/api/tenders${refresh ? '?refresh=1' : ''}`);
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) {
|
||||
if (data.code === 'SOURCE_UNAVAILABLE' && data.retryable) throw new Error('İhale kaynağı geçici olarak erişilemiyor. Birkaç dakika sonra yeniden deneyin.');
|
||||
const failure = sourceError(data, 'İhale kaynağı geçici olarak erişilemiyor. Birkaç dakika sonra yeniden deneyin.');
|
||||
if (failure) throw failure;
|
||||
throw new Error(`API hatası: HTTP ${res.status}`);
|
||||
}
|
||||
if (!data.success) throw new Error(data.error || 'API başarısız yanıt döndü');
|
||||
@@ -28,7 +37,8 @@ export async function fetchTenderDetail(tenderId, {signal, timeoutMs = 30000} =
|
||||
const res = await fetch(url, {signal:controller.signal});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) {
|
||||
if (data.code === 'SOURCE_UNAVAILABLE' && data.retryable) throw new Error('Resmi ihale kaynağı geçici olarak erişilemiyor. Birkaç dakika sonra yeniden deneyin.');
|
||||
const failure = sourceError(data, 'Resmi ihale kaynağı geçici olarak erişilemiyor. Birkaç dakika sonra yeniden deneyin.');
|
||||
if (failure) throw failure;
|
||||
throw new Error(`Detay API hatası: HTTP ${res.status}`);
|
||||
}
|
||||
if (!data.success) throw new Error(data.error || 'Detay alınamadı');
|
||||
@@ -69,7 +79,8 @@ export async function fetchOfficialTenderDetail(ikn, {signal, timeoutMs = 30000}
|
||||
const res = await fetch(`/api/documents/ilan?ikn=${encodeURIComponent(cleanIkn)}`, { signal: controller.signal });
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) {
|
||||
if (data.code === 'SOURCE_UNAVAILABLE' && data.retryable) throw new Error('Resmî ihale kaynağı geçici olarak erişilemiyor.');
|
||||
const failure = sourceError(data, 'Resmî ihale kaynağı geçici olarak erişilemiyor.');
|
||||
if (failure) throw failure;
|
||||
throw new Error(`Resmî detay API hatası: HTTP ${res.status}`);
|
||||
}
|
||||
if (!data.success || data.ikn !== cleanIkn) throw new Error('Resmî detay yanıtı aranan İKN ile uyuşmuyor.');
|
||||
|
||||
Reference in New Issue
Block a user