fix: preserve bid drafts and align tender source data
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useApp } from '../context/AppContext';
|
||||
import {
|
||||
X, Search, Loader2, Package, AlertTriangle, Building2, MapPin, CalendarDays, Info,
|
||||
@@ -28,6 +28,14 @@ export const UrunAramaModal = () => {
|
||||
isUrunAramaOpen, setIsUrunAramaOpen, setActiveTenderDetail, tenders,
|
||||
urunAramaBaslangic, setUrunAramaBaslangic,
|
||||
} = useApp();
|
||||
const requestVersion = useRef(0);
|
||||
const [submitted, setSubmitted] = useState(null);
|
||||
useEffect(() => {
|
||||
if (!isUrunAramaOpen) {
|
||||
requestVersion.current++;
|
||||
setDurum((d) => ({ ...d, yukleniyor: false }));
|
||||
}
|
||||
}, [isUrunAramaOpen]);
|
||||
const [q, setQ] = useState('');
|
||||
const [teknik, setTeknik] = useState(false);
|
||||
const [sadeceAcik, setSadeceAcik] = useState(true);
|
||||
@@ -60,30 +68,40 @@ export const UrunAramaModal = () => {
|
||||
|
||||
if (!isUrunAramaOpen) return null;
|
||||
|
||||
const araOkas = async (kodlar, sayfa = 0) => {
|
||||
if (!kodlar.length) { setDurum((d) => ({ ...d, hata: 'En az bir OKAS kodu seçin.' })); return; }
|
||||
const sorgula = async (query, sayfa = 0) => {
|
||||
const request = ++requestVersion.current;
|
||||
setDurum({ yukleniyor: true, sonuc: null, hata: null, sayfa });
|
||||
try {
|
||||
const d = await urunAra('', { skip: sayfa * SAYFA, take: SAYFA, okas: kodlar });
|
||||
const d = await urunAra(query.mod === 'metin' ? query.label : '', {
|
||||
skip: sayfa * SAYFA, take: SAYFA,
|
||||
teknik: query.teknik, okas: query.kodlar || [],
|
||||
});
|
||||
if (request !== requestVersion.current) return;
|
||||
setSubmitted(query);
|
||||
setDurum({ yukleniyor: false, sonuc: d, hata: null, sayfa });
|
||||
} catch (e) {
|
||||
if (request !== requestVersion.current) return;
|
||||
setDurum({ yukleniyor: false, sonuc: null, hata: e.message, sayfa });
|
||||
}
|
||||
};
|
||||
|
||||
const ara = async (sayfa = 0) => {
|
||||
if (mod === 'okas') return araOkas(okasSecili.map((k) => k.kod), sayfa);
|
||||
const araOkas = (kodlar, sayfa = 0) => {
|
||||
if (!kodlar.length) { setDurum((d) => ({ ...d, hata: 'En az bir OKAS kodu seçin.' })); return; }
|
||||
return sorgula({ mod: 'okas', label: kodlar.join(', '), kodlar: [...kodlar], teknik: false }, sayfa);
|
||||
};
|
||||
|
||||
const ara = () => {
|
||||
if (mod === 'okas') return araOkas(okasSecili.map((k) => k.kod));
|
||||
const terim = q.trim();
|
||||
if (terim.length < 3) { setDurum((d) => ({ ...d, hata: 'En az 3 karakter yazın.' })); return; }
|
||||
setDurum({ yukleniyor: true, sonuc: null, hata: null, sayfa });
|
||||
try {
|
||||
const d = await urunAra(terim, { skip: sayfa * SAYFA, take: SAYFA, teknik });
|
||||
setDurum({ yukleniyor: false, sonuc: d, hata: null, sayfa });
|
||||
} catch (e) {
|
||||
setDurum({ yukleniyor: false, sonuc: null, hata: e.message, sayfa });
|
||||
}
|
||||
return sorgula({ mod: 'metin', label: terim, teknik });
|
||||
};
|
||||
|
||||
const sorguDegisti = submitted && (submitted.mod !== mod ||
|
||||
(mod === 'metin'
|
||||
? submitted.label !== q.trim() || submitted.teknik !== teknik
|
||||
: submitted.label !== okasSecili.map((k) => k.kod).join(', ')));
|
||||
|
||||
const okasEkle = (k) => {
|
||||
if (!okasSecili.some((x) => x.kod === k.kod)) setOkasSecili((o) => [...o, { kod: k.kod, ad: k.ad }]);
|
||||
setOkasQ(''); setOkasAdaylar([]);
|
||||
@@ -112,7 +130,7 @@ export const UrunAramaModal = () => {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button onClick={() => setIsUrunAramaOpen(false)} className="text-slate-400 hover:text-white p-1 rounded-lg">
|
||||
<button aria-label="Ürün aramasını kapat" onClick={() => setIsUrunAramaOpen(false)} className="text-slate-400 hover:text-white p-1 rounded-lg">
|
||||
<X className="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
@@ -220,13 +238,17 @@ export const UrunAramaModal = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{sonuc && sorguDegisti && (
|
||||
<p role="status" className="text-xs text-amber-800">Arama alanları değişti. Aşağıdaki sonuçlar ve sayfalar önceki aramaya aittir. Yeni seçimler için Ara düğmesine basın.</p>
|
||||
)}
|
||||
|
||||
{sonuc && (
|
||||
<>
|
||||
<div className="flex items-baseline justify-between gap-2 flex-wrap">
|
||||
<p className="text-xs font-bold text-slate-900">
|
||||
{mod === 'okas'
|
||||
? <>OKAS <span className="text-indigo-700">{okasSecili.map((k) => k.kod).join(', ')}</span> kodlu{' '}</>
|
||||
: <>Teklif cetvelinde <span className="text-indigo-700">"{q.trim()}"</span> geçen{' '}</>}
|
||||
{submitted?.mod === 'okas'
|
||||
? <>OKAS <span className="text-indigo-700">{submitted?.label}</span> kodlu{' '}</>
|
||||
: <>Teklif cetvelinde <span className="text-indigo-700">"{submitted?.label}"</span> geçen{' '}</>}
|
||||
<span className="text-indigo-700">{sonuc.totalCount.toLocaleString('tr-TR')}</span> ihale bulundu
|
||||
</p>
|
||||
{gizlenen > 0 && (
|
||||
@@ -281,7 +303,7 @@ export const UrunAramaModal = () => {
|
||||
<div className="flex items-center justify-center gap-3 pt-2">
|
||||
<button
|
||||
disabled={durum.sayfa === 0 || durum.yukleniyor}
|
||||
onClick={() => ara(durum.sayfa - 1)}
|
||||
onClick={() => sorgula(submitted, durum.sayfa - 1)}
|
||||
className="text-xs font-bold px-3 py-1.5 rounded-lg border border-slate-300 disabled:opacity-40"
|
||||
>
|
||||
← Önceki
|
||||
@@ -291,7 +313,7 @@ export const UrunAramaModal = () => {
|
||||
</span>
|
||||
<button
|
||||
disabled={(durum.sayfa + 1) * SAYFA >= sonuc.totalCount || durum.yukleniyor}
|
||||
onClick={() => ara(durum.sayfa + 1)}
|
||||
onClick={() => sorgula(submitted, durum.sayfa + 1)}
|
||||
className="text-xs font-bold px-3 py-1.5 rounded-lg border border-slate-300 disabled:opacity-40"
|
||||
>
|
||||
Sonraki →
|
||||
|
||||
Reference in New Issue
Block a user