262 lines
11 KiB
TypeScript
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>
|
|
);
|
|
}
|