feat: İhaleist - Akıllı İhale Takip ve Analiz Platformu (Full PRD + 7 Enterprise Modül)
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useApp } from '../context/AppContext';
|
||||
import { INSTITUTION_TYPES_LIST, CITIES_LIST, SECTORS_LIST } from '../data/mockTenders';
|
||||
import { Bot, ArrowLeft, CheckCircle2, HelpCircle, Building2, MapPin, Tag } from 'lucide-react';
|
||||
|
||||
export const SmartFilterBuilder = () => {
|
||||
const { savedFilters, addSavedFilter, deleteSavedFilter, setActiveTab } = useApp();
|
||||
|
||||
const [filterName, setFilterName] = useState('');
|
||||
const [selectedKurumTip, setSelectedKurumTip] = useState('');
|
||||
const [selectedUsul, setSelectedUsul] = useState('');
|
||||
const [selectedCity, setSelectedCity] = useState('');
|
||||
const [selectedRegion, setSelectedRegion] = useState('');
|
||||
const [selectedSektor, setSelectedSektor] = useState('');
|
||||
const [successMessage, setSuccessMessage] = useState('');
|
||||
|
||||
const regions = [
|
||||
'AKDENİZ BÖLGESİ', 'DOĞU ANADOLU BÖLGESİ', 'EGE BÖLGESİ',
|
||||
'GÜNEYDOĞU ANADOLU BÖLGESİ', 'İÇ ANADOLU BÖLGESİ', 'KARADENİZ BÖLGESİ', 'MARMARA BÖLGESİ'
|
||||
];
|
||||
|
||||
const usuller = [
|
||||
'Açık İhale', 'Dış Alım', 'Doğrudan Temin', 'İstisna', 'Pazarlık Usulü', 'Yaklaşık Maliyet'
|
||||
];
|
||||
|
||||
const handleCreateFilter = (e) => {
|
||||
e.preventDefault();
|
||||
if (!filterName.trim()) {
|
||||
alert('Lütfen bir filtre adı giriniz.');
|
||||
return;
|
||||
}
|
||||
|
||||
addSavedFilter({
|
||||
name: filterName.trim(),
|
||||
kurumTipi: selectedKurumTip,
|
||||
usul: selectedUsul,
|
||||
sehir: selectedCity,
|
||||
bolge: selectedRegion,
|
||||
sektor: selectedSektor
|
||||
});
|
||||
|
||||
setSuccessMessage('Yeni akıllı filtre başarıyla oluşturuldu.');
|
||||
setFilterName('');
|
||||
setTimeout(() => setSuccessMessage(''), 4000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-[1600px] mx-auto my-4 space-y-4 animate-fade-in">
|
||||
|
||||
{/* Top Banner */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-emerald-600 text-white flex items-center justify-center shadow-md">
|
||||
<Bot className="w-6 h-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-black text-slate-900">Akıllı Filtre (Bot) Kurulumu</h1>
|
||||
<p className="text-xs text-slate-500">Sektör veya şehrinize uygun yeni ihale eklendiğinde anında haberiniz olsun.</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
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"
|
||||
>
|
||||
<HelpCircle className="w-4 h-4" />
|
||||
<span>Nasıl Çalışır?</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{successMessage && (
|
||||
<div className="bg-emerald-50 border border-emerald-200 text-emerald-800 px-4 py-3 rounded-xl text-xs font-semibold flex items-center gap-2 animate-fade-in shadow-xs">
|
||||
<CheckCircle2 className="w-5 h-5 text-emerald-600 shrink-0" />
|
||||
<span>{successMessage}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Main Grid */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
|
||||
|
||||
{/* Left Column: Ekip Filtre Listesi */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 shadow-xs p-4 h-fit">
|
||||
<div className="flex items-center justify-between mb-4 pb-2 border-b border-slate-100">
|
||||
<h3 className="font-bold text-xs uppercase tracking-wider text-slate-800 flex items-center gap-2">
|
||||
<Bot className="w-4 h-4 text-blue-600" /> Ekip Filtre Listesi
|
||||
</h3>
|
||||
<span className="bg-blue-100 text-blue-800 text-[10px] font-bold px-2 py-0.5 rounded-full">
|
||||
{savedFilters.length}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 mb-4">
|
||||
{savedFilters.map(f => (
|
||||
<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">
|
||||
<span>🤖 {f.name}</span>
|
||||
<button
|
||||
onClick={() => deleteSavedFilter(f.id)}
|
||||
className="text-slate-400 hover:text-red-600 text-xs"
|
||||
>
|
||||
🗑️
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-[10px] text-slate-500 mt-1">👤 {f.user} {f.sehir && `• 📍 ${f.sehir}`}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<button
|
||||
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"
|
||||
>
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
<span>Ana Ekrana Dön</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Right 3 Columns: Filter Form */}
|
||||
<div className="lg:col-span-3 space-y-6">
|
||||
<form onSubmit={handleCreateFilter} className="space-y-6">
|
||||
|
||||
{/* Filter Name Card */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 shadow-xs p-5 space-y-2">
|
||||
<label className="block text-xs font-bold text-slate-800 uppercase tracking-wider">
|
||||
FİLTRE ADI (ZORUNLU)
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
value={filterName}
|
||||
onChange={(e) => setFilterName(e.target.value)}
|
||||
placeholder="Örn: Ege Bölgesi Cihaz İhaleleri"
|
||||
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-4 py-2.5 text-sm text-slate-800 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<p className="text-[11px] text-slate-400">Bu isim sadece sizin takip ve bildirim akışınızda gösterilecektir.</p>
|
||||
</div>
|
||||
|
||||
{/* Middle Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
|
||||
{/* Kurum Tipi & İhale Usulü */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 shadow-xs p-5 space-y-4">
|
||||
<div className="flex items-center gap-2 border-b border-slate-100 pb-3">
|
||||
<Building2 className="w-5 h-5 text-blue-600" />
|
||||
<h3 className="font-bold text-sm text-slate-800">Kurum Tipi & İhale Usulü</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-slate-600 mb-1.5">KURUM TİPLERİ</label>
|
||||
<div className="flex flex-wrap gap-1.5 mb-2">
|
||||
{['Sağlık', 'Belediye', 'Üniversite', 'Kamu', 'Temizle'].map(badge => (
|
||||
<button
|
||||
key={badge}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (badge === 'Temizle') setSelectedKurumTip('');
|
||||
else if (badge === 'Sağlık') setSelectedKurumTip('Eğitim ve Araştırma Hastaneleri');
|
||||
else if (badge === 'Belediye') setSelectedKurumTip('Belediyeler');
|
||||
else if (badge === 'Üniversite') setSelectedKurumTip('Üniversiteler');
|
||||
else setSelectedKurumTip('Bakanlıklar');
|
||||
}}
|
||||
className="bg-red-50 text-red-600 hover:bg-red-100 text-[11px] font-bold px-2.5 py-1 rounded-md border border-red-200 transition-colors"
|
||||
>
|
||||
{badge}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<select
|
||||
value={selectedKurumTip}
|
||||
onChange={(e) => setSelectedKurumTip(e.target.value)}
|
||||
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-xs text-slate-800"
|
||||
>
|
||||
<option value="">Tüm Kurum Tipleri</option>
|
||||
{INSTITUTION_TYPES_LIST.map(k => (
|
||||
<option key={k} value={k}>{k}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-slate-600 mb-1.5">İHALE USULLERİ</label>
|
||||
<div className="space-y-1.5 max-h-40 overflow-y-auto pr-1">
|
||||
{usuller.map(usul => (
|
||||
<label key={usul} className="flex items-center gap-2 text-xs text-slate-700 cursor-pointer hover:bg-slate-50 p-1 rounded">
|
||||
<input
|
||||
type="radio"
|
||||
name="usul_radio"
|
||||
checked={selectedUsul === usul}
|
||||
onChange={() => setSelectedUsul(usul)}
|
||||
className="accent-blue-600"
|
||||
/>
|
||||
<span>{usul}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Konum Seçimi */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 shadow-xs p-5 space-y-4">
|
||||
<div className="flex items-center gap-2 border-b border-slate-100 pb-3">
|
||||
<MapPin className="w-5 h-5 text-blue-600" />
|
||||
<h3 className="font-bold text-sm text-slate-800">Konum Seçimi</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-slate-600 mb-1.5">BÖLGELER</label>
|
||||
<select
|
||||
value={selectedRegion}
|
||||
onChange={(e) => setSelectedRegion(e.target.value)}
|
||||
className="w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-xs text-slate-800"
|
||||
>
|
||||
<option value="">Tüm Bölgeler</option>
|
||||
{regions.map(r => (
|
||||
<option key={r} value={r}>{r}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-slate-600 mb-1.5">ŞEHİRLER</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-xs text-slate-800"
|
||||
>
|
||||
<option value="">Tüm Şehirler</option>
|
||||
{CITIES_LIST.map(city => (
|
||||
<option key={city} value={city}>{city}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-slate-600 mb-1.5">SEKTÖR</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-xs text-slate-800"
|
||||
>
|
||||
<option value="">Tüm Sektörler</option>
|
||||
{SECTORS_LIST.map(s => (
|
||||
<option key={s} value={s}>{s}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex justify-end gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveTab('list')}
|
||||
className="bg-slate-200 hover:bg-slate-300 text-slate-700 font-semibold px-5 py-2.5 rounded-lg text-xs transition-colors"
|
||||
>
|
||||
İptal
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-blue-600 hover:bg-blue-500 text-white font-bold px-6 py-2.5 rounded-lg text-xs transition-colors shadow-md flex items-center gap-2"
|
||||
>
|
||||
<Bot className="w-4 h-4" />
|
||||
<span>Akıllı Filtre Botunu Kaydet & Çalıştır</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user