Files
Investidor-V2/resources/js/pages/management/shared.tsx
T
2026-09-29 08:41:57 +02:00

122 lines
4.5 KiB
TypeScript

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",
in_review: "Em análise",
contacted: "Contactado",
closed: "Encerrado",
draft: "Rascunho",
published: "Publicado",
archived: "Arquivado",
};
export function Management({ title, children }: { title: string; children: ReactNode }) {
const { flash, educationEnabled, aiEnabled } = usePage<{
flash?: { success?: string };
educationEnabled?: boolean;
aiEnabled?: boolean;
}>().props;
return (
<main className="space-y-6 p-4 md:p-8">
<Head title={title} />
<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">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/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>
<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>
);
}