Files
Investidor-V2/resources/js/pages/profiles/request.tsx
T
2026-11-02 20:31:15 +02:00

215 lines
8.2 KiB
TypeScript

import { createOperationKey } from '@/lib/operation-key';
import { Head, Link, router } from '@inertiajs/react';
import { useState } from 'react';
import ProfileNavigation from '@/components/profile-navigation';
import { profileJson } from '@/lib/profile-json';
import { button, control } from '@/pages/management/shared';
import { modalityLabels } from '@/components/opportunity-search-filters';
import ProfileProofPicker from '@/components/profile-proof-picker';
const representations: Record<string, string> = {
individual: 'Em nome próprio',
company: 'Empresa',
public_entity: 'Entidade pública',
association: 'Associação',
partner: 'Parceiro ou representante',
};
const requestStates: Record<string, string> = {
pending: 'Em análise',
approved: 'Aprovado',
rejected: 'Devolvido ou recusado',
cancelled: 'Cancelado',
};
type RequestEntry = {
id: string;
status: string;
reason: string;
decision_reason: string | null;
created_at: string;
};
export default function RequestProfile({
requests,
types,
organizations,
documents,
}: {
requests: RequestEntry[];
types: string[];
organizations: { id: string; name: string }[];
documents: { id: string; file_name: string }[];
}) {
const [representation, setRepresentation] = useState('individual');
const [organization, setOrganization] = useState('');
const [selected, setSelected] = useState<string[]>([]);
const [proofs, setProofs] = useState<string[]>([]);
const [reason, setReason] = useState('');
const [key, setKey] = useState(() => createOperationKey());
const [message, setMessage] = useState('');
const [busy, setBusy] = useState(false);
async function send() {
setBusy(true);
setMessage('');
try {
const result = await profileJson('/perfil/promotor', {
creation_key: key,
representation_type: representation,
organization_id:
representation === 'individual' ? null : organization,
opportunity_types: selected,
document_ids: proofs,
reason,
});
setMessage(result.message);
setKey(createOperationKey());
router.reload();
} catch (error) {
setMessage(
error instanceof Error
? error.message
: 'Resposta indisponível. Confira o acompanhamento antes de repetir.',
);
} finally {
setBusy(false);
}
}
const toggle = (values: string[], id: string) =>
values.includes(id) ? values.filter((v) => v !== id) : [...values, id];
return (
<main className="space-y-6 p-6">
<Head title="Perfil de Promotor" />
<ProfileNavigation />
<h1 className="text-2xl font-semibold">
Solicitar perfil de Promotor
</h1>
<p>
Indique em nome de quem vai actuar, as modalidades que pretende
preparar e os comprovativos do pedido. Pode acompanhar a decisão
nesta página. A submissão do pedido não activa o perfil.
</p>
<form
className="max-w-2xl space-y-4"
onSubmit={(e) => {
e.preventDefault();
void send();
}}
>
<label className="block">
Em nome de quem vai actuar?
<select
className={control}
value={representation}
onChange={(e) => setRepresentation(e.target.value)}
>
{[
'individual',
'company',
'public_entity',
'association',
'partner',
].map((v) => (
<option key={v} value={v}>
{representations[v]}
</option>
))}
</select>
</label>
{representation !== 'individual' && (
<label className="block">
Organização representada
<select
required
className={control}
value={organization}
onChange={(e) => setOrganization(e.target.value)}
>
<option value="">Selecionar</option>
{organizations.map((o) => (
<option key={o.id} value={o.id}>
{o.name}
</option>
))}
</select>
</label>
)}
<fieldset>
<legend>Que oportunidades pretende preparar?</legend>
<div className="grid gap-2 sm:grid-cols-2">
{types.map((type) => (
<label
key={type}
className="flex gap-2 rounded border p-3"
>
<input
type="checkbox"
checked={selected.includes(type)}
onChange={() =>
setSelected(toggle(selected, type))
}
/>{' '}
{modalityLabels[type] ?? 'Outra modalidade'}
</label>
))}
</div>
</fieldset>
<ProfileProofPicker
documents={documents}
value={proofs}
onChange={setProofs}
disabled={busy}
/>
{!documents.length && (
<p>
Sem comprovativos próprios disponíveis. Pode anexar ao
seu dossier no{' '}
<Link
className="underline"
href="/balcao-virtual/painel"
>
Balcão
</Link>
; o ficheiro precisa de análise antimalware concluída.
</p>
)}
<label className="block">
Para que actividades precisa do perfil de Promotor?
<textarea
required
minLength={20}
maxLength={1000}
className={control}
value={reason}
onChange={(e) => setReason(e.target.value)}
/>
</label>
<button disabled={busy} className={button}>
Submeter pedido de perfil
</button>
</form>
<p role="status" aria-live="polite">
{message}
</p>
<section>
<h2 className="text-xl font-semibold">
Acompanhamento dos meus pedidos
</h2>
{requests.map((r) => (
<article key={r.id} className="border-b py-3">
<p>
Pedido de{' '}
{new Date(r.created_at).toLocaleDateString('pt-MZ')}{' '}
—{' '}
{requestStates[r.status] ?? 'Estado por consultar'}
</p>
<p>
{r.decision_reason ??
'Aguarda revisão independente.'}
</p>
</article>
))}
{!requests.length && <p>Nenhum pedido recebido.</p>}
</section>
</main>
);
}