Files
ihaleist/src/components/TenderSourceHistory.jsx
T

41 lines
3.4 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, {useEffect,useRef,useState} from 'react';
import {getToken} from '../services/auth';
const labels={baslik:'Başlık',kurum:'İdare',tarih:'Tarih',saat:'Saat',durum:'Durum',alimTuru:'Alım türü',aciklama:'İlan metni',documentVersion:'Doküman sürümü'};
export function TenderSourceHistory({tender}) {
const [state,setState]=useState({records:[],nextCursor:null,loaded:false,error:null,loading:false});
const active=useRef(null);
useEffect(()=>()=>{const pending=active.current;active.current=null;pending?.abort();},[]);
const load=async(before=null)=>{
if(active.current)return;
const controller=new AbortController();active.current=controller;
const token=getToken(),timer=setTimeout(()=>controller.abort(),30000);
setState(s=>({...s,loading:true,error:null}));
try {
const query=new URLSearchParams({ikn:tender.ikn,kurum:tender.kurum || ''});if(before)query.set('before',before);
const res=await fetch('/api/tenders/source-history?'+query,{headers:{Authorization:`Bearer ${token}`},signal:controller.signal});
const data=await res.json();
if(!res.ok || !data.success || !Array.isArray(data.records))throw new Error(data.error || 'Kaynak geçmişi alınamadı.');
if(!controller.signal.aborted && getToken()===token)setState(s=>({records:before?[...s.records,...data.records]:data.records,nextCursor:data.nextCursor,loaded:true,error:null,loading:false}));
} catch(error) {
if(active.current===controller && getToken()===token)setState(s=>({...s,loading:false,error:controller.signal.aborted?'Kaynak geçmişi zamanında alınamadı. Yeniden deneyin.':error.message}));
} finally {clearTimeout(timer);if(active.current===controller)active.current=null;}
};
return <details className="p-3 border-b text-sm">
<summary className="cursor-pointer font-semibold">Kaynak değişiklik geçmişi</summary>
<p className="mt-2 text-xs text-slate-600">Uygulamanın gözlemlediği sürümler gösterilir. Gözlem zamanı resmi değişiklik tarihi değildir; kayıt öncesindeki veya iki kontrol arasındaki değişiklikler bulunmayabilir. Farklı kaynaklar ayrı izlenir.</p>
{!state.loaded && <button onClick={()=>load()} disabled={state.loading} className="mt-2 px-3 py-2 border rounded">Geçmişi yükle</button>}
{state.loading && <p role="status">Kaynak geçmişi yükleniyor…</p>}
{state.error && <div role="alert"><p>{state.error}</p><button onClick={()=>load(state.loaded?state.nextCursor:null)} disabled={state.loading} className="underline py-2">Yeniden dene</button></div>}
{state.loaded && !state.records.length && <p className="mt-2">Henüz gözlem kaydı yok. Bu, ihale bilgilerinin hiç değişmediğini göstermez.</p>}
<ol className="space-y-3 mt-3">{state.records.map(record=><li key={record.id} className="border rounded p-2">
<p>{new Date(record.observedAt).toLocaleString('tr-TR')} · {record.sourceId}</p>
{!record.changes.length?<p>Bu kaynak için ilk gözlem.</p>:record.changes.map(change=><details key={change.field} className="mt-1">
<summary className="cursor-pointer">{labels[change.field] || change.field} değişti</summary>
<p className="whitespace-pre-wrap break-words">Önce: {change.before ?? 'Bilinmiyor'}</p>
<p className="whitespace-pre-wrap break-words">Sonra: {change.after ?? 'Bilinmiyor'}</p>
</details>)}
</li>)}</ol>
{state.nextCursor && <button onClick={()=>load(state.nextCursor)} disabled={state.loading} className="mt-2 px-3 py-2 border rounded">Daha eski kayıtlar</button>}
</details>;
}