Files
ihaleist/src/components/DocumentTextReview.jsx
T

79 lines
5.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 {getDocumentTextReview,saveDocumentTextReview} from '../services/account';
import {getToken} from '../services/auth';
export function DocumentTextReview({documentId,extractedText,onAnalyze}) {
const [source,setSource]=useState(null);
const [text,setText]=useState(extractedText || '');
const [note,setNote]=useState('');
const [compared,setCompared]=useState(false);
const [busy,setBusy]=useState(false);
const [error,setError]=useState(null);
const [saved,setSaved]=useState(null);
const [analyzing,setAnalyzing]=useState(false);
const live=useRef(true);
const sequence=useRef(0);
const load=async()=>{
const request=++sequence.current, token=getToken();
setBusy(true);setError(null);
try {
const data=await getDocumentTextReview(documentId);
if(!live.current || request!==sequence.current || token!==getToken())return;
setSource(data);
// A stale source must be compared afresh; do not seed from an old correction.
setText(!data.stale && data.review ? data.review.corrected_text : extractedText || '');
setNote(!data.stale && data.review ? data.review.review_note : '');
setCompared(false);setSaved(null);
} catch(e) {if(live.current && request===sequence.current && token===getToken())setError(e.message);}
finally {if(live.current && request===sequence.current && token===getToken())setBusy(false);}
};
useEffect(()=>{live.current=true;load();return()=>{live.current=false;sequence.current++;};},[documentId]);
const save=async()=>{
if(!source || busy)return;
const token=getToken();setBusy(true);setError(null);setSaved(null);
try {
const result=await saveDocumentTextReview(documentId,{fileHash:source.fileHash,
expectedRevision:source.review?.revision || 0,correctedText:text,note,allPagesCompared:compared});
if(!live.current || token!==getToken())return;
setSource(result);setSaved(result.review);setCompared(false);
} catch(e) {if(live.current && token===getToken())setError(e.message);}
finally {if(live.current && token===getToken())setBusy(false);}
};
const analyze=async()=>{
if(!source?.review || source.stale || busy || analyzing)return;
const token=getToken();setAnalyzing(true);setError(null);
try {await onAnalyze({documentId,revision:source.review.revision});}
catch(e) {if(live.current && token===getToken())setError(e.message);}
finally {if(live.current && token===getToken())setAnalyzing(false);}
};
return <section aria-label="Belge metni incelemesi" className="border-t pt-3 space-y-2">
<h5 className="font-bold text-sm">Metni karşılaştır ve düzelt</h5>
<p className="text-xs text-slate-600">Belgenin tüm sayfalarını açıp metin, miktar ve birimleri karşılaştırın. Bu kayıt kullanıcı incelemesidir; resmî onay veya e-imza değildir. Kaydetmek tek başına teklif dosyasını hazır yapmaz.</p>
{source?.stale && <p role="alert" className="text-xs text-amber-800">Kaynak dosya değişmiş. Önceki inceleme geçerli değil; tüm sayfaları yeniden karşılaştırın.</p>}
{source?.review && <p className="text-xs text-slate-500">Son kayıt: sürüm {source.review.revision} · {new Date(source.review.reviewed_at).toLocaleString('tr-TR')}</p>}
<label className="block text-xs font-semibold">Kontrol edilen metin
<textarea value={text} onChange={e=>{setText(e.target.value);setCompared(false);setSaved(null);}} disabled={busy || analyzing}
className="block w-full h-64 border rounded p-2 font-mono font-normal mt-1" />
</label>
<label className="block text-xs font-semibold">Karşılaştırılan sayfalar ve düzeltmeler
<textarea value={note} onChange={e=>{setNote(e.target.value);setCompared(false);setSaved(null);}} disabled={busy || analyzing}
placeholder="Örnek: Sayfa 1–3 karşılaştırıldı; 2. sayfadaki miktar 100 olarak düzeltildi."
className="block w-full border rounded p-2 font-normal mt-1" />
</label>
<label className="flex gap-2 text-xs"><input type="checkbox" checked={compared} onChange={e=>setCompared(e.target.checked)} disabled={busy || analyzing}/>
Bu metni kaynak dosyanın tüm sayfalarıyla karşılaştırdım.</label>
<button onClick={save} disabled={busy || analyzing || !source || !compared || text.trim().length<40 || note.trim().length<20}
className="text-xs bg-blue-700 text-white px-3 py-2 rounded disabled:opacity-40">{busy ? 'İşleniyor…' : 'İncelemeyi kaydet'}</button>
{onAnalyze && source?.review && !source.stale && <button onClick={analyze}
disabled={busy || analyzing || text.trim()!==source.review.corrected_text || note.trim()!==source.review.review_note}
className="ml-2 text-xs bg-amber-500 px-3 py-2 rounded disabled:opacity-40">
{analyzing ? 'İncelenmiş metin analiz ediliyor…' : 'Kaydedilmiş incelemeyi analiz et'}
</button>}
{error && <div role="alert" className="text-xs text-red-700">{error}
<p>Metin taslağınız bu ekranda korunuyor. Sürüm değiştiyse taslağı kopyalayıp güncel kaydı yükleyin.</p>
<button onClick={load} disabled={busy || analyzing} className="underline">Güncel kaydı yükle (taslağı değiştirir)</button>
</div>}
{saved && <p role="status" className="text-xs text-green-800">İnceleme sürüm {saved.revision} sunucuda kaydedildi. Analiz ve teklif kontrolleri ayrıca tamamlanmalıdır.</p>}
</section>;
}