diff --git a/src/App.jsx b/src/App.jsx index 01875de..8ff6c65 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -21,6 +21,7 @@ import { ResultSearch } from './components/tools/ResultSearch'; import { TenderCalendar } from './components/tools/TenderCalendar'; import { ContractSearch } from './components/tools/ContractSearch'; import { VatCalculator } from './components/tools/VatCalculator'; +import { SinirDeger } from './components/tools/SinirDeger'; import { PriceAnalysis } from './components/tools/PriceAnalysis'; import { CompetitorRadar } from './components/tools/CompetitorRadar'; import { DocumentVault } from './components/tools/DocumentVault'; @@ -61,6 +62,7 @@ const MainContent = () => { {activeTab === 'takvim' && } {activeTab === 'sozlesme' && } {activeTab === 'kdv' && } + {activeTab === 'sinir' && } {activeTab === 'fiyat' && } {activeTab === 'kanban' && } {activeTab === 'rakip_radar' && } diff --git a/src/components/TopNavigation.jsx b/src/components/TopNavigation.jsx index 08d12a7..ab53125 100644 --- a/src/components/TopNavigation.jsx +++ b/src/components/TopNavigation.jsx @@ -25,6 +25,7 @@ export const TopNavigation = () => { { id: 'takvim', label: 'İhale Takvimi', icon: CalendarDays }, { id: 'sozlesme', label: 'Sözleşme Sorgula', icon: FileCheck2 }, { id: 'kdv', label: 'KDV Hesapla', icon: Calculator }, + { id: 'sinir', label: 'Sınır Değer', icon: Calculator }, { id: 'fiyat', label: 'Fiyat Analizi', icon: TrendingUp }, { id: 'kanban', label: 'Kanban Pano', icon: Kanban, badge: 'Sürükle Takip' }, { id: 'rakip_radar', label: 'Rakip Radar', icon: Radar, badge: 'Canlı Uyar' }, diff --git a/src/components/tools/SinirDeger.jsx b/src/components/tools/SinirDeger.jsx new file mode 100644 index 0000000..e9359b5 --- /dev/null +++ b/src/components/tools/SinirDeger.jsx @@ -0,0 +1,156 @@ +import React, { useMemo, useState } from 'react'; +import { Scale, AlertTriangle, CheckCircle2, Info } from 'lucide-react'; +import { sinirDegerHizmet, sinirDegerPersonel, sinirDegerYapim, teklifleriAyir, R_2026, R_KAYNAK } from '../../services/sinirDeger'; + +/** + * Aşırı düşük teklif sınır değeri hesaplayıcı. + * Formüller Kamu İhale Genel Tebliği md. 79 (hizmet/mal) ve 45 (yapım), + * R katsayıları KİK 21.01.2026 Kurul kararı — kaynaklar services/sinirDeger.js'de. + * Teklifçinin sorusu: "Teklifim sınırın altında kalıp aşırı düşük sorgusuna girer mi?" + */ +const tl = (n) => (Number.isFinite(n) ? n.toLocaleString('tr-TR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' TL' : '—'); + +export const SinirDeger = () => { + const [tur, setTur] = useState('hizmet'); // hizmet | mal | personel | yapim + const [ym, setYm] = useState(''); + const [tekliflerMetin, setTekliflerMetin] = useState(''); + const [rSecim, setRSecim] = useState(String(R_2026[6].r)); + const [rOzel, setROzel] = useState(''); + const [nKat, setNKat] = useState('1.2'); + const [benimTeklif, setBenimTeklif] = useState(''); + + const teklifler = useMemo(() => teklifleriAyir(tekliflerMetin), [tekliflerMetin]); + const r = rSecim === 'ozel' ? Number(String(rOzel).replace(',', '.')) : Number(rSecim); + + const sonuc = useMemo(() => { + if (tur === 'personel') return ym ? sinirDegerPersonel({ karHaricYm: ym }) : null; + if (!ym || !teklifler.length) return null; + if (tur === 'yapim') return sinirDegerYapim({ ym, teklifler, n: Number(nKat) }); + return sinirDegerHizmet({ ym, teklifler, r }); + }, [tur, ym, teklifler, r, nKat]); + + const benim = teklifleriAyir(benimTeklif)[0]; + const altinda = sonuc?.sd != null && Number.isFinite(benim) ? benim < sonuc.sd : null; + + return ( +
+
+
+
+
+

Sınır Değer Hesaplayıcı

+

Teklifiniz aşırı düşük teklif sorgusuna girer mi? Kamu İhale Genel Tebliği md. 79 / 45 formülleriyle.

+
+
+
+ +
+
+
+ Alım türü +
+ {[['hizmet', 'Hizmet (personel dayalı olmayan)'], ['mal', 'Mal alımı'], ['personel', 'Hizmet (personel çalıştırmaya dayalı)'], ['yapim', 'Yapım işi']].map(([k, ad]) => ( + + ))} +
+ {tur === 'mal' &&

Md. 62/A.1 (RG 9/4/2026): mal alımında aşırı düşük değerlendirmesi 79 uncu maddeye göre yapılır — hizmet formülü uygulanır.

} +
+ + + + {tur !== 'personel' && ( +