Files
ihaleist/src/components/DetailedSearchModal.jsx
T

222 lines
9.6 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, useId } from 'react';
import {useModalFocus} from '../hooks/useModalFocus';
import { useApp } from '../context/AppContext';
import { CITIES_LIST, INSTITUTION_TYPES_LIST } from '../data/constants';
import { SlidersHorizontal, Search, RotateCcw, X } from 'lucide-react';
export const DetailedSearchModal = () => {
const {isDetailedSearchOpen}=useApp();
return isDetailedSearchOpen?<DetailedSearchForm/>:null;
};
const DetailedSearchForm = () => {
const context=useApp();
const {setIsDetailedSearchOpen,setActiveTab,sektorListesi}=context;
const titleId=useId();
const modalFocus=useModalFocus(true,()=>setIsDetailedSearchOpen(false));
const [searchQuery,setSearchQuery]=useState(context.searchQuery);
const [selectedCity,setSelectedCity]=useState(context.selectedCity);
const [selectedAlimTuru,setSelectedAlimTuru]=useState(context.selectedAlimTuru);
const [selectedKurumTipi,setSelectedKurumTipi]=useState(context.selectedKurumTipi);
const [selectedSektorler,setSelectedSektorler]=useState(context.selectedSektorler);
const [onlyValidOnly,setOnlyValidOnly]=useState(context.onlyValidOnly);
const [iknQuery,setIknQuery]=useState(context.detailedQueries.registration);
const [kurumQuery,setKurumQuery]=useState(context.detailedQueries.institution);
const toggleSektor=sector=>setSelectedSektorler(old=>old.includes(sector)?old.filter(value=>value!==sector):[...old,sector]);
const handleApplySearch = (e) => {
e.preventDefault();
context.setSearchQuery(searchQuery.trim());
context.setDetailedQueries({institution:kurumQuery.trim(),registration:iknQuery.trim()});
context.setSelectedCity(selectedCity);
context.setSelectedAlimTuru(selectedAlimTuru);
context.setSelectedKurumTipi(selectedKurumTipi);
context.setSelectedSektorler(selectedSektorler);
context.setOnlyValidOnly(onlyValidOnly);
setActiveTab('list');
setIsDetailedSearchOpen(false);
};
const handleReset = () => {
setSearchQuery('');
setSelectedCity('');
setSelectedAlimTuru('');
setSelectedKurumTipi('');
setSelectedSektorler([]);
setOnlyValidOnly(true);
setIknQuery('');
setKurumQuery('');
};
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/60 backdrop-blur-xs animate-fade-in">
<div {...modalFocus} role="dialog" aria-modal="true" aria-labelledby={titleId} tabIndex={-1} className="bg-white rounded-2xl border border-slate-200 shadow-2xl w-full max-w-2xl max-h-[92vh] overflow-y-auto">
{/* 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 id={titleId}>Detaylı İhale Arama</span>
</div>
<button type="button"
aria-label="Detaylı aramayı kapat"
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">
<p className="text-slate-600">Doldurduğunuz alanlar birlikte uygulanır. Değişiklikler İhaleleri Ara düğmesine bastığınızda listeye yansır.</p>
<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
aria-label="Anahtar Kelime"
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Başlık, kurum, İKN veya kalemde 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
aria-label="Alım Tipi"
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
aria-label="Kurum Adı"
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
aria-label="Kayıt No (İKN / DT No)"
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 className="md:col-span-2">
<label className="block font-bold text-slate-700 mb-1">
Sektör / Kategori
<span className="font-normal text-slate-400 ml-1">
(birden fazla seçebilirsiniz{selectedSektorler.length > 0 ? ` — ${selectedSektorler.length} seçili` : ''})
</span>
</label>
<div className="flex flex-wrap gap-1.5 max-h-40 overflow-y-auto bg-slate-50 border border-slate-300 rounded-lg p-2">
{sektorListesi.map((s) => {
const secili = selectedSektorler.includes(s);
return (
<button
type="button"
aria-pressed={secili}
key={s}
onClick={() => toggleSektor(s)}
className={`px-2.5 py-1 rounded-full border text-[11px] font-semibold transition-colors ${
secili
? 'bg-blue-600 border-blue-600 text-white'
: 'bg-white border-slate-300 text-slate-600 hover:border-blue-400 hover:text-blue-700'
}`}
>
{s}
</button>
);
})}
</div>
</div>
<div>
<label className="block font-bold text-slate-700 mb-1">Şehir</label>
<select
aria-label="Şehir"
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>
<label className="block font-bold text-slate-700 mb-1">Kurum Tipi</label>
<select
aria-label="Kurum Tipi"
value={selectedKurumTipi}
onChange={(e) => setSelectedKurumTipi(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>
{INSTITUTION_TYPES_LIST.map(type => <option key={type} value={type}>{type}</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>
);
};