Files
Messenger/web/src/api/chats.ts
benya 704781e359
All checks were successful
CI / test (push) Successful in 24s
feat(web): add message edit flow in context menu and composer
2026-03-08 13:22:57 +03:00

325 lines
9.5 KiB
TypeScript

import { http } from "./http";
import type {
Chat,
ChatAttachment,
ChatDetail,
ChatInviteLink,
ChatMember,
ChatMemberRole,
ChatType,
DiscoverChat,
Message,
MessageReaction,
MessageType
} from "../chat/types";
import axios from "axios";
export interface ChatNotificationSettings {
chat_id: number;
user_id: number;
muted: boolean;
}
export async function getChats(query?: string, archived = false): Promise<Chat[]> {
const { data } = await http.get<Chat[]>("/chats", {
params: {
...(query?.trim() ? { query: query.trim() } : {}),
...(archived ? { archived: true } : {})
}
});
return data;
}
export async function createPrivateChat(memberId: number): Promise<Chat> {
return createChat("private", null, [memberId]);
}
export async function createChat(type: ChatType, title: string | null, memberIds: number[] = []): Promise<Chat> {
const { data } = await http.post<Chat>("/chats", {
type,
title,
is_public: false,
member_ids: memberIds
});
return data;
}
export async function createPublicChat(type: "group" | "channel", title: string, handle: string, description?: string): Promise<Chat> {
const { data } = await http.post<Chat>("/chats", {
type,
title,
handle,
description,
is_public: true,
member_ids: []
});
return data;
}
export async function getMessages(chatId: number, beforeId?: number): Promise<Message[]> {
const { data } = await http.get<Message[]>(`/messages/${chatId}`, {
params: {
limit: 50,
before_id: beforeId
}
});
return data;
}
export async function searchMessages(query: string, chatId?: number): Promise<Message[]> {
const { data } = await http.get<Message[]>("/messages/search", {
params: {
query,
chat_id: chatId
}
});
return data;
}
export async function sendMessage(chatId: number, text: string, type: MessageType = "text"): Promise<Message> {
const { data } = await http.post<Message>("/messages", { chat_id: chatId, text, type });
return data;
}
export async function sendMessageWithClientId(
chatId: number,
text: string | null,
type: MessageType,
clientMessageId: string,
replyToMessageId?: number
): Promise<Message> {
const { data } = await http.post<Message>("/messages", {
chat_id: chatId,
text,
type,
client_message_id: clientMessageId,
reply_to_message_id: replyToMessageId
});
return data;
}
export interface UploadUrlResponse {
upload_url: string;
file_url: string;
object_key: string;
expires_in: number;
required_headers: Record<string, string>;
}
export async function requestUploadUrl(file: File): Promise<UploadUrlResponse> {
const { data } = await http.post<UploadUrlResponse>("/media/upload-url", {
file_name: file.name,
file_type: file.type || "application/octet-stream",
file_size: file.size
});
return data;
}
export async function uploadToPresignedUrl(
uploadUrl: string,
requiredHeaders: Record<string, string>,
file: File,
onProgress?: (percent: number) => void,
retries = 2
): Promise<void> {
let attempt = 0;
while (attempt <= retries) {
try {
await axios.put(uploadUrl, file, {
headers: requiredHeaders,
onUploadProgress: (progressEvent) => {
if (!onProgress || !progressEvent.total) {
return;
}
onProgress(Math.round((progressEvent.loaded * 100) / progressEvent.total));
}
});
return;
} catch (error) {
const status = axios.isAxiosError(error) ? error.response?.status : undefined;
const retryable = status === undefined || status >= 500;
if (!retryable || attempt >= retries) {
throw error;
}
attempt += 1;
await new Promise((resolve) => window.setTimeout(resolve, 400 * attempt));
}
}
}
export async function attachFile(
messageId: number,
fileUrl: string,
fileType: string,
fileSize: number,
waveformPoints?: number[] | null
): Promise<void> {
await http.post("/media/attachments", {
message_id: messageId,
file_url: fileUrl,
file_type: fileType,
file_size: fileSize,
waveform_points: waveformPoints ?? undefined
});
}
export async function updateMessageStatus(
chatId: number,
messageId: number,
status: "message_delivered" | "message_read"
): Promise<void> {
await http.post("/messages/status", {
chat_id: chatId,
message_id: messageId,
status
});
}
export async function forwardMessage(messageId: number, targetChatId: number): Promise<Message> {
const { data } = await http.post<Message>(`/messages/${messageId}/forward`, {
target_chat_id: targetChatId
});
return data;
}
export async function forwardMessageBulk(messageId: number, targetChatIds: number[]): Promise<Message[]> {
const { data } = await http.post<Message[]>(`/messages/${messageId}/forward-bulk`, {
target_chat_ids: targetChatIds
});
return data;
}
export async function listMessageReactions(messageId: number): Promise<MessageReaction[]> {
const { data } = await http.get<MessageReaction[]>(`/messages/${messageId}/reactions`);
return data;
}
export async function toggleMessageReaction(messageId: number, emoji: string): Promise<MessageReaction[]> {
const { data } = await http.post<MessageReaction[]>(`/messages/${messageId}/reactions/toggle`, { emoji });
return data;
}
export async function pinMessage(chatId: number, messageId: number | null): Promise<Chat> {
const { data } = await http.post<Chat>(`/chats/${chatId}/pin`, {
message_id: messageId
});
return data;
}
export async function deleteChat(chatId: number, forAll: boolean): Promise<void> {
await http.delete(`/chats/${chatId}`, { params: { for_all: forAll } });
}
export async function clearChat(chatId: number): Promise<void> {
await http.post(`/chats/${chatId}/clear`);
}
export async function archiveChat(chatId: number): Promise<Chat> {
const { data } = await http.post<Chat>(`/chats/${chatId}/archive`);
return data;
}
export async function unarchiveChat(chatId: number): Promise<Chat> {
const { data } = await http.post<Chat>(`/chats/${chatId}/unarchive`);
return data;
}
export async function pinChat(chatId: number): Promise<Chat> {
const { data } = await http.post<Chat>(`/chats/${chatId}/pin-chat`);
return data;
}
export async function unpinChat(chatId: number): Promise<Chat> {
const { data } = await http.post<Chat>(`/chats/${chatId}/unpin-chat`);
return data;
}
export async function createInviteLink(chatId: number): Promise<ChatInviteLink> {
const { data } = await http.post<ChatInviteLink>(`/chats/${chatId}/invite-link`);
return data;
}
export async function joinByInvite(token: string): Promise<Chat> {
const { data } = await http.post<Chat>("/chats/join-by-invite", { token });
return data;
}
export async function getChatAttachments(chatId: number, limit = 100, beforeId?: number): Promise<ChatAttachment[]> {
const { data } = await http.get<ChatAttachment[]>(`/media/chats/${chatId}/attachments`, {
params: {
limit,
before_id: beforeId
}
});
return data;
}
export async function deleteMessage(messageId: number, forAll = false): Promise<void> {
await http.delete(`/messages/${messageId}`, { params: { for_all: forAll } });
}
export async function editMessage(messageId: number, text: string): Promise<Message> {
const { data } = await http.put<Message>(`/messages/${messageId}`, { text });
return data;
}
export async function discoverChats(query?: string): Promise<DiscoverChat[]> {
const { data } = await http.get<DiscoverChat[]>("/chats/discover", {
params: query?.trim() ? { query: query.trim() } : undefined
});
return data;
}
export async function joinChat(chatId: number): Promise<Chat> {
const { data } = await http.post<Chat>(`/chats/${chatId}/join`);
return data;
}
export async function getSavedMessagesChat(): Promise<Chat> {
const { data } = await http.get<Chat>("/chats/saved");
return data;
}
export async function getChatDetail(chatId: number): Promise<ChatDetail> {
const { data } = await http.get<ChatDetail>(`/chats/${chatId}`);
return data;
}
export async function listChatMembers(chatId: number): Promise<ChatMember[]> {
const { data } = await http.get<ChatMember[]>(`/chats/${chatId}/members`);
return data;
}
export async function updateChatTitle(chatId: number, title: string): Promise<Chat> {
const { data } = await http.patch<Chat>(`/chats/${chatId}/title`, { title });
return data;
}
export async function addChatMember(chatId: number, userId: number): Promise<ChatMember> {
const { data } = await http.post<ChatMember>(`/chats/${chatId}/members`, { user_id: userId });
return data;
}
export async function updateChatMemberRole(chatId: number, userId: number, role: ChatMemberRole): Promise<ChatMember> {
const { data } = await http.patch<ChatMember>(`/chats/${chatId}/members/${userId}/role`, { role });
return data;
}
export async function removeChatMember(chatId: number, userId: number): Promise<void> {
await http.delete(`/chats/${chatId}/members/${userId}`);
}
export async function leaveChat(chatId: number): Promise<void> {
await http.post(`/chats/${chatId}/leave`);
}
export async function getChatNotificationSettings(chatId: number): Promise<ChatNotificationSettings> {
const { data } = await http.get<ChatNotificationSettings>(`/chats/${chatId}/notifications`);
return data;
}
export async function updateChatNotificationSettings(chatId: number, muted: boolean): Promise<ChatNotificationSettings> {
const { data } = await http.put<ChatNotificationSettings>(`/chats/${chatId}/notifications`, { muted });
return data;
}