Files
ihaleist/src/components/SmartFilterBuilder.jsx
T

305 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 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>
);
};