123 lines
4.6 KiB
TypeScript
123 lines
4.6 KiB
TypeScript
import {
|
|
useTechnicalIncidentHandling,
|
|
type HandlingProps,
|
|
type Command,
|
|
} from '@/lib/technical-incident-handling';
|
|
import { button, control } from '@/pages/management/shared';
|
|
import { handlingLabels, commandLabels } from '@/lib/technical-incident-labels';
|
|
export default function TechnicalIncidentHandling(props: HandlingProps) {
|
|
const edit = useTechnicalIncidentHandling(props),
|
|
state = props.incident.handling;
|
|
const actions: Command[] =
|
|
state.status === 'resolved'
|
|
? ['note', 'reopen']
|
|
: [
|
|
'claim',
|
|
'note',
|
|
'resolve',
|
|
...(state.status === 'in_progress'
|
|
? ['release' as const]
|
|
: []),
|
|
];
|
|
return (
|
|
<section
|
|
className="space-y-3 rounded border p-4"
|
|
aria-label="Tratar incidente técnico"
|
|
>
|
|
<h2 className="text-xl font-semibold">Tratar incidente técnico</h2>
|
|
<p>
|
|
O tratamento é partilhado pela equipa autorizada neste âmbito.
|
|
Assumir um tratamento em curso substitui o responsável e
|
|
conserva o histórico.
|
|
</p>
|
|
<p>
|
|
Resolver este incidente não submete, publica ou aprova a
|
|
oportunidade.
|
|
</p>
|
|
{edit.notice && <p role="status">{edit.notice}</p>}
|
|
{edit.error && <p role="alert">{edit.error}</p>}
|
|
{edit.stale && (
|
|
<section
|
|
className="rounded border p-3"
|
|
aria-label="Comparar tratamento"
|
|
>
|
|
<p>
|
|
O incidente mudou. Compare antes de confirmar o estado
|
|
actual.
|
|
</p>
|
|
<p>
|
|
Analisado: {handlingLabels[edit.base.status]} ·
|
|
responsável {edit.base.assignee_name || 'por assumir'} ·
|
|
versão {edit.base.version}
|
|
</p>
|
|
<p>
|
|
Actual: {handlingLabels[state.status]} · responsável{' '}
|
|
{state.assignee_name || 'por assumir'} · versão{' '}
|
|
{state.version}
|
|
</p>
|
|
<button
|
|
type="button"
|
|
className={button}
|
|
disabled={!edit.canAdopt}
|
|
onClick={edit.adopt}
|
|
>
|
|
Confirmar leitura do estado actual
|
|
</button>
|
|
</section>
|
|
)}
|
|
<label className="block">
|
|
Nota interna do tratamento
|
|
<textarea
|
|
className={control}
|
|
value={edit.note}
|
|
maxLength={3000}
|
|
onChange={(event) => edit.change(event.target.value)}
|
|
/>
|
|
</label>
|
|
<p>
|
|
A nota é visível à equipa de suporte autorizada e fica no
|
|
histórico. O autor da tentativa acompanha apenas o estado
|
|
técnico.
|
|
</p>
|
|
<div className="flex flex-wrap gap-3">
|
|
{actions
|
|
.filter(
|
|
(action) =>
|
|
action !== 'claim' ||
|
|
state.assignee_user_id !== props.actorId,
|
|
)
|
|
.map((action) => (
|
|
<button
|
|
type="button"
|
|
key={action}
|
|
className={button}
|
|
disabled={edit.blocked}
|
|
onClick={() => void edit.send(action)}
|
|
>
|
|
{commandLabels[action]}
|
|
</button>
|
|
))}
|
|
{edit.canRetry && (
|
|
<button
|
|
type="button"
|
|
className={button}
|
|
onClick={() =>
|
|
void edit.send(edit.pendingAction ?? 'note', true)
|
|
}
|
|
>
|
|
Repetir o registo original
|
|
</button>
|
|
)}
|
|
<button
|
|
type="button"
|
|
className={button}
|
|
disabled={edit.refreshing}
|
|
onClick={edit.refresh}
|
|
>
|
|
Actualizar incidente
|
|
</button>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|