254 lines
9.4 KiB
TypeScript
254 lines
9.4 KiB
TypeScript
import { Link, useForm } from '@inertiajs/react';
|
|
import { useEffect, useState } from 'react';
|
|
import { Management, Field, button, control } from '../management/shared';
|
|
import EditorialReading, {
|
|
type EditorialArticle,
|
|
} from '@/components/editorial-reading';
|
|
type Content = {
|
|
body: string;
|
|
image_resource_id: number | null;
|
|
image_mode?: string;
|
|
};
|
|
export default function ArticleEditor({
|
|
resource,
|
|
content,
|
|
source,
|
|
images,
|
|
revisions,
|
|
}: {
|
|
resource: {
|
|
id: number;
|
|
title: string;
|
|
metadata_version: number;
|
|
published: boolean;
|
|
};
|
|
content: Content | null;
|
|
source?: {
|
|
source_url?: string;
|
|
image_source_url?: string;
|
|
published_at?: string;
|
|
modified_at?: string;
|
|
legacy_id?: number;
|
|
} | null;
|
|
images: { id: number; title: string }[];
|
|
revisions: {
|
|
revision_no: number;
|
|
change_type: string;
|
|
created_at: string;
|
|
}[];
|
|
}) {
|
|
const initial = () => ({
|
|
body: content?.body ?? '',
|
|
image_resource_id: content?.image_resource_id
|
|
? String(content.image_resource_id)
|
|
: '',
|
|
image_mode:
|
|
content?.image_mode ??
|
|
(content?.image_resource_id ? 'selected' : 'none'),
|
|
metadata_version: resource.metadata_version,
|
|
});
|
|
const form = useForm(initial());
|
|
const [preview, setPreview] = useState<EditorialArticle | null>(null);
|
|
const [error, setError] = useState('');
|
|
const [busy, setBusy] = useState(false);
|
|
useEffect(() => {
|
|
form.setData(initial());
|
|
setPreview(null);
|
|
setError('');
|
|
}, [resource.id, resource.metadata_version]);
|
|
useEffect(() => {
|
|
setPreview(null);
|
|
}, [form.data.body, form.data.image_mode, form.data.image_resource_id]);
|
|
const showPreview = async () => {
|
|
setBusy(true);
|
|
setError('');
|
|
try {
|
|
const token = document.cookie
|
|
.split('; ')
|
|
.find((v) => v.startsWith('XSRF-TOKEN='))
|
|
?.slice(11);
|
|
const response = await fetch(
|
|
`/management/portal-services/resources/${resource.id}/article/preview`,
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
'X-XSRF-TOKEN': decodeURIComponent(token ?? ''),
|
|
},
|
|
body: JSON.stringify(form.data),
|
|
},
|
|
);
|
|
const data = await response
|
|
.json()
|
|
.catch(() => ({
|
|
message:
|
|
'Não foi possível abrir a prévia. Recupere o editor e confirme a sessão e o MFA existentes.',
|
|
}));
|
|
if (!response.ok)
|
|
throw new Error(
|
|
Object.values(data.errors ?? {})
|
|
.flat()
|
|
.join(' ') ||
|
|
data.message ||
|
|
'Não foi possível preparar a prévia.',
|
|
);
|
|
setPreview(data.article);
|
|
} catch (e) {
|
|
setError(
|
|
e instanceof Error
|
|
? e.message
|
|
: 'Não foi possível preparar a prévia.',
|
|
);
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
};
|
|
return (
|
|
<Management title={`Editar artigo — ${resource.title}`}>
|
|
<p>
|
|
O original, a origem e as versões permanecem na biblioteca.
|
|
Guardar cria uma revisão editorial e retira a publicação até à
|
|
sua acção expressa no acervo.
|
|
</p>
|
|
<p role="status">
|
|
Revisão guardada {resource.metadata_version} ·{' '}
|
|
{resource.published ? 'Publicado' : 'Rascunho privado'}
|
|
</p>
|
|
{source && (
|
|
<p>
|
|
Original {source.legacy_id} · publicado em{' '}
|
|
{source.published_at} · modificado em {source.modified_at}.
|
|
A imagem de origem mantém a sua referência mesmo quando não
|
|
existe exemplar disponível.
|
|
</p>
|
|
)}
|
|
<form
|
|
className="max-w-3xl space-y-5"
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
setError('');
|
|
form.put(
|
|
`/management/portal-services/resources/${resource.id}/article`,
|
|
);
|
|
}}
|
|
>
|
|
{!!Object.keys(form.errors).length && (
|
|
<div role="alert">
|
|
{Object.values(form.errors).join(' ')}
|
|
</div>
|
|
)}
|
|
<Field label="Corpo do artigo" error={form.errors.body}>
|
|
<textarea
|
|
className={control}
|
|
rows={16}
|
|
value={form.data.body}
|
|
onChange={(e) => form.setData('body', e.target.value)}
|
|
/>
|
|
<p>
|
|
Texto simples, com uma linha em branco entre parágrafos.
|
|
Se mantiver o texto original, a leitura conserva também
|
|
a sua formatação; as correcções ficam numa edição
|
|
separada.
|
|
</p>
|
|
</Field>
|
|
<Field
|
|
label="Tratamento da imagem"
|
|
error={form.errors.image_mode}
|
|
>
|
|
<select
|
|
className={control}
|
|
value={form.data.image_mode}
|
|
onChange={(e) =>
|
|
form.setData('image_mode', e.target.value)
|
|
}
|
|
>
|
|
<option value="original">
|
|
Manter referência e imagem de origem disponível
|
|
</option>
|
|
<option value="selected">
|
|
Escolher imagem pública da biblioteca
|
|
</option>
|
|
<option value="none">
|
|
Não mostrar imagem nesta edição
|
|
</option>
|
|
</select>
|
|
</Field>
|
|
{form.data.image_mode === 'selected' && (
|
|
<Field
|
|
label="Imagem da biblioteca"
|
|
error={form.errors.image_resource_id}
|
|
>
|
|
<select
|
|
className={control}
|
|
value={form.data.image_resource_id}
|
|
onChange={(e) =>
|
|
form.setData(
|
|
'image_resource_id',
|
|
e.target.value,
|
|
)
|
|
}
|
|
>
|
|
<option value="">Seleccione uma imagem</option>
|
|
{images.map((i) => (
|
|
<option key={i.id} value={i.id}>
|
|
{i.title}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</Field>
|
|
)}
|
|
<div className="flex flex-wrap gap-4">
|
|
<button className={button} disabled={form.processing}>
|
|
Guardar artigo como rascunho
|
|
</button>
|
|
<button
|
|
className={button}
|
|
type="button"
|
|
disabled={busy}
|
|
onClick={() => void showPreview()}
|
|
>
|
|
Pré-visualizar alterações
|
|
</button>
|
|
<Link
|
|
className="underline"
|
|
href={`/management/portal-services/resources/${resource.id}/article/preview`}
|
|
>
|
|
Ler revisão guardada
|
|
</Link>
|
|
<Link
|
|
className="underline"
|
|
href="/management/portal-services"
|
|
>
|
|
Voltar ao acervo para metadados e publicação
|
|
</Link>
|
|
</div>
|
|
</form>
|
|
{error && <p role="alert">{error}</p>}
|
|
{preview && (
|
|
<section
|
|
aria-label="Prévia das alterações"
|
|
className="my-6 max-w-3xl rounded border p-5"
|
|
>
|
|
<EditorialReading article={preview} />
|
|
</section>
|
|
)}
|
|
<h2>Histórico</h2>
|
|
<ul>
|
|
{revisions.map((r) => (
|
|
<li key={r.revision_no}>
|
|
Revisão {r.revision_no} · {r.change_type} ·{' '}
|
|
{r.created_at}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
<p>
|
|
Título, descrição, autor, fonte, direitos e acesso são
|
|
corrigidos em Editar metadados no acervo. Carregue e analise
|
|
imagens na biblioteca antes de as seleccionar. Publicar continua
|
|
a ser uma acção separada.
|
|
</p>
|
|
</Management>
|
|
);
|
|
}
|