Files
Investidor-V2/resources/js/pages/partnerships/shared.tsx
T

166 lines
4.5 KiB
TypeScript

import { Link } from '@inertiajs/react';
import { cloneElement, isValidElement, useId, type ReactNode } from 'react';
import { Layout } from '../portfolio/shared';
export type Option = { id: string | number; name: string };
export type Territory = {
id: string;
name: string;
location_type: string;
parent_id: string | null;
};
export type Source = {
type: string;
target_id: string;
title: string;
href: string;
};
export type Catalogues = {
types: Record<string, string>;
criteria: Record<string, string>;
sectors: Option[];
territories: Territory[];
organizations: Option[];
sources?: Source[];
};
export type Partnership = {
id: number;
title: string;
status: string;
version: number;
client_key?: string | null;
kind: string;
partnership_type: string | null;
sector_id: number | null;
organization_id?: string | null;
deadline: string | null;
offer: string | null;
seeking: string | null;
payload: {
summary?: string;
requirements?: string;
mandatory?: string[];
confidentiality?: string;
consent?: boolean;
availability?: string;
};
};
export type Match = {
weights_hash?: string;
score_min: number | null;
score_max: number | null;
eligibility: string;
criteria: {
code: string;
label: string;
weight: number;
state: string;
mandatory: boolean;
evidence: string | null;
explanation: string;
}[];
};
export type Interest = {
id: number;
user_id: number;
partnership_id: number;
version: number;
proposal: string;
status: string;
decision_reason: string | null;
organization_id: string | null;
can_edit?: boolean;
commands?: { key: string; version: number; action: string }[];
payload: {
capacity?: string;
availability?: string;
contribution?: string;
conflicts?: string;
consent?: boolean;
sector_id?: number | null;
territory_id?: string | null;
};
assessment: Record<string, { state: string; evidence?: string }>;
match: Match;
room_id: number | null;
};
export const labels: Record<string, string> = {
draft: 'Rascunho',
pending: 'Submetida — legado',
submitted: 'Submetida',
returned: 'Devolvida',
rejected: 'Rejeitada',
published: 'Publicada',
suspended: 'Suspensa',
archived: 'Arquivada',
withdrawn: 'Retirada',
clarification: 'Em esclarecimento',
shortlisted: 'Lista curta',
negotiation: 'Em negociação',
agreement_recorded: 'Acordo registado',
agreed: 'Confirmado pelas partes',
execution: 'Em execução',
closed: 'Concluída',
cancelled: 'Cancelada',
progress: 'Em curso',
completed: 'Concluído',
met: 'Comprovadamente cumprido',
unmet: 'Comprovadamente incumprido',
unknown: 'Informação insuficiente',
};
export const control = 'w-full rounded border bg-background p-2';
export const button =
'inline-flex rounded bg-emerald-800 px-4 py-2 text-white disabled:opacity-50';
export function Frame({
title,
children,
}: {
title: string;
children: ReactNode;
}) {
return (
<Layout title={title} mainLandmark={false}>
<nav className="mb-6 flex flex-wrap gap-5 underline">
<Link href="/parcerias">Catálogo</Link>
<Link href="/parcerias/painel">O meu painel</Link>
<Link href="/parcerias/criar">Preparar parceria</Link>
<Link href="/como-investir">Como investir</Link>
<Link href="/simulador-fiscal">
Simulador e ficha de projeto
</Link>
</nav>
{children}
</Layout>
);
}
export function Errors({ errors }: { errors: Record<string, string> }) {
return (
<>
{Object.entries(errors).map(([key, message]) => (
<p role="alert" className="text-red-700" key={key}>
{message}
</p>
))}
</>
);
}
export function Field({
label,
children,
}: {
label: string;
children: ReactNode;
}) {
const id = useId();
return (
<label className="block space-y-2">
<span id={id} className="font-medium">
{label}
</span>
{isValidElement<{ 'aria-labelledby'?: string }>(children)
? cloneElement(children, { 'aria-labelledby': id })
: children}
</label>
);
}