Files
Investidor-V2/resources/js/pages/dashboard.tsx
T
nala 01405cbf8a
tests / ci (push) Canceled after 0s
oportunidades 5
2026-10-10 14:15:28 +02:00

312 lines
15 KiB
TypeScript

import ProfileNavigation from '@/components/profile-navigation';
import { Head, Link } from '@inertiajs/react';
import { dashboard } from '@/routes';
import type { InvestmentContext } from '@/pages/investor-path/index';
import type { OpportunityManagementAccess } from '@/types/opportunity-management';
type Summary = {
canCreateOpportunity?: boolean;
requestsByStatus: Record<string, number>;
publishedOpportunities: number;
draftOpportunities: number;
activeSectors: number;
recentRequests: {
id: number;
reference: string;
sector_interest: string;
status: string;
created_at: string;
}[];
};
const states: Record<string, string> = {
received: 'Recebidos',
in_review: 'Em análise',
contacted: 'Contactados',
closed: 'Encerrados',
};
const card =
'rounded-xl border p-5 transition-colors hover:bg-muted focus-visible:outline-2 focus-visible:outline-primary';
export default function Dashboard({
summary,
investorPath,
opportunityManagement,
}: {
summary: Summary | null;
opportunityManagement?: OpportunityManagementAccess | null;
investorPath?: {
contexts: InvestmentContext[];
current: {
id: string;
next: { code: string; title: string } | null;
pending: number;
documents: number;
results: number;
tasks: number;
} | null;
} | null;
}) {
return (
<main className="space-y-8 p-4 md:p-8">
<Head title="Painel" />
<h1 className="text-2xl font-semibold">Painel do portal</h1>
<ProfileNavigation />
{summary ? (
<>
{opportunityManagement && (
<section
aria-label="Gestão de Oportunidades"
className="space-y-4 rounded-xl border p-5"
>
<h2 className="text-lg font-semibold">
Gestão de Oportunidades
</h2>
<nav
aria-label="Ações de oportunidades"
className="flex flex-wrap gap-3"
>
<Link
className="rounded-lg border px-4 py-2 underline"
href={opportunityManagement.manage.href}
>
{opportunityManagement.manage.label}
</Link>
{opportunityManagement.installed ? (
<Link
className="bg-primary text-primary-foreground rounded-lg px-4 py-2"
href={opportunityManagement.create.href}
>
{opportunityManagement.create.label}
</Link>
) : (
<Link
className="underline"
href={
opportunityManagement.installationHref
}
>
Preparar instalação da gestão de
rascunhos
</Link>
)}
</nav>
<p className="text-muted-foreground text-sm">
Os rascunhos de oportunidades não publicam o
dossier privado do investidor. Publicação exige
uma ação própria.
</p>
</section>
)}
<section className="space-y-4">
<h2 className="text-lg font-semibold">
Manifestações de interesse
</h2>
<div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
{Object.entries(states).map(([status, label]) => (
<Link
key={status}
href={`/management/interests?status=${status}`}
className={card}
>
<p className="text-muted-foreground text-sm">
{label}
</p>
<p className="mt-2 text-3xl font-semibold">
{summary.requestsByStatus[status] ?? 0}
</p>
</Link>
))}
</div>
</section>
<section className="space-y-4">
<h2 className="text-lg font-semibold">
<Link href="/management/opportunities">
{opportunityManagement
? 'Indicadores de oportunidades'
: 'Gestão de Oportunidades'}
</Link>
</h2>
<div className="grid gap-4 sm:grid-cols-3">
{[
{
label: 'Oportunidades publicadas',
value: summary.publishedOpportunities,
href: '/management/opportunities?status=published',
},
{
label: 'Oportunidades em rascunho',
value: summary.draftOpportunities,
href: '/management/opportunities?status=draft',
},
{
label: 'Sectores activos',
value: summary.activeSectors,
href: '/management/sectors?status=active',
},
].map((item) => (
<Link
key={item.label}
href={item.href}
className={card}
>
<p className="text-muted-foreground text-sm">
{item.label}
</p>
<p className="mt-2 text-3xl font-semibold">
{item.value}
</p>
</Link>
))}
</div>
</section>
<section className="space-y-4">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 className="text-lg font-semibold">
Pedidos mais recentes
</h2>
<Link
href="/management/interests"
className="underline"
>
Ver todos
</Link>
</div>
{summary.recentRequests.length ? (
<ul className="divide-y rounded-xl border">
{summary.recentRequests.map((item) => (
<li
key={item.id}
className="flex flex-wrap items-center justify-between gap-3 p-4"
>
<div className="min-w-0">
<Link
href={`/management/interests/${item.id}`}
className="font-medium break-all underline"
>
{item.reference}
</Link>
<p className="text-muted-foreground text-sm">
{item.sector_interest} ·{' '}
{states[item.status] ??
item.status}
</p>
</div>
<time
dateTime={item.created_at}
className="text-muted-foreground text-sm"
>
{new Intl.DateTimeFormat('pt-MZ', {
dateStyle: 'medium',
timeZone: 'Africa/Maputo',
}).format(
new Date(item.created_at),
)}
</time>
</li>
))}
</ul>
) : (
<p className="text-muted-foreground rounded-xl border p-6">
Ainda não existem manifestações de interesse.
</p>
)}
</section>
<nav
aria-label="Acções rápidas"
className="flex flex-wrap gap-4"
>
{summary.canCreateOpportunity !== false && <Link
className="underline"
href="/management/opportunities/create"
>
{opportunityManagement?.create.label ??
'Criar oportunidade'}
</Link>}
<Link
className="underline"
href="/management/sectors/create"
>
Criar sector
</Link>
</nav>
</>
) : investorPath ? (
<section className="space-y-4 rounded-xl border p-6">
<h2 className="text-lg font-semibold">
Os meus investimentos
</h2>
{investorPath.current && (
<div className="space-y-2">
<p>
{investorPath.current.pending} etapas pendentes
· {investorPath.current.documents} documentos ·{' '}
{investorPath.current.results} resultados ·{' '}
{investorPath.current.tasks} tarefas
</p>
{investorPath.current.next && (
<Link
className="underline"
href={`/investimentos/${investorPath.current.id}#${investorPath.current.next.code}`}
>
Próxima acção:{' '}
{investorPath.current.next.code} ·{' '}
{investorPath.current.next.title}
</Link>
)}
</div>
)}
{investorPath.contexts.map((item, index) => (
<div className="rounded border p-4" key={item.id}>
<p>
{index === 0
? 'Investimento actualizado mais recentemente'
: 'Outro investimento'}
</p>
<Link
className="font-semibold underline"
href={`/investimentos/${item.id}`}
>
{item.title}
</Link>
<p>
Percurso, pendências, documentos, resultados e
próxima acção no dossier.
</p>
</div>
))}
{!investorPath.contexts.length && (
<p>
Comece pela sua ideia e prepare as etapas ao seu
ritmo.
</p>
)}
<Link className="underline" href="/investimentos">
Preparar ou escolher um investimento
</Link>
</section>
) : (
<section className="max-w-2xl space-y-4 rounded-xl border p-6">
<h2 className="text-lg font-semibold">
Configure o acesso quando estiver pronto
</h2>
<p>
A gestão está disponível para contas autorizadas. Pode
consultar os passos de configuração ou continuar a
explorar as oportunidades públicas.
</p>
<Link
href="/acesso-gestao"
className="bg-primary text-primary-foreground inline-block rounded-lg px-4 py-2"
>
Consultar o meu acesso
</Link>
</section>
)}
<Link href="/" className="inline-block underline">
Voltar ao portal público
</Link>
</main>
);
}
Dashboard.layout = { breadcrumbs: [{ title: 'Painel', href: dashboard() }] };