make non submit buttons explicit
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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ç`}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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'}`}
|
||||||
|
|||||||
@@ -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"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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)}
|
||||||
|
|||||||
@@ -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"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -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ı' : ''}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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"
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user