Files
Investidor-V2/resources/js/pages/investor-path/context-start.tsx
T

262 lines
11 KiB
TypeScript

import ContextDocuments from '@/components/context-documents';
import {
SelectedComplements,
type Complement,
} from '@/components/investment-complements';
import { Link } from '@inertiajs/react';
import { useState } from 'react';
import { Frame, card, input, button } from '@/pages/investment/shared';
import {
contextApi,
type ContextReference,
type OpportunityChoice,
} from '@/lib/investor-context';
import { createOperationKey } from '@/lib/operation-key';
export default function ContextStart({
contexts,
source,
opportunityChoices = [],
step = null,
entryQuery = {},
entryComplements = [],
entrySubmission = null,
}: {
contexts: { id: string; title: string; version: number }[];
source: ContextReference | null;
opportunityChoices?: OpportunityChoice[];
step?: string | null;
entryQuery?: Record<string, string>;
entryComplements?: Complement[];
entrySubmission?: { id: string; version: number } | null;
}) {
const [chosen, setChosen] = useState('');
const [title, setTitle] = useState(
entryComplements[0]?.kind === 'need'
? `Preparação de ${entryComplements[0].title} — ${entryComplements[0].origin.title}`.slice(
0,
200,
)
: (source?.title ?? opportunityChoices[0]?.opportunity.title ?? ''),
);
const [consent, setConsent] = useState(false);
const [busy, setBusy] = useState(false);
const [error, setError] = useState('');
const [key] = useState(createOperationKey);
const sourceSuffix = opportunityChoices.length
? '?' +
opportunityChoices
.map(
(c) =>
`opportunities[]=${encodeURIComponent(c.opportunity.id)}`,
)
.join('&')
: source
? '?source=' + encodeURIComponent(source.key)
: '';
const suffix =
sourceSuffix || Object.keys(entryQuery).length
? (sourceSuffix || '?') +
(sourceSuffix ? '&' : '') +
'selection_key=' +
encodeURIComponent(key) +
'&' +
new URLSearchParams(entryQuery).toString()
: '';
const continueIn = async (id: string) => {
if (entrySubmission) {
const view = await contextApi<{ case: { version: number } }>(
`/investimentos/${id}/contexto`,
);
await contextApi(
`/investidor/manifestacoes/${entrySubmission.id}/contexto`,
{
case_id: id,
case_version: view.case.version,
version: entrySubmission.version,
},
);
}
window.location.assign(`/investimentos/${id}/contexto/editar${suffix}`);
};
return (
<Frame title="Iniciar ou continuar um investimento">
<SelectedComplements items={entryComplements} />
{!!opportunityChoices.length && (
<section className={card}>
<h2 className="font-bold">Oportunidades escolhidas</h2>
<ul>
{opportunityChoices.map((c) => (
<li key={c.opportunity.key}>
<Link
className="underline"
href={c.opportunity.href}
>
{c.opportunity.title}
</Link>{' '}
·{' '}
{c.territory?.title ??
'Localização por escolher'}
{c.portfolio_origins?.map((origin) => (
<p key={origin.id}>
Associação escolhida:{' '}
<Link
className="underline"
href={origin.href}
>
{origin.title}
</Link>
</p>
))}
</li>
))}
</ul>
<p>
Confirme a localização de cada ficha na comparação do
dossier. Ao continuar um dossier, as escolhas já
guardadas conservam-se.
</p>
</section>
)}
<p>
Ideia, oportunidade, sector e localização convergem no mesmo
dossier. A referência é para preparação e não confirma direitos
ou benefícios.
</p>
<ContextDocuments source={source ?? undefined} />
{source && !opportunityChoices.length && (
<section className={card}>
<h2 className="font-bold">A sua escolha</h2>
<Link className="underline" href={source.href}>
{source.title}
</Link>
{source.kind === 'portfolio' && (
<p>
Sector documentado:{' '}
{source.analysis?.documented_sector ??
'Por definir'}
. Cobertura documental:{' '}
{source.analysis?.documented_location ??
'Por definir'}
. Confirme o enquadramento e a localização do seu
investimento no dossier.
</p>
)}
</section>
)}
<section className={card + ' space-y-3'}>
{entrySubmission && (
<p>
Ao continuar, esta manifestação será associada ao
dossier escolhido, conservando a ficha de origem. Nenhum
pedido será submetido.
</p>
)}
<h2 className="text-xl font-bold">
Continuar um dossier existente
</h2>
<label className="grid gap-1">
Dossier
<select
className={input + ' max-w-full min-w-0'}
value={chosen}
onChange={(e) => setChosen(e.target.value)}
>
<option value="">Selecionar dossier autorizado</option>
{contexts.map((c) => (
<option key={c.id} value={c.id}>
{c.title}
</option>
))}
</select>
</label>
{chosen && entrySubmission && (
<button
className={button}
disabled={busy}
onClick={() => {
if (step && !source && !opportunityChoices.length) {
window.location.assign(
`/investimentos/${chosen}#${step}`,
);
return;
}
setBusy(true);
setError('');
void continueIn(chosen).catch((e) => {
setError(e.message);
setBusy(false);
});
}}
>
{step && !source && !opportunityChoices.length
? 'Abrir ' + step + ' no mesmo dossier'
: 'Preparar neste dossier'}
</button>
)}
{chosen && !entrySubmission && (
<Link
className={button}
href={
step && !source && !opportunityChoices.length
? `/investimentos/${chosen}#${step}`
: `/investimentos/${chosen}/contexto/editar${suffix}`
}
>
{step && !source && !opportunityChoices.length
? 'Abrir ' + step + ' no mesmo dossier'
: 'Preparar neste dossier'}
</Link>
)}
<p>
Se já preparou este investimento, continue nele. Não é
necessário criar outro dossier.
</p>
</section>
<form
className={card + ' space-y-3'}
onSubmit={(e) => {
e.preventDefault();
setBusy(true);
setError('');
void contextApi<{ id: string }>('/investimentos', {
title,
client_key: key,
reuse_consent: consent,
})
.then((r) => continueIn(r.id))
.catch((e) => setError(e.message))
.finally(() => setBusy(false));
}}
>
<h2 className="text-xl font-bold">Iniciar uma nova ideia</h2>
<p>
Organize a sua ideia e acompanhe a preparação do
investimento.
</p>
<label className="grid gap-1">
Título do investimento
<input
className={input}
maxLength={200}
required
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
</label>
<label>
<input
type="checkbox"
checked={consent}
onChange={(e) => setConsent(e.target.checked)}
/>{' '}
Autorizo reutilizar o meu perfil neste dossier privado.
</label>
<button className={button} disabled={!consent || busy}>
Criar dossier e preparar investimento
</button>
{error && <p role="alert">{error}</p>}
</form>
</Frame>
);
}