refactor: update menu and routing for ticket management

- Replaced references to "Solicitar Acesso" with "Abrir Chamado" across the application for consistency in terminology.
- Updated routing logic to reflect the new ticket management flow, ensuring that the dashboard and sidebar components point to the correct paths.
- Removed the obsolete "Solicitar Acesso" page, streamlining the user experience and reducing unnecessary navigation options.
- Enhanced backend schema to support new ticket functionalities, including ticket creation and management.
This commit is contained in:
2025-11-14 22:50:03 -03:00
parent 9b3b095c01
commit 118051ad56
17 changed files with 2353 additions and 358 deletions

View File

@@ -0,0 +1,123 @@
import type { Doc } from "@sgse-app/backend/convex/_generated/dataModel";
type Ticket = Doc<"tickets">;
type TicketStatus = Ticket["status"];
type TimelineEntry = NonNullable<Ticket["timeline"]>[number];
const UM_DIA_MS = 24 * 60 * 60 * 1000;
const statusConfig: Record<
TicketStatus,
{
label: string;
badge: string;
description: string;
}
> = {
aberto: {
label: "Aberto",
badge: "badge badge-info badge-outline",
description: "Chamado recebido e aguardando triagem.",
},
em_andamento: {
label: "Em andamento",
badge: "badge badge-primary",
description: "Equipe de TI trabalhando no chamado.",
},
aguardando_usuario: {
label: "Aguardando usuário",
badge: "badge badge-warning",
description: "Aguardando retorno ou aprovação do solicitante.",
},
resolvido: {
label: "Resolvido",
badge: "badge badge-success badge-outline",
description: "Solução aplicada, aguardando confirmação.",
},
encerrado: {
label: "Encerrado",
badge: "badge badge-success",
description: "Chamado finalizado.",
},
cancelado: {
label: "Cancelado",
badge: "badge badge-neutral",
description: "Chamado cancelado.",
},
};
export function getStatusLabel(status: TicketStatus): string {
return statusConfig[status]?.label ?? status;
}
export function getStatusBadge(status: TicketStatus): string {
return statusConfig[status]?.badge ?? "badge";
}
export function getStatusDescription(status: TicketStatus): string {
return statusConfig[status]?.description ?? "";
}
export function formatarData(timestamp?: number | null) {
if (!timestamp) return "--";
return new Date(timestamp).toLocaleString("pt-BR", {
day: "2-digit",
month: "short",
hour: "2-digit",
minute: "2-digit",
});
}
export function prazoRestante(timestamp?: number | null) {
if (!timestamp) return null;
const diff = timestamp - Date.now();
const dias = Math.floor(diff / UM_DIA_MS);
const horas = Math.floor((diff % UM_DIA_MS) / (60 * 60 * 1000));
if (diff < 0) {
return `Vencido há ${Math.abs(dias)}d ${Math.abs(horas)}h`;
}
if (dias === 0 && horas >= 0) {
return `Vence em ${horas}h`;
}
return `Vence em ${dias}d ${Math.abs(horas)}h`;
}
export function corPrazo(timestamp?: number | null) {
if (!timestamp) return "info";
const diff = timestamp - Date.now();
if (diff < 0) return "error";
if (diff <= UM_DIA_MS) return "warning";
return "success";
}
export function timelineStatus(entry: TimelineEntry) {
if (entry.status === "concluido") {
return "success";
}
if (!entry.prazo) {
return "info";
}
const diff = entry.prazo - Date.now();
if (diff < 0) {
return "error";
}
if (diff <= UM_DIA_MS) {
return "warning";
}
return "info";
}
export function formatarTimelineEtapa(etapa: string) {
const mapa: Record<string, string> = {
abertura: "Registro",
resposta_inicial: "Resposta inicial",
conclusao: "Conclusão",
encerramento: "Encerramento",
};
return mapa[etapa] ?? etapa;
}