feat: read index
This commit is contained in:
@@ -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 (
|
||||
<NavLink
|
||||
data-cid={id}
|
||||
|
||||
@@ -13,12 +13,11 @@ export default function DMChat({ uid = "", dropFiles = [] }) {
|
||||
console.log("dm files", dropFiles);
|
||||
const [dragFiles, setDragFiles] = useState([]);
|
||||
// const [mids, setMids] = useState([]);
|
||||
const { msgIds, currUser, messageData, readUsers } = useSelector((store) => {
|
||||
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 (
|
||||
<Layout
|
||||
setDragFiles={setDragFiles}
|
||||
@@ -62,14 +60,11 @@ export default function DMChat({ uid = "", dropFiles = [] }) {
|
||||
})
|
||||
.map((mid, idx) => {
|
||||
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",
|
||||
});
|
||||
})}
|
||||
|
||||
@@ -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 }) => {
|
||||
</NavLink>
|
||||
);
|
||||
};
|
||||
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 (
|
||||
<NavItem
|
||||
key={uid}
|
||||
|
||||
@@ -16,16 +16,14 @@ import ChannelList from "./ChannelList";
|
||||
import ContactsModal from "../../common/component/ContactsModal";
|
||||
import ChannelModal from "../../common/component/ChannelModal";
|
||||
import DMList from "./DMList";
|
||||
import { getUnreadCount } from "./utils";
|
||||
|
||||
export default function ChatPage() {
|
||||
const [channelDropFiles, setChannelDropFiles] = useState([]);
|
||||
const [userDropFiles, setUserDropFiles] = useState([]);
|
||||
const { contactsData, UserMsgData, messageData } = useSelector((store) => {
|
||||
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() {
|
||||
/>
|
||||
</h3>
|
||||
<nav className="nav">
|
||||
<DMList sessions={sessions} setDropFiles={setUserDropFiles} />
|
||||
{user_id && UserMsgData.ids.findIndex((i) => i == user_id) == -1 && (
|
||||
<DMList uids={sessionUids} setDropFiles={setUserDropFiles} />
|
||||
{user_id && sessionUids.findIndex((i) => i == user_id) == -1 && (
|
||||
<NavLink className="session" to={`/chat/dm/${user_id}`}>
|
||||
<Contact
|
||||
compact
|
||||
@@ -112,7 +106,6 @@ export default function ChatPage() {
|
||||
|
||||
<div className="down">
|
||||
<div className="msg"></div>
|
||||
{/* <i className="badge">3</i> */}
|
||||
</div>
|
||||
</div>
|
||||
</NavLink>
|
||||
@@ -123,11 +116,7 @@ export default function ChatPage() {
|
||||
</div>
|
||||
<div className="right">
|
||||
{channel_id && (
|
||||
<ChannelChat
|
||||
unreads={getUnreadCount(channel_id)}
|
||||
cid={channel_id}
|
||||
dropFiles={channelDropFiles}
|
||||
/>
|
||||
<ChannelChat cid={channel_id} dropFiles={channelDropFiles} />
|
||||
)}
|
||||
{user_id && <DMChat uid={user_id} dropFiles={userDropFiles} />}
|
||||
</div>
|
||||
|
||||
+31
-16
@@ -3,16 +3,38 @@ import dayjs from "dayjs";
|
||||
import { ContentTypes } from "../../app/config";
|
||||
import Divider from "../../common/component/Divider";
|
||||
import Message from "../../common/component/Message";
|
||||
export const getUnreadCount = (mids, messageData) => {
|
||||
if (!mids || !messageData) return 0;
|
||||
let unreads = 0;
|
||||
mids.forEach((id) => {
|
||||
if (messageData[id] && !messageData[id].read) {
|
||||
unreads++;
|
||||
function debounce(callback, wait = 2000, immediate = false) {
|
||||
let timeout = null;
|
||||
return function () {
|
||||
const callNow = immediate && !timeout;
|
||||
const next = () => callback.apply(this, arguments);
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(next, wait);
|
||||
if (callNow) {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
export function getUnreadCount({
|
||||
mids = [],
|
||||
messageData = {},
|
||||
loginUid = 0,
|
||||
readIndex = 0,
|
||||
}) {
|
||||
console.log({ mids, loginUid, readIndex });
|
||||
// 先过滤掉from自己的
|
||||
const others = mids.filter((mid) => {
|
||||
const { from_uid } = messageData[mid];
|
||||
return from_uid != loginUid;
|
||||
});
|
||||
return unreads;
|
||||
};
|
||||
if (others.length == 0) return 0;
|
||||
if (readIndex == 0) return others.length;
|
||||
// 再过滤掉大于read-index,
|
||||
const final = others.filter((mid) => {
|
||||
return mid > readIndex;
|
||||
});
|
||||
return final.length;
|
||||
}
|
||||
export const renderPreviewMessage = (message = null) => {
|
||||
if (!message) return null;
|
||||
const { content_type, content } = message;
|
||||
@@ -52,7 +74,6 @@ export const renderMessageFragment = ({
|
||||
prev = null,
|
||||
curr = null,
|
||||
contextId = 0,
|
||||
read = true,
|
||||
context = "user",
|
||||
}) => {
|
||||
if (!curr) return null;
|
||||
@@ -71,13 +92,7 @@ export const renderMessageFragment = ({
|
||||
return (
|
||||
<React.Fragment key={mid}>
|
||||
{divider && <Divider content={divider}></Divider>}
|
||||
<Message
|
||||
read={read}
|
||||
context={context}
|
||||
mid={mid}
|
||||
key={mid}
|
||||
contextId={contextId}
|
||||
/>
|
||||
<Message context={context} mid={mid} key={mid} contextId={contextId} />
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,6 +10,8 @@ const StyledWrapper = styled.div`
|
||||
box-shadow: inset -1px 0px 0px rgba(0, 0, 0, 0.1);
|
||||
.list {
|
||||
margin: 12px 8px;
|
||||
overflow: scroll;
|
||||
padding-bottom: 50px;
|
||||
> .nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -54,11 +54,13 @@ export default function usePreload() {
|
||||
getServer();
|
||||
}
|
||||
}, [rehydrated]);
|
||||
const canStreaming =
|
||||
contactsSuccess && rehydrated && !initializing && !streaming;
|
||||
useEffect(() => {
|
||||
if (rehydrated && !initializing && !streaming) {
|
||||
if (canStreaming) {
|
||||
request = startStreaming(store);
|
||||
}
|
||||
}, [rehydrated, store, streaming, initializing]);
|
||||
}, [canStreaming]);
|
||||
|
||||
// console.log("loading", contactsLoading, serverLoading, !checked);
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user