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

185 lines
6.2 KiB
TypeScript

import ProfileNavigation from '@/components/profile-navigation';
import { Head, Link, usePage } from '@inertiajs/react';
import type { ReactNode } from 'react';
import { cloneElement, isValidElement, useId } from 'react';
export type Paginated<T> = {
data: T[];
total: number;
current_page: number;
last_page: number;
prev_page_url: string | null;
next_page_url: string | null;
};
export const control =
'w-full rounded-md border border-input bg-background p-2 text-foreground';
export const button =
'inline-flex items-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground disabled:opacity-50';
export const states: Record<string, string> = {
received: 'Recebido',
submitted: 'Submetido',
in_review: 'Em análise',
contacted: 'Contactado',
reviewed: 'Revisto',
qualification: 'Em qualificação',
qualified: 'Qualificado',
contact_accepted: 'Contacto aceite',
referred: 'Encaminhado',
due_diligence: 'Diligência devida',
negotiation: 'Em negociação',
pending: 'Pendente',
refused: 'Recusado',
converted: 'Convertido',
cancelled: 'Cancelado',
closed: 'Encerrado',
draft: 'Rascunho',
published: 'Publicado',
archived: 'Arquivado',
returned: 'Devolvida',
approved: 'Aprovada internamente',
suspended: 'Suspensa',
};
export function Management({
title,
children,
}: {
title: string;
children: ReactNode;
}) {
const { flash, educationEnabled, aiEnabled, auth, basePath } = usePage<{
auth?: {canManagePortal?: boolean};
basePath?: string;
flash?: { success?: string };
educationEnabled?: boolean;
aiEnabled?: boolean;
}>().props;
return (
<main className="space-y-6 p-4 md:p-8">
<Head title={title} />
{auth?.canManagePortal && basePath !== '/minhas-oportunidades' ? <nav
className="flex flex-wrap gap-4 text-sm underline"
aria-label="Gestão do portal"
>
<Link href="/management/interests">Pedidos de interesse</Link>
<Link href="/management/sectors">Sectores</Link>
<Link href="/management/opportunities">
Gestão de Oportunidades
</Link>
<Link href="/management/opportunity-origin">
Revisão da origem das oportunidades
</Link>
<Link href="/management/history">Histórico</Link>
<Link href="/management/crm/leads">CRM</Link>
<Link href="/management/crm/investors">Investidores</Link>
<Link href="/management/projects">Projectos</Link>
<Link href="/management/clusters">Clusters</Link>
<Link href="/management/relationship-repair">
Revisão das associações documentadas
</Link>
<Link href="/management/partnerships-install">
Aplicação da Bolsa de Parcerias
</Link>
<Link href="/management/corridors">Corredores</Link>
<Link href="/management/territory-associations">
Localizações dos investimentos
</Link>
<Link href="/management/investment/zones">
ZEE, ZFI e parques
</Link>
{educationEnabled && (
<Link href="/management/education">
Competências e formação
</Link>
)}
{aiEnabled && (
<Link href="/management/ai">Assistência e fontes</Link>
)}
<Link href="/management/portfolio">
Corredores e matriz de investimento
</Link>
<Link href="/management/portal-services">
Documentos e parcerias
</Link>
<Link href="/management/investment/references">
Referências e formulários
</Link>
<a href="/">Portal público</a>
</nav> : <ProfileNavigation />}
<h1 className="text-2xl font-semibold break-words">{title}</h1>
{flash?.success && (
<p
role="status"
className="rounded border border-emerald-600 p-3"
>
{flash.success}
</p>
)}
{children}
</main>
);
}
export function Pagination<T>({ page }: { page: Paginated<T> }) {
return (
<nav
aria-label="Paginação"
className="flex flex-wrap items-center gap-4"
>
{page.prev_page_url && (
<Link className={button} href={page.prev_page_url}>
Anterior
</Link>
)}
<span>
{page.total} registos · Página {page.current_page} de{' '}
{page.last_page}
</span>
{page.next_page_url && (
<Link className={button} href={page.next_page_url}>
Seguinte
</Link>
)}
</nav>
);
}
export function Field({
label,
error,
children,
}: {
label: string;
error?: string;
children: ReactNode;
}) {
const id = useId();
return (
<label className="block space-y-1">
<span id={id} className="text-sm font-medium">
{label}
</span>
{isValidElement<{
'aria-labelledby'?: string;
'aria-describedby'?: string;
'aria-invalid'?: boolean;
}>(children)
? cloneElement(children, {
'aria-labelledby': id,
'aria-describedby': error ? `${id}-error` : undefined,
'aria-invalid': Boolean(error),
})
: children}
{error && (
<span
id={`${id}-error`}
role="alert"
className="block text-sm text-red-600"
>
{error}
</span>
)}
</label>
);
}