import { inputText } from '../lib/input-text.ts'; import { InvestmentConsumerIdentity } from './investment-consumer-identity'; import InvestmentRequirements from './investment-requirements'; import { useEffect, useRef, useState } from 'react'; import { InvestmentContextAssessment } from './investment-context-assessment'; import { Link } from '@inertiajs/react'; import { contextApi, contextFieldNames, type ContextView, } from '@/lib/investor-context'; import { inheritCompatibleFields } from '@/lib/context-inheritance'; import OpportunityChoices from './investment-opportunity-choices'; import { SelectedComplements } from './investment-complements'; type Props = { contextId?: string | null; consumer: 'simulator' | 'land' | 'desk' | 'submission'; values: Record; enabled?: boolean; readOnly?: boolean; allowedFields?: string[]; persistInheritance?: boolean; boundRevision?: number; initialOpportunity?: string; onApply: (patch: Record, replace: boolean) => void; onReview?: (revision: number, reviewed: boolean) => void; }; const geo = ['province_id', 'district_id', 'admin_post_id', 'locality_id']; const empty = (v: unknown) => v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0); const text = (v: unknown) => typeof v === 'string' ? v : JSON.stringify(v ?? ''); function savedOpportunity(values: Record): string { if (values.context_opportunity) return inputText(values.context_opportunity); try { return ( JSON.parse(inputText(values.context_applicability_snapshot ?? '')) .consumer_opportunity ?? '' ); } catch { return ''; } } const displayField = (values: Record, key: string) => key.endsWith('_id') ? text(values[`${key}_label`]) || (empty(values[key]) ? 'não informado' : 'Referência escolhida; designação por recuperar') : text(values[key]) || 'não informado'; export function DossierPrefill(props: Props) { const { contextId, consumer, enabled = true, readOnly = false, boundRevision = 0, } = props; const latest = useRef(props); latest.current = props; const [view, setView] = useState(null); const [error, setError] = useState(''); const [retry, setRetry] = useState(0); const [selected, setSelected] = useState([]); const [reviewed, setReviewed] = useState(false); const [message, setMessage] = useState(''); const userChose = useRef(false); const [opportunity, setOpportunity] = useState(() => String( props.initialOpportunity || (typeof window !== 'undefined' ? new URLSearchParams(window.location.search).get( 'opportunity', ) || '' : '') || savedOpportunity(props.values), ), ); useEffect(() => { if (!userChose.current && !opportunity && enabled) { const saved = savedOpportunity(props.values); if (saved) setOpportunity(saved); } }, [enabled, props.values, opportunity]); const loadedOpportunity = useRef(''); useEffect(() => { if (!contextId) return; let stopped = false; setView(null); setError(''); void contextApi( `/investimentos/${contextId}/contexto${opportunity ? '?opportunity=' + encodeURIComponent(opportunity) : ''}`, ) .then((v) => { if (!stopped) { loadedOpportunity.current = opportunity; setView(v); setReviewed(false); } }) .catch((e) => { if (!stopped) setError(e.message); }); return () => { stopped = true; }; }, [contextId, retry, opportunity]); useEffect(() => { if ( !view || loadedOpportunity.current !== opportunity || view.case.id !== contextId || !enabled || readOnly || !view.can_write ) return; const choices = view.context.opportunity_choices ?? []; const chosen = opportunity || (choices.length === 1 ? choices[0].opportunity.key : ''); const source = view.prefill[consumer] ?? {}; const now = latest.current; if ( (chosen || consumer === 'simulator') && now.values.context_opportunity !== chosen && (!now.allowedFields || now.allowedFields.includes('context_opportunity')) ) now.onApply({ context_opportunity: chosen }, true); const inherited = inheritCompatibleFields( `dossier:${contextId}:${consumer}`, now.values, source, now.values.context_reuse, now.allowedFields, ); if ( Object.keys(inherited.patch).length || (now.persistInheritance !== false && now.values.context_reuse !== inherited.metadata) ) { // The shared reconciliation has already selected safe fields; metadata travels with the same saved form. now.onApply( { ...inherited.patch, ...(now.persistInheritance === false ? {} : { context_reuse: inherited.metadata }), }, true, ); setMessage( 'Dados compatíveis reutilizados do mesmo dossier. Os valores herdados acompanham o contexto; as suas alterações locais foram preservadas.', ); } setReviewed(true); now.onReview?.(view.context.revision, true); }, [view, enabled, readOnly, contextId, consumer, props.values]); if (!contextId) return null; if (error) return (

{error} Os dados do formulário foram preservados.

); if (!view) return (

A recuperar os dados autorizados do dossier…

); const source = Object.fromEntries( Object.entries(view.prefill[consumer] ?? {}).filter( ([k]) => !props.allowedFields || props.allowedFields.includes(k), ), ); const chosenKey = opportunity || (view.context.opportunity_choices?.length === 1 ? view.context.opportunity_choices[0].opportunity.key : ''); const chosenChoice = view.context.opportunity_choices?.find( (c) => c.opportunity.key === chosenKey, ); const differences = Object.keys(source).filter( (k) => k !== 'context_applicability_snapshot' && !k.endsWith('_label') && text(props.values[k]) !== text(source[k]), ); const linkedRevision = consumer === 'simulator' ? (view.simulator_context_revision ?? 0) : boundRevision; const stale = view.context.revision !== linkedRevision && !reviewed; return (

Dados do seu investimento

{view.case.title} {' · '} Voltar ao dossier

{(opportunity || view.context.opportunity_choices?.length === 1) && ( )} {contextId && ( step.state === 'dispensed') .map((step) => step.code)} assessment={ view.context.requirements_assessment ? { ...view.context.requirements_assessment, requirements: view.context.requirements_assessment.requirements.filter( (r) => r.opportunity_key === chosenKey, ), } : null } /> )} {!!view.context.opportunity_choices?.length && ( )} {stale && (

{linkedRevision > 0 ? 'Os dados do dossier mudaram desde a última análise.' : 'Confira os valores deste formulário para o contexto atual; não há uma revisão anterior vinculada a estas entradas.'}{' '} Os valores e resultados anteriores permanecem guardados; confira os pressupostos antes de os usar no cenário atual.

)} {message &&

{message}

} {!!chosenChoice && ( c.opportunity.key === chosenKey, )} /> )} {consumer !== 'simulator' && chosenChoice?.opportunity.fields.sector && (

Sector desta oportunidade:{' '} {chosenChoice.opportunity.fields.sector}

)} {Object.entries(view.context.selection) .filter( ([slot]) => !view.context.opportunity_choices?.length || ![ 'opportunity', 'territory', 'park', ...(consumer === 'simulator' ? [] : ['sector']), ].includes(slot), ) .map( ([, r]) => r && (

{r.title}

), )} {!readOnly && view.can_write && differences.length > 0 && (
Comparar com os campos já preenchidos

Os seus valores conservam-se por defeito. Selecione apenas os campos que pretende substituir; o formulário continua a precisar de ser guardado/submetido pela ação existente.

{differences.map((k) => ( ))}
Substituir Valor atual Valor proposto pelo dossier
{displayField(props.values, k)} {displayField(source, k)}
)} {!readOnly && reviewed && (

Os dados disponíveis foram recuperados. Preencha o que falta; as suas alterações conservam-se.

)}

Associar uma referência não confirma incentivos, licenças, terra disponível, reserva ou autorização.

); }