Files
Investidor-V2/resources/js/components/opportunity-library-reuse.tsx
T

122 lines
4.5 KiB
TypeScript

import { router } from '@inertiajs/react';
import { useState } from 'react';
import { createOperationKey } from '@/lib/operation-key';
import { contextApi } from '@/lib/investor-context';
export type LibrarySource = {
id: number;
title: string;
version_label: string | null;
metadata_version: number;
sha256: string;
};
export default function OpportunityLibraryReuse({
sources,
action,
etag,
}: {
sources: LibrarySource[];
action: string;
etag: string;
}) {
const [selected, setSelected] = useState('');
const [section, setSection] = useState('');
const [reason, setReason] = useState('');
const [key, setKey] = useState(createOperationKey);
const [message, setMessage] = useState('');
const [busy, setBusy] = useState(false);
return (
<section
aria-label="Reutilizar original da biblioteca"
className="space-y-3 rounded border p-4"
>
<h2 className="text-xl font-semibold">
Reutilizar original da biblioteca
</h2>
<p>
O suporte aponta para os mesmos bytes e conserva edição, hash e
histórico. Mantém-se privado; a ficha e o original têm
permissões e publicação próprias.
</p>
<label className="grid gap-1">
Original da biblioteca
<select
aria-label="Original da biblioteca"
className="w-full rounded border p-2"
value={selected}
onChange={(e) => setSelected(e.target.value)}
>
<option value="">Seleccionar original acessível</option>
{sources.map((s) => (
<option key={s.id} value={s.id}>
{s.title} · {s.version_label ?? 'sem edição'} ·
metadados v{s.metadata_version}
</option>
))}
</select>
</label>
<label className="grid gap-1">
Secções utilizadas
<input
aria-label="Secções utilizadas"
className="w-full rounded border p-2"
value={section}
maxLength={255}
onChange={(e) => setSection(e.target.value)}
/>
</label>
<label className="grid gap-1">
Motivo da reutilização
<textarea
aria-label="Motivo da reutilização"
className="w-full rounded border p-2"
value={reason}
minLength={20}
maxLength={1000}
onChange={(e) => setReason(e.target.value)}
/>
</label>
<button
className="rounded border bg-emerald-800 px-4 py-2 text-white disabled:opacity-50"
type="button"
disabled={!selected || reason.length < 20 || busy}
onClick={async () => {
setBusy(true);
setMessage('');
try {
const result = await contextApi<{ message: string }>(
action,
{
resource_id: Number(selected),
section: section || null,
reason,
etag,
creation_key: key,
},
);
setMessage(result.message);
setKey(createOperationKey);
router.reload();
} catch (e) {
setMessage(
e instanceof Error
? e.message
: 'Não foi possível associar o original. Selecção preservada.',
);
} finally {
setBusy(false);
}
}}
>
Associar original como suporte privado
</button>
<p role="status">
{message ||
(!sources.length
? 'Não há originais acessíveis à conta neste âmbito.'
: 'Seleccionar não grava nem divulga o original.')}
</p>
</section>
);
}