import { Link } from '@inertiajs/react'; import { useEffect, useState } from 'react'; import { profileJson } from '@/lib/profile-json'; type Report = { id: string; version: number; status: string; reason: string; resolution_reason: string | null; source_record_version: number; source_snapshot?: { title?: string; summary?: string; description?: string; } | null; }; type Highlight = { version: number; status: string; label: string; note: string; starts_at: string | null; ends_at: string | null; }; type Operation = { id: number; etag: string; availability: { state: string; expires_at: string | null; policy_pending: boolean; }; editorial_state: string; owner: boolean; reviewer: boolean; publisher: boolean; reports: Report[]; highlight: Highlight | null; history: { id: string; action: string; at: string; cycle: number }[]; }; const labels: Record = { available: 'Disponível', withdrawn: 'Retirada', expired: 'Expirada', revalidation: 'Aguarda nova validação', unavailable: 'Indisponível', }; export default function OfferOperations({ id, onChanged, }: { id: number; onChanged: () => void; }) { const [value, setValue] = useState(null); const [message, setMessage] = useState(''); const [busy, setBusy] = useState(false); const [reason, setReason] = useState(''); const [confirm, setConfirm] = useState(false); const [plan, setPlan] = useState({ label: '', starts_at: '', ends_at: '', note: '', status: 'draft', }); const base = `/minhas-oportunidades/ofertas/${id}`; useEffect(() => { let active = true; profileJson(`${base}/operacoes`, {}, 'GET') .then((result) => { if (active) { setValue(result); if (result.highlight) setPlan({ label: result.highlight.label, starts_at: result.highlight.starts_at ?? '', ends_at: result.highlight.ends_at ?? '', note: result.highlight.note, status: result.highlight.status, }); } }) .catch((error) => { if (active) setMessage(error.message); }); return () => { active = false; }; }, [base]); async function command(path: string, data: object) { if (busy) return; setBusy(true); setMessage(''); try { const result = await profileJson(`${base}/${path}`, data); setValue(result); setConfirm(false); onChanged(); setMessage( 'Operação guardada em privado. A publicação permanece bloqueada.', ); } catch (error) { setMessage( error instanceof Error ? error.message : 'Não foi possível concluir.', ); } finally { setBusy(false); } } async function refresh(loadPlan = false) { setBusy(true); try { const next: Operation = await profileJson( `${base}/operacoes`, {}, 'GET', ); setValue((previous) => loadPlan ? next : { ...next, highlight: previous?.highlight ?? null }, ); if (loadPlan) setPlan({ label: next.highlight?.label ?? '', starts_at: next.highlight?.starts_at ?? '', ends_at: next.highlight?.ends_at ?? '', note: next.highlight?.note ?? '', status: next.highlight?.status ?? 'draft', }); setConfirm(false); onChanged(); setMessage( loadPlan ? 'Plano guardado carregado para conferência.' : 'Disponibilidade e denúncias actualizadas. As observações e o plano local foram preservados.', ); } catch (error) { setMessage( error instanceof Error ? error.message : 'Não foi possível actualizar.', ); } finally { setBusy(false); } } function owner(action: string) { if (value) void command('operacoes', { action, etag: value.etag, confirm: true, reason, }); } return (

Disponibilidade e acompanhamento

{value && ( <>

{labels[value.availability.state] ?? 'Indisponível'}

{value.availability.policy_pending ? 'Prazo de validade por definir.' : value.availability.expires_at ? `Validade até ${new Date(value.availability.expires_at).toLocaleString('pt-MZ')}.` : 'A contagem de validade inicia-se com a publicação da versão.'}{' '} O NDA tem controlo independente.

{value.owner && (