168 lines
4.7 KiB
TypeScript
168 lines
4.7 KiB
TypeScript
/**
|
||
* API модуль для чата
|
||
*/
|
||
|
||
import apiClient from '@/lib/api-client';
|
||
|
||
export interface Chat {
|
||
id: number;
|
||
uuid?: string;
|
||
participants?: number[];
|
||
participant_name?: string;
|
||
avatar_url?: string | null;
|
||
other_user_id?: number | null;
|
||
other_is_online?: boolean;
|
||
other_last_activity?: string | null;
|
||
last_message?: string;
|
||
last_message_time?: string;
|
||
unread_count?: number;
|
||
created_at?: string;
|
||
// расширенные поля из бэка (для удобного маппинга)
|
||
my_participant?: { unread_count?: number; is_muted?: boolean; is_pinned?: boolean };
|
||
other_participant?: {
|
||
full_name?: string;
|
||
first_name?: string;
|
||
last_name?: string;
|
||
avatar?: string | null;
|
||
avatar_url?: string | null;
|
||
role?: string;
|
||
};
|
||
last_message_obj?: any;
|
||
}
|
||
|
||
export interface Message {
|
||
id: number;
|
||
uuid?: string;
|
||
chat: number;
|
||
// у системных сообщений может быть строка/NULL
|
||
sender: any;
|
||
sender_id?: number | null;
|
||
sender_name?: string;
|
||
content: string;
|
||
file?: string;
|
||
file_type?: string;
|
||
created_at?: string;
|
||
is_read?: boolean;
|
||
}
|
||
|
||
export interface PaginatedResponse<T> {
|
||
count: number;
|
||
next: string | null;
|
||
previous: string | null;
|
||
results: T[];
|
||
}
|
||
|
||
/**
|
||
* Получить список чатов (conversations)
|
||
*/
|
||
export async function getConversations(params?: {
|
||
page?: number;
|
||
page_size?: number;
|
||
}): Promise<PaginatedResponse<Chat>> {
|
||
const response = await apiClient.get<Chat[] | PaginatedResponse<Chat>>('/chat/chats/', {
|
||
params,
|
||
});
|
||
const data: any = response.data;
|
||
if (Array.isArray(data)) {
|
||
return { count: data.length, next: null, previous: null, results: data };
|
||
}
|
||
return {
|
||
count: data?.count ?? (data?.results?.length ?? 0),
|
||
next: data?.next ?? null,
|
||
previous: data?.previous ?? null,
|
||
results: data?.results ?? [],
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Получить чат по UUID (detail=true в DRF)
|
||
*/
|
||
export async function getChatById(uuid: string): Promise<Chat> {
|
||
const response = await apiClient.get<Chat>(`/chat/chats/${uuid}/`);
|
||
return response.data;
|
||
}
|
||
|
||
/**
|
||
* Создать чат
|
||
*/
|
||
export async function createChat(participantId: number): Promise<Chat> {
|
||
const response = await apiClient.post<Chat>('/chat/chats/', {
|
||
participants: [participantId],
|
||
});
|
||
return response.data;
|
||
}
|
||
|
||
/**
|
||
* Получить сообщения чата
|
||
*/
|
||
export async function getMessages(
|
||
chatId: number,
|
||
params?: { page?: number; page_size?: number }
|
||
): Promise<PaginatedResponse<Message>> {
|
||
// fallback: если нет uuid — используем общий endpoint
|
||
const response = await apiClient.get<PaginatedResponse<Message>>('/chat/messages/', {
|
||
params: { ...params, chat: chatId },
|
||
});
|
||
return response.data;
|
||
}
|
||
|
||
export async function getChatMessagesByUuid(
|
||
chatUuid: string,
|
||
params?: { page?: number; page_size?: number }
|
||
): Promise<PaginatedResponse<Message>> {
|
||
const response = await apiClient.get<PaginatedResponse<Message>>(
|
||
`/chat/chats/${chatUuid}/messages/`,
|
||
{ params }
|
||
);
|
||
return response.data;
|
||
}
|
||
|
||
/**
|
||
* Отправить сообщение
|
||
*/
|
||
export async function sendMessage(
|
||
chatId: number,
|
||
content: string,
|
||
file?: File
|
||
): Promise<Message> {
|
||
const formData = new FormData();
|
||
formData.append('chat', chatId.toString());
|
||
formData.append('content', content);
|
||
if (file) {
|
||
formData.append('file', file);
|
||
}
|
||
|
||
const response = await apiClient.post<any>('/chat/messages/', formData, {
|
||
headers: {
|
||
'Content-Type': 'multipart/form-data',
|
||
},
|
||
});
|
||
const data: any = response.data;
|
||
// backend может возвращать { success: true, data: {...} }
|
||
if (data && typeof data === 'object' && 'data' in data) {
|
||
return data.data as Message;
|
||
}
|
||
return data as Message;
|
||
}
|
||
|
||
/**
|
||
* Отметить сообщения как прочитанные
|
||
*/
|
||
export async function markMessagesAsRead(chatUuid: string, messageUuids?: string[]): Promise<void> {
|
||
await apiClient.post(`/chat/chats/${chatUuid}/mark_read/`, messageUuids ? { message_uuids: messageUuids } : {});
|
||
}
|
||
|
||
/**
|
||
* Получить или создать чат для урока
|
||
*/
|
||
export async function getOrCreateLessonChat(lessonId: number): Promise<Chat> {
|
||
const res = await apiClient.get<{ success: boolean; data: Chat } | Chat>(
|
||
`/chat/chats/lesson_chat/?lesson_id=${lessonId}`
|
||
);
|
||
const data = res.data;
|
||
if (data && typeof data === 'object' && 'success' in data && 'data' in data) {
|
||
return (data as { success: boolean; data: Chat }).data;
|
||
}
|
||
return data as Chat;
|
||
}
|