230 lines
10 KiB
TypeScript
230 lines
10 KiB
TypeScript
import { useEducationReview } from '@/lib/education-review';
|
|
import type { EducationReviewProps } from '@/lib/education-review';
|
|
import { Field, button, control } from '@/pages/management/shared';
|
|
const states: Record<string, string> = {
|
|
submitted: 'Submetida',
|
|
reviewed: 'Revista internamente',
|
|
rejected: 'Rejeitada',
|
|
};
|
|
export default function EducationReview(props: EducationReviewProps) {
|
|
const edit = useEducationReview(props),
|
|
{ form } = edit,
|
|
row = props.declaration;
|
|
return (
|
|
<section
|
|
className="space-y-4"
|
|
aria-label="Revisão interna da declaração"
|
|
>
|
|
{edit.notice && <p role="status">{edit.notice}</p>}
|
|
{(edit.stale || edit.conflict) && (
|
|
<section
|
|
className="space-y-3 rounded border p-4"
|
|
aria-label="Comparação da declaração"
|
|
>
|
|
<h2 className="font-semibold">A declaração mudou</h2>
|
|
<p>
|
|
Compare a versão analisada com os dados actuais antes de
|
|
confirmar a decisão.
|
|
</p>
|
|
<dl className="space-y-2">
|
|
<dt>Qualificação</dt>
|
|
<dd>
|
|
Analisada: {edit.base.qualification} · Actual:{' '}
|
|
{edit.current.qualification}
|
|
</dd>
|
|
<dt>
|
|
Quantidade de{' '}
|
|
{props.kind === 'demands'
|
|
? 'trabalhadores'
|
|
: 'vagas formativas'}
|
|
</dt>
|
|
<dd>
|
|
Analisada: {edit.base.quantity} · Actual:{' '}
|
|
{edit.current.quantity}
|
|
</dd>
|
|
<dt>Período</dt>
|
|
<dd>
|
|
Analisado: {edit.base.period_start} a{' '}
|
|
{edit.base.period_end} · Actual:{' '}
|
|
{edit.current.period_start} a{' '}
|
|
{edit.current.period_end}
|
|
</dd>
|
|
<dt>Validade da fonte</dt>
|
|
<dd>
|
|
Analisada: {edit.base.valid_until} · Actual:{' '}
|
|
{edit.current.valid_until}
|
|
</dd>
|
|
<dt>Fonte</dt>
|
|
<dd className="break-words whitespace-pre-wrap">
|
|
Analisada: {edit.base.source} · Actual:{' '}
|
|
{edit.current.source}
|
|
</dd>
|
|
<dt>Data de referência</dt>
|
|
<dd>
|
|
Analisada:{' '}
|
|
{edit.base.reference_date || 'Não identificada'} ·
|
|
Actual:{' '}
|
|
{edit.current.reference_date || 'Não identificada'}
|
|
</dd>
|
|
{props.kind === 'demands' && (
|
|
<>
|
|
<dt>Empregador declarado</dt>
|
|
<dd>
|
|
Analisado:{' '}
|
|
{edit.base.employer || 'Não identificado'} ·
|
|
Actual:{' '}
|
|
{edit.current.employer ||
|
|
'Não identificado'}
|
|
</dd>
|
|
</>
|
|
)}
|
|
{Array.from(
|
|
new Set([
|
|
...Object.keys(edit.base.references),
|
|
...Object.keys(edit.current.references),
|
|
]),
|
|
).map((field) => (
|
|
<div key={field}>
|
|
<dt>
|
|
{(
|
|
{
|
|
occupation: 'Ocupação',
|
|
skill: 'Competência',
|
|
project: 'Projecto',
|
|
course: 'Curso',
|
|
location: 'Localização',
|
|
} as Record<string, string>
|
|
)[field] ?? 'Referência'}
|
|
</dt>
|
|
<dd>
|
|
Analisada:{' '}
|
|
{edit.base.references[field] ||
|
|
'Não identificada'}{' '}
|
|
· Actual:{' '}
|
|
{edit.current.references[field] ||
|
|
'Não identificada'}
|
|
</dd>
|
|
</div>
|
|
))}
|
|
<dt>Estado</dt>
|
|
<dd>
|
|
Analisado:{' '}
|
|
{states[edit.base.status] ?? edit.base.status} ·
|
|
Actual:{' '}
|
|
{states[edit.current.status] ?? edit.current.status}
|
|
</dd>
|
|
</dl>
|
|
<button
|
|
type="button"
|
|
className={button}
|
|
onClick={edit.refresh}
|
|
disabled={edit.refreshing || form.processing}
|
|
>
|
|
Actualizar declaração
|
|
</button>
|
|
{edit.canAdopt && (
|
|
<button
|
|
type="button"
|
|
className={button}
|
|
onClick={edit.adopt}
|
|
>
|
|
Confirmar a leitura desta versão
|
|
</button>
|
|
)}
|
|
</section>
|
|
)}
|
|
{row.can_review !== true && !edit.uncertain ? (
|
|
<p>
|
|
{row.review_unavailable === 'self'
|
|
? 'Esta declaração foi submetida por si. A revisão cabe a outro gestor.'
|
|
: row.review_unavailable === 'expired'
|
|
? 'A fonte expirou. A declaração permanece disponível para consulta.'
|
|
: 'Actualize a declaração para confirmar as opções de revisão.'}
|
|
</p>
|
|
) : (
|
|
<form
|
|
id="education-review"
|
|
className="max-w-xl space-y-3"
|
|
onSubmit={(event) => {
|
|
event.preventDefault();
|
|
edit.submit();
|
|
}}
|
|
>
|
|
<h2 className="text-lg font-semibold">
|
|
Decisão de revisão interna
|
|
</h2>
|
|
{edit.uncertain && (
|
|
<p>
|
|
A recuperação repete a decisão enviada:{' '}
|
|
{states[edit.sent?.status ?? ''] ?? 'Por confirmar'}
|
|
. Fundamento: {edit.sent?.review_reason}. As edições
|
|
posteriores ficam conservadas.
|
|
</p>
|
|
)}
|
|
<Field label="Decisão interna" error={form.errors.status}>
|
|
<select
|
|
className={control}
|
|
value={form.data.status}
|
|
onChange={(event) =>
|
|
edit.change('status', event.target.value)
|
|
}
|
|
>
|
|
<option value="reviewed">Registar revisão</option>
|
|
<option value="rejected">
|
|
Rejeitar declaração
|
|
</option>
|
|
</select>
|
|
</Field>
|
|
<Field
|
|
label="Justificação e evidência da revisão"
|
|
error={form.errors.review_reason}
|
|
>
|
|
<textarea
|
|
className={control}
|
|
required
|
|
minLength={15}
|
|
maxLength={3000}
|
|
value={form.data.review_reason}
|
|
onChange={(event) =>
|
|
edit.change('review_reason', event.target.value)
|
|
}
|
|
/>
|
|
</Field>
|
|
{form.errors.version_no && (
|
|
<p role="alert">
|
|
Actualize e compare a declaração antes de continuar.
|
|
A decisão preparada foi conservada.
|
|
</p>
|
|
)}
|
|
<div className="flex flex-wrap gap-3">
|
|
<button
|
|
className={button}
|
|
disabled={edit.blocked || form.processing}
|
|
>
|
|
{edit.uncertain
|
|
? 'Recuperar a mesma revisão'
|
|
: 'Guardar decisão'}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className={button}
|
|
onClick={edit.refresh}
|
|
disabled={edit.refreshing || form.processing}
|
|
>
|
|
Actualizar dados da declaração
|
|
</button>
|
|
</div>
|
|
</form>
|
|
)}
|
|
{row.can_review !== true &&
|
|
!edit.uncertain &&
|
|
form.data.review_reason && (
|
|
<p className="break-words whitespace-pre-wrap">
|
|
Fundamento preparado nesta página:{' '}
|
|
{form.data.review_reason}
|
|
</p>
|
|
)}
|
|
</section>
|
|
);
|
|
}
|