import React,{useEffect,useRef,useState} from 'react'; const labels={clients:'Clientes',services:'Serviços',service_drafts:'Prestações em rascunho',billing_drafts:'Rascunhos de facturação'}; const moduleName=(id,modules)=>modules.find(m=>m.id===id)?.label||id; export function AssociationImpact({review,modules}) { const names=values=>values.length?values.map(id=>moduleName(id,modules)).join(', '):'Sem associação'; return

Conferir antes de confirmar

{review.record.name} · #{review.record.id} · versão {review.record.version}

Antes: {names(review.before)}

Depois: {names(review.after)}

Fundamento: {review.reason}

{review.impact}

{review.warnings?.map(w=>

{w}

)}

Registo e dependências conferidos

Histórico recente (até 20 eventos)

{review.history.length?:

Sem eventos anteriores.

}
; } export default function ModuleRecordsWorkspace(props) { return ; } function Queue({context,can,api}) { const areas=Object.keys(labels).filter(a=>can(`${a}.view`,a.endsWith('_drafts')?context.unit?.id??null:null)&&(!a.endsWith('_drafts')||context.unit)); const [area,setArea]=useState(areas[0]||'clients'),[state,setState]=useState('pending'),[search,setSearch]=useState(''),[query,setQuery]=useState(''),[page,setPage]=useState(1); const [data,setData]=useState(null),[error,setError]=useState(''),[busy,setBusy]=useState(false),[loading,setLoading]=useState(false),[review,setReview]=useState(null),[message,setMessage]=useState(''),[refresh,setRefresh]=useState(0); const generation=useRef(0); useEffect(()=>{const current=++generation.current;setLoading(true);setData(null);setReview(null);setError(''); const params=new URLSearchParams({area,state,search:query,page:String(page),per_page:'25'}); api(`/api/module-records?${params}`).then(result=>{if(current===generation.current)setData(result);}).catch(e=>{if(current===generation.current)setError(e.message);}).finally(()=>{if(current===generation.current)setLoading(false);}); return ()=>{generation.current++;}; },[context.token,area,state,query,page,refresh]); async function preview(e,row){e.preventDefault();setBusy(true);setError('');setMessage('');setReview(null);const current=generation.current; try{const result=await api('/api/module-records/preview','POST',{area,id:row.id,version:row.version,...Object.fromEntries(new FormData(e.currentTarget))});if(current===generation.current)setReview(result);}catch(e){setError(e.message);}finally{setBusy(false);}} async function confirm(){setBusy(true);setError('');try{const result=await api('/api/module-records','POST',{review_token:review.review_token});setReview(null);setMessage(result.replayed?'Decisão já registada; repetição reconhecida sem duplicação.':'Decisão individual registada. Dependências preservadas.');setRefresh(n=>n+1);}catch(e){setError(`${e.message} Pode repetir a confirmação se a resposta se perdeu; se o servidor indicar mudança, cancele e faça nova conferência.`);}finally{setBusy(false);}} function reset(set,value){set(value);setPage(1);setReview(null);} return

Conferência de associações de módulos

Opções gerais da empresa. Apenas registos do âmbito autorizado; os rascunhos pertencem à unidade activa: {context.unit?.name||'nenhuma seleccionada'}.

Cada decisão é individual e auditada. Não altera direitos, documentos ou responsabilidade financeira e não associa dependências automaticamente.

{error&&

{error}

}{message&&

{message}

}
Filtros da fila
{e.preventDefault();reset(setQuery,search);}}>
{loading&&

A carregar…

}{data&&<>

{data.pagination.total} registos · página {data.pagination.page} de {data.pagination.last_page}

{(data.records[area]||[]).map(row=>

#{row.id} · {row.name} · versão {row.version}

Associações: {row.modules.length?row.modules.map(id=>moduleName(id,data.modules)).join(', '):'Sem associação activa — exige decisão explícita.'}

Dependências

{row.dependencies_restricted?

Conferência bloqueada: dependência fora do âmbito de consulta autorizado.

:row.dependencies.length?
    {row.dependencies.map(d=>
  • {labels[d.area]} #{d.id} · versão {d.version} · {d.modules.map(id=>moduleName(id,data.modules)).join(', ')||'Sem associação'}
  • )}
:

Sem dependências explícitas neste percurso.

} {!row.dependencies_restricted&&can('access.manage')&&can(`${area}.edit`,area.endsWith('_drafts')?context.unit?.id??null:null)&&
preview(e,row)} onChange={()=>setReview(null)}>
Decisão individual