/** * 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 { count: number; next: string | null; previous: string | null; results: T[]; } /** * Получить список чатов (conversations) */ export async function getConversations(params?: { page?: number; page_size?: number; }): Promise> { const response = await apiClient.get>('/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 { const response = await apiClient.get(`/chat/chats/${uuid}/`); return response.data; } /** * Создать чат */ export async function createChat(participantId: number): Promise { const response = await apiClient.post('/chat/chats/', { participants: [participantId], }); return response.data; } /** * Получить сообщения чата */ export async function getMessages( chatId: number, params?: { page?: number; page_size?: number } ): Promise> { // fallback: если нет uuid — используем общий endpoint const response = await apiClient.get>('/chat/messages/', { params: { ...params, chat: chatId }, }); return response.data; } export async function getChatMessagesByUuid( chatUuid: string, params?: { page?: number; page_size?: number } ): Promise> { const response = await apiClient.get>( `/chat/chats/${chatUuid}/messages/`, { params } ); return response.data; } /** * Отправить сообщение */ export async function sendMessage( chatId: number, content: string, file?: File ): Promise { const formData = new FormData(); formData.append('chat', chatId.toString()); formData.append('content', content); if (file) { formData.append('file', file); } const response = await apiClient.post('/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 { await apiClient.post(`/chat/chats/${chatUuid}/mark_read/`, messageUuids ? { message_uuids: messageUuids } : {}); } /** * Получить или создать чат для урока */ export async function getOrCreateLessonChat(lessonId: number): Promise { 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; }