305 lines
14 KiB
React
305 lines
14 KiB
React
import React, { useState } from 'react';
|
||
import { useApp } from '../context/AppContext';
|
||
import { INSTITUTION_TYPES_LIST, CITIES_LIST } from '../data/constants';
|
||
import { Bot, ArrowLeft, CheckCircle2, HelpCircle, Building2, MapPin, Tag } from 'lucide-react';
|
||
|
||
export const SmartFilterBuilder = () => {
|
||
const { savedFilters, applySavedFilter, addSavedFilter, deleteSavedFilter, setActiveTab, sektorListesi, savingCount, saveError,
|
||
searchQuery, detailedQueries, selectedCity: activeCity, selectedRegion: activeRegion, selectedAlimTuru: activeProcedure,
|
||
selectedKurumTipi: activeInstitution, selectedSektorler: activeSectors } = useApp();
|
||
|
||
const [filterName, setFilterName] = useState('');
|
||
const [keyword,setKeyword] = useState(searchQuery || '');
|
||
const [institutionName,setInstitutionName] = useState(detailedQueries?.institution || '');
|
||
const [registration,setRegistration] = useState(detailedQueries?.registration || '');
|
||
const [selectedKurumTip, setSelectedKurumTip] = useState(activeInstitution || '');
|
||
const [selectedUsul, setSelectedUsul] = useState(activeProcedure || '');
|
||
const [selectedCity, setSelectedCity] = useState(activeCity || '');
|
||
const [selectedRegion, setSelectedRegion] = useState(activeRegion || '');
|
||
const [selectedSektor, setSelectedSektor] = useState(activeSectors?.[0] || '');
|
||
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 = async (e) => {
|
||
e.preventDefault();
|
||
if (!filterName.trim()) {
|
||
setSuccessMessage('');
|
||
return;
|
||
}
|
||
|
||
setSuccessMessage('');
|
||
const saved=await addSavedFilter({
|
||
name: filterName.trim(),
|
||
anahtarKelime: keyword.trim(),
|
||
kurumAdi: institutionName.trim(),
|
||
ikn: registration.trim(),
|
||
kurumTipi: selectedKurumTip,
|
||
usul: selectedUsul,
|
||
sehir: selectedCity,
|
||
bolge: selectedRegion,
|
||
sektor: selectedSektor
|
||
});
|
||
|
||
if(!saved)return;
|
||
setSuccessMessage('Filtre sunucuya kaydedildi. Bu kayıt bildirim aboneliği oluşturmaz.');
|
||
setFilterName('');
|
||
|
||
};
|
||
|
||
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">Kayıtlı Filtreler</h1>
|
||
<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>
|
||
<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>İhale listesine dön</span>
|
||
</button>
|
||
</div>
|
||
|
||
{savingCount > 0 && <p role="status" className="text-sm">Filtre işlemi kaydediliyor…</p>}
|
||
{saveError && <p role="alert" className="text-sm text-red-700">{saveError}</p>}
|
||
{successMessage && (
|
||
<div role="status" 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">
|
||
<button type="button" className="text-blue-800 underline" onClick={()=>applySavedFilter(f)} aria-label={`${f.name} filtresini uygula`}>{f.name}</button>
|
||
<button
|
||
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"
|
||
>
|
||
🗑️
|
||
</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}><fieldset disabled={savingCount > 0} 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
|
||
aria-label="Filtre adı"
|
||
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 ad kayıtlı filtre listenizde görünür.</p>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-xl border border-slate-200 p-5 space-y-3">
|
||
<h3 className="font-bold text-sm">Arama metinleri</h3>
|
||
<p className="text-xs text-slate-600">Dolu alanlar birlikte uygulanır. Boş bıraktığınız alan aramayı sınırlamaz.</p>
|
||
{[
|
||
['Anahtar kelime',keyword,setKeyword],
|
||
['Kurum adı',institutionName,setInstitutionName],
|
||
['İKN / DT no',registration,setRegistration],
|
||
].map(([label,value,setValue])=><label key={label} className="block text-xs font-semibold text-slate-600">
|
||
{label}<input type="text" value={value} onChange={e=>setValue(e.target.value)} className="mt-1 w-full bg-slate-50 border border-slate-300 rounded-lg px-3 py-2 text-sm"/>
|
||
</label>)}
|
||
</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
|
||
aria-label="Filtre kurum tipi"
|
||
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
|
||
aria-label="Filtre bölgesi"
|
||
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
|
||
aria-label="Filtre şehri"
|
||
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
|
||
aria-label="Filtre sektörü"
|
||
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>
|
||
{sektorListesi.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>Filtreyi kaydet</span>
|
||
</button>
|
||
</div>
|
||
|
||
</fieldset></form>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
);
|
||
};
|