UNPKG

@droppii-org/chat-sdk

Version:

Droppii React Chat SDK

289 lines (288 loc) 12.3 kB
import { MessageStatus, } from "@openim/wasm-client-sdk"; import { DChatSDK } from "../../constants/sdk"; import { v4 as uuidv4 } from "uuid"; import { useChatContext } from "../../context/ChatContext"; import { useCallback } from "react"; import { pushNewMessage, updateOneMessage } from "./useMessage"; import { emit } from "../../utils/events"; import useConversationStore from "../../store/conversation"; import useAuthStore from "../../store/auth"; import { extractLinks, generateContentBasedOnMessageType, } from "../../utils/common"; export const createTextMessage = async (text) => { let textMessage = await DChatSDK.createTextMessage(text, new Date().getTime().toString()) .then(({ data }) => { return data; }) .catch(({ errCode, errMsg }) => { console.error("createTextMessage", errCode, errMsg); return null; }); return textMessage; }; export const createImageMessageByFile = async (file) => { let imageMessage = await DChatSDK.createImageMessageByFile(file, new Date().getTime().toString()) .then(({ data }) => { return data; }) .catch(({ errCode, errMsg }) => { console.error("createImageMessageByFile", errCode, errMsg); return null; }); return imageMessage; }; export const createMergerMessage = async (mergerMsgParams) => { let mergerMessage = await DChatSDK.createMergerMessage(mergerMsgParams, new Date().getTime().toString()) .then(({ data }) => { return data; }) .catch(({ errCode, errMsg }) => { console.error("createMergerMessage", errCode, errMsg); return null; }); return mergerMessage; }; export const createVideoMessageByFile = async (file) => { let videoMessage = await DChatSDK.createVideoMessageByFile(file, new Date().getTime().toString()) .then(({ data }) => { return data; }) .catch(({ errCode, errMsg }) => { console.error("createVideoMessageByFile", errCode, errMsg); return null; }); return videoMessage; }; export const createFileMessageByFile = async (file) => { let fileMessage = await DChatSDK.createFileMessageByFile(file, new Date().getTime().toString()) .then(({ data }) => { return data; }) .catch(({ errCode, errMsg }) => { console.error("createFileMessageByFile", errCode, errMsg); return null; }); return fileMessage; }; export const createUrlTextMessage = async (text, urls) => { let textMessage = await DChatSDK.createUrlTextMessage(text, JSON.stringify(urls), new Date().getTime().toString()) .then(({ data }) => { return data; }) .catch(({ errCode, errMsg }) => { console.error("createUrlTextMessage", errCode, errMsg); return null; }); return textMessage; }; export const useSendMessage = () => { const { user } = useChatContext(); const conversationData = useConversationStore((state) => state.conversationData); const { userID: recvID, groupID } = conversationData || {}; const sendMessage = useCallback(async (message) => { var _a, _b; try { pushNewMessage(message); emit("CHAT_LIST_SCROLL_TO_BOTTOM"); const { data: successMessage } = await DChatSDK.sendMessage({ recvID: recvID || "", groupID: groupID || "", message: message, offlinePushInfo: { title: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "Droppii Chat", desc: `${generateContentBasedOnMessageType(message.contentType, ((_a = message === null || message === void 0 ? void 0 : message.textElem) === null || _a === void 0 ? void 0 : _a.content) || "")}` || "Bạn có tin nhắn mới", ex: JSON.stringify({ icon: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL) || "", conversationId: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "", title: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "Droppii Chat", desc: `${generateContentBasedOnMessageType(message.contentType, ((_b = message === null || message === void 0 ? void 0 : message.textElem) === null || _b === void 0 ? void 0 : _b.content) || "")}` || "Bạn có tin nhắn mới", }), iOSPushSound: "default", iOSBadgeCount: true, }, }); updateOneMessage(successMessage); } catch (error) { updateOneMessage(Object.assign(Object.assign({}, message), { status: MessageStatus.Failed })); } }, [recvID, groupID]); const sendTextMessage = useCallback(async ({ plainText, richText, currentSession, }) => { if (!recvID && !groupID) return; const urls = extractLinks(plainText); const isUrlMessage = urls.length > 0; let message = null; if (isUrlMessage) { message = await createUrlTextMessage(plainText, urls); } else { message = await createTextMessage(plainText); } if (!message) return; const extendMessageInfo = generateExtendMessageInfo({ richText, currentSession, }); let messageItem = Object.assign(Object.assign({}, message), { ex: JSON.stringify(extendMessageInfo) || "{}" }); sendMessage(messageItem); }, [recvID, groupID, user, sendMessage]); const sendMergeMessage = useCallback(async ({ richText, plainText, files, currentSession, }) => { if (!recvID && !groupID) return; const messageList = []; for (const fileWrapper of files) { const file = fileWrapper.originFileObj; if (!file) continue; const isImage = file.type.startsWith("image/"); const isVideo = file.type.startsWith("video/"); const isDocument = file.type.startsWith("application/"); try { if (isImage) { const picInfo = await createPicBaseInfoFromFile(file); const baseInfo = { uuid: uuidv4(), type: file.type, size: file.size, width: picInfo.width, height: picInfo.height, url: URL.createObjectURL(file), }; const parsedImage = { sourcePicture: baseInfo, bigPicture: baseInfo, snapshotPicture: baseInfo, sourcePath: "", file: file, }; const imageMessage = await createImageMessageByFile(parsedImage); if (!imageMessage) continue; messageList.push(imageMessage); } else if (isVideo) { const videoBaseInfo = await createVideoInfoWithThumbnail(file); const thumbFile = new File([videoBaseInfo.thumbnail], file.name + "-thumb.jpg", { type: "image/jpeg", }); const videoMessage = await createVideoMessageByFile({ videoPath: "", duration: videoBaseInfo.duration, videoType: file.type, snapshotPath: "", videoUUID: uuidv4(), videoUrl: "", videoSize: file.size, snapshotUUID: "", snapshotSize: file.size, snapshotUrl: "", snapshotWidth: videoBaseInfo.width, snapshotHeight: videoBaseInfo.height, snapShotType: file.type, videoFile: file, snapshotFile: thumbFile, }); if (!videoMessage) continue; messageList.push(videoMessage); } else if (isDocument) { const fileMessage = await createFileMessageByFile({ filePath: "", fileName: file.name, uuid: uuidv4(), sourceUrl: "", fileSize: file.size, fileType: file.type, file: file, }); if (!fileMessage) continue; messageList.push(fileMessage); } } catch (err) { console.error("Lỗi xử lý tin nhắn:", err); } } if (!!plainText && plainText.trim() !== "") { const textMessage = await createTextMessage(plainText); if (!textMessage) return; messageList.push(textMessage); } for (const message of messageList) { const extendMessageInfo = generateExtendMessageInfo({ richText, currentSession, }); const mMessage = Object.assign(Object.assign({}, message), { ex: JSON.stringify(extendMessageInfo) || "{}" }); await sendMessage(mMessage); } }, [recvID, groupID, sendMessage]); return { sendTextMessage, sendMergeMessage, }; }; export const generateExtendMessageInfo = ({ richText, currentSession, }) => { return { messageInfo: { type: "MESSAGE_INFO", data: { type: "rich_text", content: richText || "", }, }, sessionId: (currentSession === null || currentSession === void 0 ? void 0 : currentSession.id) || "", applicationType: useAuthStore.getState().applicationType, }; }; const createPicBaseInfoFromFile = (file) => new Promise((resolve, reject) => { const _URL = window.URL || window.webkitURL; const img = new Image(); img.onload = function () { resolve(img); }; img.src = _URL.createObjectURL(file); }); function createVideoInfoWithThumbnail(file) { return new Promise((resolve, reject) => { try { const video = document.createElement("video"); video.preload = "metadata"; video.src = URL.createObjectURL(file); video.onloadedmetadata = () => { const duration = Math.floor(video.duration * 1000); const width = video.videoWidth; const height = video.videoHeight; // Seek tới giây 1 (nếu video dài hơn 1s) để lấy frame đẹp hơn video.currentTime = Math.min(1, video.duration / 2); }; video.onseeked = () => { const canvas = document.createElement("canvas"); canvas.width = video.videoWidth; canvas.height = video.videoHeight; const ctx = canvas.getContext("2d"); if (!ctx) return reject("Canvas not supported"); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); canvas.toBlob((blob) => { if (!blob) return reject("Thumbnail capture failed"); resolve({ duration: Math.floor(video.duration * 1000), width: video.videoWidth, height: video.videoHeight, thumbnail: blob, }); }, "image/jpeg", 0.85); }; video.onerror = (err) => reject(err); } catch (e) { reject(e); } }); }