Files
Investidor-V2/resources/js/pages/profiles/technical-support.tsx
T

151 lines
6.2 KiB
TypeScript

import { Management, Pagination, type Paginated } from '../management/shared';
import type { OpportunityTechnicalIncident } from '@/components/opportunity-technical-incidents';
import { Link } from '@inertiajs/react';
import {
handlingLabels,
incidentOperationLabel,
incidentErrorLabel,
} from '@/lib/technical-incident-labels';
import type { HandlingState } from '@/lib/technical-incident-handling';
import TechnicalIncidentNotice from '@/components/technical-incident-notice';
export default function TechnicalSupport({
incidents,
actorId,
filters = { status: 'all' },
}: {
actorId?: number;
incidents: Paginated<
OpportunityTechnicalIncident & {
handling?: HandlingState | null;
details_url?: string;
unread?: boolean;
}
>;
filters?: { status: string; unread?: boolean };
}) {
function href(status: string, unread = !!filters.unread) {
const query = new URLSearchParams({
...(status !== 'all' ? { status } : {}),
...(unread ? { unread: '1' } : {}),
}).toString();
return '/suporte-tecnico/incidentes' + (query ? '?' + query : '');
}
return (
<Management title="Suporte técnico — incidentes">
<p>
Incidentes de submissão, publicação, uploads e preparação de
imagens nas organizações e tipos abrangidos pela sua atribuição
actual. A fila apresenta metadados técnicos; o perfil de suporte
não concede acesso aos processos ou documentos.
</p>
<nav
aria-label="Filtrar por estado técnico"
className="flex flex-wrap gap-4"
>
{Object.entries({ all: 'Todos', ...handlingLabels }).map(
([value, label]) => (
<Link
key={value}
className="underline"
href={href(value)}
aria-current={
filters.status === value ? 'page' : undefined
}
>
{label}
</Link>
),
)}
</nav>
<nav
aria-label="Filtrar avisos de suporte"
className="flex flex-wrap gap-4"
>
<Link
className="underline"
href={href(filters.status, false)}
aria-current={!filters.unread ? 'page' : undefined}
>
Todos os avisos
</Link>
<Link
className="underline"
href={href(filters.status, true)}
aria-current={filters.unread ? 'page' : undefined}
>
Por consultar
</Link>
</nav>
{!incidents.data.length && (
<p>Não existem incidentes disponíveis neste âmbito.</p>
)}
{incidents.data.map((incident) => (
<article
key={incident.reference}
className="space-y-2 rounded border p-4"
>
<h2 className="font-semibold">
{incidentOperationLabel(incident.operation)} · versão
observada {incident.version}
</h2>
<p>{incident.occurred_at}</p>
<p>{incidentErrorLabel(incident.error_code)}</p>
<p className="break-all">
Referência: {incident.reference}
</p>
{actorId && typeof incident.unread === 'boolean' && (
<TechnicalIncidentNotice
key={`notice:${actorId}:${incident.reference}`}
actorId={actorId}
reference={incident.reference}
unread={incident.unread}
/>
)}
{incident.handling ? (
<p>
Estado técnico:{' '}
{handlingLabels[incident.handling.status]} ·{' '}
{incident.handling.assignee_name || 'Por assumir'}
</p>
) : (
<p>
Estado técnico indisponível; registos preservados.
</p>
)}
{incident.details_url && (
<Link
className="underline"
href={
incident.details_url +
(incidents.current_page > 1 ||
filters.status !== 'all' ||
filters.unread
? '?' +
new URLSearchParams({
...(incidents.current_page > 1
? {
page: String(
incidents.current_page,
),
}
: {}),
...(filters.status !== 'all'
? { status: filters.status }
: {}),
...(filters.unread
? { unread: '1' }
: {}),
}).toString()
: '')
}
>
Consultar e tratar incidente
</Link>
)}
</article>
))}
<Pagination page={incidents} />
</Management>
);
}