Files
ihaleist/src/components/tools/DeliveryQueue.jsx
T

50 lines
5.1 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 {useApp} from '../../context/AppContext';
import {getToken} from '../../services/auth';
import {accountRequest,requireArray} from '../../services/accountRequest';
export function DeliveryQueue({weekly=false}){
const {isAdmin,authUser}=useApp();
return isAdmin?<Queue weekly={weekly} key={`${authUser.email}:${getToken()}:${weekly}`}/>:null;
}
function Queue({weekly}){
const endpoint=weekly?'/api/admin/brief/outbox':'/api/admin/notify/outbox';
const [rows,setRows]=useState(null),[error,setError]=useState(null),[busy,setBusy]=useState(false);
const alive=useRef(true),locked=useRef(false);
const load=async()=>{
const data=await accountRequest(endpoint);
const received=requireArray(data,'deliveries');
const rows=received.filter(row=>row && typeof row==='object' && typeof row.id==='string' && row.id.trim() && typeof row.state==='string' && (row.subject == null || typeof row.subject==='string') && (row.to == null || ['string','number'].includes(typeof row.to)) && (row.error == null || typeof row.error==='string') && (row.providerId == null || typeof row.providerId==='string') && (row.review == null || (typeof row.review==='object' && typeof row.review.actor==='string' && typeof row.review.note==='string' && Number.isFinite(Date.parse(row.review.at)))));
if(rows.length!==received.length)throw new Error('Sunucu gönderim kayıtlarından birini geçersiz döndürdü. Liste yenilenemedi.');
if(alive.current)setRows(rows);
};
const act=async fn=>{if(locked.current)return;locked.current=true;setBusy(true);setError(null);try{await fn();}catch(e){if(alive.current)setError(e.message);}finally{locked.current=false;if(alive.current)setBusy(false);}};
useEffect(()=>{alive.current=true;void act(load);return()=>{alive.current=false;};},[]);
return <section role="region" aria-label={weekly?'Haftalık özet gönderim incelemesi':'E-posta gönderim incelemesi'} aria-busy={busy} className="bg-white border rounded-xl p-5 space-y-3">
<h3 className="font-bold">{weekly?'Haftalık özet gönderim incelemesi':'E-posta gönderim incelemesi'} · Yönetici</h3>
<p className="text-sm">{weekly?'Haftalık özetin bekleyen mesajları ve inceleme kararları gösterilir.':'Bekleyen işler ve son inceleme kararları gösterilir (en fazla 50).'} Belirsiz gönderimi sağlayıcı kaydıyla karşılaştırın. Bu işlemler yeni mesaj göndermez.</p>
<button type="button" disabled={busy} onClick={()=>act(load)} className="border rounded px-3 py-2">Gönderim listesini yenile</button>
{busy&&<p role="status">Gönderim kayıtları işleniyor…</p>}
{error&&<p role="alert" className="text-red-700">{error}</p>}
{rows?.length===0&&<p>İncelenecek veya bekleyen gönderim yok.</p>}
{rows?.map(row=><Review key={row.id} row={row} weekly={weekly} busy={busy} resolve={input=>act(async()=>{await accountRequest(endpoint,{method:'POST',body:JSON.stringify({id:row.id,...input})});await load();})}/>)}
</section>;
}
function Review({row,weekly,busy,resolve}){
const [note,setNote]=useState(''),[providerId,setProviderId]=useState(''),[confirmed,setConfirmed]=useState(false);
const labels={pending:'Bekliyor',sending:'Gönderiliyor',uncertain:'Sonuç belirsiz',sent_manual:'Gönderildiği yönetici tarafından doğrulandı',skipped:'Yeniden gönderilmeden kapatıldı'};
return <div className="border rounded p-3 space-y-2 text-sm">
<p className="font-bold">{row.subject}</p><p>{String(row.to)} · {labels[row.state]}</p><p className="break-all">Kayıt: {row.id}</p>
{row.error&&<p>{row.error}</p>}
{row.providerId&&<p className="break-all">Sağlayıcı kaydı: {row.providerId}</p>}
{row.review&&<p>{row.review.actor} · {new Date(row.review.at).toLocaleString('tr-TR', { timeZone: 'Europe/Istanbul' })} · {row.review.note}</p>}
{row.state==='uncertain'&&<fieldset disabled={busy} className="space-y-2">
<label className="block">Kontrol açıklaması<textarea className="block border w-full p-2" value={note} onChange={e=>setNote(e.target.value)} minLength={20}/></label>
<label className="block">Sağlayıcı gönderim kimliği<input className="block border w-full p-2" value={providerId} onChange={e=>setProviderId(e.target.value)}/></label>
<label className="block"><input type="checkbox" checked={confirmed} onChange={e=>setConfirmed(e.target.checked)}/> Sağlayıcı kaydında bu gönderimin kabul edildiğini kontrol ettim.</label>
<button type="button" disabled={note.trim().length<20||!providerId.trim()||!confirmed} onClick={()=>resolve({action:'confirmed_sent',note,providerId,confirmed})} className="border rounded p-2 mr-2">Gönderildi olarak kapat</button>
<button type="button" disabled={note.trim().length<20} onClick={()=>resolve({action:'skip',note})} className="border rounded p-2">Yeniden göndermeden kapat</button>
<p>{weekly?'İkinci seçenek bu mesajı yeniden göndermeden kapatır; teslim edildiği iddia edilmez. Diğer bekleyen mesajlar ve sonraki haftalar bu kararla kapatılmaz.':'İkinci seçenek bu grubu tekrar göndermez; teslim edildiği iddia edilmez. Sonraki yeni ihaleler için abonelik devam eder.'}</p>
</fieldset>}
</div>;
}