Show tender source changes against saved preparation metadata

This commit is contained in:
2026-09-06 10:47:07 +03:00
parent f51f9b4eb0
commit a0f4824c7e
6 changed files with 46 additions and 3 deletions
+5
View File
@@ -105,6 +105,11 @@ export const TenderDetailModal = () => {
<div ref={dialogRef} role="dialog" aria-modal="true" aria-labelledby={dialogTitleId} tabIndex={-1} onKeyDown={handleDialogKey} className="bg-white w-full max-w-6xl rounded-2xl shadow-2xl border border-slate-200 overflow-hidden my-auto flex flex-col max-h-[92vh]">
{(actionError || saveError) && <p role="alert" className="p-3 bg-red-50 text-red-900">{actionError || saveError}</p>}
{tender.sourceChanges?.length > 0 && <div role="alert" className="p-3 bg-amber-50 text-amber-900 text-sm">
<p className="font-bold">Son kaydettiğiniz bilgilere göre ihale değişmiş</p>
<ul className="list-disc pl-5">{tender.sourceChanges.map(change => <li key={change.field}>{change.label}: {change.before} → {change.after}</li>)}</ul>
<p>Takip, not ve hazırlık kayıtlarınız korundu. Yeni koşulları resmi kaynakla karşılaştırın.</p>
</div>}
{tender.sourceWarning && <p role="alert" className="p-3 bg-amber-50 text-amber-900 text-sm">{tender.sourceWarning}</p>}
{detailLoad?.id === tender.id && detailLoad.status === 'loading' && <p role="status" className="p-3 bg-blue-50 text-blue-900">Kaynak ilan metni yükleniyor…</p>}
{detailLoad?.id === tender.id && detailLoad.status === 'error' && <div role="alert" className="p-3 bg-amber-50 text-amber-900 text-sm">
+2 -1
View File
@@ -7,7 +7,7 @@ import { getToken } from '../services/auth';
import { fetchLiveTenders, fetchTenderDetail, mergeUserState } from '../services/tenderApi';
import { restoreSession, clearSession, getStoredUser } from '../services/auth';
import { getAllUserData, setUserData, getPlan, bildirimleriGetir, bildirimOkundu, listDocuments } from '../services/account';
import { applyTenderStates, tenderStateKey, tenderSnapshot, publicTender } from '../services/tenderState';
import { applyTenderStates, tenderStateKey, tenderSnapshot, publicTender, tenderSourceChanges } from '../services/tenderState';
import { getTenderStates, saveTenderState } from '../services/account';
import { SECTORS_LIST, INSTITUTION_TYPES_LIST } from '../data/constants';
@@ -310,6 +310,7 @@ export const AppProvider = ({ children }) => {
.then(detail => {
if (cancelled) return;
const source = publicTender(detail);
source.sourceChanges = tenderSourceChanges(savedTenderStates.current[tenderStateKey(t)]?.snapshot, {...t,...source});
setDetailLoad({id:t.id,status:'loaded'});
setActiveTenderDetail(prev =>
prev && prev.id === t.id ? { ...prev, ...source } : prev
+1
View File
@@ -32,6 +32,7 @@ export function bidSourceSnapshot(tender, results, rows = sourceRows(tender, res
tender: tender?.ikn || tender?.id,
announcement: tender?.aciklama || '',
deadline: [tender?.tarih || '', tender?.saat || ''],
status: tender?.durum || '',
documentVersion: results?.documentVersion ?? tender?.documentVersion ?? null,
procurementTerms: results?.procurementTerms || null,
analysis: preparationAnalysisSource(results),
+10 -2
View File
@@ -1,11 +1,19 @@
export const tenderStateKey = t => String(t?.ikn || t?.id || '').trim();
export const TENDER_SOURCE_FIELDS = [['tarih','İhale tarihi'],['saat','İhale saati'],['durum','İhale durumu'],['baslik','İhale başlığı'],['kurum','İdare'],['alimTuru','Alım türü'],['documentVersion','Doküman sürümü']];
export function tenderSourceChanges(previous = {}, current = {}) {
return TENDER_SOURCE_FIELDS.flatMap(([field,label]) => {
const before = previous[field], after = current[field];
if (before == null || before === '' || after == null || after === '' || String(before) === String(after)) return [];
return [{field,label,before:String(before),after:String(after)}];
});
}
export const USER_STATE_FIELDS = ['takipte', 'incelendi', 'kanbanStatus', 'atananPersonel', 'gorev', 'notes', 'checklist', 'bidDraft'];
export function applyTenderStates(tenders, records = {}) {
const seen = new Set();
const result = tenders.map(t => {
const key = tenderStateKey(t); seen.add(key);
const record = records[key];
return record ? { ...t, ...record.data } : t;
return record ? { ...t, ...record.data, sourceChanges:tenderSourceChanges(record.snapshot,t) } : t;
});
for (const [key, record] of Object.entries(records)) {
if (!seen.has(key) && record.snapshot && (record.data.takipte || record.data.gorev || record.data.incelendi || record.data.bidDraft || record.data.notes?.length))
@@ -14,7 +22,7 @@ export function applyTenderStates(tenders, records = {}) {
return result;
}
export function tenderSnapshot(t) {
return Object.fromEntries(['id','ikn','baslik','kurum','tarih','saat','sehir','alimTuru'].map(k => [k,t[k] ?? '']));
return Object.fromEntries(['id','ikn','baslik','kurum','tarih','saat','sehir','alimTuru','durum','documentVersion'].map(k => [k,t[k] ?? '']));
}
export function publicTender(tender) {