Files
Investidor-V2/resources/js/components/technical-incident-notice.tsx
T

109 lines
3.4 KiB
TypeScript

import { useEffect, useRef, useState } from 'react';
import { router } from '@inertiajs/react';
import { portalRequest } from '@/lib/portal-api';
import { button } from '@/pages/management/shared';
export default function TechnicalIncidentNotice({
actorId,
reference,
unread,
}: {
actorId: number;
reference: string;
unread: boolean;
}) {
const [read, setRead] = useState(!unread),
[busy, setBusy] = useState(false),
[error, setError] = useState('');
const scope = useRef({ actorId, reference }),
alive = useRef(true),
active = useRef(false),
confirmed = useRef(!unread);
const current = useRef({ actorId, reference });
current.current = { actorId, reference };
useEffect(() => {
alive.current = true;
return () => {
alive.current = false;
};
}, []);
useEffect(() => {
if (!unread) {
confirmed.current = true;
setRead(true);
setError('');
}
}, [unread]);
function applicable() {
return (
alive.current &&
current.current.actorId === scope.current.actorId &&
current.current.reference === scope.current.reference
);
}
async function mark() {
if (!applicable() || active.current || confirmed.current) return;
active.current = true;
setBusy(true);
setError('');
try {
const value = await portalRequest<unknown>(
'/suporte-tecnico/incidentes/' +
scope.current.reference +
'/consultado',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: '{}',
},
);
if (!applicable() || confirmed.current) return;
if (
!value ||
typeof value !== 'object' ||
!('actor_id' in value) ||
value.actor_id !== scope.current.actorId ||
!('reference' in value) ||
value.reference !== scope.current.reference ||
!('read' in value) ||
value.read !== true
)
throw new Error('Unconfirmed receipt');
confirmed.current = true;
setRead(true);
router.reload({
only: ['incidents', 'profileAccess', 'notice'],
});
} catch {
if (applicable() && !confirmed.current)
setError(
'Não foi possível confirmar a consulta. Pode repetir esta acção; o tratamento e as notas mantêm-se.',
);
} finally {
if (applicable()) {
active.current = false;
setBusy(false);
}
}
}
return (
<div className="space-y-2">
{read ? (
<p>Aviso consultado por si.</p>
) : (
<button
type="button"
className={button}
disabled={busy}
onClick={() => void mark()}
>
{error
? 'Repetir confirmação de consulta'
: 'Marcar aviso como consultado'}
</button>
)}
{error && <p role="alert">{error}</p>}
</div>
);
}