diff --git a/src/app/config.js b/src/app/config.js
index fbd4c907..b06b1982 100644
--- a/src/app/config.js
+++ b/src/app/config.js
@@ -1,12 +1,10 @@
// const BASE_URL = `${location.origin}/api`;
const BASE_URL = `https://dev.rustchat.com/api`;
-export const CACHE_VERSION = `0.3.2`;
+export const CACHE_VERSION = `0.3.3`;
// const BASE_URL = `https://rustchat.net/api`;
export const ContentTypes = {
text: "text/plain",
markdown: "text/markdown",
- image: "image/png",
- imageJPG: "image/jpeg",
file: "rustchat/file",
formData: "multipart/form-data",
json: "application/json",
@@ -26,6 +24,7 @@ export const googleClientID =
// "840319286941-6ds7lbvk55eq8mjortf68cb2ll65lprt.apps.googleusercontent.com";
export const tokenHeader = "X-API-Key";
export const FILE_SLICE_SIZE = 1000 * 200 * 8; //200kb
+export const FILE_IMAGE_SIZE = 1000 * 10000 * 8; //10mb
export const KEY_TOKEN = "RUSTCHAT_TOKEN";
export const KEY_EXPIRE = "RUSTCHAT_TOKEN_EXPIRE";
export const KEY_REFRESH_TOKEN = "RUSTCHAT_REFRESH_TOKEN";
diff --git a/src/app/services/channel.js b/src/app/services/channel.js
index b248cd96..0cfa48e0 100644
--- a/src/app/services/channel.js
+++ b/src/app/services/channel.js
@@ -46,6 +46,33 @@ export const channelApi = createApi({
}
},
}),
+ getHistoryMessages: builder.query({
+ query: ({ gid, mid = 0, limit = 50 }) => ({
+ url: `/group/${gid}/history?before=${mid}&limit=${limit}`,
+ }),
+ // async onQueryStarted(id, { dispatch, getState, queryFulfilled }) {
+ // const {
+ // ui: { channelSetting },
+ // channelMessage,
+ // } = getState();
+ // try {
+ // await queryFulfilled;
+ // dispatch(removeChannel(id));
+ // if (id == channelSetting) {
+ // dispatch(toggleChannelSetting());
+ // }
+ // // 删掉该channel下的所有消息&reaction
+ // const mids = channelMessage[id];
+ // if (mids) {
+ // dispatch(removeChannelSession(id));
+ // dispatch(removeMessage(mids));
+ // dispatch(removeReactionMessage(mids));
+ // }
+ // } catch {
+ // console.log("remove channel error");
+ // }
+ // },
+ }),
removeChannel: builder.query({
query: (id) => ({
url: `group/${id}`,
@@ -82,7 +109,7 @@ export const channelApi = createApi({
},
url: `group/${id}/send`,
method: "POST",
- body: content,
+ body: type == "file" ? JSON.stringify(content) : content,
}),
async onQueryStarted(param1, param2) {
await onMessageSendStarted.call(this, param1, param2, "channel");
@@ -106,6 +133,7 @@ export const channelApi = createApi({
});
export const {
+ useLazyGetHistoryMessagesQuery,
useGetChannelQuery,
useUpdateChannelMutation,
useLazyRemoveChannelQuery,
diff --git a/src/app/services/contact.js b/src/app/services/contact.js
index 7ebbac5b..0d90bbce 100644
--- a/src/app/services/contact.js
+++ b/src/app/services/contact.js
@@ -95,7 +95,7 @@ export const contactApi = createApi({
},
url: `user/${id}/send`,
method: "POST",
- body: content,
+ body: type == "file" ? JSON.stringify(content) : content,
}),
async onQueryStarted(param1, param2) {
await onMessageSendStarted.call(this, param1, param2, "user");
diff --git a/src/app/services/handlers.js b/src/app/services/handlers.js
index 0db71588..bdf96134 100644
--- a/src/app/services/handlers.js
+++ b/src/app/services/handlers.js
@@ -17,6 +17,8 @@ export const onMessageSendStarted = async (
from = "channel"
) => {
// id: who send to ,from_uid: who sent
+ console.log("handlers data", content, type, properties);
+ const isImage = properties.file_type?.startsWith("image");
const ts = properties.local_id || new Date().getTime();
// let imageData = null;
// if (type == "image") {
@@ -31,7 +33,7 @@ export const onMessageSendStarted = async (
// }
// }
const tmpMsg = {
- content: type == "image" ? URL.createObjectURL(content) : content,
+ content: isImage ? content.path : content,
content_type: ContentTypes[type],
created_at: ts,
properties,
diff --git a/src/app/services/message.js b/src/app/services/message.js
index 264741f0..be0ea666 100644
--- a/src/app/services/message.js
+++ b/src/app/services/message.js
@@ -1,7 +1,7 @@
import { createApi } from "@reduxjs/toolkit/query/react";
// import { batch } from "react-redux";
-import BASE_URL, { ContentTypes } from "../config";
+import { ContentTypes } from "../config";
import { updateReadChannels, updateReadUsers } from "../slices/footprint";
import { onMessageSendStarted } from "./handlers";
@@ -59,19 +59,6 @@ export const messageApi = createApi({
return data ? data : {};
},
}),
- uploadImage: builder.mutation({
- query: (image) => ({
- headers: {
- "content-type": ContentTypes.image,
- },
- url: `/resource/image`,
- method: "POST",
- body: image,
- }),
- transformResponse: (image_id) => {
- return `${BASE_URL}/resource/image?id=${encodeURIComponent(image_id)}`;
- },
- }),
replyMessage: builder.mutation({
query: ({ reply_mid, content, type = "text" }) => ({
headers: {
@@ -93,29 +80,16 @@ export const messageApi = createApi({
}),
async onQueryStarted(data, { dispatch, queryFulfilled }) {
const { users = null, groups = null } = data;
- // const { readUsers, readChannels } = getState().footprint;
- // const prevUsers = users.map(({ uid }) => {
- // return { uid, mid: readUsers[uid] };
- // });
- // const prevChannels = users.map(({ gid }) => {
- // return { gid, mid: readChannels[gid] };
- // });
- // batch(() => {
if (users) {
dispatch(updateReadUsers(users));
}
if (groups) {
dispatch(updateReadChannels(groups));
}
- // });
try {
await queryFulfilled;
} catch {
// todo
- // batch(() => {
- // dispatch(updateReadChannels(prevChannels));
- // dispatch(updateReadUsers(prevUsers));
- // });
}
},
}),
@@ -125,7 +99,6 @@ export const messageApi = createApi({
export const {
usePrepareUploadFileMutation,
useUploadFileMutation,
- useUploadImageMutation,
useEditMessageMutation,
useReactMessageMutation,
useReplyMessageMutation,
diff --git a/src/app/slices/message.js b/src/app/slices/message.js
index d5f32250..c74363a7 100644
--- a/src/app/slices/message.js
+++ b/src/app/slices/message.js
@@ -1,5 +1,6 @@
import { createSlice } from "@reduxjs/toolkit";
import BASE_URL, { ContentTypes } from "../config";
+import { isImage } from "../../common/utils";
const initialState = {
replying: {},
};
@@ -19,27 +20,25 @@ const messageSlice = createSlice({
},
addMessage(state, action) {
const data = action.payload;
- const { mid, sending, content_type, content } = data;
+ const { mid, sending, content_type, content, properties = {} } = data;
// 如果是正发送,并且已存在,则不覆盖
if (sending && state[mid]) return;
- const isImage = content_type.startsWith("image");
const isFile = content_type == ContentTypes.file;
- // file
if (!sending && isFile) {
data.file_path = content;
data.content = `${BASE_URL}/resource/file?file_path=${encodeURIComponent(
data.file_path
)}`;
- }
- // image
- if (!sending && isImage) {
- data.image_id = content;
- data.content = `${BASE_URL}/resource/image?id=${encodeURIComponent(
- data.image_id
- )}`;
- data.thumbnail = `${BASE_URL}/resource/thumbnail?id=${encodeURIComponent(
- data.image_id
- )}`;
+ data.download = `${BASE_URL}/resource/file?file_path=${encodeURIComponent(
+ data.file_path
+ )}&download=true`;
+ // image
+ const isPic = isImage(properties.file_type, properties.size);
+ if (isPic) {
+ data.thumbnail = `${BASE_URL}/resource/file?file_path=${encodeURIComponent(
+ data.file_path
+ )}&thumbnail=true`;
+ }
}
state[mid] = data;
},
diff --git a/src/common/component/MarkdownEditor/index.js b/src/common/component/MarkdownEditor/index.js
index fed17716..9e771060 100644
--- a/src/common/component/MarkdownEditor/index.js
+++ b/src/common/component/MarkdownEditor/index.js
@@ -6,22 +6,22 @@ import "@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin
import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight-all.js";
import StyledWrapper from "./styled";
-import { useUploadImageMutation } from "../../../app/services/message";
+import useUploadFile from "../../hook/useUploadFile";
import Button from "../../component/styled/Button";
function MarkdownEditor({ placeholder, sendMarkdown, setEditorInstance }) {
const editorRef = useRef(undefined);
+ const { uploadFile } = useUploadFile();
// const [pHolder, setPHolder] = useState(placeholder);
- const [uploadImage] = useUploadImageMutation();
useEffect(() => {
const editor = editorRef?.current;
if (editor) {
const editorInstance = editor.getInstance();
editorInstance.removeHook("addImageBlobHook");
editorInstance.addHook("addImageBlobHook", async (blob, callback) => {
- const { data: url } = await uploadImage(blob);
- callback(url);
+ const { thumbnail = "" } = await uploadFile(blob);
+ callback(thumbnail);
});
setEditorInstance(editorInstance);
}
diff --git a/src/common/component/Message/Reply.js b/src/common/component/Message/Reply.js
index d54fc17f..ecea38f4 100644
--- a/src/common/component/Message/Reply.js
+++ b/src/common/component/Message/Reply.js
@@ -4,7 +4,7 @@ import { useSelector } from "react-redux";
import MrakdownRender from "../MrakdownRender";
import { ContentTypes } from "../../../app/config";
-import { getFileIcon } from "../../utils";
+import { getFileIcon, isImage } from "../../utils";
import Avatar from "../Avatar";
const Styled = styled.div`
cursor: pointer;
@@ -98,20 +98,20 @@ const renderContent = (data) => {
);
break;
- case ContentTypes.image:
- case ContentTypes.imageJPG:
- res =
;
- break;
case ContentTypes.file:
{
- const { file_type, name } = properties;
+ const { file_type, name, size } = properties;
const icon = getFileIcon(file_type, name);
- res = (
- <>
- {icon}
- {name}
- >
- );
+ if (isImage(file_type, size)) {
+ res =
;
+ } else {
+ res = (
+ <>
+ {icon}
+ {name}
+ >
+ );
+ }
}
break;
diff --git a/src/common/component/Message/renderContent.js b/src/common/component/Message/renderContent.js
index e7fa8f90..7ca538ea 100644
--- a/src/common/component/Message/renderContent.js
+++ b/src/common/component/Message/renderContent.js
@@ -6,7 +6,7 @@ import Linkit from "react-linkify";
import dayjs from "dayjs";
import Mention from "./Mention";
import MrakdownRender from "../MrakdownRender";
-import { getDefaultSize } from "../../utils";
+import { getDefaultSize, isImage } from "../../utils";
import FileBox from "../FileBox";
import URLPreview from "./URLPreview";
import reactStringReplace from "react-string-replace";
@@ -68,35 +68,38 @@ const renderContent = ({
ctn = ;
}
break;
- case "image/png":
- case "image/jpeg":
- {
- const { name, size, type } = properties;
- const { width, height } = getDefaultSize(properties);
- ctn = (
-
- );
- }
- break;
case "rustchat/file":
{
const { size, name, file_type } = properties;
- ctn = (
-
- );
+ if (isImage(file_type, size)) {
+ const { width, height } = getDefaultSize(properties);
+ ctn = (
+
+ );
+ } else {
+ ctn = (
+
+ );
+ }
}
break;
diff --git a/src/common/component/MixedInput/index.js b/src/common/component/MixedInput/index.js
index 11e96bfb..b98b0690 100644
--- a/src/common/component/MixedInput/index.js
+++ b/src/common/component/MixedInput/index.js
@@ -27,6 +27,7 @@ import Styled from "./styled";
import ImageElement from "./ImageElement";
import { CONFIG } from "./config";
import Contact from "../Contact";
+import useUploadFile from "../../hook/useUploadFile";
// import Mention from "./Mention";
export const TEXT_EDITOR_PREFIX = "rustchat_text_editor";
export const setEditorFocus = (edtr) => {
@@ -55,6 +56,9 @@ const Plugins = ({
sendMessages,
members = [],
}) => {
+ const enableMentions = members.length > 0;
+ const { uploadFile } = useUploadFile();
+ const filesRef = useRef([]);
// const plateEditor = usePlateEditorRef(`${TEXT_EDITOR_PREFIX}_${id}`);
const contactData = useSelector((store) => store.contacts.byId);
const [msgs, setMsgs] = useState([]);
@@ -66,6 +70,7 @@ const Plugins = ({
className: "box",
placeholder,
};
+
useKey(
"Enter",
(evt) => {
@@ -96,36 +101,44 @@ const Plugins = ({
target: editableRef,
}
);
- const plugins = createPlugins(
- [
- createParagraphPlugin(),
- createImagePlugin(),
- createNodeIdPlugin(),
- createSoftBreakPlugin(CONFIG.softBreak),
- createTrailingBlockPlugin(CONFIG.trailingBlock),
- createExitBreakPlugin(CONFIG.exitBreak),
- createComboboxPlugin(),
- createMentionPlugin({
- // component: Mention,
- // handlers: {
- // onKeyDown: ({ query }) => {
- // console.log("mention", query);
- // return true;
- // },
- // },
- options: {
- createMentionNode: (item) => {
- console.log("mention", item);
- const {
- text,
- data: { uid },
- } = item;
- return { value: `@${text}`, uid };
- },
- insertSpaceAfterMention: true,
+ const pluginArr = [
+ createParagraphPlugin(),
+ createImagePlugin({
+ options: {
+ uploadImage: async (dataUrl) => {
+ const resp = await fetch(dataUrl);
+ const blob = await resp.blob();
+ const { thumbnail, ...rest } = await uploadFile(blob);
+ const { name, file_type, size, path, hash } = rest;
+ filesRef.current.push({ name, file_type, size, path, hash });
+ return thumbnail;
},
- }),
- ],
+ },
+ }),
+ createNodeIdPlugin(),
+ createSoftBreakPlugin(CONFIG.softBreak),
+ createTrailingBlockPlugin(CONFIG.trailingBlock),
+ createExitBreakPlugin(CONFIG.exitBreak),
+ ];
+ const plugins = createPlugins(
+ enableMentions
+ ? pluginArr.concat([
+ createComboboxPlugin(),
+ createMentionPlugin({
+ options: {
+ createMentionNode: (item) => {
+ console.log("mention", item);
+ const {
+ text,
+ data: { uid },
+ } = item;
+ return { value: `@${text}`, uid };
+ },
+ insertSpaceAfterMention: true,
+ },
+ }),
+ ])
+ : pluginArr,
{
components,
}
@@ -146,27 +159,40 @@ const Plugins = ({
});
return { value: arr.join(""), mentions };
};
- for await (const v of val) {
+ for (const v of val) {
if (v.type == "img") {
// img
- const resp = await fetch(v.url);
- const value = await resp.blob();
- tmps.push({ type: "image", value });
+ const url = v.url;
+ const file_path = decodeURIComponent(
+ new URL(url).searchParams.get("file_path")
+ );
+ console.log("files", filesRef.current, file_path);
+ const json = filesRef.current.find((f) => f.path == file_path) || {};
+ const { name, size, hash, path, ...rest } = json;
+ tmps.push({
+ type: "file",
+ content: { name, size, hash, path },
+ properties: rest,
+ });
} else {
// p
const { value, mentions } = getMixedText(v.children);
const prev = tmps[tmps.length - 1];
if (!prev) {
- tmps.push([{ type: "text", value, mentions }]);
+ tmps.push([
+ { type: "text", content: value, properties: { mentions } },
+ ]);
} else {
if (Array.isArray(prev)) {
tmps[tmps.length - 1].push({
type: "text",
- value,
- mentions,
+ content: value,
+ properties: { mentions },
});
} else {
- tmps.push([{ type: "text", value, mentions }]);
+ tmps.push([
+ { type: "text", content: value, properties: { mentions } },
+ ]);
}
}
}
@@ -175,14 +201,14 @@ const Plugins = ({
return Array.isArray(tmp)
? {
type: "text",
- value: tmp.map((t) => t.value).join("\n"),
- mentions: tmp.map((t) => t.mentions).flat(),
+ content: tmp.map((t) => t.content).join("\n"),
+ properties: { mentions: tmp.map((t) => t.mentions).flat() },
}
: tmp;
});
- const msgs = arr.filter(({ value }) => !!value);
+ const msgs = arr.filter(({ content }) => !!content);
setMsgs(msgs);
- console.log("tmps", val, tmps, msgs);
+ console.log("tmps", tmps, arr, msgs);
},
[msgs]
);
@@ -197,26 +223,28 @@ const Plugins = ({
initialValue={initialValue}
plugins={plugins}
>
- {
- console.log("wtf", item);
- return ;
- }}
- items={members.map((id) => {
- const data = contactData[id];
- if (!data) return null;
- const { uid, name, ...rest } = data;
- return {
- key: uid,
- text: name,
- data: {
- uid,
- ...rest,
- },
- };
- })}
- />
+ {enableMentions ? (
+ {
+ console.log("wtf", item);
+ return ;
+ }}
+ items={members.map((id) => {
+ const data = contactData[id];
+ if (!data) return null;
+ const { uid, name, ...rest } = data;
+ return {
+ key: uid,
+ text: name,
+ data: {
+ uid,
+ ...rest,
+ },
+ };
+ })}
+ />
+ ) : null}
);
diff --git a/src/common/component/MrakdownRender.js b/src/common/component/MrakdownRender.js
index 1b904507..31bdcdd1 100644
--- a/src/common/component/MrakdownRender.js
+++ b/src/common/component/MrakdownRender.js
@@ -34,10 +34,15 @@ export default function MrakdownRender({ content }) {
"click",
(evt) => {
console.log(evt);
+ evt.stopPropagation();
const { target } = evt;
// 图片
if (target.nodeName == "IMG") {
- const data = { originUrl: target.dataset.origin || target.src };
+ const urlObj = new URL(target.src);
+ const originUrl = `${urlObj.origin}${
+ urlObj.pathname
+ }?file_path=${urlObj.searchParams.get("file_path")}`;
+ const data = { originUrl };
setPreviewImage(data);
}
},
diff --git a/src/common/component/Send/Replying.js b/src/common/component/Send/Replying.js
index c45bdb53..51012740 100644
--- a/src/common/component/Send/Replying.js
+++ b/src/common/component/Send/Replying.js
@@ -4,7 +4,7 @@ import { ContentTypes } from "../../../app/config";
import MrakdownRender from "../MrakdownRender";
import closeIcon from "../../../assets/icons/close.circle.svg?url";
import pictureIcon from "../../../assets/icons/picture.svg?url";
-import { getFileIcon } from "../../utils";
+import { getFileIcon, isImage } from "../../utils";
import { removeReplyingMessage } from "../../../app/slices/message";
import styled from "styled-components";
const Styled = styled.div`
@@ -97,20 +97,20 @@ const renderContent = (data) => {
);
break;
- case ContentTypes.image:
- case ContentTypes.imageJPG:
- res =
;
- break;
case ContentTypes.file:
{
- const { file_type, name } = properties;
- const icon = getFileIcon(file_type, name);
- res = (
- <>
- {icon}
- {name}
- >
- );
+ const { file_type, name, size } = properties;
+ if (isImage(file_type, size)) {
+ res =
;
+ } else {
+ const icon = getFileIcon(file_type, name);
+ res = (
+ <>
+ {icon}
+ {name}
+ >
+ );
+ }
}
break;
default:
diff --git a/src/common/component/Send/index.js b/src/common/component/Send/index.js
index 947d7cfd..0a2aa03a 100644
--- a/src/common/component/Send/index.js
+++ b/src/common/component/Send/index.js
@@ -75,7 +75,8 @@ function Send({
const handleSendMessage = async (msgs = []) => {
if (!msgs || msgs.length == 0 || !id) return;
for await (const msg of msgs) {
- const { type: content_type, value: content, mentions = [] } = msg;
+ console.log("send msg", msg);
+ const { type: content_type, content, properties = {} } = msg;
if (replying_mid) {
console.log("replying", replying_mid);
await replyMessage({
@@ -93,7 +94,7 @@ function Send({
type: content_type,
content,
from_uid,
- properties: { local_id: new Date().getTime(), mentions },
+ properties,
});
}
}
diff --git a/src/common/component/UploadModal/index.js b/src/common/component/UploadModal/index.js
index cd4bc384..9f75a8ac 100644
--- a/src/common/component/UploadModal/index.js
+++ b/src/common/component/UploadModal/index.js
@@ -1,12 +1,12 @@
import { useEffect } from "react";
import { useSelector } from "react-redux";
import FileItem from "./FileItem";
-import useSendImageMessage from "../../hook/useSendImageMessage";
-import useSendFileMessage from "../../hook/useSendFileMessage";
+import useUploadFile from "../../hook/useUploadFile";
import Modal from "../Modal";
import Button from "../styled/Button";
-import { isTreatAsImage } from "../../utils";
+// import { isTreatAsImage } from "../../utils";
import StyledWrapper from "./styled";
+import useSendMessage from "../../hook/useSendMessage";
export default function UploadModal({
context = "user",
@@ -16,42 +16,45 @@ export default function UploadModal({
}) {
const from_uid = useSelector((store) => store.authData.uid);
const {
- sendImageMessage,
- isSending: isSendingImage,
- isSuccess: sendImageSuccess,
- } = useSendImageMessage({
+ sendMessage,
+ isSuccess: sendMessageSuccess,
+ isSending,
+ } = useSendMessage({
context,
from: from_uid,
to: sendTo,
});
const {
- sendFileMessage,
+ data,
+ uploadFile,
progress,
- isSending: isSendingFile,
- isSuccess: sendFileSuccess,
- } = useSendFileMessage({
- context,
- from: from_uid,
- to: sendTo,
- });
+ isUploading,
+ isSuccess: uploadSuccess,
+ } = useUploadFile();
const handleUpload = () => {
const file = files[0];
- // const { type } = file;
- if (isTreatAsImage(file)) {
- sendImageMessage(file);
- } else {
- sendFileMessage(file);
- }
+ uploadFile(file);
};
useEffect(() => {
- if (sendFileSuccess || sendImageSuccess) {
+ if (uploadSuccess) {
+ // 把已经上传的东西当做消息发出去
+ const { size, path, name, hash, ...rest } = data;
+ sendMessage({
+ type: "file",
+ content: { size, name, path, hash },
+ properties: rest,
+ });
+ }
+ }, [uploadSuccess, data]);
+ useEffect(() => {
+ if (sendMessageSuccess) {
closeModal();
}
- }, [sendImageSuccess, sendFileSuccess]);
+ }, [sendMessageSuccess]);
if (!sendTo) return null;
console.log("upload file modal", files, sendTo);
- const isSending = isSendingFile || isSendingImage;
+ const sending = isUploading || isSending;
return (
>
}
diff --git a/src/common/hook/useSendImageMessage.js b/src/common/hook/useSendMessage.js
similarity index 66%
rename from src/common/hook/useSendImageMessage.js
rename to src/common/hook/useSendMessage.js
index b518a62c..c0b25661 100644
--- a/src/common/hook/useSendImageMessage.js
+++ b/src/common/hook/useSendMessage.js
@@ -1,7 +1,7 @@
// import second from 'first'
import { useSendChannelMsgMutation } from "../../app/services/channel";
import { useSendMsgMutation } from "../../app/services/contact";
-export default function useSendImageMessage({
+export default function useSendMessage({
context = "user",
from = null,
to = null,
@@ -18,20 +18,18 @@ export default function useSendImageMessage({
sendUserMsg,
{ isLoading: userSending, isSuccess: userSuccess, isError: userError },
] = useSendMsgMutation();
- const uploadFn = context == "user" ? sendUserMsg : sendChannelMsg;
- const sendImageMessage = (file) => {
- if (!file) return;
- const { name, size, type } = file;
- uploadFn({
+ const sendFn = context == "user" ? sendUserMsg : sendChannelMsg;
+ const sendMessage = ({ type = "text", content, properties = {} }) => {
+ sendFn({
id: to,
- content: file,
- properties: { name, size, type, local_id: new Date().getTime() },
- type: "image",
+ content,
+ properties: { ...properties, local_id: new Date().getTime() },
+ type,
from_uid: from,
});
};
return {
- sendImageMessage,
+ sendMessage,
isError: channelError || userError,
isSending: userSending || channelSending,
isSuccess: channelSuccess || userSuccess,
diff --git a/src/common/hook/useSendFileMessage.js b/src/common/hook/useUploadFile.js
similarity index 62%
rename from src/common/hook/useSendFileMessage.js
rename to src/common/hook/useUploadFile.js
index 3bd0f371..fc3b0cb0 100644
--- a/src/common/hook/useSendFileMessage.js
+++ b/src/common/hook/useUploadFile.js
@@ -1,57 +1,41 @@
import { useState, useRef } from "react";
// import { ContentTypes } from "../../app/config";
-// import { sliceFile } from "../utils";
-import { FILE_SLICE_SIZE } from "../../app/config";
+import BASE_URL, { FILE_SLICE_SIZE } from "../../app/config";
import {
usePrepareUploadFileMutation,
useUploadFileMutation,
} from "../../app/services/message";
-import { useSendMsgMutation } from "../../app/services/contact";
-import { useSendChannelMsgMutation } from "../../app/services/channel";
-export default function useUploadImageMessage({
- context = "user",
- from = null,
- to = null,
-}) {
- // const slicedRef = useRef(false);
+export default function useUploadFile() {
+ const [data, setData] = useState(null);
const [uploadingFile, setUploadingFile] = useState(false);
const sliceUploadedCountRef = useRef(0);
const totalSliceCountRef = useRef(1);
- // const [uploadedSliceCount, setUploadedSliceCount] = useState(0)
const [
prepareUploadFile,
{ isLoading: isPreparing, isSuccess: isPrepared },
] = usePrepareUploadFileMutation();
const [
- uploadFile,
+ uploadFileFn,
{ isLoading: isUploading, isSuccess: isUploaded, isError: uploadFileError },
] = useUploadFileMutation();
- const [
- sendChannelMsg,
- {
- isLoading: channelSending,
- isSuccess: channelSuccess,
- isError: channelError,
- },
- ] = useSendChannelMsgMutation();
- const [
- sendUserMsg,
- { isLoading: userSending, isSuccess: userSuccess, isError: userError },
- ] = useSendMsgMutation();
- const sendFn = context == "user" ? sendUserMsg : sendChannelMsg;
const uploadChunk = async (data) => {
const { file_id, chunk, is_last } = data;
const formData = new FormData();
formData.append("file_id", file_id);
formData.append("chunk_data", chunk);
formData.append("chunk_is_last", is_last);
- return uploadFile(formData);
+ return uploadFileFn(formData);
};
- const sendFileMessage = async (file) => {
+ const uploadFile = async (file) => {
if (!file) return;
- const { name, type: file_type, size: file_size } = file;
+ setData(null);
+ const {
+ name = `rustchat-${new Date().getTime()}.${file.type.split("/")[1]}`,
+ type: file_type,
+ size: file_size,
+ } = file;
// 拿file id
const { data: file_id } = await prepareUploadFile({
content_type: file_type,
@@ -101,30 +85,30 @@ export default function useUploadImageMessage({
const {
data: { path, size, hash },
} = uploadResult;
- const content = JSON.stringify({
+ const encodedPath = encodeURIComponent(path);
+ const res = {
name,
+ file_type,
+ path,
size,
hash,
- path,
- });
- console.log("upload content", content);
- await sendFn({
- id: to,
- content,
- type: "file",
- properties: { file_type },
- from_uid: from,
- });
+ url: `${BASE_URL}/resource/file?file_path=${encodedPath}`,
+ thumbnail: file_type.startsWith("image")
+ ? `${BASE_URL}/resource/file?file_path=${encodedPath}&thumbnail=true`
+ : "",
+ download: `${BASE_URL}/resource/file?file_path=${encodedPath}&download=true`,
+ };
+ setData(res);
+ return res;
};
- const isSending =
- userSending || channelSending || isPreparing || uploadingFile;
return {
- progress: isSending
- ? sliceUploadedCountRef.current / totalSliceCountRef.current
- : 1,
- sendFileMessage,
- isError: channelError || userError || uploadFileError,
- isSending,
- isSuccess: (channelSuccess || userSuccess) && isPrepared,
+ data,
+ isUploading: uploadingFile,
+ progress: Number(
+ (sliceUploadedCountRef.current / totalSliceCountRef.current) * 100
+ ).toFixed(2),
+ uploadFile,
+ isError: uploadFileError,
+ isSuccess: !!data,
};
}
diff --git a/src/common/utils.js b/src/common/utils.js
index da504e65..dd939181 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -1,3 +1,4 @@
+import { FILE_IMAGE_SIZE } from "../app/config";
import IconPdf from "../assets/icons/file.pdf.svg";
import IconAudio from "../assets/icons/file.audio.svg";
import IconVideo from "../assets/icons/file.video.svg";
@@ -5,6 +6,9 @@ import IconUnkown from "../assets/icons/file.unkown.svg";
import IconDoc from "../assets/icons/file.doc.svg";
import IconCode from "../assets/icons/file.code.svg";
import IconImage from "../assets/icons/file.image.svg";
+export const isImage = (file_type = "", size = 0) => {
+ return file_type.startsWith("image") && size <= FILE_IMAGE_SIZE;
+};
export const isObjectEqual = (obj1, obj2) => {
let o1 = Object.entries(obj1 ?? {})
.sort()
diff --git a/src/routes/chat/utils.js b/src/routes/chat/utils.js
index 2ffc343f..09c5a427 100644
--- a/src/routes/chat/utils.js
+++ b/src/routes/chat/utils.js
@@ -1,5 +1,6 @@
import React from "react";
import dayjs from "dayjs";
+import { isImage } from "../../common/utils";
import { ContentTypes } from "../../app/config";
import Divider from "../../common/component/Divider";
import Message from "../../common/component/Message";
@@ -37,20 +38,13 @@ export function getUnreadCount({
}
export const renderPreviewMessage = (message = null) => {
if (!message) return null;
- const { content_type, content } = message;
+ const { content_type, content, properties = {} } = message;
let res = null;
switch (content_type) {
case ContentTypes.text:
{
res = content;
}
- break;
- case ContentTypes.imageJPG:
- case ContentTypes.image:
- {
- res = `[image]`;
- }
-
break;
case ContentTypes.markdown:
{
@@ -60,7 +54,11 @@ export const renderPreviewMessage = (message = null) => {
break;
case ContentTypes.file:
{
- res = `[file]`;
+ if (isImage(properties.file_type, properties.size)) {
+ res = `[image]`;
+ } else {
+ res = `[file]`;
+ }
}
break;