feat: İhaleist - Akıllı İhale Takip ve Analiz Platformu (Full PRD + 7 Enterprise Modül)

This commit is contained in:
2026-08-07 16:30:24 +03:00
commit ece74feefe
35 changed files with 7820 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
import React, { useState } from 'react';
import { useApp } from '../context/AppContext';
import { SECTORS_LIST, CITIES_LIST, INSTITUTION_TYPES_LIST } from '../data/mockTenders';
import { SlidersHorizontal, Search, RotateCcw, X } from 'lucide-react';
export const DetailedSearchModal = () => {
const {
isDetailedSearchOpen,
setIsDetailedSearchOpen,
searchQuery,
setSearchQuery,
selectedCity,
setSelectedCity,
selectedAlimTuru,
setSelectedAlimTuru,
selectedSektor,
setSelectedSektor,
selectedKurumTipi,
setSelectedKurumTipi,
onlyValidOnly,
setOnlyValidOnly,
setActiveTab
} = useApp();
const [iknQuery, setIknQuery] = useState('');
const [kurumQuery, setKurumQuery] = useState('');
if (!isDetailedSearchOpen) return null;
const handleApplySearch = (e) => {
e.preventDefault();
if (kurumQuery) setSearchQuery(kurumQuery);
else if (iknQuery) setSearchQuery(iknQuery);
setActiveTab('list');
setIsDetailedSearchOpen(false);
};
const handleReset = () => {
setSearchQuery('');
setSelectedCity('');
setSelectedAlimTuru('');
setSelectedSektor('');
setSelectedKurumTipi('');
setIknQuery('');
setKurumQuery('');
};
return (
<div className="fixed inset-[#00000080] z-50 flex items-center justify-center p-4 bg-slate-900/60 backdrop-blur-xs animate-fade-in">
<div className="bg-white rounded-2xl border border-slate-200 shadow-2xl w-full max-w-2xl overflow-hidden">
{/* Header */}
<div className="bg-[#1f2937] text-white px-6 py-4 flex items-center justify-between">
<div className="flex items-center gap-2.5 font-bold text-base">
<SlidersHorizontal className="w-5 h-5 text-blue-400" />
<span>Detaylı İhale Arama</span>
</div>
<button
onClick={() => setIsDetailedSearchOpen(false)}
className="text-slate-400 hover:text-white p-1 rounded-lg transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
{/* Form Body */}
<form onSubmit={handleApplySearch} className="p-6 space-y-4 text-xs">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block font-bold text-slate-700 mb-1">Anahtar Kelime</label>
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Başlık, açıklama içinde aranır..."
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-800 focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label className="block font-bold text-slate-700 mb-1">Alım Tipi</label>
<select
value={selectedAlimTuru}
onChange={(e) => setSelectedAlimTuru(e.target.value)}
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-800"
>
<option value="">Tümü</option>
<option value="Doğrudan Temin">Doğrudan Temin</option>
<option value="Açık İhale">Açık İhale</option>
<option value="Pazarlık Usulü">Pazarlık Usulü</option>
</select>
</div>
<div>
<label className="block font-bold text-slate-700 mb-1">Kurum Adı</label>
<input
type="text"
value={kurumQuery}
onChange={(e) => setKurumQuery(e.target.value)}
placeholder="Kurum adında aranır..."
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-800 focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label className="block font-bold text-slate-700 mb-1">Kayıt No (İKN / DT No)</label>
<input
type="text"
value={iknQuery}
onChange={(e) => setIknQuery(e.target.value)}
placeholder="2026/... veya 26DT..."
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-800 focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label className="block font-bold text-slate-700 mb-1">Sektör / Kategori</label>
<select
value={selectedSektor}
onChange={(e) => setSelectedSektor(e.target.value)}
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-800"
>
<option value="">Tümü</option>
{SECTORS_LIST.map(s => <option key={s} value={s}>{s}</option>)}
</select>
</div>
<div>
<label className="block font-bold text-slate-700 mb-1">Şehir</label>
<select
value={selectedCity}
onChange={(e) => setSelectedCity(e.target.value)}
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-slate-800"
>
<option value="">Tümü</option>
{CITIES_LIST.map(c => <option key={c} value={c}>{c}</option>)}
</select>
</div>
</div>
<div className="pt-2">
<label className="flex items-center gap-2 cursor-pointer font-medium text-slate-700">
<input
type="checkbox"
checked={onlyValidOnly}
onChange={(e) => setOnlyValidOnly(e.target.checked)}
className="accent-blue-600 w-4 h-4 rounded"
/>
<span>Sadece teklif verilebilir ihaleleri göster (ihale tarihi geçmemiş ihaleler)</span>
</label>
</div>
{/* Footer Buttons */}
<div className="pt-4 border-t border-slate-200 flex items-center justify-center gap-4">
<button
type="submit"
className="bg-emerald-600 hover:bg-emerald-500 text-white font-bold px-8 py-2.5 rounded-xl shadow-md flex items-center gap-2 transition-colors"
>
<Search className="w-4 h-4" />
<span>İhaleleri Ara</span>
</button>
<button
type="button"
onClick={handleReset}
className="bg-slate-100 hover:bg-slate-200 text-slate-700 font-semibold px-5 py-2.5 rounded-xl border border-slate-300 flex items-center gap-2 transition-colors"
>
<RotateCcw className="w-4 h-4" />
<span>Temizle</span>
</button>
</div>
</form>
</div>
</div>
);
};