Files
ihaleist/src/components/KullanimKilavuzu.jsx
T
hikmettanandClaude Fable 5.1 782b361d24 feat: Gemini Flash ücretli yedek — analiz zincirinin sonunda her zaman denenir
Panelde seçilen modeller tıkanınca (limit/429) şartname analizi ve teklif asistanı
boş kalıyordu; analyzeSpec zincire yoksa 'gemini'yi sona ekler. Panel ve kılavuz notu.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 13:45:04 +03:00

150 lines
14 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createPortal } from 'react-dom';
import React, { useEffect, useState } from 'react';
import { useApp } from '../context/AppContext';
import { HelpCircle, X, BookOpen, Lightbulb, ListChecks } from 'lucide-react';
/**
* Kullanım kılavuzu — sağdan açılan yan panel, açık sekmeye göre içerik.
* Her sayfada aynı düğme (sağ altta "?"); "?" tuşu da açar. İçerik kod
* içinde tutuluyor ki özellik değişince aynı commit'te güncellensin.
*/
const KILAVUZ = {
list: {
baslik: 'Ana İhale Listesi',
ne: 'Türkiye kamu ihaleleri (ilan.gov.tr + EKAP), doğrudan temin ve geçmiş sonuçlar tek listede. Kartta ihale/ilan tarihi, sektör, CPV, teklif cetveli kalemleri ve şirket uyum skoru görünür.',
adimlar: [
'Sağ paneldeki \'Yaklaşan İhale Tarihleri\' kutusu yıldızladığınız / panoya aldığınız ihalelerin 14 günlük geri sayımını gösterir (≤3 gün kırmızı, ≤7 gün turuncu); tıklayınca detay açılır.',
'Detaydaki \'Teklif Asistanı\' sekmesi: Belgeye Sor (dokümanda teminat, teslim, ceza gibi soruları [n] atıflı yanıtlar), Taslağı Denetle (teklif metninizi gerekliliklerle karşılaştırır: karşılanıyor / eksik / belirsiz), Taslak Üret (kapak / teknik / ticari / tam dosya; bilinmeyen yerler [DOLDURUN]).',
'Üstteki kutuya ürün, kurum ya da İKN yazın — arama başlıkla birlikte teklif cetveli kalemlerinde de yapılır.',
'Başlıkta geçmeyen ürününüz için sarı "ÜRÜN ARA" düğmesini kullanın: EKAP dokümanlarının içinde arar.',
'Sol menüden il, tür, sektör, CPV/OKAS ile daraltın; "Sadece açık ihaleler" varsayılan açıktır.',
'Sıralamayı "Şirketime En Uyumlu" yapın — profilinizdeki ürünlere göre puanlar.',
'Karta tıklayıp detayda dokümanı yükleyin: kalemler otomatik çıkarılır, derin analiz ve yol haritası oradan.',
],
ipuclari: ['Teklif Asistanı doküman metnini EKAP\'tan alır; alamazsa sekmedeki \'Doküman yükle\' ile PDF\'i verin.', 'Yıldız = takip. Takipteki ihalede zeyilname/düzeltme ilanı çıkarsa ve sonuçlanınca bildirim gelir.', '"%N Uyumlu" rozetine gelince neden eşleştiği görünür.'],
},
bulten: { baslik: 'Günlük Bülten', ne: 'Bugün eklenen ihalelerin özeti.', adimlar: ['Sabah bir bakış için tasarlandı; e-posta bülteni için "Mobil PWA → Bildirimler"i kullanın.'], ipuclari: [] },
sonuc: { baslik: 'Sonuç Sorgula', ne: 'EKAP sonuç ilanlarından kazanan firma, sözleşme bedeli, teklif sayısı.', adimlar: ['Firma, idare veya il ile filtreleyin.', 'Rakibinizin hangi idarelerden ne bedelle aldığını görün; "Rakip Radar"a ekleyin.'], ipuclari: ['Kısmi ihalelerde bedel kısım başına, yaklaşık maliyet tüm ihale içindir — kırım oranı bu yüzden yalnız kısımsız ihalelerde gösterilir.'] },
takvim: { baslik: 'İhale Takvimi', ne: 'Takipteki ve açık ihalelerin tarih görünümü.', adimlar: ['Detaydan .ics indirip kendi takviminize ekleyebilirsiniz.'], ipuclari: [] },
sozlesme: { baslik: 'Sözleşme Sorgula', ne: 'İmzalanmış sözleşmelerin sorgusu.', adimlar: ['Firma adıyla arayın; aynı firmanın diğer sözleşmeleri listelenir.'], ipuclari: [] },
kdv: { baslik: 'KDV Hesapla', ne: 'KDV dahil/hariç dönüşüm.', adimlar: ['Tutarı girin, oranı seçin.'], ipuclari: [] },
sinir: {
baslik: 'Sınır Değer',
ne: 'Aşırı düşük teklif sınır değeri — Kamu İhale Genel Tebliği md. 79 (hizmet/mal) ve 45 (yapım) formülleriyle. Teklifiniz sınırın altında kalırsa idare açıklama ister.',
adimlar: ['Alım türünü seçin (mal alımında da hizmet formülü uygulanır — md. 62/A.1).', 'Yaklaşık maliyeti ve ilk oturumda okunan geçerli teklifleri girin.', 'Hizmet/mal için R katsayısını (2026 KİK tablosu) ya da yapım için N katsayısını seçin.', 'Kendi teklifinizi girin: sınırın altında mı, üstünde mi anında görünür.'],
ipuclari: ['Yapım hesabı Tebliğ\'in kendi örneğiyle (52.281,00 TL) birebir doğrulanmıştır.', 'R katsayıları her yıl 1 Şubat\'ta yenilenir.'],
},
fiyat: { baslik: 'Fiyat Analizi', ne: 'Geçmiş sonuçlardan kalem/sektör bazlı fiyat eğilimleri.', adimlar: ['Ürün adıyla arayın; benzer kalemlerin sözleşme bedellerini karşılaştırın.'], ipuclari: [] },
kanban: {
baslik: 'Kanban Pano',
ne: 'Takipteki ihalelerin süreç panosu: İncelenecek → İnceleniyor → Teklif Hazırlanıyor → Verildi → Kazanıldı/Kaybedildi.',
adimlar: ['Kartları sürükleyerek kolon değiştirin.', 'İhale detayında "Hazırlık Görevi Aç" deyin: teslim tarihi ihale saati olur, kartta geri sayım başlar (BUGÜN / 2 gün / süresi geçti).', 'Derin analizden gelen belge kontrol listesi görevin içinde işaretlenir.'],
ipuclari: ['Görev açılmış ihale sonuçlanınca bildirim gelir: kim, kaça, %kaç kırım.'],
},
rakip_radar: { baslik: 'Rakip Radar', ne: 'Kazanan firmalar, kırım oranı, ortalama teklif sayısı, tek teklifle kazanma oranı.', adimlar: ['"Radara Ekle" ile izleyin; teklif verince/kazanınca uyarı alın.', '"⛔ yasaklı sorgula" KİK sorgusunu açar, firma adını panoya kopyalar.'], ipuclari: ['Kırım oranı yalnız kısımsız ihalelerde hesaplanır — kısmi ihalede sayı yanıltıcı olurdu.'] },
dokuman_deposu: {
baslik: 'Doküman Deposu',
ne: 'Şirket belgeleriniz (imza sirküleri, oda kaydı…) ve ihale dokümanları sunucuda saklanır.',
adimlar: [
'Derin analizdeki \'Belge Kontrol Listesi\' her madde için depodaki evrakla eşleşir: Depoda hazır / Yakında dolacak (≤30 gün) / Süresi dolmuş / Depoda yok — rozetin üzerine gelince hangi belge ve kaç gün kaldığı görünür.','Her belgeye son kullanma tarihi girin — süresi dolan/30 gün içinde dolacak belgeler kırmızı/sarı uyarıyla listelenir, girişte bildirim gelir.', '"İhale Dokümanlarını Toplu Yükle": EKAP\'tan indirdiğiniz şartnameleri hepsini birden seçin; her dosyanın İKN\'si metninden bulunur, teklif cetveli kalemleri otomatik çıkarılır.', 'Taranmış (görüntü) PDF\'ler de okunur — OCR otomatik devreye girer.'],
ipuclari: ['Kategoriyi doğru seçin (Yasal / Kalite / Mali / Resmi / Teknik): eşleştirme önce kategoriye, sonra belge adına bakar.', 'Kalemleri çıkarılan ihale herkesin kartında kalemleriyle görünür; ilk yükleyen herkes için açar.'],
},
analitik_dashboard: { baslik: 'Analitik Dashboard', ne: 'Sektör, il ve kurum bazlı dağılımlar, hacim ve rekabet grafikleri.', adimlar: ['Filtreler listedekiyle aynıdır; sol menü seçimleri buraya da yansır.'], ipuclari: [] },
kirmizi_bayrak: { baslik: 'Kırmızı Bayrak', ne: 'Şeffaflık sinyalleri: tek teklifli ihaleler, düşük kırım, tahmin üstü bedel, tedarikçi yoğunlaşması.', adimlar: [
'Yeni kurallar: Kısa süre (ilan→ihale <7 gün), Hafta sonu tarih, Geç sözleşme (ihaleden 180+ gün sonra), Kazananı gizli (sonuç var ad yok), Parçalama şüphesi (aynı idare + sektörde 30 günde 3+ doğrudan temin — 4734 md. 5 / 22-d).','Seviye (Yüksek/Orta) ile süzün; ihaleye tıklayıp detaya gidin.'], ipuclari: ['Parçalama şüphesi bayrağı yalnız doğrudan temin verisi (DT worker) açıksa dolar.', ] },
kik_kararlari: { baslik: 'KİK Kurul Kararları', ne: 'İtirazen şikâyet kararlarında arama.', adimlar: ['Konu, idare veya başvuran ile arayın; benzer uyuşmazlıklarda Kurul\'un ne dediğini görün.'], ipuclari: [] },
ted_eu: { baslik: 'AB İhaleleri (TED)', ne: 'Türkiye\'deki idarelerin AB\'de yayımladığı ve Türk firmalarına açık AB ihaleleri.', adimlar: ['"Açık AB İhaleleri" sekmesiyle teklif verilebilir olanları listeleyin.'], ipuclari: [] },
planlar: { baslik: 'Planlar', ne: 'Pro ve Kurumsal planlar, yıllık indirim.', adimlar: ['Stripe ile ödeme; iptal dönem sonunda geçerli olur.'], ipuclari: [] },
api_webhooks: { baslik: 'API & Webhooks', ne: 'Kendi sistemlerinize ihale akışı.', adimlar: [
'MCP: bir API anahtarı üretin, karttaki Claude Code komutunu veya mcp.json\'u kopyalayıp anahtarı yerine yazın; asistanınız search_tenders, get_tender, search_results, search_items, upcoming_deadlines araçlarını kullanır.',
'RSS: /api/feeds/tenders.rss?key=… adresini (il, sektor, q filtreleri) Feedly / Outlook / Slack RSS\'e ekleyin; sonuç ilanları için /api/feeds/sonuc.rss anahtarsızdır.','API anahtarı üretin; webhook adresinize yeni ihaleler gönderilir.'], ipuclari: [] },
ai_ayarlari: { baslik: 'AI Model Ayarları', ne: 'Analizlerde kullanılacak model zinciri (yedekli).', adimlar: ['Sırayı sürükleyerek değiştirin; ilk başarılı model sonucu döner.', 'Gemini Flash ücretli yedek olarak zincirin sonunda her zaman denenir; seçtiğiniz modeller (ör. limitli/ücretsiz olanlar) tıkanınca analiz boş kalmaz.'], ipuclari: [] },
pwa_settings: {
baslik: 'Mobil PWA & Bildirimler',
ne: 'Uygulamayı telefona kurma, e-posta ve Telegram bildirimleri.',
adimlar: [
'Haftalık Brief (Pazartesi 08:00): bu hafta yapılacak takipli ihaleler ve geçen hafta sonuçlanan takipliler tek mesajda (Telegram + e-posta). \'Önizle\' ile şimdiki içeriği görün; anahtarla kapatın.','E-posta aboneliğinde konu/il/sektör seçin; yalnız eşleşen yeni ihaleler gelir.', 'Telegram: bota gösterilen 6 haneli kodu yazıp "Doğrula" deyin — ihale özeti, zeyilname ve sonuç bildirimleri Telegram\'a da gider.'],
ipuclari: ['Telegram için sunucuda bot tokenı tanımlı olmalı; yoksa ekran kurulum adımlarını gösterir.'],
},
smart_filter_builder: { baslik: 'Akıllı Filtre', ne: 'Kaydedilebilir çok ölçütlü filtre.', adimlar: ['Ölçütleri birleştirip kaydedin; sol menüden tek tıkla uygulanır.'], ipuclari: [] },
};
const GENEL = {
baslik: 'İhale Detayı & Analiz',
ne: 'Herhangi bir karta tıklayınca açılan detayda: ilan metni, teklif cetveli kalemleri, dokümanlar ve AI analizi.',
adimlar: ['"Tüm Evrakı Derin Analiz Et": ilan + yüklediğiniz dokümanlar birlikte okunur; elenme sebepleri, gözden kaçan ince detaylar, belge kontrol listesi, kritik tarihler ve teklife kadar yol haritası çıkar.', 'Rapor sonundaki "İhale Dosyası Hazırla": kalemleri fiyatlandırın, eksik firma bilgilerini girin; teklif mektubu, birim fiyat cetveli ve evrak kontrol listesi yazdırılabilir çıkar.', 'Profil (şirket tarama): ürünlerinizi ekleyin ya da web sitenizi taratın; uyum skoru ve "Şirketime En Uyumlu" sıralaması buna göre çalışır. Uyum eşiğini kaydırıcıdan ayarlayın.'],
ipuclari: ['Analiz yapay zekâ ürünüdür; teklif kararından önce şartnamenin aslını doğrulayın.'],
};
export const KullanimKilavuzu = () => {
const { activeTab } = useApp();
const [acik, setAcik] = useState(false);
useEffect(() => {
const h = (e) => {
if (e.key === '?' && !/input|textarea|select/i.test(e.target?.tagName || '')) setAcik((o) => !o);
if (e.key === 'Escape') setAcik(false);
};
window.addEventListener('keydown', h);
return () => window.removeEventListener('keydown', h);
}, []);
const k = KILAVUZ[activeTab] || KILAVUZ.list;
const Bolum = ({ icon: Icon, renk, baslik, satirlar, sirali }) => satirlar?.length ? (
<div className="space-y-1.5">
<h4 className="text-[11px] font-black uppercase tracking-wider text-slate-500 flex items-center gap-1.5"><Icon className={`w-3.5 h-3.5 ${renk}`} /> {baslik}</h4>
{sirali
? <ol className="list-decimal pl-5 space-y-1.5 text-xs text-slate-700 leading-relaxed">{satirlar.map((s, i) => <li key={i}>{s}</li>)}</ol>
: <ul className="pl-1 space-y-1.5 text-xs text-slate-700 leading-relaxed">{satirlar.map((s, i) => <li key={i} className="flex gap-2"><span className="text-amber-500">•</span><span>{s}</span></li>)}</ul>}
</div>
) : null;
return createPortal(
<>
<button
type="button"
onClick={() => setAcik(true)}
title="Kullanım kılavuzu (? tuşu)"
className="fixed bottom-5 right-5 z-40 w-11 h-11 rounded-full bg-slate-900 text-white shadow-lg hover:bg-blue-700 flex items-center justify-center transition-colors"
>
<HelpCircle className="w-5 h-5" />
</button>
{acik && (
<div className="fixed inset-0 z-50 flex justify-end" onClick={() => setAcik(false)}>
<div className="absolute inset-0 bg-slate-900/40" />
<aside
onClick={(e) => e.stopPropagation()}
className="relative h-full w-full max-w-md bg-white shadow-2xl flex flex-col animate-fade-in"
>
<div className="bg-slate-900 text-white px-5 py-4 flex items-center justify-between">
<div className="flex items-center gap-2">
<BookOpen className="w-5 h-5 text-amber-400" />
<div>
<p className="text-[10px] uppercase tracking-wider text-slate-400 font-bold">Kullanım kılavuzu</p>
<h3 className="font-extrabold text-sm">{k.baslik}</h3>
</div>
</div>
<button onClick={() => setAcik(false)} className="text-slate-400 hover:text-white p-1" aria-label="Kapat"><X className="w-5 h-5" /></button>
</div>
<div className="flex-1 overflow-y-auto p-5 space-y-5">
<p className="text-xs text-slate-700 leading-relaxed bg-slate-50 border border-slate-200 rounded-xl p-3">{k.ne}</p>
<Bolum icon={ListChecks} renk="text-blue-600" baslik="Nasıl kullanılır" satirlar={k.adimlar} sirali />
<Bolum icon={Lightbulb} renk="text-amber-500" baslik="İpuçları" satirlar={k.ipuclari} />
<div className="border-t border-slate-200 pt-4 space-y-3">
<h4 className="text-[11px] font-black uppercase tracking-wider text-slate-500">{GENEL.baslik}</h4>
<p className="text-xs text-slate-600 leading-relaxed">{GENEL.ne}</p>
<Bolum icon={ListChecks} renk="text-emerald-600" baslik="Detay ekranında" satirlar={GENEL.adimlar} sirali />
<Bolum icon={Lightbulb} renk="text-amber-500" baslik="Not" satirlar={GENEL.ipuclari} />
</div>
</div>
<div className="border-t border-slate-200 px-5 py-3 text-[10px] text-slate-400 flex justify-between">
<span>Her sayfada sağ alttaki ? düğmesi ya da klavyede ?</span><span>Esc kapatır</span>
</div>
</aside>
</div>
)}
</>,
document.body,
);
};