185 lines
6.2 KiB
TypeScript
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>
|
|
);
|
|
}
|