Files
GNX-WEB/frontEnd/lib/api/supportService.ts
Iliyan Angelov 366f28677a update
2025-11-24 03:52:08 +02:00

415 lines
11 KiB
TypeScript

import { API_CONFIG } from '../config/api';
const BASE_URL = `${API_CONFIG.BASE_URL}/api/support`;
// ==================== Types ====================
export interface TicketStatus {
id: number;
name: string;
color: string;
description: string;
is_closed: boolean;
display_order: number;
}
export interface TicketPriority {
id: number;
name: string;
level: number;
color: string;
description: string;
sla_hours: number;
}
export interface TicketCategory {
id: number;
name: string;
description: string;
color: string;
icon: string;
display_order: number;
}
export interface TicketMessage {
id: number;
ticket: number;
message_type: string;
content: string;
author_name: string;
author_email: string;
is_internal: boolean;
created_at: string;
updated_at: string;
attachments: string[];
is_read: boolean;
}
export interface TicketActivity {
id: number;
activity_type: string;
description: string;
user_name: string;
old_value: string;
new_value: string;
created_at: string;
}
export interface SupportTicket {
id: number;
ticket_number: string;
title: string;
description: string;
ticket_type: string;
user_name: string;
user_email: string;
user_phone: string;
company: string;
category: number | null;
category_name: string;
priority: number | null;
priority_name: string;
priority_color: string;
status: number | null;
status_name: string;
status_color: string;
assigned_to: number | null;
assigned_at: string | null;
created_at: string;
updated_at: string;
closed_at: string | null;
last_activity: string;
first_response_at: string | null;
sla_deadline: string | null;
tags: string;
is_escalated: boolean;
escalation_reason: string;
attachments: string[];
messages: TicketMessage[];
activities: TicketActivity[];
}
export interface CreateTicketData {
title: string;
description: string;
ticket_type: string;
user_name: string;
user_email: string;
user_phone?: string;
company?: string;
category?: number;
}
export interface KnowledgeBaseCategory {
id: number;
name: string;
slug: string;
description: string;
icon: string;
color: string;
display_order: number;
article_count: number;
}
export interface KnowledgeBaseArticle {
id: number;
title: string;
slug: string;
category: number;
category_name: string;
category_slug: string;
content?: string;
summary: string;
meta_description?: string;
keywords?: string;
is_featured: boolean;
view_count: number;
helpful_count: number;
not_helpful_count: number;
created_at: string;
updated_at: string;
published_at: string;
}
export interface SupportSettings {
id: number;
setting_name: string;
setting_value: string;
description: string;
is_active: boolean;
}
// ==================== API Functions ====================
/**
* Fetch all ticket categories
*/
export const getTicketCategories = async (): Promise<TicketCategory[]> => {
try {
const response = await fetch(`${BASE_URL}/categories/`);
if (!response.ok) throw new Error('Failed to fetch ticket categories');
const data = await response.json();
// Handle paginated response
return data.results || data;
} catch (error) {
throw error;
}
};
/**
* Fetch all ticket statuses
*/
export const getTicketStatuses = async (): Promise<TicketStatus[]> => {
try {
const response = await fetch(`${BASE_URL}/statuses/`);
if (!response.ok) throw new Error('Failed to fetch ticket statuses');
const data = await response.json();
// Handle paginated response
return data.results || data;
} catch (error) {
throw error;
}
};
/**
* Fetch all ticket priorities
*/
export const getTicketPriorities = async (): Promise<TicketPriority[]> => {
try {
const response = await fetch(`${BASE_URL}/priorities/`);
if (!response.ok) throw new Error('Failed to fetch ticket priorities');
const data = await response.json();
// Handle paginated response
return data.results || data;
} catch (error) {
throw error;
}
};
/**
* Create a new support ticket
*/
export const createTicket = async (data: CreateTicketData): Promise<SupportTicket> => {
try {
const response = await fetch(`${BASE_URL}/tickets/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
// Handle specific HTTP status codes
if (response.status === 400) {
// Handle validation errors
if (errorData.user_email) {
throw new Error(errorData.user_email[0] || 'Email validation failed');
}
if (errorData.title) {
throw new Error(errorData.title[0] || 'Title is required');
}
if (errorData.description) {
throw new Error(errorData.description[0] || 'Description is required');
}
if (errorData.user_name) {
throw new Error(errorData.user_name[0] || 'Name is required');
}
// Generic validation error
throw new Error(errorData.detail || errorData.message || 'Please check all required fields and try again');
} else if (response.status === 429) {
throw new Error('Too many requests. Please wait a moment and try again');
} else if (response.status >= 500) {
throw new Error('Server error. Please try again later');
} else if (response.status === 403) {
throw new Error('Access denied. Please contact support if this persists');
} else if (response.status === 404) {
throw new Error('Service not found. Please refresh the page and try again');
}
throw new Error(errorData.detail || errorData.message || 'An unexpected error occurred');
}
return await response.json();
} catch (error) {
throw error;
}
};
/**
* Check ticket status by ticket number
*/
export const checkTicketStatus = async (ticketNumber: string): Promise<SupportTicket> => {
try {
const response = await fetch(`${BASE_URL}/tickets/check-status/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ ticket_number: ticketNumber }),
});
if (!response.ok) {
if (response.status === 404) {
throw new Error('Ticket not found');
}
throw new Error('Failed to check ticket status');
}
return await response.json();
} catch (error) {
throw error;
}
};
/**
* Add a message to a ticket
*/
export const addTicketMessage = async (
ticketId: number,
content: string,
authorName: string,
authorEmail: string
): Promise<TicketMessage> => {
try {
const response = await fetch(`${BASE_URL}/tickets/${ticketId}/add-message/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
content,
author_name: authorName,
author_email: authorEmail,
}),
});
if (!response.ok) throw new Error('Failed to add ticket message');
return await response.json();
} catch (error) {
throw error;
}
};
/**
* Fetch all knowledge base categories
*/
export const getKnowledgeBaseCategories = async (): Promise<KnowledgeBaseCategory[]> => {
try {
const response = await fetch(`${BASE_URL}/knowledge-base-categories/`);
if (!response.ok) throw new Error('Failed to fetch knowledge base categories');
const data = await response.json();
// Handle paginated response
return data.results || data;
} catch (error) {
throw error;
}
};
/**
* Fetch all knowledge base articles
*/
export const getKnowledgeBaseArticles = async (search?: string): Promise<KnowledgeBaseArticle[]> => {
try {
const url = search
? `${BASE_URL}/knowledge-base/?search=${encodeURIComponent(search)}`
: `${BASE_URL}/knowledge-base/`;
const response = await fetch(url);
if (!response.ok) throw new Error('Failed to fetch knowledge base articles');
const data = await response.json();
// Handle paginated response
return data.results || data;
} catch (error) {
throw error;
}
};
/**
* Fetch featured knowledge base articles
*/
export const getFeaturedArticles = async (): Promise<KnowledgeBaseArticle[]> => {
try {
const response = await fetch(`${BASE_URL}/knowledge-base/featured/`);
if (!response.ok) throw new Error('Failed to fetch featured articles');
const data = await response.json();
// Handle both array and paginated responses
return Array.isArray(data) ? data : (data.results || data);
} catch (error) {
throw error;
}
};
/**
* Fetch a single knowledge base article by slug
*/
export const getKnowledgeBaseArticle = async (slug: string): Promise<KnowledgeBaseArticle> => {
try {
const response = await fetch(`${BASE_URL}/knowledge-base/${slug}/`);
if (!response.ok) throw new Error('Failed to fetch knowledge base article');
return await response.json();
} catch (error) {
throw error;
}
};
/**
* Fetch articles by category
*/
export const getArticlesByCategory = async (categorySlug: string): Promise<KnowledgeBaseArticle[]> => {
try {
const response = await fetch(`${BASE_URL}/knowledge-base/by-category/${categorySlug}/`);
if (!response.ok) throw new Error('Failed to fetch articles by category');
const data = await response.json();
// Handle paginated response
return data.results || data;
} catch (error) {
throw error;
}
};
/**
* Mark an article as helpful or not helpful
*/
export const markArticleHelpful = async (slug: string, helpful: boolean): Promise<{ helpful_count: number; not_helpful_count: number }> => {
try {
const response = await fetch(`${BASE_URL}/knowledge-base/${slug}/mark-helpful/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ helpful }),
});
if (!response.ok) throw new Error('Failed to mark article helpful');
return await response.json();
} catch (error) {
throw error;
}
};
/**
* Fetch support settings
*/
export const getSupportSettings = async (): Promise<SupportSettings[]> => {
try {
const response = await fetch(`${BASE_URL}/settings/`);
if (!response.ok) throw new Error('Failed to fetch support settings');
const data = await response.json();
// Handle paginated response
return data.results || data;
} catch (error) {
throw error;
}
};
/**
* Fetch a specific support setting by name
*/
export const getSupportSetting = async (settingName: string): Promise<SupportSettings> => {
try {
const response = await fetch(`${BASE_URL}/settings/${settingName}/`);
if (!response.ok) throw new Error('Failed to fetch support setting');
return await response.json();
} catch (error) {
throw error;
}
};