Files
Messenger/web/src/api/chats.ts

274 lines
8.3 KiB
TypeScript

import { http } from "./http";
import type { Chat, ChatDetail, 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,
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): Promise<void> {
await http.post("/media/attachments", {
message_id: messageId,
file_url: fileUrl,
file_type: fileType,
file_size: fileSize
});
}
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 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 deleteMessage(messageId: number, forAll = false): Promise<void> {
await http.delete(`/messages/${messageId}`, { params: { for_all: forAll } });
}
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;
}