341 lines
8.0 KiB
TypeScript
341 lines
8.0 KiB
TypeScript
const API_BASE = process.env.NEXT_PUBLIC_API_URL || "http://localhost:5000";
|
|
|
|
async function fetchApi<T>(
|
|
path: string,
|
|
options: RequestInit = {}
|
|
): Promise<T> {
|
|
const token =
|
|
typeof window !== "undefined" ? localStorage.getItem("helpdesk_token") : null;
|
|
|
|
const headers: Record<string, string> = {
|
|
"Content-Type": "application/json",
|
|
...((options.headers as Record<string, string>) || {}),
|
|
};
|
|
|
|
if (token) {
|
|
headers["Authorization"] = `Bearer ${token}`;
|
|
}
|
|
|
|
const res = await fetch(`${API_BASE}${path}`, { ...options, headers });
|
|
|
|
if (!res.ok) {
|
|
const errorData = await res.json().catch(() => ({}));
|
|
throw new Error(errorData.message || `API Error: ${res.status}`);
|
|
}
|
|
|
|
if (res.status === 204) return undefined as T;
|
|
return res.json();
|
|
}
|
|
|
|
// ==================== Auth ====================
|
|
export async function login(idUsuario: string, password: string) {
|
|
return fetchApi<{ success: boolean; message?: string; token?: string; user?: HelpDeskUser }>(
|
|
"/api/helpdesk/login",
|
|
{ method: "POST", body: JSON.stringify({ idUsuario, password }) }
|
|
);
|
|
}
|
|
|
|
export async function getMe() {
|
|
return fetchApi<HelpDeskUser>("/api/helpdesk/me");
|
|
}
|
|
|
|
// ==================== Tickets ====================
|
|
export async function getTickets(params?: {
|
|
status?: string;
|
|
priority?: string;
|
|
assigneeId?: number;
|
|
requesterId?: number;
|
|
groupId?: number;
|
|
search?: string;
|
|
page?: number;
|
|
pageSize?: number;
|
|
}) {
|
|
const query = new URLSearchParams();
|
|
if (params) {
|
|
Object.entries(params).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== "" && value !== null)
|
|
query.set(key, String(value));
|
|
});
|
|
}
|
|
return fetchApi<TicketListResult>(`/api/helpdesk/tickets?${query.toString()}`);
|
|
}
|
|
|
|
export async function getTicket(id: number) {
|
|
return fetchApi<Ticket>(`/api/helpdesk/ticket/${id}`);
|
|
}
|
|
|
|
export async function createTicket(data: {
|
|
title: string;
|
|
description: string;
|
|
priority?: string;
|
|
assigneeId?: number;
|
|
groupId?: number;
|
|
slaPolicyId?: number;
|
|
}) {
|
|
return fetchApi<{ id: number }>("/api/helpdesk/tickets", {
|
|
method: "POST",
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
export async function updateTicket(id: number, data: {
|
|
title?: string;
|
|
description?: string;
|
|
priority?: string;
|
|
assigneeId?: number;
|
|
groupId?: number;
|
|
}) {
|
|
return fetchApi<void>(`/api/helpdesk/ticket/${id}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
export async function deleteTicket(id: number) {
|
|
return fetchApi<void>(`/api/helpdesk/ticket/${id}`, { method: "DELETE" });
|
|
}
|
|
|
|
export async function updateTicketStatus(id: number, status: string) {
|
|
return fetchApi<void>(`/api/helpdesk/ticket/${id}/status`, {
|
|
method: "PUT",
|
|
body: JSON.stringify({ status }),
|
|
});
|
|
}
|
|
|
|
export async function assignTicket(id: number, assigneeId: number, groupId?: number) {
|
|
return fetchApi<void>(`/api/helpdesk/ticket/${id}/assign`, {
|
|
method: "PUT",
|
|
body: JSON.stringify({ assigneeId, groupId }),
|
|
});
|
|
}
|
|
|
|
export async function getTicketStats() {
|
|
return fetchApi<DashboardStats>("/api/helpdesk/stats");
|
|
}
|
|
|
|
// ==================== Comments ====================
|
|
export async function getComments(ticketId: number) {
|
|
return fetchApi<Comment[]>(`/api/helpdesk/comments/${ticketId}`);
|
|
}
|
|
|
|
export async function addComment(
|
|
ticketId: number,
|
|
content: string,
|
|
isInternal: boolean = false
|
|
) {
|
|
return fetchApi<{ id: number }>(`/api/helpdesk/comments/${ticketId}`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ content, isInternal }),
|
|
});
|
|
}
|
|
|
|
// ==================== Knowledge Base ====================
|
|
export async function getKBArticles() {
|
|
return fetchApi<KBArticle[]>("/api/helpdesk/kb/published");
|
|
}
|
|
|
|
export async function searchKB(query: string) {
|
|
return fetchApi<KBArticle[]>(`/api/helpdesk/kb/search?q=${encodeURIComponent(query)}`);
|
|
}
|
|
|
|
export async function getKBCategories() {
|
|
return fetchApi<KBCategory[]>("/api/helpdesk/kb/categories");
|
|
}
|
|
|
|
// ==================== Groups & SLA ====================
|
|
export async function getGroups() {
|
|
return fetchApi<Group[]>("/api/helpdesk/groups");
|
|
}
|
|
|
|
export async function getSLAPolicies() {
|
|
return fetchApi<SLAPolicy[]>("/api/helpdesk/sla");
|
|
}
|
|
|
|
// ==================== Types ====================
|
|
export interface HelpDeskUser {
|
|
idUsuario: string;
|
|
nombres: string;
|
|
apPaterno: string;
|
|
apMaterno?: string;
|
|
email: string;
|
|
tipo?: string;
|
|
activo: number;
|
|
fono?: string;
|
|
idSede?: number;
|
|
role?: string;
|
|
departmentId?: number;
|
|
departmentName?: string;
|
|
}
|
|
|
|
export interface Ticket {
|
|
id: number;
|
|
title: string;
|
|
description: string;
|
|
status: string;
|
|
priority: string;
|
|
ticketNumber: string;
|
|
requesterId: number;
|
|
requesterName?: string;
|
|
requesterEmail?: string;
|
|
assigneeId?: number;
|
|
assigneeName?: string;
|
|
groupId?: number;
|
|
groupName?: string;
|
|
slaPolicyId?: number;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
firstResponseAt?: string;
|
|
resolvedAt?: string;
|
|
closedAt?: string;
|
|
}
|
|
|
|
export interface TicketListResult {
|
|
items: Ticket[];
|
|
total: number;
|
|
page: number;
|
|
pageSize: number;
|
|
totalPages: number;
|
|
}
|
|
|
|
export interface Comment {
|
|
id: number;
|
|
ticketId: number;
|
|
userId: string;
|
|
userName?: string;
|
|
content: string;
|
|
isInternal: boolean;
|
|
createdAt: string;
|
|
}
|
|
|
|
export interface Group {
|
|
id: number;
|
|
name: string;
|
|
description?: string;
|
|
isActive: boolean;
|
|
}
|
|
|
|
export interface KBArticle {
|
|
id: number;
|
|
title: string;
|
|
content: string;
|
|
categoryId: number;
|
|
categoryName?: string;
|
|
authorId: string;
|
|
authorName?: string;
|
|
isPublished: boolean;
|
|
viewCount: number;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface KBCategory {
|
|
id: number;
|
|
name: string;
|
|
description?: string;
|
|
sortOrder: number;
|
|
}
|
|
|
|
export interface SLAPolicy {
|
|
id: number;
|
|
name: string;
|
|
description?: string;
|
|
responseTimeHours: number;
|
|
resolutionTimeHours: number;
|
|
isActive: boolean;
|
|
}
|
|
|
|
export interface DashboardStats {
|
|
totalTickets: number;
|
|
openTickets: number;
|
|
inProgressTickets: number;
|
|
resolvedTickets: number;
|
|
closedTickets: number;
|
|
unassignedTickets: number;
|
|
criticalTickets: number;
|
|
dailyCounts: { date: string; count: number }[];
|
|
}
|
|
|
|
// ==================== Departamentos ====================
|
|
export async function createGroup(data: { name: string; description?: string }) {
|
|
return fetchApi<Group>("/api/helpdesk/groups", {
|
|
method: "POST",
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
export async function updateGroup(
|
|
id: number,
|
|
data: { name?: string; description?: string; isActive?: boolean }
|
|
) {
|
|
return fetchApi<void>(`/api/helpdesk/groups/${id}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
export async function deleteGroup(id: number) {
|
|
return fetchApi<void>(`/api/helpdesk/groups/${id}`, { method: "DELETE" });
|
|
}
|
|
|
|
// ==================== Equipo ====================
|
|
export interface TeamMember extends HelpDeskUser {
|
|
role: string;
|
|
departmentId?: number;
|
|
departmentName?: string;
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export async function getTeam() {
|
|
return fetchApi<TeamMember[]>("/api/helpdesk/users");
|
|
}
|
|
|
|
export async function addMember(data: {
|
|
idUsuario: string;
|
|
role?: string;
|
|
departmentId?: number;
|
|
}) {
|
|
return fetchApi<TeamMember>("/api/helpdesk/users", {
|
|
method: "POST",
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
export async function updateMember(
|
|
idUsuario: string,
|
|
data: { role?: string; departmentId?: number; isActive?: boolean }
|
|
) {
|
|
return fetchApi<TeamMember>(`/api/helpdesk/users/${encodeURIComponent(idUsuario)}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
// ==================== SLA ====================
|
|
export async function createSla(data: {
|
|
name: string;
|
|
description?: string;
|
|
responseTimeHours?: number;
|
|
resolutionTimeHours?: number;
|
|
}) {
|
|
return fetchApi<SLAPolicy>("/api/helpdesk/sla", {
|
|
method: "POST",
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
export async function updateSla(
|
|
id: number,
|
|
data: {
|
|
name?: string;
|
|
description?: string;
|
|
responseTimeHours?: number;
|
|
resolutionTimeHours?: number;
|
|
isActive?: boolean;
|
|
}
|
|
) {
|
|
return fetchApi<void>(`/api/helpdesk/sla/${id}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|