import { useEffect, useState } from 'react'; import { Link } from '@inertiajs/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 [loaded, setLoaded] = useState<{ key: string; data: Result } | null>( null, ); const [busy, setBusy] = useState(false); const [error, setError] = useState(''); const [query, setQuery] = useState<{ territory: string; activity: string; sector: string; page: number; } | null>(null); const requestKey = query?.territory === territoryId ? JSON.stringify([recordId, query]) : ''; const result = requestKey && loaded?.key === requestKey ? loaded.data : null; useEffect(() => { setLoaded(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((data) => { if (!controller.signal.aborted) setLoaded({ key: JSON.stringify([recordId, query]), data }); }) .catch((e) => { if (!controller.signal.aborted && e.name !== 'AbortError') { setLoaded(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 Conferir origens, repetições e correspondências por resolver

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.'}