fix: preserve bid drafts and align tender source data

This commit is contained in:
2026-09-06 08:40:10 +03:00
parent c91631d99f
commit 456728b4bd
26 changed files with 510 additions and 81 deletions
+41 -19
View File
@@ -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 →