import {useEffect,useState} from 'react'; import {button,control,Field} from '@/pages/management/shared'; import {createOperationKey} from '@/lib/operation-key'; import type {ProactiveAnalysis} from './proactive-investment'; type Observation={id:string;name:string;province:string;district:string;territory_id:string;cae:string;activity:string;sector:string;source_date:string;sheet:string;row_number:number;source_hash:string;source_name:string;source_period:string;identity_conflict:boolean}; type Result={installed:boolean;rows:Observation[];total:number|null;duplicate_sightings?:number;page?:number;per_page?:number;sectors?:string[];territory_coverage?:{unmapped:number;province_only:number};limitations:string;status:string}; export function ProactiveSupplyBrowser({value,onChange,territoryId,recordId}:{value:ProactiveAnalysis;onChange:(v:ProactiveAnalysis)=>void;territoryId?:string;recordId?:number}){ const [activity,setActivity]=useState('');const [sector,setSector]=useState(''); const [result,setResult]=useState(null);const [busy,setBusy]=useState(false);const [error,setError]=useState(''); const [query,setQuery]=useState<{territory:string;activity:string;sector:string;page:number}|null>(null); useEffect(()=>{setResult(null);setQuery(null);setSector('');setError('');setBusy(false);},[territoryId]); useEffect(()=>{ if(!query)return;const controller=new AbortController();setBusy(true);setError(''); const p=new URLSearchParams({territory_id:query.territory,activity:query.activity,sector:query.sector,page:String(query.page)});if(recordId)p.set('record_id',String(recordId)); fetch('/minhas-oportunidades/oferta-interna?'+p,{headers:{Accept:'application/json'},credentials:'same-origin',signal:controller.signal}) .then(async r=>{if(!r.ok)throw new Error(r.status===403?'Consulta interna fora do âmbito de acesso desta sessão.':'Não foi possível consultar a base interna. A oferta permanece por determinar.');return r.json() as Promise;}) .then(setResult).catch(e=>{if(e.name!=='AbortError'){setResult(null);setError(e.message);}}).finally(()=>{if(!controller.signal.aborted)setBusy(false);}); return ()=>controller.abort(); },[query,recordId]); const selected=value.supply_comparisons??[]; const compare=(row:Observation)=>{ if(selected.some(c=>c.observation_id===row.id))return; const proof=value.evidence.find(e=>e.observation_id===row.id); onChange({...value,supply_comparisons:[...selected,{observation_id:row.id,relationship:'uncertain',rationale:'',limitations:'Actividade actual, capacidade, procura e disponibilidade para parceria por confirmar.'}],evidence:proof?value.evidence:[...value.evidence,{ id:createOperationKey(),observation_id:row.id,category:'supply',purpose:'local',access:'internal',document_id:'', statement:`Registo administrativo: ${row.name}; CAE ${row.cae}; ${row.activity||'actividade por classificar'}; ${row.district}, ${row.province}. Não confirma actividade actual.`, interpretation:'',source:`${row.source_name}; SHA256 ${row.source_hash}`,locator:`${row.sheet}!linha ${row.row_number}`, period:`${row.source_date}; ${row.source_period}`,scope:`${row.district}, ${row.province}`, coverage:result?.limitations??'Cobertura incompleta; situação actual por confirmar.',verified_on:new Date().toISOString().slice(0,10), }]}); }; return
Consultar oferta existente — base interna

Consulta a localização escolhida nesta ficha e os seus territórios subordinados. Os filtros por sector e actividade CAE não limitam a análise ao sector da ideia: podem existir concorrentes, complementos e parceiros noutros sectores. Nenhuma empresa é publicada.

setActivity(e.target.value)}/> {!territoryId&&

Escolha a localização para consultar. Sem localização, a oferta permanece por determinar.

} {error&&

{error}

} {result&&<>

{result.status}

{result.limitations}

{result.territory_coverage&&

Cobertura territorial da base nacional: {result.territory_coverage.unmapped} observações sem correspondência territorial única; {result.territory_coverage.province_only} apenas com província. Estas últimas não comprovam oferta num distrito específico.

}{result.total!==null&&

{result.total} observações distintas; {result.duplicate_sightings??0} repetições dos mesmos campos administrativos conservadas na origem. Não é uma contagem de empresas únicas.

} {result.rows.map(row=>

{row.name}

{row.district}, {row.province} · {row.sector||'Sector por classificar'} · CAE {row.cae||'não indicado'} · {row.activity||'Actividade por classificar'}

Fonte: {row.source_name} · {row.sheet}, linha {row.row_number} · {row.source_date} · {row.source_period}

Rastreabilidade do exemplar

SHA256: {row.source_hash}

Observação: {row.id}

{row.identity_conflict&&

Identificador partilhado por denominações divergentes; identidade por conferir. Os registos não foram fundidos.

}
)} {query&&
Página {result.page??1}
} } {selected.map((c,i)=>{const proof=value.evidence.find(e=>e.observation_id===c.observation_id);const patch=(p:Partial)=>onChange({...value,supply_comparisons:selected.map(x=>x.observation_id===c.observation_id?{...x,...p}:x)});return
Comparação {i+1}

{proof?.statement??'Evidência retirada: volte a associar a observação antes de guardar.'}

{proof?.source} · {proof?.locator}

Ideia em preparação: {value.idea.solution||'Descreva a ideia no campo existente abaixo.'}