Corp/frontend/src/lib/api/messages.ts

117 lines
8.3 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
import type { ChatMessageSearchResponse } from '@/types/api';
import type { RequestFn, GetTokenFn } from './utils';
export function createMessagesApi(request: RequestFn, getToken: GetTokenFn) {
async function uploadMessage(chatId: number | string, text: string, files: File[], replyTo?: number) {
const fd = new FormData();
fd.append('content', text);
fd.append('chat_id', chatId.toString());
if (replyTo) fd.append('reply_to', replyTo.toString());
files.forEach((file, i) => fd.append(`file_${i}`, file));
const token = getToken();
const headers: Record<string, string> = {};
if (token) headers['Authorization'] = `Bearer ${token}`;
const response = await fetch('/api/v1/communications/messages/upload/', { method: 'POST', headers, body: fd });
if (!response.ok) {
let d = ''; try { const e = await response.json(); d = e.detail || JSON.stringify(e); } catch { d = response.statusText; }
throw new Error(`API Error: ${response.status} ${d}`);
}
const result = await response.json();
return result.message || result;
}
function buildChatsQuery(params?: { search?: string; page?: number; page_size?: number }) {
const qp = new URLSearchParams();
if (params?.search) qp.append('search', params.search);
if (params?.page) qp.append('page', params.page.toString());
if (params?.page_size) qp.append('page_size', params.page_size.toString());
const qs = qp.toString();
return `/api/v1/communications/chats/${qs ? '?' + qs : ''}`;
}
return {
getChats: (params?: { search?: string; page?: number; page_size?: number }) => request(buildChatsQuery(params)),
getAllChats: async (params?: { search?: string; page_size?: number }) => {
const pageSize = params?.page_size ?? 200;
const chats: any[] = [];
let page = 1;
for (;;) {
const response = await request(buildChatsQuery({
search: params?.search,
page,
page_size: pageSize,
})) as { results?: any[]; next?: string | null } | any[];
const results = Array.isArray(response) ? response : (response.results || []);
chats.push(...results);
if (Array.isArray(response) || !response.next) {
break;
}
page += 1;
}
return chats;
},
getChat: (chatId: number) => request(`/api/v1/communications/chats/${chatId}/`),
createChat: (data: { type: string; participants?: number[]; name?: string; description?: string; department?: number; include_all_employees?: boolean; avatar?: File }) => {
if (data.avatar) {
const fd = new FormData();
fd.append('type', data.type);
if (data.name) fd.append('name', data.name);
if (data.description) fd.append('description', data.description);
if (data.avatar) fd.append('avatar', data.avatar);
data.participants?.forEach(id => fd.append('participants', id.toString()));
if (data.department) fd.append('department', data.department.toString());
if (data.include_all_employees !== undefined) fd.append('include_all_employees', data.include_all_employees.toString());
return request('/api/v1/communications/chats/', { method: 'POST', body: fd });
}
return request('/api/v1/communications/chats/', { method: 'POST', body: JSON.stringify(data) });
},
getChatMessages: (chatId: number, params?: { limit?: number; before_id?: number; after_id?: number; mark_read?: boolean; before?: string; after?: string }) => {
const qp = new URLSearchParams();
if (params?.limit) qp.append('limit', params.limit.toString());
if (params?.before_id) qp.append('before_id', params.before_id.toString());
if (params?.after_id) qp.append('after_id', params.after_id.toString());
if (typeof params?.mark_read === 'boolean') qp.append('mark_read', String(params.mark_read));
if (params?.before) qp.append('before', params.before);
if (params?.after) qp.append('after', params.after);
const qs = qp.toString();
return request(`/api/v1/communications/chats/${chatId}/messages/${qs ? '?' + qs : ''}`);
},
getChatMessagesAround: (chatId: number | string, params?: { limit?: number; around_id?: number }) => {
const qp = new URLSearchParams();
if (params?.limit) qp.append('limit', params.limit.toString());
if (params?.around_id) qp.append('around_id', params.around_id.toString());
const qs = qp.toString();
return request(`/api/v1/communications/chats/${chatId}/messages-around/${qs ? '?' + qs : ''}`);
},
searchChatMessages: (chatId: number | string, params: { q: string; limit?: number; offset?: number }) => {
const qp = new URLSearchParams();
qp.append('q', params.q);
if (params.limit) qp.append('limit', params.limit.toString());
if (typeof params.offset === 'number') qp.append('offset', params.offset.toString());
return request(`/api/v1/communications/chats/${chatId}/search-messages/?${qp.toString()}`) as Promise<ChatMessageSearchResponse>;
},
sendMessage: (chatId: number | string, text: string, replyTo?: number) => uploadMessage(chatId, text, [], replyTo),
sendMessageWithFiles: (chatId: number | string, text: string, files: File[], replyTo?: number) => uploadMessage(chatId, text, files, replyTo),
updateMessage: (messageId: number, text: string) => request(`/api/v1/communications/messages/${messageId}/`, { method: 'PATCH', body: JSON.stringify({ content: text }) }),
deleteMessage: (messageId: number): Promise<void> => request(`/api/v1/communications/messages/${messageId}/`, { method: 'DELETE' }),
markChatAsRead: (chatId: number, lastReadMessageId?: number) => request(`/api/v1/communications/chats/${chatId}/mark-read/`, { method: 'POST', body: JSON.stringify({ message_id: lastReadMessageId }) }),
togglePinChat: (chatId: number) => request(`/api/v1/communications/chats/${chatId}/pin/`, { method: 'POST' }),
toggleChatNotifications: (chatId: number) => request(`/api/v1/communications/chats/${chatId}/notifications/`, { method: 'POST' }),
leaveChat: (chatId: number) => request(`/api/v1/communications/chats/${chatId}/leave/`, { method: 'POST' }),
deleteChat: (chatId: number) => request(`/api/v1/communications/chats/${chatId}/`, { method: 'DELETE' }),
updateChat: (chatId: number, data: Record<string, any>) => request(`/api/v1/communications/chats/${chatId}/`, { method: 'PATCH', body: JSON.stringify(data) }),
uploadChatAvatar: (chatId: number, file: File) => { const fd = new FormData(); fd.append('avatar', file); return request(`/api/v1/communications/chats/${chatId}/`, { method: 'PATCH', body: fd }); },
addChatMember: (chatId: number, userId: number) => request(`/api/v1/communications/chats/${chatId}/add-member/`, { method: 'POST', body: JSON.stringify({ user_id: userId }) }),
removeChatMember: (chatId: number, userId: number) => request(`/api/v1/communications/chats/${chatId}/remove-member/`, { method: 'POST', body: JSON.stringify({ user_id: userId }) }),
changeChatMemberRole: (chatId: number, userId: number, role: 'admin' | 'moderator' | 'member' | 'guest') => request(`/api/v1/communications/chats/${chatId}/change-role/`, { method: 'POST', body: JSON.stringify({ user_id: userId, role }) }),
updateChatUserSettings: (chatId: number, data: Record<string, any>) => request(`/api/v1/communications/chats/${chatId}/user-settings/`, { method: 'PATCH', body: JSON.stringify(data) }),
reactToMessage: (messageId: number, emoji: string) => request(`/api/v1/communications/messages/${messageId}/react/`, { method: 'POST', body: JSON.stringify({ emoji }) }),
unreactToMessage: (messageId: number, emoji: string) => request(`/api/v1/communications/messages/${messageId}/unreact/`, { method: 'POST', body: JSON.stringify({ emoji }) }),
};
}