- 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.
124 lines
3.0 KiB
TypeScript
124 lines
3.0 KiB
TypeScript
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;
|
|
}
|
|
|