fix: combine detailed tender search fields
This commit is contained in:
@@ -5,37 +5,34 @@ import { CITIES_LIST, INSTITUTION_TYPES_LIST } from '../data/constants';
|
||||
import { SlidersHorizontal, Search, RotateCcw, X } from 'lucide-react';
|
||||
|
||||
export const DetailedSearchModal = () => {
|
||||
const {
|
||||
isDetailedSearchOpen,
|
||||
setIsDetailedSearchOpen,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
selectedCity,
|
||||
setSelectedCity,
|
||||
selectedAlimTuru,
|
||||
setSelectedAlimTuru,
|
||||
selectedSektorler,
|
||||
setSelectedSektorler,
|
||||
toggleSektor,
|
||||
sektorListesi,
|
||||
selectedKurumTipi,
|
||||
setSelectedKurumTipi,
|
||||
onlyValidOnly,
|
||||
setOnlyValidOnly,
|
||||
setActiveTab
|
||||
} = useApp();
|
||||
const {isDetailedSearchOpen}=useApp();
|
||||
return isDetailedSearchOpen?<DetailedSearchForm/>:null;
|
||||
};
|
||||
|
||||
const DetailedSearchForm = () => {
|
||||
const context=useApp();
|
||||
const {setIsDetailedSearchOpen,setActiveTab,sektorListesi}=context;
|
||||
const titleId=useId();
|
||||
const modalFocus=useModalFocus(isDetailedSearchOpen,()=>setIsDetailedSearchOpen(false));
|
||||
|
||||
const [iknQuery, setIknQuery] = useState('');
|
||||
const [kurumQuery, setKurumQuery] = useState('');
|
||||
|
||||
if (!isDetailedSearchOpen) return null;
|
||||
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();
|
||||
if (kurumQuery) setSearchQuery(kurumQuery);
|
||||
else if (iknQuery) setSearchQuery(iknQuery);
|
||||
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);
|
||||
@@ -45,8 +42,9 @@ export const DetailedSearchModal = () => {
|
||||
setSearchQuery('');
|
||||
setSelectedCity('');
|
||||
setSelectedAlimTuru('');
|
||||
setSelectedSektorler([]);
|
||||
setSelectedKurumTipi('');
|
||||
setSelectedSektorler([]);
|
||||
setOnlyValidOnly(true);
|
||||
setIknQuery('');
|
||||
setKurumQuery('');
|
||||
};
|
||||
@@ -72,6 +70,7 @@ export const DetailedSearchModal = () => {
|
||||
|
||||
{/* 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">
|
||||
|
||||
@@ -82,7 +81,7 @@ export const DetailedSearchModal = () => {
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder="Başlık, açıklama içinde aranır..."
|
||||
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>
|
||||
@@ -168,6 +167,19 @@ export const DetailedSearchModal = () => {
|
||||
</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">
|
||||
|
||||
@@ -67,6 +67,7 @@ export const Header = () => {
|
||||
{searchQuery && (
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Anahtar kelime aramasını temizle"
|
||||
onClick={() => setSearchQuery('')}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-white text-xs"
|
||||
>
|
||||
|
||||
@@ -31,7 +31,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
|
||||
setSelectedKurumTipi,
|
||||
selectedCity,
|
||||
setSelectedCity,
|
||||
clearAllFilters
|
||||
clearAllFilters,detailedQueries
|
||||
} = useApp();
|
||||
|
||||
const [sektorAra, setSektorAra] = useState('');
|
||||
@@ -89,7 +89,7 @@ export const LeftSidebar = ({onOpenProductSearch} = {}) => {
|
||||
<span className="font-bold text-xs uppercase tracking-wider text-slate-700 flex items-center gap-1.5">
|
||||
<Compass className="w-4 h-4 text-blue-600" /> Hızlı Erişim
|
||||
</span>
|
||||
{(selectedRegion || quickFilter !== 'all' || selectedSektorler.length || selectedCpvler.length || selectedCity || selectedAlimTuru || selectedKurumTipi) && (
|
||||
{(detailedQueries.institution || detailedQueries.registration || selectedRegion || quickFilter !== 'all' || selectedSektorler.length || selectedCpvler.length || selectedCity || selectedAlimTuru || selectedKurumTipi) && (
|
||||
<button
|
||||
onClick={clearAllFilters}
|
||||
className="text-[11px] font-medium text-blue-600 hover:underline"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {matchesRegion,matchesProcurement} from '../services/savedFilterCriteria';
|
||||
import { matchesTenderSearch } from '../services/tenderSearch';
|
||||
import { matchesTenderSearch, matchesDetailedSearch } from '../services/tenderSearch';
|
||||
import React, { useState, useMemo, useEffect, useRef, useCallback } from 'react';
|
||||
import { useApp } from '../context/AppContext';
|
||||
import { TenderCard } from './TenderCard';
|
||||
@@ -17,6 +17,7 @@ export const TenderList = () => {
|
||||
const {
|
||||
tenders,
|
||||
searchQuery,
|
||||
detailedQueries,setDetailedQueries,
|
||||
kalemEslesen, itemSearchState, retryItemSearch,
|
||||
uyumEsigi,
|
||||
selectedCity,selectedRegion,setSelectedRegion,
|
||||
@@ -46,6 +47,7 @@ export const TenderList = () => {
|
||||
return tenders.filter(tender => {
|
||||
// Search Query
|
||||
if (!matchesTenderSearch(tender,searchQuery,kalemEslesen)) return false;
|
||||
if (!matchesDetailedSearch(tender,detailedQueries)) return false;
|
||||
|
||||
// Geçmiş ihaleler: varsayılan olarak GİZLİ. Kullanıcı "geçmişi de göster"
|
||||
// derse (onlyValidOnly=false) hepsi gelir. Tarihi okunamayan kayıt gizlenmez.
|
||||
@@ -71,7 +73,7 @@ export const TenderList = () => {
|
||||
if (sortBy === 'distant') return compareTenderDeadlines(a,b,-1);
|
||||
return 0;
|
||||
});
|
||||
}, [tenders, searchQuery, kalemEslesen, uyumEsigi, selectedCity, selectedRegion, selectedAlimTuru, selectedSektorler, selectedCpvler, selectedKurumTipi, quickFilter, sortBy, onlyValidOnly, now, favoriteKurumlar, oncekiGiris]);
|
||||
}, [tenders, searchQuery, detailedQueries, kalemEslesen, uyumEsigi, selectedCity, selectedRegion, selectedAlimTuru, selectedSektorler, selectedCpvler, selectedKurumTipi, quickFilter, sortBy, onlyValidOnly, now, favoriteKurumlar, oncekiGiris]);
|
||||
|
||||
const gorunenTenders = filteredTenders.slice(0, gosterilen);
|
||||
const dahaVar = gosterilen < filteredTenders.length;
|
||||
@@ -80,7 +82,7 @@ export const TenderList = () => {
|
||||
// dizisine bağlansaydı havuz her yenilendiğinde (10 dk) kullanıcı listenin
|
||||
// başına fırlardı.
|
||||
useEffect(() => { setGosterilen(SAYFA_ADIM); }, [
|
||||
searchQuery, selectedCity, selectedRegion, selectedAlimTuru, selectedSektorler,
|
||||
searchQuery, detailedQueries, selectedCity, selectedRegion, selectedAlimTuru, selectedSektorler,
|
||||
selectedCpvler, selectedKurumTipi, quickFilter, sortBy, onlyValidOnly,
|
||||
]);
|
||||
|
||||
@@ -129,6 +131,10 @@ export const TenderList = () => {
|
||||
|
||||
return (
|
||||
<div className="w-full min-w-0 flex-1 space-y-4">
|
||||
{Object.entries(detailedQueries).filter(([,value])=>value).map(([key,value])=><div key={key} className="flex gap-3 items-center flex-wrap text-sm bg-blue-50 border rounded p-3">
|
||||
<span>{key==='institution'?'Kurum adı':'İKN / DT no'}: {value}</span>
|
||||
<button className="underline text-blue-800" onClick={()=>setDetailedQueries(old=>({...old,[key]:''}))}>{key==='institution'?'Kurum adı filtresini kaldır':'İKN filtresini kaldır'}</button>
|
||||
</div>)}
|
||||
|
||||
{selectedRegion&&<div className="flex gap-3 items-center flex-wrap text-sm bg-blue-50 border rounded p-3"><span>İl bazında bölge filtresi: {selectedRegion}</span><button className="underline text-blue-800" onClick={()=>setSelectedRegion('')}>Bölge filtresini kaldır</button></div>}
|
||||
{/* Header bar above list */}
|
||||
|
||||
Reference in New Issue
Block a user