make non submit buttons explicit

This commit is contained in:
2026-09-06 19:17:30 +03:00
parent b909468afd
commit fc9e9a2a54
23 changed files with 86 additions and 80 deletions
+6
View File
@@ -2218,3 +2218,9 @@ Browser QA, dinamik sekme yüklemesi sonrası günlük bülten başlığını do
Headless browser kabulü artık giriş sonrası Günlük Bülten sekmesini dinamik olarak açıyor ve `Günlük İhale Bülteni` başlığını doğruluyor. Böylece İstanbul günü düzeltmesiyle birlikte sekme yükleme ve erişilebilir başlık regresyonu da otomatik izleniyor. Headless browser kabulü artık giriş sonrası Günlük Bülten sekmesini dinamik olarak açıyor ve `Günlük İhale Bülteni` başlığını doğruluyor. Böylece İstanbul günü düzeltmesiyle birlikte sekme yükleme ve erişilebilir başlık regresyonu da otomatik izleniyor.
Doğrulama: browser QA başarılı; günlük bülten, analitik, ICS, çıktı ve mobil kontrolleri aynı koşuda geçti. Doğrulama: browser QA başarılı; günlük bülten, analitik, ICS, çıktı ve mobil kontrolleri aynı koşuda geçti.
### 2026-09-06 · Örtük düğme gönderimlerinin kaldırılması
Tüm JSX ekranlarında form dışında kalan düğmeler açık `type="button"` kullanacak şekilde standardize edildi. Filtre, gezinme, dışa aktarma, modal, pazar, bildirim ve yönetim eylemleri artık bir form kapsayıcısına taşınsa bile istemeden submit tetiklemiyor; gerçek form gönderimleri `type="submit"` olarak korunuyor.
Doğrulama: 293 otomatik test, üretim derlemesi ve browser QA başarılı. QA akışı Günlük Bülten, Analitik, ICS, çıktı ve 390px mobil kontrollerini geçti.
+1 -1
View File
@@ -371,7 +371,7 @@ export const AiSpecAnalyzerModal = () => {
</div> </div>
<div className="bg-slate-50 p-4 border-t border-slate-200 flex justify-end"> <div className="bg-slate-50 p-4 border-t border-slate-200 flex justify-end">
<button <button type="button"
onClick={() => setIsAiSpecAnalyzerOpen(false)} onClick={() => setIsAiSpecAnalyzerOpen(false)}
className="bg-slate-800 hover:bg-slate-700 text-white font-bold text-xs px-6 py-2.5 rounded-xl transition-colors" className="bg-slate-800 hover:bg-slate-700 text-white font-bold text-xs px-6 py-2.5 rounded-xl transition-colors"
> >
+1 -1
View File
@@ -139,7 +139,7 @@ export const KanbanBoard = () => {
{info.label} {info.label}
</span>; </span>;
})()} })()}
<button <button type="button"
onClick={() => setActiveTenderDetail(t)} onClick={() => setActiveTenderDetail(t)}
className="text-slate-400 hover:text-blue-600 p-0.5" className="text-slate-400 hover:text-blue-600 p-0.5"
aria-label={`${t.ikn} ihale detayını aç`} aria-label={`${t.ikn} ihale detayını aç`}
+4 -4
View File
@@ -200,7 +200,7 @@ export const LandingPage = ({ onGiris }) => {
<a href="#nasil" className="transition hover:text-white">Nasıl çalışır?</a> <a href="#nasil" className="transition hover:text-white">Nasıl çalışır?</a>
<a href="#rakamlar" className="transition hover:text-white">Rakamlarla</a> <a href="#rakamlar" className="transition hover:text-white">Rakamlarla</a>
</nav> </nav>
<button onClick={onGiris} className="group flex items-center gap-2 rounded-xl bg-white px-5 py-2.5 text-sm font-black text-slate-900 transition hover:bg-cyan-300"> <button type="button" onClick={onGiris} className="group flex items-center gap-2 rounded-xl bg-white px-5 py-2.5 text-sm font-black text-slate-900 transition hover:bg-cyan-300">
Giriş Yap <ArrowRight size={15} className="transition group-hover:translate-x-0.5" /> Giriş Yap <ArrowRight size={15} className="transition group-hover:translate-x-0.5" />
</button> </button>
</header> </header>
@@ -225,7 +225,7 @@ export const LandingPage = ({ onGiris }) => {
fiyat analizini tek panelde toplar. Siz teklife odaklanın, takibi biz yapalım. fiyat analizini tek panelde toplar. Siz teklife odaklanın, takibi biz yapalım.
</p> </p>
<div className="lp-hero-in mt-9 flex flex-col gap-3 sm:flex-row" style={{ animationDelay: '0.24s' }}> <div className="lp-hero-in mt-9 flex flex-col gap-3 sm:flex-row" style={{ animationDelay: '0.24s' }}>
<button onClick={onGiris} className="group flex items-center justify-center gap-2 rounded-xl bg-gradient-to-r from-cyan-400 to-blue-500 px-7 py-3.5 text-base font-black text-white shadow-xl shadow-cyan-500/25 transition hover:shadow-cyan-400/40 hover:brightness-110"> <button type="button" onClick={onGiris} className="group flex items-center justify-center gap-2 rounded-xl bg-gradient-to-r from-cyan-400 to-blue-500 px-7 py-3.5 text-base font-black text-white shadow-xl shadow-cyan-500/25 transition hover:shadow-cyan-400/40 hover:brightness-110">
Hemen Başla — Ücretsiz <ArrowRight size={17} className="transition group-hover:translate-x-1" /> Hemen Başla — Ücretsiz <ArrowRight size={17} className="transition group-hover:translate-x-1" />
</button> </button>
<a href="#ozellikler" className="flex items-center justify-center gap-2 rounded-xl border border-white/15 bg-white/[0.05] px-7 py-3.5 text-base font-bold text-white/85 backdrop-blur transition hover:border-white/30 hover:bg-white/10"> <a href="#ozellikler" className="flex items-center justify-center gap-2 rounded-xl border border-white/15 bg-white/[0.05] px-7 py-3.5 text-base font-bold text-white/85 backdrop-blur transition hover:border-white/30 hover:bg-white/10">
@@ -329,7 +329,7 @@ export const LandingPage = ({ onGiris }) => {
<CalendarDays size={34} className="mx-auto text-cyan-300" /> <CalendarDays size={34} className="mx-auto text-cyan-300" />
<h2 className="mx-auto mt-5 max-w-2xl text-4xl font-black tracking-tight sm:text-5xl">Yarınki ilanlar sizi beklemeyecek.</h2> <h2 className="mx-auto mt-5 max-w-2xl text-4xl font-black tracking-tight sm:text-5xl">Yarınki ilanlar sizi beklemeyecek.</h2>
<p className="mx-auto mt-4 max-w-xl text-lg leading-8 text-white/55">Bugün girin, kriterlerinizi kurun; yarın sabah ilk bülteniniz hazır olsun.</p> <p className="mx-auto mt-4 max-w-xl text-lg leading-8 text-white/55">Bugün girin, kriterlerinizi kurun; yarın sabah ilk bülteniniz hazır olsun.</p>
<button onClick={onGiris} className="group mx-auto mt-9 flex items-center gap-2 rounded-xl bg-gradient-to-r from-cyan-400 to-blue-500 px-8 py-4 text-lg font-black text-white shadow-xl shadow-cyan-500/30 transition hover:shadow-cyan-400/50 hover:brightness-110"> <button type="button" onClick={onGiris} className="group mx-auto mt-9 flex items-center gap-2 rounded-xl bg-gradient-to-r from-cyan-400 to-blue-500 px-8 py-4 text-lg font-black text-white shadow-xl shadow-cyan-500/30 transition hover:shadow-cyan-400/50 hover:brightness-110">
Ücretsiz Giriş Yap <ArrowRight size={19} className="transition group-hover:translate-x-1" /> Ücretsiz Giriş Yap <ArrowRight size={19} className="transition group-hover:translate-x-1" />
</button> </button>
</div> </div>
@@ -347,7 +347,7 @@ export const LandingPage = ({ onGiris }) => {
<div className="flex flex-wrap items-center gap-x-6 gap-y-2 font-semibold"> <div className="flex flex-wrap items-center gap-x-6 gap-y-2 font-semibold">
<a href="/gizlilik.html" className="transition hover:text-white">Gizlilik Politikası</a> <a href="/gizlilik.html" className="transition hover:text-white">Gizlilik Politikası</a>
<a href="/kullanim-kosullari.html" className="transition hover:text-white">Kullanım Şartları</a> <a href="/kullanim-kosullari.html" className="transition hover:text-white">Kullanım Şartları</a>
<button onClick={onGiris} className="transition hover:text-white">Giriş</button> <button type="button" onClick={onGiris} className="transition hover:text-white">Giriş</button>
</div> </div>
</div> </div>
</footer> </footer>
+16 -16
View File
@@ -90,7 +90,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
<Compass className="w-4 h-4 text-blue-600" /> Hızlı Erişim <Compass className="w-4 h-4 text-blue-600" /> Hızlı Erişim
</span> </span>
{(detailedQueries.institution || detailedQueries.registration || selectedRegion || quickFilter !== 'all' || selectedSektorler.length || selectedCpvler.length || selectedCity || selectedAlimTuru || selectedKurumTipi) && ( {(detailedQueries.institution || detailedQueries.registration || selectedRegion || quickFilter !== 'all' || selectedSektorler.length || selectedCpvler.length || selectedCity || selectedAlimTuru || selectedKurumTipi) && (
<button <button type="button"
onClick={clearAllFilters} onClick={clearAllFilters}
className="text-[11px] font-medium text-blue-600 hover:underline" className="text-[11px] font-medium text-blue-600 hover:underline"
> >
@@ -103,7 +103,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
const Icon = item.icon; const Icon = item.icon;
const isSelected = quickFilter === item.id; const isSelected = quickFilter === item.id;
return ( return (
<button <button type="button"
key={item.id} key={item.id}
onClick={() => { onClick={() => {
setQuickFilter(item.id); setQuickFilter(item.id);
@@ -156,12 +156,12 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
className="bg-slate-50 hover:bg-slate-100 p-2.5 rounded-lg border border-slate-200 flex items-center justify-between text-xs transition-colors group" className="bg-slate-50 hover:bg-slate-100 p-2.5 rounded-lg border border-slate-200 flex items-center justify-between text-xs transition-colors group"
> >
<div className="flex-1 min-w-0 pr-2"> <div className="flex-1 min-w-0 pr-2">
<button className="font-bold text-blue-800 underline text-left" onClick={()=>applySavedFilter(filter)} aria-label={`${filter.name} filtresini uygula`}>{filter.name}</button> <button type="button" className="font-bold text-blue-800 underline text-left" onClick={()=>applySavedFilter(filter)} aria-label={`${filter.name} filtresini uygula`}>{filter.name}</button>
<p className="text-[10px] text-slate-500 truncate mt-0.5"> <p className="text-[10px] text-slate-500 truncate mt-0.5">
👤 {filter.user} {filter.sehir && `• 📍 ${filter.sehir}`} 👤 {filter.user} {filter.sehir && `• 📍 ${filter.sehir}`}
</p> </p>
</div> </div>
<button <button type="button"
disabled={savingCount > 0} aria-label={`${filter.name} filtresini sil`} onClick={() => deleteSavedFilter(filter.id)} disabled={savingCount > 0} aria-label={`${filter.name} filtresini sil`} onClick={() => deleteSavedFilter(filter.id)}
title="Filtreyi Sil" title="Filtreyi Sil"
className="text-slate-400 hover:text-red-600 p-1 opacity-60 group-hover:opacity-100 transition-opacity" className="text-slate-400 hover:text-red-600 p-1 opacity-60 group-hover:opacity-100 transition-opacity"
@@ -173,7 +173,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
</div> </div>
)} )}
<button <button type="button"
onClick={() => setActiveTab('smart_filter_builder')} onClick={() => setActiveTab('smart_filter_builder')}
className="w-full bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-3 rounded-lg text-xs flex items-center justify-center gap-2 transition-colors shadow-xs" className="w-full bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-3 rounded-lg text-xs flex items-center justify-center gap-2 transition-colors shadow-xs"
> >
@@ -187,7 +187,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
{/* Alım Türü */} {/* Alım Türü */}
<div> <div>
<button <button type="button"
onClick={() => toggleSection('alimTuru')} onClick={() => toggleSection('alimTuru')}
className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors" className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors"
> >
@@ -219,7 +219,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
{/* Sektörler */} {/* Sektörler */}
<div> <div>
<button <button type="button"
onClick={() => toggleSection('sektorler')} onClick={() => toggleSection('sektorler')}
className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors" className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors"
> >
@@ -238,7 +238,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
className="w-full border border-slate-200 rounded-lg px-2 py-1.5 mb-1 text-xs focus:outline-hidden focus:ring-2 focus:ring-blue-500/30" className="w-full border border-slate-200 rounded-lg px-2 py-1.5 mb-1 text-xs focus:outline-hidden focus:ring-2 focus:ring-blue-500/30"
/> />
<div className="max-h-56 overflow-y-auto space-y-1"> <div className="max-h-56 overflow-y-auto space-y-1">
<button <button type="button"
onClick={() => { setSelectedSektorler([]); setActiveTab('list'); }} onClick={() => { setSelectedSektorler([]); setActiveTab('list'); }}
className={`w-full text-left px-2 py-1 rounded font-medium ${!selectedSektorler.length ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`} className={`w-full text-left px-2 py-1 rounded font-medium ${!selectedSektorler.length ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`}
> >
@@ -271,7 +271,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
{/* CPV Kodu */} {/* CPV Kodu */}
<div> <div>
<button <button type="button"
onClick={() => toggleSection('cpv')} onClick={() => toggleSection('cpv')}
className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors" className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors"
> >
@@ -313,7 +313,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
className="w-full border border-slate-200 rounded-lg px-2 py-1.5 mb-1 text-xs focus:outline-hidden focus:ring-2 focus:ring-blue-500/30" className="w-full border border-slate-200 rounded-lg px-2 py-1.5 mb-1 text-xs focus:outline-hidden focus:ring-2 focus:ring-blue-500/30"
/> />
<div className="max-h-56 overflow-y-auto space-y-1"> <div className="max-h-56 overflow-y-auto space-y-1">
<button <button type="button"
onClick={() => { setSelectedCpvler([]); setActiveTab('list'); }} onClick={() => { setSelectedCpvler([]); setActiveTab('list'); }}
className={`w-full text-left px-2 py-1 rounded font-medium ${!selectedCpvler.length ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`} className={`w-full text-left px-2 py-1 rounded font-medium ${!selectedCpvler.length ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`}
> >
@@ -346,7 +346,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
{/* Kurum Tipleri */} {/* Kurum Tipleri */}
<div> <div>
<button <button type="button"
onClick={() => toggleSection('kurumTipleri')} onClick={() => toggleSection('kurumTipleri')}
className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors" className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors"
> >
@@ -357,14 +357,14 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
</button> </button>
{openSections.kurumTipleri && ( {openSections.kurumTipleri && (
<div className="p-3 space-y-1 text-xs max-h-48 overflow-y-auto"> <div className="p-3 space-y-1 text-xs max-h-48 overflow-y-auto">
<button <button type="button"
onClick={() => { setSelectedKurumTipi(''); setActiveTab('list'); }} onClick={() => { setSelectedKurumTipi(''); setActiveTab('list'); }}
className={`w-full text-left px-2 py-1 rounded font-medium ${!selectedKurumTipi ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`} className={`w-full text-left px-2 py-1 rounded font-medium ${!selectedKurumTipi ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`}
> >
Tüm Kurumlar Tüm Kurumlar
</button> </button>
{INSTITUTION_TYPES_LIST.map(k => ( {INSTITUTION_TYPES_LIST.map(k => (
<button <button type="button"
key={k} key={k}
onClick={() => { setSelectedKurumTipi(k); setActiveTab('list'); }} onClick={() => { setSelectedKurumTipi(k); setActiveTab('list'); }}
className={`w-full text-left px-2 py-1 rounded truncate font-medium ${selectedKurumTipi === k ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`} className={`w-full text-left px-2 py-1 rounded truncate font-medium ${selectedKurumTipi === k ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`}
@@ -378,7 +378,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
{/* İl Dağılımları */} {/* İl Dağılımları */}
<div> <div>
<button <button type="button"
onClick={() => toggleSection('iller')} onClick={() => toggleSection('iller')}
className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors" className="w-full px-4 py-3 flex items-center justify-between text-xs font-bold text-slate-800 bg-slate-50/50 hover:bg-slate-100 transition-colors"
> >
@@ -389,14 +389,14 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
</button> </button>
{openSections.iller && ( {openSections.iller && (
<div className="p-3 space-y-1 text-xs max-h-48 overflow-y-auto"> <div className="p-3 space-y-1 text-xs max-h-48 overflow-y-auto">
<button <button type="button"
onClick={() => { setSelectedCity(''); setActiveTab('list'); }} onClick={() => { setSelectedCity(''); setActiveTab('list'); }}
className={`w-full text-left px-2 py-1 rounded font-medium ${!selectedCity ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`} className={`w-full text-left px-2 py-1 rounded font-medium ${!selectedCity ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`}
> >
Tüm Şehirler Tüm Şehirler
</button> </button>
{CITIES_LIST.map(city => ( {CITIES_LIST.map(city => (
<button <button type="button"
key={city} key={city}
onClick={() => { setSelectedCity(city); setActiveTab('list'); }} onClick={() => { setSelectedCity(city); setActiveTab('list'); }}
className={`w-full text-left px-2 py-1 rounded font-medium ${selectedCity === city ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`} className={`w-full text-left px-2 py-1 rounded font-medium ${selectedCity === city ? 'bg-blue-50 text-blue-700 font-bold' : 'text-slate-600 hover:bg-slate-50'}`}
+3 -3
View File
@@ -68,7 +68,7 @@ export const SmartFilterBuilder = () => {
<p className="text-xs text-slate-500">Arama ölçütlerinizi kaydedin; soldaki filtre adına tıklayarak ihale listesine uygulayın. E-posta bildirimleri Yönetim → Mobil PWA bölümünden ayrıca kurulur.</p> <p className="text-xs text-slate-500">Arama ölçütlerinizi kaydedin; soldaki filtre adına tıklayarak ihale listesine uygulayın. E-posta bildirimleri Yönetim → Mobil PWA bölümünden ayrıca kurulur.</p>
</div> </div>
</div> </div>
<button <button type="button"
onClick={() => setActiveTab('list')} onClick={() => setActiveTab('list')}
className="bg-slate-800 hover:bg-slate-700 text-white font-semibold text-xs px-4 py-2 rounded-lg flex items-center gap-2 transition-colors shadow-xs" className="bg-slate-800 hover:bg-slate-700 text-white font-semibold text-xs px-4 py-2 rounded-lg flex items-center gap-2 transition-colors shadow-xs"
> >
@@ -105,7 +105,7 @@ export const SmartFilterBuilder = () => {
<div key={f.id} className="p-3 bg-slate-50 border border-slate-200 rounded-lg text-xs hover:bg-slate-100 transition-colors"> <div key={f.id} className="p-3 bg-slate-50 border border-slate-200 rounded-lg text-xs hover:bg-slate-100 transition-colors">
<div className="flex items-center justify-between font-bold text-slate-900"> <div className="flex items-center justify-between font-bold text-slate-900">
<button type="button" className="text-blue-800 underline" onClick={()=>applySavedFilter(f)} aria-label={`${f.name} filtresini uygula`}>{f.name}</button> <button type="button" className="text-blue-800 underline" onClick={()=>applySavedFilter(f)} aria-label={`${f.name} filtresini uygula`}>{f.name}</button>
<button <button type="button"
disabled={savingCount > 0} aria-label={`${f.name} filtresini sil`} onClick={async()=>{setSuccessMessage('');await deleteSavedFilter(f.id);}} disabled={savingCount > 0} aria-label={`${f.name} filtresini sil`} onClick={async()=>{setSuccessMessage('');await deleteSavedFilter(f.id);}}
className="text-slate-400 hover:text-red-600 text-xs" className="text-slate-400 hover:text-red-600 text-xs"
> >
@@ -117,7 +117,7 @@ export const SmartFilterBuilder = () => {
))} ))}
</div> </div>
<button <button type="button"
onClick={() => setActiveTab('list')} onClick={() => setActiveTab('list')}
className="w-full bg-slate-100 hover:bg-slate-200 text-slate-700 font-bold py-2.5 px-3 rounded-lg text-xs flex items-center justify-center gap-2 transition-colors border border-slate-200" className="w-full bg-slate-100 hover:bg-slate-200 text-slate-700 font-bold py-2.5 px-3 rounded-lg text-xs flex items-center justify-center gap-2 transition-colors border border-slate-200"
> >
+1 -1
View File
@@ -84,7 +84,7 @@ export const TenderCard = ({ tender }) => {
<span className="flex items-center gap-1 text-slate-700 font-semibold truncate max-w-md"> <span className="flex items-center gap-1 text-slate-700 font-semibold truncate max-w-md">
<Building2 className="w-3.5 h-3.5 text-slate-400 shrink-0" /> <Building2 className="w-3.5 h-3.5 text-slate-400 shrink-0" />
<span className="truncate">{tender.kurum}</span> <span className="truncate">{tender.kurum}</span>
<button <button type="button"
onClick={(e) => { e.stopPropagation(); toggleFavoriteKurum(tender.kurum); }} onClick={(e) => { e.stopPropagation(); toggleFavoriteKurum(tender.kurum); }}
disabled={favoriteSaving || !tender.kurum?.trim()} disabled={favoriteSaving || !tender.kurum?.trim()}
aria-busy={favoriteSaving} aria-pressed={Boolean(isFavKurum)} aria-busy={favoriteSaving} aria-pressed={Boolean(isFavKurum)}
+2 -2
View File
@@ -172,7 +172,7 @@ export const TenderList = () => {
<option value="distant">Tarihi Uzak Olanlar</option> <option value="distant">Tarihi Uzak Olanlar</option>
</select> </select>
<button <button type="button"
onClick={handleExportExcel} disabled={exporting || !filteredTenders.length} onClick={handleExportExcel} disabled={exporting || !filteredTenders.length}
className="bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs px-3.5 py-2 rounded-lg flex items-center gap-1.5 transition-colors shadow-xs shrink-0" className="bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs px-3.5 py-2 rounded-lg flex items-center gap-1.5 transition-colors shadow-xs shrink-0"
> >
@@ -218,7 +218,7 @@ export const TenderList = () => {
{gorunenTenders.length.toLocaleString('tr-TR')} / {filteredTenders.length.toLocaleString('tr-TR')} ihale gösteriliyor {gorunenTenders.length.toLocaleString('tr-TR')} / {filteredTenders.length.toLocaleString('tr-TR')} ihale gösteriliyor
</div> </div>
{/* Gözlemci çalışmazsa elle yükleme yolu açık kalsın */} {/* Gözlemci çalışmazsa elle yükleme yolu açık kalsın */}
<button <button type="button"
onClick={dahaGoster} onClick={dahaGoster}
className="mt-2 text-xs font-bold text-blue-600 hover:text-blue-700 hover:underline" className="mt-2 text-xs font-bold text-blue-600 hover:text-blue-700 hover:underline"
> >
+1 -1
View File
@@ -151,7 +151,7 @@ export const TopNavigation = () => {
const isActive = bekleyen ? bekleyen === item.id : activeTab === item.id; const isActive = bekleyen ? bekleyen === item.id : activeTab === item.id;
const yukleniyor = bekleyen === item.id; const yukleniyor = bekleyen === item.id;
return ( return (
<button <button type="button"
key={item.id} key={item.id}
data-tab={item.id} data-tab={item.id}
aria-current={isActive ? 'page' : undefined} aria-current={isActive ? 'page' : undefined}
+3 -3
View File
@@ -290,7 +290,7 @@ export const UrunAramaModal = () => {
)} )}
<span className="text-slate-400">{t.durum}</span> <span className="text-slate-400">{t.durum}</span>
{/^\d{4}\/\d+$/.test(String(t.ikn || '')) && ( {/^\d{4}\/\d+$/.test(String(t.ikn || '')) && (
<button <button type="button"
onClick={() => { openSearchTender(t); setIsUrunAramaOpen(false); }} onClick={() => { openSearchTender(t); setIsUrunAramaOpen(false); }}
className="font-bold text-indigo-700 hover:underline" className="font-bold text-indigo-700 hover:underline"
> >
@@ -312,7 +312,7 @@ export const UrunAramaModal = () => {
{sonuc.totalCount > SAYFA && ( {sonuc.totalCount > SAYFA && (
<div className="flex items-center justify-center gap-3 pt-2"> <div className="flex items-center justify-center gap-3 pt-2">
<button <button type="button"
disabled={durum.sayfa === 0 || durum.yukleniyor} disabled={durum.sayfa === 0 || durum.yukleniyor}
onClick={() => sorgula(submitted, durum.sayfa - 1)} onClick={() => sorgula(submitted, durum.sayfa - 1)}
className="text-xs font-bold px-3 py-1.5 rounded-lg border border-slate-300 disabled:opacity-40" className="text-xs font-bold px-3 py-1.5 rounded-lg border border-slate-300 disabled:opacity-40"
@@ -322,7 +322,7 @@ export const UrunAramaModal = () => {
<span className="text-xs text-slate-500"> <span className="text-xs text-slate-500">
{durum.sayfa + 1} / {Math.ceil(sonuc.totalCount / SAYFA).toLocaleString('tr-TR')} {durum.sayfa + 1} / {Math.ceil(sonuc.totalCount / SAYFA).toLocaleString('tr-TR')}
</span> </span>
<button <button type="button"
disabled={(durum.sayfa + 1) * SAYFA >= sonuc.totalCount || durum.yukleniyor} disabled={(durum.sayfa + 1) * SAYFA >= sonuc.totalCount || durum.yukleniyor}
onClick={() => sorgula(submitted, durum.sayfa + 1)} onClick={() => sorgula(submitted, durum.sayfa + 1)}
className="text-xs font-bold px-3 py-1.5 rounded-lg border border-slate-300 disabled:opacity-40" className="text-xs font-bold px-3 py-1.5 rounded-lg border border-slate-300 disabled:opacity-40"
+6 -6
View File
@@ -98,7 +98,7 @@ export const AiModelSettings = () => {
<p className="text-xs text-indigo-200 mt-0.5">Şartname analizi ve AI özelliklerinde kullanılacak modeli ve yedek (fallback) sırasını belirleyin.</p> <p className="text-xs text-indigo-200 mt-0.5">Şartname analizi ve AI özelliklerinde kullanılacak modeli ve yedek (fallback) sırasını belirleyin.</p>
</div> </div>
</div> </div>
<button <button type="button"
onClick={handleSave} onClick={handleSave}
className={`px-4 py-2.5 rounded-xl font-bold text-sm flex items-center gap-2 transition ${saved ? 'bg-emerald-500 text-white' : 'bg-white text-indigo-900 hover:bg-indigo-50'}`} className={`px-4 py-2.5 rounded-xl font-bold text-sm flex items-center gap-2 transition ${saved ? 'bg-emerald-500 text-white' : 'bg-white text-indigo-900 hover:bg-indigo-50'}`}
> >
@@ -127,11 +127,11 @@ export const AiModelSettings = () => {
className={`flex items-center gap-4 p-4 rounded-xl border ${idx === 0 ? 'border-indigo-300 bg-indigo-50/40 ring-1 ring-indigo-200' : 'border-slate-200 bg-slate-50/60'}`} className={`flex items-center gap-4 p-4 rounded-xl border ${idx === 0 ? 'border-indigo-300 bg-indigo-50/40 ring-1 ring-indigo-200' : 'border-slate-200 bg-slate-50/60'}`}
> >
<div className="flex flex-col items-center gap-1 w-8"> <div className="flex flex-col items-center gap-1 w-8">
<button onClick={() => move(idx, -1)} disabled={idx === 0} className="text-slate-400 hover:text-indigo-600 disabled:opacity-30"> <button type="button" onClick={() => move(idx, -1)} disabled={idx === 0} className="text-slate-400 hover:text-indigo-600 disabled:opacity-30">
<ArrowUp className="w-4 h-4" /> <ArrowUp className="w-4 h-4" />
</button> </button>
<span className="text-xs font-black text-slate-400">{idx + 1}</span> <span className="text-xs font-black text-slate-400">{idx + 1}</span>
<button onClick={() => move(idx, 1)} disabled={idx === chain.length - 1} className="text-slate-400 hover:text-indigo-600 disabled:opacity-30"> <button type="button" onClick={() => move(idx, 1)} disabled={idx === chain.length - 1} className="text-slate-400 hover:text-indigo-600 disabled:opacity-30">
<ArrowDown className="w-4 h-4" /> <ArrowDown className="w-4 h-4" />
</button> </button>
</div> </div>
@@ -155,11 +155,11 @@ export const AiModelSettings = () => {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{idx !== 0 && ( {idx !== 0 && (
<button onClick={() => setPrimary(idx)} className="text-[11px] font-bold text-indigo-600 hover:text-indigo-800 border border-indigo-200 rounded-lg px-2.5 py-1.5"> <button type="button" onClick={() => setPrimary(idx)} className="text-[11px] font-bold text-indigo-600 hover:text-indigo-800 border border-indigo-200 rounded-lg px-2.5 py-1.5">
Birincil yap Birincil yap
</button> </button>
)} )}
<button onClick={() => remove(idx)} disabled={chain.length <= 1} className="text-slate-400 hover:text-red-500 disabled:opacity-30 p-1.5"> <button type="button" onClick={() => remove(idx)} disabled={chain.length <= 1} className="text-slate-400 hover:text-red-500 disabled:opacity-30 p-1.5">
<X className="w-4 h-4" /> <X className="w-4 h-4" />
</button> </button>
</div> </div>
@@ -178,7 +178,7 @@ export const AiModelSettings = () => {
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
{available.map(m => ( {available.map(m => (
<button <button type="button"
key={m.id} key={m.id}
onClick={() => add(m.id)} onClick={() => add(m.id)}
className="text-left p-4 rounded-xl border border-slate-200 hover:border-indigo-300 hover:bg-indigo-50/40 transition group" className="text-left p-4 rounded-xl border border-slate-200 hover:border-indigo-300 hover:bg-indigo-50/40 transition group"
+4 -4
View File
@@ -89,7 +89,7 @@ const ApiKeySession = () => {
return ( return (
<div className="space-y-6 animate-fade-in"> <div className="space-y-6 animate-fade-in">
{hata && <button disabled={busy || loading} onClick={yukle} className="px-4 py-2 border rounded-lg">Yeniden dene</button>} {hata && <button type="button" disabled={busy || loading} onClick={yukle} className="px-4 py-2 border rounded-lg">Yeniden dene</button>}
<div className="bg-linear-to-r from-slate-900 via-violet-950 to-indigo-900 text-white p-6 rounded-2xl shadow-lg border border-violet-800/40"> <div className="bg-linear-to-r from-slate-900 via-violet-950 to-indigo-900 text-white p-6 rounded-2xl shadow-lg border border-violet-800/40">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-12 h-12 rounded-2xl bg-violet-600 flex items-center justify-center shadow-md"> <div className="w-12 h-12 rounded-2xl bg-violet-600 flex items-center justify-center shadow-md">
@@ -124,7 +124,7 @@ const ApiKeySession = () => {
<code className="flex-1 bg-white border border-emerald-200 rounded-lg px-3 py-2 text-[11px] font-mono break-all"> <code className="flex-1 bg-white border border-emerald-200 rounded-lg px-3 py-2 text-[11px] font-mono break-all">
{yeniAnahtar.anahtar} {yeniAnahtar.anahtar}
</code> </code>
<button onClick={() => kopyala(yeniAnahtar.anahtar)} <button type="button" onClick={() => kopyala(yeniAnahtar.anahtar)}
className="bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs px-3 py-2 rounded-lg flex items-center gap-1.5 shrink-0"> className="bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs px-3 py-2 rounded-lg flex items-center gap-1.5 shrink-0">
{kopyalandi ? <Check className="w-3.5 h-3.5" /> : <Copy className="w-3.5 h-3.5" />} {kopyalandi ? <Check className="w-3.5 h-3.5" /> : <Copy className="w-3.5 h-3.5" />}
{kopyalandi ? 'Kopyalandı' : 'Kopyala'} {kopyalandi ? 'Kopyalandı' : 'Kopyala'}
@@ -167,7 +167,7 @@ const ApiKeySession = () => {
{k.son_kullanim ? `son kullanım: ${new Date(k.son_kullanim).toLocaleString('tr-TR')}` : 'hiç kullanılmadı'} {k.son_kullanim ? `son kullanım: ${new Date(k.son_kullanim).toLocaleString('tr-TR')}` : 'hiç kullanılmadı'}
</p> </p>
</div> </div>
<button onClick={() => iptal(k.id)} disabled={busy || loading} <button type="button" onClick={() => iptal(k.id)} disabled={busy || loading}
className="text-slate-400 hover:text-red-500 shrink-0" title="Anahtarı iptal et"> className="text-slate-400 hover:text-red-500 shrink-0" title="Anahtarı iptal et">
<Trash2 className="w-4 h-4" /> <Trash2 className="w-4 h-4" />
</button> </button>
@@ -180,7 +180,7 @@ const ApiKeySession = () => {
<input value={yeniAd} onChange={(e) => setYeniAd(e.target.value)} <input value={yeniAd} onChange={(e) => setYeniAd(e.target.value)}
aria-label="Anahtar adı" placeholder="Anahtar adı (ör. ERP Entegrasyonu)" disabled={kilitli || busy || loading || !durum} aria-label="Anahtar adı" placeholder="Anahtar adı (ör. ERP Entegrasyonu)" disabled={kilitli || busy || loading || !durum}
className="min-w-0 flex-1 bg-slate-50 border border-slate-200 rounded-lg px-2.5 py-2 text-xs disabled:opacity-50" /> className="min-w-0 flex-1 bg-slate-50 border border-slate-200 rounded-lg px-2.5 py-2 text-xs disabled:opacity-50" />
<button onClick={olustur} disabled={busy || loading || !durum || kilitli || (limit != null && durum.anahtarlar.length >= limit)} <button type="button" onClick={olustur} disabled={busy || loading || !durum || kilitli || (limit != null && durum.anahtarlar.length >= limit)}
className="bg-violet-600 hover:bg-violet-500 disabled:opacity-40 text-white font-bold text-xs px-4 rounded-lg flex items-center gap-1.5"> className="bg-violet-600 hover:bg-violet-500 disabled:opacity-40 text-white font-bold text-xs px-4 rounded-lg flex items-center gap-1.5">
{busy ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Plus className="w-3.5 h-3.5" />} Oluştur {busy ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Plus className="w-3.5 h-3.5" />} Oluştur
</button> </button>
+3 -3
View File
@@ -34,9 +34,9 @@ function BriefPanel(){
<h3 className="font-bold text-sm flex gap-2"><CalendarClock className="w-4 h-4"/>Haftalık Brief</h3> <h3 className="font-bold text-sm flex gap-2"><CalendarClock className="w-4 h-4"/>Haftalık Brief</h3>
<p className="text-xs text-slate-500">Haftanın takipli ihaleleri ve geçen hafta sonuçlanan takipliler için özet tercihi. Gönderim, sunucu zamanlayıcısının ve ilgili e-posta/Telegram hizmetinin etkin olmasına bağlıdır.</p> <p className="text-xs text-slate-500">Haftanın takipli ihaleleri ve geçen hafta sonuçlanan takipliler için özet tercihi. Gönderim, sunucu zamanlayıcısının ve ilgili e-posta/Telegram hizmetinin etkin olmasına bağlıdır.</p>
<div className="flex gap-3 flex-wrap"> <div className="flex gap-3 flex-wrap">
{value&&<button role="switch" aria-label="Haftalık özet gönderimi" aria-checked={!value.kapali} disabled={busy} onClick={()=>run(false)} className="border rounded px-3 py-2 text-xs">{value.kapali?'Haftalık özet kapalı':'Haftalık özet açık'}</button>} {value&&<button type="button" role="switch" aria-label="Haftalık özet gönderimi" aria-checked={!value.kapali} disabled={busy} onClick={()=>run(false)} className="border rounded px-3 py-2 text-xs">{value.kapali?'Haftalık özet kapalı':'Haftalık özet açık'}</button>}
<button disabled={busy||!value} onClick={()=>run(true)} className="border rounded px-3 py-2 text-xs">Önizle</button> <button type="button" disabled={busy||!value} onClick={()=>run(true)} className="border rounded px-3 py-2 text-xs">Önizle</button>
<button disabled={busy} onClick={()=>setAttempt(n=>n+1)} className="border rounded px-3 py-2 text-xs">Özet ayarını yenile</button> <button type="button" disabled={busy} onClick={()=>setAttempt(n=>n+1)} className="border rounded px-3 py-2 text-xs">Özet ayarını yenile</button>
</div> </div>
{busy&&<p role="status" className="text-xs">Haftalık özet işlemi sürüyor…</p>} {busy&&<p role="status" className="text-xs">Haftalık özet işlemi sürüyor…</p>}
{error&&<p role="alert" className="text-xs text-red-700">{error}</p>} {error&&<p role="alert" className="text-xs text-red-700">{error}</p>}
+5 -5
View File
@@ -59,7 +59,7 @@ export const CompetitorRadar = () => {
</div> </div>
</div> </div>
<button <button type="button"
onClick={() => setActiveTab('sozlesme')} onClick={() => setActiveTab('sozlesme')}
className="bg-white/10 hover:bg-white/20 text-white font-bold text-xs px-4 py-2.5 rounded-xl border border-white/20 transition-colors flex items-center gap-2 shrink-0" className="bg-white/10 hover:bg-white/20 text-white font-bold text-xs px-4 py-2.5 rounded-xl border border-white/20 transition-colors flex items-center gap-2 shrink-0"
> >
@@ -120,7 +120,7 @@ export const CompetitorRadar = () => {
)} )}
</div> </div>
</div> </div>
<button <button type="button"
onClick={() => addFromReal(f)} onClick={() => addFromReal(f)}
disabled={competitorSaving || watched.has(f.name.trim().toLocaleLowerCase('tr-TR'))} disabled={competitorSaving || watched.has(f.name.trim().toLocaleLowerCase('tr-TR'))}
className="text-[11px] font-bold px-3 py-1.5 rounded-lg border border-indigo-200 text-indigo-700 hover:bg-indigo-50 disabled:opacity-40 shrink-0" className="text-[11px] font-bold px-3 py-1.5 rounded-lg border border-indigo-200 text-indigo-700 hover:bg-indigo-50 disabled:opacity-40 shrink-0"
@@ -207,7 +207,7 @@ export const CompetitorRadar = () => {
{/* Notification Toggles & Actions */} {/* Notification Toggles & Actions */}
<div className="flex items-center gap-3 shrink-0"> <div className="flex items-center gap-3 shrink-0">
<button <button type="button"
disabled title="Rakip teklif bildirimleri henüz etkin değil" disabled title="Rakip teklif bildirimleri henüz etkin değil"
className="text-xs font-extrabold px-3 py-1.5 rounded-xl border flex items-center gap-1.5 bg-slate-100 text-slate-400 border-slate-200" className="text-xs font-extrabold px-3 py-1.5 rounded-xl border flex items-center gap-1.5 bg-slate-100 text-slate-400 border-slate-200"
> >
@@ -215,7 +215,7 @@ export const CompetitorRadar = () => {
<span>Teklif uyarısı etkin değil</span> <span>Teklif uyarısı etkin değil</span>
</button> </button>
<button <button type="button"
disabled title="Rakip kazanım bildirimleri henüz etkin değil" disabled title="Rakip kazanım bildirimleri henüz etkin değil"
className="text-xs font-extrabold px-3 py-1.5 rounded-xl border flex items-center gap-1.5 bg-slate-100 text-slate-400 border-slate-200" className="text-xs font-extrabold px-3 py-1.5 rounded-xl border flex items-center gap-1.5 bg-slate-100 text-slate-400 border-slate-200"
> >
@@ -223,7 +223,7 @@ export const CompetitorRadar = () => {
<span>Kazanım uyarısı etkin değil</span> <span>Kazanım uyarısı etkin değil</span>
</button> </button>
<button <button type="button"
disabled={competitorSaving} aria-label={`${comp.name} radardan çıkar`} onClick={() => removeCompetitor(comp.id)} disabled={competitorSaving} aria-label={`${comp.name} radardan çıkar`} onClick={() => removeCompetitor(comp.id)}
className="p-2 text-slate-400 hover:text-red-600 rounded-lg transition-colors" className="p-2 text-slate-400 hover:text-red-600 rounded-lg transition-colors"
title="Radardan Çıkar" title="Radardan Çıkar"
+2 -2
View File
@@ -61,7 +61,7 @@ export const KikDecisions = () => {
/> />
<Search className="w-4 h-4 text-slate-400 absolute left-3 top-1/2 -translate-y-1/2" /> <Search className="w-4 h-4 text-slate-400 absolute left-3 top-1/2 -translate-y-1/2" />
</div> </div>
<button <button type="button"
onClick={() => ara()} onClick={() => ara()}
disabled={loading || !q.trim()} disabled={loading || !q.trim()}
className="bg-amber-600 hover:bg-amber-500 disabled:opacity-40 text-white font-bold text-xs px-5 rounded-lg flex items-center gap-2" className="bg-amber-600 hover:bg-amber-500 disabled:opacity-40 text-white font-bold text-xs px-5 rounded-lg flex items-center gap-2"
@@ -74,7 +74,7 @@ export const KikDecisions = () => {
<div className="flex gap-2 flex-wrap items-center"> <div className="flex gap-2 flex-wrap items-center">
<span className="text-[11px] text-slate-400 font-semibold">Takibinizdeki idareler:</span> <span className="text-[11px] text-slate-400 font-semibold">Takibinizdeki idareler:</span>
{oneriler.map((k) => ( {oneriler.map((k) => (
<button key={k} onClick={() => { setQ(k); ara(k); }} <button type="button" key={k} onClick={() => { setQ(k); ara(k); }}
className="text-[11px] bg-slate-100 hover:bg-slate-200 text-slate-700 px-2 py-1 rounded-md font-medium truncate max-w-[220px]"> className="text-[11px] bg-slate-100 hover:bg-slate-200 text-slate-700 px-2 py-1 rounded-md font-medium truncate max-w-[220px]">
{k} {k}
</button> </button>
+2 -2
View File
@@ -24,7 +24,7 @@ export const McpRssKarti = () => {
<div key={o.k} className="space-y-1"> <div key={o.k} className="space-y-1">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="text-xs font-bold text-slate-800">{o.ad} <span className="font-normal text-slate-500">— {o.not}</span></p> <p className="text-xs font-bold text-slate-800">{o.ad} <span className="font-normal text-slate-500">— {o.not}</span></p>
<button onClick={() => kopyala(o.k, o.kod)} className="text-[11px] flex items-center gap-1 border border-slate-200 rounded-lg px-2 py-1 hover:bg-slate-50">{kopya === o.k ? <Check className="w-3 h-3 text-emerald-600" /> : <Copy className="w-3 h-3" />} Kopyala</button> <button type="button" onClick={() => kopyala(o.k, o.kod)} className="text-[11px] flex items-center gap-1 border border-slate-200 rounded-lg px-2 py-1 hover:bg-slate-50">{kopya === o.k ? <Check className="w-3 h-3 text-emerald-600" /> : <Copy className="w-3 h-3" />} Kopyala</button>
</div> </div>
<pre className="overflow-x-auto rounded-lg bg-slate-900 text-slate-100 p-2 text-[11px]">{o.kod}</pre> <pre className="overflow-x-auto rounded-lg bg-slate-900 text-slate-100 p-2 text-[11px]">{o.kod}</pre>
</div> </div>
@@ -32,7 +32,7 @@ export const McpRssKarti = () => {
<div className="border-t border-slate-100 pt-3 space-y-1"> <div className="border-t border-slate-100 pt-3 space-y-1">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="text-xs font-bold text-slate-800 flex items-center gap-1"><Rss className="w-3.5 h-3.5 text-orange-500" /> RSS beslemesi <span className="font-normal text-slate-500">— Feedly, Outlook, Slack RSS, n8n… (il, sektor, q filtreleri)</span></p> <p className="text-xs font-bold text-slate-800 flex items-center gap-1"><Rss className="w-3.5 h-3.5 text-orange-500" /> RSS beslemesi <span className="font-normal text-slate-500">— Feedly, Outlook, Slack RSS, n8n… (il, sektor, q filtreleri)</span></p>
<button onClick={() => kopyala('rss', rss)} className="text-[11px] flex items-center gap-1 border border-slate-200 rounded-lg px-2 py-1 hover:bg-slate-50">{kopya === 'rss' ? <Check className="w-3 h-3 text-emerald-600" /> : <Copy className="w-3 h-3" />} Kopyala</button> <button type="button" onClick={() => kopyala('rss', rss)} className="text-[11px] flex items-center gap-1 border border-slate-200 rounded-lg px-2 py-1 hover:bg-slate-50">{kopya === 'rss' ? <Check className="w-3 h-3 text-emerald-600" /> : <Copy className="w-3 h-3" />} Kopyala</button>
</div> </div>
<pre className="overflow-x-auto rounded-lg bg-slate-900 text-slate-100 p-2 text-[11px]">{rss}</pre> <pre className="overflow-x-auto rounded-lg bg-slate-900 text-slate-100 p-2 text-[11px]">{rss}</pre>
<p className="text-[11px] text-slate-500">Sonuç ilanları beslemesi anahtarsız: <code>{origin}/api/feeds/sonuc.rss</code> (firma, idare, il filtreleri). Anahtarı <code>ih_live_ANAHTARINIZ</code> yerine yazın.</p> <p className="text-[11px] text-slate-500">Sonuç ilanları beslemesi anahtarsız: <code>{origin}/api/feeds/sonuc.rss</code> (firma, idare, il filtreleri). Anahtarı <code>ih_live_ANAHTARINIZ</code> yerine yazın.</p>
+9 -9
View File
@@ -126,7 +126,7 @@ const SubscriptionForm = () => {
{a.deliveryStatus && <span className="block text-amber-700">{a.deliveryStatus.state==='uncertain'?'Gönderim sonucu belirsiz. Uygulama yöneticisinin sağlayıcı kaydını kontrol etmesi gerekiyor.':'E-posta gönderimi bekliyor.'}</span>} {a.deliveryStatus && <span className="block text-amber-700">{a.deliveryStatus.state==='uncertain'?'Gönderim sonucu belirsiz. Uygulama yöneticisinin sağlayıcı kaydını kontrol etmesi gerekiyor.':'E-posta gönderimi bekliyor.'}</span>}
</p> </p>
</div> </div>
<button onClick={() => sil(a.id)} disabled={busy} className="text-slate-400 hover:text-red-500 shrink-0 mt-0.5" aria-label={`Aboneliği sil: ${ozet(a)}`} title="Sil"> <button type="button" onClick={() => sil(a.id)} disabled={busy} className="text-slate-400 hover:text-red-500 shrink-0 mt-0.5" aria-label={`Aboneliği sil: ${ozet(a)}`} title="Sil">
<Trash2 className="w-3.5 h-3.5" /> <Trash2 className="w-3.5 h-3.5" />
</button> </button>
</div> </div>
@@ -143,7 +143,7 @@ const SubscriptionForm = () => {
<input value={site} onChange={(e) => setSite(e.target.value)} <input value={site} onChange={(e) => setSite(e.target.value)}
placeholder="firmasitesi.com" placeholder="firmasitesi.com"
className="flex-1 bg-white border border-blue-200 rounded-lg px-2.5 py-2 text-xs" /> className="flex-1 bg-white border border-blue-200 rounded-lg px-2.5 py-2 text-xs" />
<button onClick={siteyiTara} disabled={taraniyor || !site.trim()} <button type="button" onClick={siteyiTara} disabled={taraniyor || !site.trim()}
className="bg-blue-600 hover:bg-blue-500 disabled:opacity-40 text-white font-bold text-xs px-3.5 rounded-lg flex items-center gap-1.5"> className="bg-blue-600 hover:bg-blue-500 disabled:opacity-40 text-white font-bold text-xs px-3.5 rounded-lg flex items-center gap-1.5">
{taraniyor ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Sparkles className="w-3.5 h-3.5" />} {taraniyor ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Sparkles className="w-3.5 h-3.5" />}
{taraniyor ? 'Taranıyor…' : 'Tara'} {taraniyor ? 'Taranıyor…' : 'Tara'}
@@ -163,7 +163,7 @@ const SubscriptionForm = () => {
<p className="text-[10px] text-blue-700 font-semibold">Önerilen konular — eklemek için tıklayın:</p> <p className="text-[10px] text-blue-700 font-semibold">Önerilen konular — eklemek için tıklayın:</p>
<div className="flex flex-wrap gap-1.5"> <div className="flex flex-wrap gap-1.5">
{oneriler.map((k) => ( {oneriler.map((k) => (
<button key={k} onClick={() => konuEkle(k)} <button type="button" key={k} onClick={() => konuEkle(k)}
className="text-[11px] bg-white hover:bg-blue-100 border border-blue-300 text-blue-900 px-2 py-1 rounded-md font-medium"> className="text-[11px] bg-white hover:bg-blue-100 border border-blue-300 text-blue-900 px-2 py-1 rounded-md font-medium">
+ {k} + {k}
</button> </button>
@@ -185,7 +185,7 @@ const SubscriptionForm = () => {
{konular.map((k) => ( {konular.map((k) => (
<span key={k} className="text-[11px] bg-emerald-50 border border-emerald-300 text-emerald-900 px-2 py-1 rounded-md font-semibold flex items-center gap-1"> <span key={k} className="text-[11px] bg-emerald-50 border border-emerald-300 text-emerald-900 px-2 py-1 rounded-md font-semibold flex items-center gap-1">
{k} {k}
<button onClick={() => konuCikar(k)} className="text-emerald-700 hover:text-red-600"><X className="w-3 h-3" /></button> <button type="button" onClick={() => konuCikar(k)} className="text-emerald-700 hover:text-red-600"><X className="w-3 h-3" /></button>
</span> </span>
))} ))}
</div> </div>
@@ -196,14 +196,14 @@ const SubscriptionForm = () => {
onKeyDown={(e) => { if (e.key === 'Enter') { konuEkle(ozelKonu); setOzelKonu(''); } }} onKeyDown={(e) => { if (e.key === 'Enter') { konuEkle(ozelKonu); setOzelKonu(''); } }}
placeholder="Kendi konunuzu yazın ve Enter'a basın" placeholder="Kendi konunuzu yazın ve Enter'a basın"
className="flex-1 bg-slate-50 border border-slate-200 rounded-lg px-2.5 py-2 text-xs" /> className="flex-1 bg-slate-50 border border-slate-200 rounded-lg px-2.5 py-2 text-xs" />
<button onClick={() => { konuEkle(ozelKonu); setOzelKonu(''); }} <button type="button" onClick={() => { konuEkle(ozelKonu); setOzelKonu(''); }}
className="bg-slate-800 hover:bg-slate-700 text-white font-bold text-xs px-3 rounded-lg">Ekle</button> className="bg-slate-800 hover:bg-slate-700 text-white font-bold text-xs px-3 rounded-lg">Ekle</button>
</div> </div>
<p className="text-[10px] text-slate-400 pt-1">Hazır sektörler:</p> <p className="text-[10px] text-slate-400 pt-1">Hazır sektörler:</p>
<div className="flex flex-wrap gap-1.5"> <div className="flex flex-wrap gap-1.5">
{sektorListesi.map((s) => ( {sektorListesi.map((s) => (
<button key={s} onClick={() => konuEkle(s)} <button type="button" key={s} onClick={() => konuEkle(s)}
className="text-[11px] bg-slate-100 hover:bg-slate-200 text-slate-700 px-2 py-1 rounded-md"> className="text-[11px] bg-slate-100 hover:bg-slate-200 text-slate-700 px-2 py-1 rounded-md">
+ {s} + {s}
</button> </button>
@@ -213,7 +213,7 @@ const SubscriptionForm = () => {
{/* Gelişmiş daraltma (isteğe bağlı) */} {/* Gelişmiş daraltma (isteğe bağlı) */}
<div> <div>
<button onClick={() => setGelismis(!gelismis)} className="text-[11px] font-bold text-slate-500 hover:text-slate-800 flex items-center gap-1"> <button type="button" onClick={() => setGelismis(!gelismis)} className="text-[11px] font-bold text-slate-500 hover:text-slate-800 flex items-center gap-1">
{gelismis ? <ChevronUp className="w-3.5 h-3.5" /> : <ChevronDown className="w-3.5 h-3.5" />} {gelismis ? <ChevronUp className="w-3.5 h-3.5" /> : <ChevronDown className="w-3.5 h-3.5" />}
Daha da daralt (isteğe bağlı) — varsayılan: tüm Türkiye Daha da daralt (isteğe bağlı) — varsayılan: tüm Türkiye
</button> </button>
@@ -235,7 +235,7 @@ const SubscriptionForm = () => {
)} )}
</div> </div>
<button onClick={kaydet} disabled={busy || abonelikler===null || !konular.length} <button type="button" onClick={kaydet} disabled={busy || abonelikler===null || !konular.length}
className="w-full bg-emerald-600 hover:bg-emerald-500 disabled:opacity-40 text-white font-bold text-xs py-2.5 rounded-xl flex items-center justify-center gap-2"> className="w-full bg-emerald-600 hover:bg-emerald-500 disabled:opacity-40 text-white font-bold text-xs py-2.5 rounded-xl flex items-center justify-center gap-2">
{busy ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Plus className="w-3.5 h-3.5" />} {busy ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Plus className="w-3.5 h-3.5" />}
Bildirimi Kaydet Bildirimi Kaydet
@@ -244,7 +244,7 @@ const SubscriptionForm = () => {
{error && ( {error && (
<div role="alert" className="bg-red-50 border border-red-200 rounded-lg p-2.5 flex gap-2"> <div role="alert" className="bg-red-50 border border-red-200 rounded-lg p-2.5 flex gap-2">
<AlertTriangle className="w-3.5 h-3.5 text-red-600 shrink-0 mt-0.5" /> <AlertTriangle className="w-3.5 h-3.5 text-red-600 shrink-0 mt-0.5" />
<p className="text-[11px] text-red-800">{error} <button disabled={busy} onClick={yukle} className="underline">Abonelikleri yeniden yükle</button></p> <p className="text-[11px] text-red-800">{error} <button type="button" disabled={busy} onClick={yukle} className="underline">Abonelikleri yeniden yükle</button></p>
</div> </div>
)} )}
+4 -4
View File
@@ -62,10 +62,10 @@ export const Pricing = () => {
{/* Aylık / Yıllık */} {/* Aylık / Yıllık */}
<div className="flex justify-center"> <div className="flex justify-center">
<div className="bg-white border border-slate-200 rounded-xl p-1 inline-flex text-xs font-bold shadow-xs"> <div className="bg-white border border-slate-200 rounded-xl p-1 inline-flex text-xs font-bold shadow-xs">
<button onClick={() => setYillik(true)} className={`px-4 py-2 rounded-lg transition-colors flex items-center gap-1.5 ${yillik ? 'bg-blue-600 text-white' : 'text-slate-600 hover:bg-slate-50'}`}> <button type="button" onClick={() => setYillik(true)} className={`px-4 py-2 rounded-lg transition-colors flex items-center gap-1.5 ${yillik ? 'bg-blue-600 text-white' : 'text-slate-600 hover:bg-slate-50'}`}>
Yıllık <span className={`text-[10px] px-1.5 py-0.5 rounded-full ${yillik ? 'bg-amber-400 text-slate-900' : 'bg-emerald-100 text-emerald-800'}`}>%17 indirim</span> Yıllık <span className={`text-[10px] px-1.5 py-0.5 rounded-full ${yillik ? 'bg-amber-400 text-slate-900' : 'bg-emerald-100 text-emerald-800'}`}>%17 indirim</span>
</button> </button>
<button onClick={() => setYillik(false)} className={`px-4 py-2 rounded-lg transition-colors ${!yillik ? 'bg-blue-600 text-white' : 'text-slate-600 hover:bg-slate-50'}`}> <button type="button" onClick={() => setYillik(false)} className={`px-4 py-2 rounded-lg transition-colors ${!yillik ? 'bg-blue-600 text-white' : 'text-slate-600 hover:bg-slate-50'}`}>
Aylık Aylık
</button> </button>
</div> </div>
@@ -107,7 +107,7 @@ export const Pricing = () => {
</div> </div>
</div> </div>
{plan.iptalEdilebilir && ( {plan.iptalEdilebilir && (
<button <button type="button"
onClick={() => setIptalAcik(true)} onClick={() => setIptalAcik(true)}
className="text-xs font-bold text-red-600 hover:text-red-700 hover:bg-red-50 border border-red-200 px-3 py-2 rounded-xl flex items-center gap-1.5 transition-colors" className="text-xs font-bold text-red-600 hover:text-red-700 hover:bg-red-50 border border-red-200 px-3 py-2 rounded-xl flex items-center gap-1.5 transition-colors"
> >
@@ -183,7 +183,7 @@ export const Pricing = () => {
Mevcut planınız Mevcut planınız
</div> </div>
) : ( ) : (
<button <button type="button"
onClick={() => upgrade(p.id)} onClick={() => upgrade(p.id)}
disabled={!(yillik ? p.satinAlinabilirYillik : p.satinAlinabilir) || busy === p.id || !authUser} disabled={!(yillik ? p.satinAlinabilirYillik : p.satinAlinabilir) || busy === p.id || !authUser}
title={!authUser ? 'Önce giriş yapın' : !(yillik ? p.satinAlinabilirYillik : p.satinAlinabilir) ? 'Ödeme altyapısı bağlanmadı' : ''} title={!authUser ? 'Önce giriş yapın' : !(yillik ? p.satinAlinabilirYillik : p.satinAlinabilir) ? 'Ödeme altyapısı bağlanmadı' : ''}
+6 -6
View File
@@ -162,7 +162,7 @@ const PwaPanel = () => {
</p> </p>
</div> </div>
<button <button type="button"
onClick={refreshCacheStatus} disabled={cacheLoading} onClick={refreshCacheStatus} disabled={cacheLoading}
className="w-full bg-slate-100 hover:bg-slate-200 text-slate-800 font-bold text-xs py-2.5 rounded-xl border border-slate-200 transition-colors" className="w-full bg-slate-100 hover:bg-slate-200 text-slate-800 font-bold text-xs py-2.5 rounded-xl border border-slate-200 transition-colors"
> >
@@ -192,17 +192,17 @@ const PwaPanel = () => {
{permission === 'denied' ? ( {permission === 'denied' ? (
<div className="space-y-2 text-xs text-slate-700"> <div className="space-y-2 text-xs text-slate-700">
<p>Bu site için bildirimler tarayıcı tarafından engellenmiş. Adres çubuğundaki site bilgileri veya tarayıcının site ayarlarından bildirim iznini değiştirin, ardından buraya dönün.</p> <p>Bu site için bildirimler tarayıcı tarafından engellenmiş. Adres çubuğundaki site bilgileri veya tarayıcının site ayarlarından bildirim iznini değiştirin, ardından buraya dönün.</p>
<button onClick={refreshPermission} className="border rounded px-3 py-2">Bildirim iznini yeniden kontrol et</button> <button type="button" onClick={refreshPermission} className="border rounded px-3 py-2">Bildirim iznini yeniden kontrol et</button>
</div> </div>
) : permission === 'unsupported' ? ( ) : permission === 'unsupported' ? (
<p className="text-xs text-slate-700">Bu tarayıcıda bildirim özelliği kullanılamıyor. Uygulama içindeki bildirim listesini kullanabilirsiniz.</p> <p className="text-xs text-slate-700">Bu tarayıcıda bildirim özelliği kullanılamıyor. Uygulama içindeki bildirim listesini kullanabilirsiniz.</p>
) : permission !== 'granted' ? ( ) : permission !== 'granted' ? (
<button onClick={handleEnablePush} disabled={reminderSaving || permissionBusy} <button type="button" onClick={handleEnablePush} disabled={reminderSaving || permissionBusy}
className="w-full bg-amber-500 hover:bg-amber-400 disabled:opacity-40 text-white font-bold text-xs py-2.5 rounded-xl"> className="w-full bg-amber-500 hover:bg-amber-400 disabled:opacity-40 text-white font-bold text-xs py-2.5 rounded-xl">
{permissionBusy?'İzin yanıtı bekleniyor…':'Bildirimlere İzin Ver'} {permissionBusy?'İzin yanıtı bekleniyor…':'Bildirimlere İzin Ver'}
</button> </button>
) : ( ) : (
<button onClick={() => notify('Test bildirimi', isQuietNow() || !reminderSettings.pushEnabled ? 'Tarayıcı bildirimi kapalı veya sessiz saatte — listeye eklendi.' : 'Tarayıcı bildirimi gösterim denemesi.')} <button type="button" onClick={() => notify('Test bildirimi', isQuietNow() || !reminderSettings.pushEnabled ? 'Tarayıcı bildirimi kapalı veya sessiz saatte — listeye eklendi.' : 'Tarayıcı bildirimi gösterim denemesi.')}
className="w-full bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs py-2.5 rounded-xl"> className="w-full bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs py-2.5 rounded-xl">
Test Bildirimi Gönder Test Bildirimi Gönder
</button> </button>
@@ -268,7 +268,7 @@ const PwaPanel = () => {
<button type="button" disabled={emailSending} onClick={()=>setEmailConfigAttempt(n=>n+1)} className="text-xs underline">E-posta durumunu yenile</button> <button type="button" disabled={emailSending} onClick={()=>setEmailConfigAttempt(n=>n+1)} className="text-xs underline">E-posta durumunu yenile</button>
<p className="text-xs text-slate-600">E-posta gönderimlerini aşağıdaki bildirim aboneliklerinden yönetin. Tarayıcı bildirim seçimi ve sessiz saatler e-posta aboneliklerini kapatmaz.</p> <p className="text-xs text-slate-600">E-posta gönderimlerini aşağıdaki bildirim aboneliklerinden yönetin. Tarayıcı bildirim seçimi ve sessiz saatler e-posta aboneliklerini kapatmaz.</p>
<button <button type="button"
onClick={sendTestEmail} onClick={sendTestEmail}
disabled={emailSending || emailCfg !== true || !authUser} disabled={emailSending || emailCfg !== true || !authUser}
className="w-full bg-blue-600 hover:bg-blue-500 disabled:opacity-40 text-white font-bold text-xs py-2.5 rounded-xl flex items-center justify-center gap-2" className="w-full bg-blue-600 hover:bg-blue-500 disabled:opacity-40 text-white font-bold text-xs py-2.5 rounded-xl flex items-center justify-center gap-2"
@@ -300,7 +300,7 @@ const PwaPanel = () => {
İhaleist'i iOS, Android, Windows veya Mac cihazınıza bir tıklama ile uygulama olarak kurun. İhaleist'i iOS, Android, Windows veya Mac cihazınıza bir tıklama ile uygulama olarak kurun.
</p> </p>
<button <button type="button"
onClick={handleInstallPwa} onClick={handleInstallPwa}
disabled={installed} disabled={installed}
className="w-full bg-cyan-500 hover:bg-cyan-400 disabled:bg-slate-700 text-slate-950 font-black text-xs py-3 rounded-xl flex items-center justify-center gap-2 shadow-md transition-colors cursor-pointer" className="w-full bg-cyan-500 hover:bg-cyan-400 disabled:bg-slate-700 text-slate-950 font-black text-xs py-3 rounded-xl flex items-center justify-center gap-2 shadow-md transition-colors cursor-pointer"
+1 -1
View File
@@ -102,7 +102,7 @@ export const RedFlags = () => {
</div> </div>
<p className="text-xs text-slate-700 mt-1.5 leading-relaxed">{f.aciklama}</p> <p className="text-xs text-slate-700 mt-1.5 leading-relaxed">{f.aciklama}</p>
{f.tender ? ( {f.tender ? (
<button <button type="button"
onClick={() => setActiveTenderDetail(f.tender)} onClick={() => setActiveTenderDetail(f.tender)}
className="text-[11px] font-bold text-blue-700 hover:underline mt-1.5 text-left" className="text-[11px] font-bold text-blue-700 hover:underline mt-1.5 text-left"
> >
+2 -2
View File
@@ -65,7 +65,7 @@ export const TedTenders = () => {
{/* Mod seçici */} {/* Mod seçici */}
<div className="flex gap-2 flex-wrap"> <div className="flex gap-2 flex-wrap">
{MODLAR.map((m) => ( {MODLAR.map((m) => (
<button <button type="button"
key={m.id} key={m.id}
onClick={() => setMod(m.id)} onClick={() => setMod(m.id)}
className={`px-4 py-2 rounded-xl text-xs font-bold border transition-colors ${ className={`px-4 py-2 rounded-xl text-xs font-bold border transition-colors ${
@@ -75,7 +75,7 @@ export const TedTenders = () => {
{m.label} {m.label}
</button> </button>
))} ))}
<button <button type="button"
onClick={() => yukle(mod)} onClick={() => yukle(mod)}
disabled={loading} disabled={loading}
className="px-3 py-2 rounded-xl text-xs font-bold border border-slate-200 bg-white text-slate-600 hover:bg-slate-50 flex items-center gap-1.5 disabled:opacity-50" className="px-3 py-2 rounded-xl text-xs font-bold border border-slate-200 bg-white text-slate-600 hover:bg-slate-50 flex items-center gap-1.5 disabled:opacity-50"
+1 -1
View File
@@ -61,7 +61,7 @@ export const TurkeyHeatMap = () => {
const c = density.get(normProvince(il)) || 0; const c = density.get(normProvince(il)) || 0;
const { bg, fg } = heat(c, max); const { bg, fg } = heat(c, max);
return ( return (
<button <button type="button"
key={il} key={il}
onClick={() => c && openCity(il)} onClick={() => c && openCity(il)}
disabled={!c} disabled={!c}
+3 -3
View File
@@ -58,7 +58,7 @@ export const VatCalculator = () => {
{/* Mode Selector */} {/* Mode Selector */}
<div className="grid grid-cols-2 gap-3 p-1 bg-slate-100 rounded-xl"> <div className="grid grid-cols-2 gap-3 p-1 bg-slate-100 rounded-xl">
<button <button type="button"
onClick={() => setMode('haric')} onClick={() => setMode('haric')}
className={`py-2.5 rounded-lg text-xs font-extrabold transition-all ${ className={`py-2.5 rounded-lg text-xs font-extrabold transition-all ${
mode === 'haric' ? 'bg-white text-blue-700 shadow-2xs' : 'text-slate-600 hover:text-slate-900' mode === 'haric' ? 'bg-white text-blue-700 shadow-2xs' : 'text-slate-600 hover:text-slate-900'
@@ -66,7 +66,7 @@ export const VatCalculator = () => {
> >
KDV Hariç ➔ KDV Dahil Hesapla KDV Hariç ➔ KDV Dahil Hesapla
</button> </button>
<button <button type="button"
onClick={() => setMode('dahil')} onClick={() => setMode('dahil')}
className={`py-2.5 rounded-lg text-xs font-extrabold transition-all ${ className={`py-2.5 rounded-lg text-xs font-extrabold transition-all ${
mode === 'dahil' ? 'bg-white text-blue-700 shadow-2xs' : 'text-slate-600 hover:text-slate-900' mode === 'dahil' ? 'bg-white text-blue-700 shadow-2xs' : 'text-slate-600 hover:text-slate-900'
@@ -130,7 +130,7 @@ export const VatCalculator = () => {
<div className="bg-slate-900 text-white p-6 rounded-xl space-y-4 shadow-lg"> <div className="bg-slate-900 text-white p-6 rounded-xl space-y-4 shadow-lg">
<div className="flex items-center justify-between border-b border-slate-800 pb-3"> <div className="flex items-center justify-between border-b border-slate-800 pb-3">
<span className="font-bold text-xs uppercase tracking-wider text-slate-300">Hesaplama Sonucu</span> <span className="font-bold text-xs uppercase tracking-wider text-slate-300">Hesaplama Sonucu</span>
<button <button type="button"
onClick={handleCopy} onClick={handleCopy}
className="bg-slate-800 hover:bg-slate-700 text-blue-400 font-semibold px-3 py-1.5 rounded-lg text-xs flex items-center gap-1.5 transition-colors border border-slate-700" className="bg-slate-800 hover:bg-slate-700 text-blue-400 font-semibold px-3 py-1.5 rounded-lg text-xs flex items-center gap-1.5 transition-colors border border-slate-700"
> >