feat: pestañas Mensajes/Correos, ocultar leídas, solicitud inicial, login al expirar, fusión de tickets (UI)
This commit is contained in:
1 parent
f88d79e2e8
commit
ce3fa29b69
4 files changed
+282
-89
No files matched your search
@@ -1,5 +1,16 @@
|
||||
const API_BASE = process.env.NEXT_PUBLIC_API_URL || "http://localhost:5000";
|
||||
|
||||
// Sesión expirada o inválida: limpia el token y lleva al login.
|
||||
// Se omite en el propio login (ahí el 401 es "credenciales inválidas")
|
||||
// y si ya estamos en /login para no recargar en bucle.
|
||||
function handleUnauthorized(path: string) {
|
||||
if (typeof window === "undefined") return;
|
||||
if (path.includes("/login")) return;
|
||||
if (window.location.pathname === "/login") return;
|
||||
localStorage.removeItem("helpdesk_token");
|
||||
window.location.href = "/login";
|
||||
}
|
||||
|
||||
async function fetchApi<T>(
|
||||
path: string,
|
||||
options: RequestInit = {}
|
||||
@@ -18,6 +29,8 @@ async function fetchApi<T>(
|
||||
|
||||
const res = await fetch(`${API_BASE}${path}`, { ...options, headers });
|
||||
|
||||
if (res.status === 401) handleUnauthorized(path);
|
||||
|
||||
if (!res.ok) {
|
||||
const errorData = await res.json().catch(() => ({}));
|
||||
throw new Error(errorData.message || `API Error: ${res.status}`);
|
||||
@@ -110,6 +123,13 @@ export async function updateTicketStatus(id: number, status: string) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function mergeTickets(targetId: number, sourceId: number) {
|
||||
return fetchApi<{ ticket: Ticket; merged: { comments: number; attachments: number; inbound: number; sourceId: number } }>(
|
||||
`/api/helpdesk/ticket/${targetId}/merge`,
|
||||
{ method: "POST", body: JSON.stringify({ sourceId }) }
|
||||
);
|
||||
}
|
||||
|
||||
export async function setTicketArchived(id: number, archived: boolean) {
|
||||
return fetchApi<void>(`/api/helpdesk/ticket/${id}/archive`, {
|
||||
method: "PUT",
|
||||
@@ -167,6 +187,7 @@ export async function uploadTicketAttachments(ticketId: number, files: File[]) {
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
body: form,
|
||||
});
|
||||
if (res.status === 401) handleUnauthorized("attachments");
|
||||
if (!res.ok) {
|
||||
const errorData = await res.json().catch(() => ({}));
|
||||
throw new Error(errorData.message || `API Error: ${res.status}`);
|
||||
@@ -184,6 +205,7 @@ export async function downloadAttachment(attachment: TicketAttachment) {
|
||||
const res = await fetch(`${API_BASE}/api/helpdesk/attachments/${attachment.id}`, {
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
});
|
||||
if (res.status === 401) handleUnauthorized("attachments");
|
||||
if (!res.ok) throw new Error(`No se pudo descargar (${res.status})`);
|
||||
const blob = await res.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
Reference in new issue
Block a user