diff --git a/src/app/listener.middleware/handler.channels.js b/src/app/listener.middleware/handler.channels.js
index 986961c6..e076b707 100644
--- a/src/app/listener.middleware/handler.channels.js
+++ b/src/app/listener.middleware/handler.channels.js
@@ -11,7 +11,7 @@ export default async function handler({ operation, data, payload }) {
const chs = payload;
await Promise.all(
chs.map(({ gid, ...rest }) => {
- return table.setItem(gid, { gid, ...rest });
+ return table.setItem(gid + "", { gid, ...rest });
})
);
}
diff --git a/src/app/listener.middleware/handler.contacts.js b/src/app/listener.middleware/handler.contacts.js
index 5a5d83d3..773777ad 100644
--- a/src/app/listener.middleware/handler.contacts.js
+++ b/src/app/listener.middleware/handler.contacts.js
@@ -11,7 +11,7 @@ export default async function handler({ operation, data, payload }) {
const contacts = payload;
await Promise.all(
contacts.map(({ uid, ...rest }) => {
- return table.setItem(uid, { uid, ...rest });
+ return table.setItem(uid + "", { uid, ...rest });
})
);
}
diff --git a/src/app/services/channel.js b/src/app/services/channel.js
index 0db7cf87..7908a89c 100644
--- a/src/app/services/channel.js
+++ b/src/app/services/channel.js
@@ -75,9 +75,10 @@ export const channelApi = createApi({
},
}),
sendChannelMsg: builder.mutation({
- query: ({ id, content, type = "text" }) => ({
+ query: ({ id, content, type = "text", properties = "" }) => ({
headers: {
"content-type": ContentTypes[type],
+ "X-Properties": properties,
},
url: `group/${id}/send`,
method: "POST",
diff --git a/src/app/services/contact.js b/src/app/services/contact.js
index 5eb1e494..9cb67d9b 100644
--- a/src/app/services/contact.js
+++ b/src/app/services/contact.js
@@ -73,9 +73,10 @@ export const contactApi = createApi({
}),
}),
sendMsg: builder.mutation({
- query: ({ id, content, type = "text" }) => ({
+ query: ({ id, content, type = "text", properties = "" }) => ({
headers: {
"content-type": ContentTypes[type],
+ "X-Properties": properties,
},
url: `user/${id}/send`,
method: "POST",
diff --git a/src/app/services/message.js b/src/app/services/message.js
index 283d0265..5be3505a 100644
--- a/src/app/services/message.js
+++ b/src/app/services/message.js
@@ -1,5 +1,5 @@
import { createApi } from "@reduxjs/toolkit/query/react";
-import { batch } from "react-redux";
+// import { batch } from "react-redux";
import { ContentTypes } from "../config";
import { updateReadChannels, updateReadUsers } from "../slices/footprint";
@@ -57,27 +57,31 @@ export const messageApi = createApi({
method: "POST",
body: data,
}),
- async onQueryStarted(data, { dispatch, getState, queryFulfilled }) {
- const { users = [], groups = [] } = data;
- const { readUsers, readChannels } = getState().footprint.readUsers;
- const prevUsers = users.map(({ uid }) => {
- return { uid, mid: readUsers[uid] };
- });
- const prevChannels = users.map(({ gid }) => {
- return { gid, mid: readChannels[gid] };
- });
- batch(() => {
- dispatch(updateReadChannels(groups));
+ 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));
- });
+ // batch(() => {
+ // dispatch(updateReadChannels(prevChannels));
+ // dispatch(updateReadUsers(prevUsers));
+ // });
}
},
}),
diff --git a/src/app/slices/contacts.js b/src/app/slices/contacts.js
index 1fb1c92a..d3d85562 100644
--- a/src/app/slices/contacts.js
+++ b/src/app/slices/contacts.js
@@ -50,7 +50,10 @@ const contactsSlice = createSlice({
case "create":
{
state.byId[uid] = { uid, ...rest };
- state.ids.push(uid);
+ const idx = state.ids.findIndex((i) => i == uid);
+ if (idx == -1) {
+ state.ids.push(uid);
+ }
}
break;
case "delete":
diff --git a/src/common/component/Contact.js b/src/common/component/Contact.js
index 191afa1a..08cfe83d 100644
--- a/src/common/component/Contact.js
+++ b/src/common/component/Contact.js
@@ -83,10 +83,8 @@ export default function Contact({
content={}
>
{!compact && {curr?.name}}
diff --git a/src/common/component/Message/index.js b/src/common/component/Message/index.js
index ec498203..c9b15ce6 100644
--- a/src/common/component/Message/index.js
+++ b/src/common/component/Message/index.js
@@ -1,36 +1,41 @@
import React, { useRef, useState, useEffect } from "react";
import dayjs from "dayjs";
-import { useSelector, useDispatch } from "react-redux";
-import { useInViewRef } from "rooks";
+import { useSelector } from "react-redux";
+import { useInViewRef, useDebounce } from "rooks";
import Tippy from "@tippyjs/react";
import Reaction from "./Reaction";
import Reply from "./Reply";
import Profile from "../Profile";
import Avatar from "../Avatar";
-import { readMessage } from "../../../app/slices/message";
import { useReadMessageMutation } from "../../../app/services/message";
import StyledWrapper from "./styled";
import Commands from "./Commands";
import EditMessage from "./EditMessage";
import renderContent from "./renderContent";
-function Message({ contextId = 0, mid = "", read = true, context = "user" }) {
+function Message({ contextId = 0, mid = "", context = "user" }) {
const [updateReadIndex] = useReadMessageMutation();
+ const updateReadDebounced = useDebounce(updateReadIndex, 300);
const [myRef, inView] = useInViewRef();
const [edit, setEdit] = useState(false);
const [emojiPopVisible, setEmojiPopVisible] = useState(false);
const [menuVisible, setMenuVisible] = useState(false);
- const disptach = useDispatch();
const avatarRef = useRef(null);
- const { message = {}, reactionMessageData, contactsData } = useSelector(
- (store) => {
- return {
- reactionMessageData: store.reactionMessage,
- message: store.message[mid],
- contactsData: store.contacts.byId,
- };
- }
- );
+ const {
+ footprint,
+ message = {},
+ reactionMessageData,
+ contactsData,
+ loginUid,
+ } = useSelector((store) => {
+ return {
+ footprint: store.footprint,
+ loginUid: store.authData.uid,
+ reactionMessageData: store.reactionMessage,
+ message: store.message[mid] || {},
+ contactsData: store.contacts.byId,
+ };
+ });
const toggleMenu = () => {
setMenuVisible((prev) => !prev);
};
@@ -40,38 +45,35 @@ function Message({ contextId = 0, mid = "", read = true, context = "user" }) {
const toggleEmojiPopover = () => {
setEmojiPopVisible((prev) => !prev);
};
- // useEffect(() => {
- // if (!read) {
- // avatarRef.current?.scrollIntoView();
- // }
- // }, [read]);
- // console.log("message", mid, messageData[mid]);
-
- useEffect(() => {
- if (inView && !read) {
- disptach(readMessage(mid));
- const data =
- context == "user"
- ? { users: [{ uid: +contextId, mid }] }
- : { groups: [{ gid: +contextId, mid }] };
- updateReadIndex(data);
- }
- }, [mid, read, inView]);
- if (!message) return null;
const {
reply_mid,
from_uid: fromUid,
created_at: time,
- sending,
+ sending = false,
content,
thumbnail,
content_type = "text/plain",
edited,
properties,
} = message;
+ const readIndex =
+ context == "user"
+ ? footprint.readUsers[contextId]
+ : footprint.readChannels[contextId];
+ useEffect(() => {
+ const read = fromUid == loginUid || mid <= readIndex;
+ if (inView && !read) {
+ const data =
+ context == "user"
+ ? { users: [{ uid: +contextId, mid }] }
+ : { groups: [{ gid: +contextId, mid }] };
+ updateReadDebounced(data);
+ }
+ }, [mid, readIndex, inView, fromUid, loginUid]);
const reactions = reactionMessageData[mid];
const currUser = contactsData[fromUid] || {};
+ // if (!message) return null;
return (
{
- // files.forEach((file, idx) => {
- // const { name, size, type } = file;
- // setProperties((prevs) => {
- // prevs[idx] = { name, size, type };
- // return prevs;
- // });
- // var fileReader = new FileReader();
- // fileReader.onloadend = (e) => {
- // let dataUrl = e.target.result;
- // let tmp = new Image();
- // tmp.src = dataUrl;
- // tmp.onload = function () {
- // console.log("image load", this.width, this.height);
- // setProperties((prevs) => {
- // prevs[idx].width = this.width;
- // prevs[idx].height = this.height;
- // return prevs;
- // });
- // };
- // };
- // fileReader.readAsDataURL(file);
- // });
- // }, [files]);
+ const [properties, setProperties] = useState([]);
+ useEffect(() => {
+ files.forEach((file, idx) => {
+ const { name, size, type } = file;
+ setProperties((prevs) => {
+ prevs[idx] = { name, size, type };
+ return prevs;
+ });
+ // var fileReader = new FileReader();
+ // fileReader.onloadend = (e) => {
+ // let dataUrl = e.target.result;
+ // let tmp = new Image();
+ // tmp.src = dataUrl;
+ // tmp.onload = function () {
+ // console.log("image load", this.width, this.height);
+ // setProperties((prevs) => {
+ // prevs[idx].width = this.width;
+ // prevs[idx].height = this.height;
+ // return prevs;
+ // });
+ // };
+ // };
+ // fileReader.readAsDataURL(file);
+ });
+ }, [files]);
const handleUpload = () => {
const uploadFn = type == "user" ? sendUserMsg : sendChannelMsg;
uploadFn({
id: sendTo,
content: files[0],
- // properties: properties[0],
+ properties: btoa(JSON.stringify(properties[0])),
type: "image",
from_uid,
});
diff --git a/src/routes/chat/ChannelList/NavItem.js b/src/routes/chat/ChannelList/NavItem.js
index e0ee0bd0..412b4cdb 100644
--- a/src/routes/chat/ChannelList/NavItem.js
+++ b/src/routes/chat/ChannelList/NavItem.js
@@ -2,6 +2,7 @@ import { NavLink, useNavigate } from "react-router-dom";
import { useDrop } from "react-dnd";
import { NativeTypes } from "react-dnd-html5-backend";
import { useDispatch, useSelector } from "react-redux";
+// import { useDebounce} from "rooks";
import { toggleChannelSetting } from "../../../app/slices/ui";
import ChannelIcon from "../../../common/component/ChannelIcon";
import { getUnreadCount } from "../utils";
@@ -9,13 +10,18 @@ import { getUnreadCount } from "../utils";
const NavItem = ({ id, setFiles, contextMenuEventHandler }) => {
const dispatch = useDispatch();
const navigate = useNavigate();
- const { channel, mids, messageData } = useSelector((store) => {
- return {
- channel: store.channels.byId[id],
- mids: store.channelMessage[id],
- messageData: store.message,
- };
- });
+ // const getUnreadCountDebounced=useDebounce(getUnreadCount,300)
+ const { channel, mids, messageData, readIndex, loginUid } = useSelector(
+ (store) => {
+ return {
+ channel: store.channels.byId[id],
+ mids: store.channelMessage[id],
+ messageData: store.message,
+ loginUid: store.authData.uid,
+ readIndex: store.footprint.readChannels[id],
+ };
+ }
+ );
const handleChannelSetting = (evt) => {
evt.preventDefault();
evt.stopPropagation();
@@ -39,7 +45,7 @@ const NavItem = ({ id, setFiles, contextMenuEventHandler }) => {
}),
}));
const { is_public, name } = channel;
- const unreads = getUnreadCount(mids, messageData);
+ const unreads = getUnreadCount({ mids, messageData, readIndex, loginUid });
return (
{
+ const { msgIds, currUser, messageData } = useSelector((store) => {
return {
currUser: store.contacts.byId[uid],
msgIds: store.userMessage.byId[uid] || [],
messageData: store.message,
- readUsers: store.footprint.readUser || {},
};
});
const ref = useChatScroll(msgIds);
@@ -33,7 +32,6 @@ export default function DMChat({ uid = "", dropFiles = [] }) {
if (!currUser) return null;
// console.log("user msgs", msgs);
- const readIndex = readUsers[uid] || 0;
return (
{
const curr = messageData[mid];
- const self = curr.from_uid == currUser.uid;
- const read = self ? true : mid <= readIndex ? true : false;
const prev = idx == 0 ? null : messageData[msgIds[idx - 1]];
return renderMessageFragment({
prev,
curr,
contextId: uid,
- read,
context: "user",
});
})}
diff --git a/src/routes/chat/DMList.js b/src/routes/chat/DMList.js
index ad7022e6..a7df2e0f 100644
--- a/src/routes/chat/DMList.js
+++ b/src/routes/chat/DMList.js
@@ -5,7 +5,7 @@ import relativeTime from "dayjs/plugin/relativeTime";
import { useDrop } from "react-dnd";
import { NativeTypes } from "react-dnd-html5-backend";
import { useSelector } from "react-redux";
-import { renderPreviewMessage } from "./utils";
+import { renderPreviewMessage, getUnreadCount } from "./utils";
import Contact from "../../common/component/Contact";
dayjs.extend(relativeTime);
const NavItem = ({ uid, mid, unreads, setFiles }) => {
@@ -60,9 +60,32 @@ const NavItem = ({ uid, mid, unreads, setFiles }) => {
);
};
-export default function DMList({ sessions, setDropFiles }) {
- return sessions.map(({ uid, lastMid, unreads } = {}) => {
- if (!uid) return null;
+// mids: ChannelMsgData[channel_id],
+// messageData,
+// readIndex: readChannels[channel_id],
+// loginUid,
+export default function DMList({ uids, setDropFiles }) {
+ const { userMessage, messageData, readUsers, loginUid } = useSelector(
+ (store) => {
+ return {
+ loginUid: store.authData.uid,
+ readUsers: store.footprint.readUsers,
+ contactData: store.contacts.byId,
+ userMessage: store.userMessage.byId,
+ messageData: store.message,
+ };
+ }
+ );
+ const sessions = uids.map((uid) => {
+ const mids = userMessage[uid];
+ const lastMid = [...mids].pop();
+ const readIndex = readUsers[uid];
+ const unreads = getUnreadCount({ mids, readIndex, messageData, loginUid });
+
+ return { lastMid, unreads, uid };
+ });
+
+ return sessions.map(({ lastMid, uid, unreads }) => {
return (
{
+ const { contactsData, sessionUids } = useSelector((store) => {
return {
contactsData: store.contacts.byId,
- UserMsgData: store.userMessage,
- messageData: store.message,
+ sessionUids: store.userMessage.ids,
};
});
const [channelModalVisible, setChannelModalVisible] = useState(false);
@@ -43,10 +41,6 @@ export default function ChatPage() {
listEle.classList.toggle("collapse");
};
const tmpSessionUser = contactsData[user_id];
- const sessions = UserMsgData.ids.map((uid) => {
- const unreads = getUnreadCount(UserMsgData.byId[uid], messageData);
- return { uid, unreads, lastMid: [...UserMsgData.byId[uid]].pop() };
- });
return (
<>
{channelModalVisible && (
@@ -95,8 +89,8 @@ export default function ChatPage() {
/>