refactor: lots updates
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import dayjs from "dayjs";
|
||||
// import dayjs from "dayjs";
|
||||
import useChatScroll from "../../../common/hook/useChatScroll";
|
||||
|
||||
import Message from "../../../common/component/Message";
|
||||
import ChannelIcon from "../../../common/component/ChannelIcon";
|
||||
import Send from "../../../common/component/Send";
|
||||
import { clearChannelMsgUnread } from "../../../app/slices/message.channel";
|
||||
// import { readMessage } from "../../../app/slices/message";
|
||||
import Contact from "../../../common/component/Contact";
|
||||
import Layout from "../Layout";
|
||||
import {
|
||||
@@ -16,37 +17,29 @@ import {
|
||||
StyledHeader,
|
||||
} from "./styled";
|
||||
|
||||
export default function ChannelChat({
|
||||
cid = "",
|
||||
unreads = 0,
|
||||
data = {},
|
||||
dropFiles = [],
|
||||
}) {
|
||||
export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
// const containerRef = useRef(null);
|
||||
const [dragFiles, setDragFiles] = useState([]);
|
||||
const dispatch = useDispatch();
|
||||
const { msgs, users } = useSelector((store) => {
|
||||
// const dispatch = useDispatch();
|
||||
const { msgIds, userIds, data } = useSelector((store) => {
|
||||
return {
|
||||
msgs: store.channelMessage[cid] || {},
|
||||
users: store.contacts,
|
||||
msgIds: store.channelMessage[cid] || [],
|
||||
userIds: store.contacts.ids,
|
||||
data: store.channels.byId[cid],
|
||||
};
|
||||
});
|
||||
const handleClearUnreads = () => {
|
||||
dispatch(clearChannelMsgUnread(cid));
|
||||
};
|
||||
const ref = useChatScroll(msgIds);
|
||||
// const handleClearUnreads = () => {
|
||||
// dispatch(readMessage(msgIds));
|
||||
// };
|
||||
useEffect(() => {
|
||||
if (dropFiles.length) {
|
||||
setDragFiles(dropFiles);
|
||||
}
|
||||
}, [dropFiles]);
|
||||
const { name, description, is_public, members = [] } = data;
|
||||
const filteredUsers =
|
||||
members.length == 0
|
||||
? users
|
||||
: users.filter((u) => {
|
||||
return members.includes(u.uid);
|
||||
});
|
||||
console.log("channel message list", msgs);
|
||||
const memberIds = members.length == 0 ? userIds : members;
|
||||
console.log("channel message list", msgIds);
|
||||
return (
|
||||
<Layout
|
||||
setDragFiles={setDragFiles}
|
||||
@@ -82,61 +75,31 @@ export default function ChannelChat({
|
||||
}
|
||||
contacts={
|
||||
<StyledContacts>
|
||||
{filteredUsers.map(({ name, uid }) => {
|
||||
return <Contact key={name} uid={uid} popover />;
|
||||
{memberIds.map((uid) => {
|
||||
return <Contact key={uid} uid={uid} popover />;
|
||||
})}
|
||||
</StyledContacts>
|
||||
}
|
||||
>
|
||||
<StyledChannelChat>
|
||||
<div className="wrapper">
|
||||
<div className="wrapper" ref={ref}>
|
||||
<div className="info">
|
||||
<h2 className="title">Welcome to #{name} !</h2>
|
||||
<p className="desc">This is the start of the #{name} channel. </p>
|
||||
{/* <button className="edit">Edit Channel</button> */}
|
||||
</div>
|
||||
<div className="chat">
|
||||
{Object.entries(msgs)
|
||||
.sort(([, msg1], [, msg2]) => {
|
||||
return msg1.created_at - msg2.created_at;
|
||||
})
|
||||
.map(([mid, msg], idx) => {
|
||||
if (!msg) return null;
|
||||
const {
|
||||
likes = {},
|
||||
pending = false,
|
||||
from_uid,
|
||||
content,
|
||||
content_type,
|
||||
created_at,
|
||||
unread,
|
||||
edited,
|
||||
reply,
|
||||
} = msg;
|
||||
return (
|
||||
<Message
|
||||
reply={reply}
|
||||
edited={edited}
|
||||
likes={likes}
|
||||
pending={pending}
|
||||
content_type={content_type}
|
||||
unread={unread}
|
||||
gid={cid}
|
||||
mid={mid}
|
||||
key={idx}
|
||||
time={created_at}
|
||||
fromUid={from_uid}
|
||||
content={content}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{msgIds.map((mid, idx) => {
|
||||
// if (!msg) return null;
|
||||
return <Message contextId={cid} mid={mid} key={idx} />;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Send dragFiles={dragFiles} id={cid} type="channel" name={name} />
|
||||
<div className="placeholder"></div>
|
||||
</StyledChannelChat>
|
||||
{unreads != 0 && (
|
||||
{/* {unreads != 0 && (
|
||||
<StyledNotification>
|
||||
<div className="content">
|
||||
{unreads} new messages
|
||||
@@ -148,7 +111,7 @@ export default function ChannelChat({
|
||||
Mark As Read
|
||||
</button>
|
||||
</StyledNotification>
|
||||
)}
|
||||
)} */}
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,19 +2,26 @@
|
||||
import { NavLink, useNavigate } from "react-router-dom";
|
||||
import { useDrop } from "react-dnd";
|
||||
import { NativeTypes } from "react-dnd-html5-backend";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import useContextMenu from "../../common/hook/useContextMenu";
|
||||
import ContextMenu from "../../common/component/ContextMenu";
|
||||
import { toggleChannelSetting } from "../../app/slices/ui";
|
||||
import ChannelIcon from "../../common/component/ChannelIcon";
|
||||
const NavItem = ({ data, setFiles, contextMenuEventHandler }) => {
|
||||
import getUnreadCount from "./getUnreadCount";
|
||||
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 handleChannelSetting = (evt) => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
dispatch(toggleChannelSetting(data.id));
|
||||
dispatch(toggleChannelSetting(id));
|
||||
};
|
||||
const [{ isActive }, drop] = useDrop(() => ({
|
||||
accept: [NativeTypes.FILE],
|
||||
@@ -22,7 +29,7 @@ const NavItem = ({ data, setFiles, contextMenuEventHandler }) => {
|
||||
if (dataTransfer.files.length) {
|
||||
// console.log(files, rest);
|
||||
setFiles([...dataTransfer.files]);
|
||||
navigate(`/chat/channel/${data.id}`);
|
||||
navigate(`/chat/channel/${id}`);
|
||||
// 重置
|
||||
setTimeout(() => {
|
||||
setFiles([]);
|
||||
@@ -33,7 +40,8 @@ const NavItem = ({ data, setFiles, contextMenuEventHandler }) => {
|
||||
isActive: monitor.canDrop() && monitor.isOver(),
|
||||
}),
|
||||
}));
|
||||
const { id, is_public, name, unreads } = data;
|
||||
const { is_public, name } = channel;
|
||||
const unreads = getUnreadCount(mids, messageData);
|
||||
return (
|
||||
<NavLink
|
||||
onContextMenu={contextMenuEventHandler}
|
||||
@@ -57,7 +65,8 @@ const NavItem = ({ data, setFiles, contextMenuEventHandler }) => {
|
||||
</NavLink>
|
||||
);
|
||||
};
|
||||
export default function ChannelList({ channels, setDropFiles }) {
|
||||
export default function ChannelList({ setDropFiles }) {
|
||||
const channelIds = useSelector((store) => store.channels.ids);
|
||||
const {
|
||||
visible: contextMenuVisible,
|
||||
posX,
|
||||
@@ -67,12 +76,12 @@ export default function ChannelList({ channels, setDropFiles }) {
|
||||
} = useContextMenu();
|
||||
return (
|
||||
<>
|
||||
{channels.map(({ id, is_public, name, description, unreads }) => {
|
||||
{channelIds.map((cid) => {
|
||||
return (
|
||||
<NavItem
|
||||
contextMenuEventHandler={handleContextMenuEvent}
|
||||
key={id}
|
||||
data={{ id, is_public, name, description, unreads }}
|
||||
key={cid}
|
||||
id={cid}
|
||||
setFiles={setDropFiles}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import useChatScroll from "../../../common/hook/useChatScroll";
|
||||
import Message from "../../../common/component/Message";
|
||||
import Send from "../../../common/component/Send";
|
||||
import Contact from "../../../common/component/Contact";
|
||||
@@ -10,19 +11,17 @@ import { StyledHeader, StyledDMChat } from "./styled";
|
||||
export default function DMChat({ uid = "", dropFiles = [] }) {
|
||||
console.log("dm files", dropFiles);
|
||||
const [dragFiles, setDragFiles] = useState([]);
|
||||
const contacts = useSelector((store) => store.contacts);
|
||||
const { msgs } = useSelector((store) => {
|
||||
// const [mids, setMids] = useState([]);
|
||||
const { msgIds, currUser } = useSelector((store) => {
|
||||
return {
|
||||
msgs: store.userMessage[uid] || {},
|
||||
currUser: store.contacts.byId[uid],
|
||||
msgIds: store.userMessage.byId[uid] || [],
|
||||
};
|
||||
});
|
||||
const [currUser, setCurrUser] = useState(null);
|
||||
useEffect(() => {
|
||||
console.log({ uid });
|
||||
if (uid && contacts) {
|
||||
setCurrUser(contacts.find((c) => c.uid == uid));
|
||||
}
|
||||
}, [uid, contacts]);
|
||||
const ref = useChatScroll(msgIds);
|
||||
// useEffect(() => {
|
||||
// setMids(msgIds);
|
||||
// }, [msgIds]);
|
||||
useEffect(() => {
|
||||
if (dropFiles.length) {
|
||||
setDragFiles(dropFiles);
|
||||
@@ -67,42 +66,12 @@ export default function DMChat({ uid = "", dropFiles = [] }) {
|
||||
}
|
||||
>
|
||||
<StyledDMChat>
|
||||
<div className="chat">
|
||||
{Object.entries(msgs)
|
||||
.sort(([, msg1], [, msg2]) => {
|
||||
return msg1.created_at - msg2.created_at;
|
||||
})
|
||||
.map(([mid, msg], idx) => {
|
||||
if (!msg) return null;
|
||||
// console.log("user msg", msg);
|
||||
const {
|
||||
likes = {},
|
||||
from_uid,
|
||||
content,
|
||||
content_type,
|
||||
created_at,
|
||||
unread,
|
||||
pending = false,
|
||||
edited,
|
||||
reply,
|
||||
} = msg;
|
||||
return (
|
||||
<Message
|
||||
reply={reply}
|
||||
likes={likes}
|
||||
edited={edited}
|
||||
pending={pending}
|
||||
content_type={content_type}
|
||||
unread={unread}
|
||||
fromUid={from_uid}
|
||||
mid={mid}
|
||||
key={idx}
|
||||
time={created_at}
|
||||
uid={uid}
|
||||
content={content}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<div className="chat" ref={ref}>
|
||||
{msgIds.map((mid) => {
|
||||
// if (!msg) return null;
|
||||
// console.log("user msg", msg);
|
||||
return <Message mid={mid} key={mid} contextId={uid} />;
|
||||
})}
|
||||
</div>
|
||||
</StyledDMChat>
|
||||
<div className="placeholder"></div>
|
||||
|
||||
@@ -45,13 +45,12 @@ export const StyledHeader = styled.header`
|
||||
export const StyledDMChat = styled.article`
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 25px;
|
||||
/* margin-bottom: 120px; */
|
||||
padding-top: 20px;
|
||||
> .chat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 16px;
|
||||
padding-top: 10px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 25px;
|
||||
height: calc(100vh - 56px - 80px);
|
||||
overflow-y: scroll;
|
||||
|
||||
+19
-10
@@ -4,9 +4,16 @@ import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import { useDrop } from "react-dnd";
|
||||
import { NativeTypes } from "react-dnd-html5-backend";
|
||||
import { useSelector } from "react-redux";
|
||||
import Contact from "../../common/component/Contact";
|
||||
dayjs.extend(relativeTime);
|
||||
const NavItem = ({ data, setFiles }) => {
|
||||
const NavItem = ({ uid, mid, unreads, setFiles }) => {
|
||||
const { currMsg, currUser } = useSelector((store) => {
|
||||
return {
|
||||
currUser: store.contacts.byId[uid],
|
||||
currMsg: store.message[mid],
|
||||
};
|
||||
});
|
||||
const navigate = useNavigate();
|
||||
const [{ isActive }, drop] = useDrop(() => ({
|
||||
accept: [NativeTypes.FILE],
|
||||
@@ -14,7 +21,7 @@ const NavItem = ({ data, setFiles }) => {
|
||||
if (dataTransfer.files.length) {
|
||||
// console.log(files, rest);
|
||||
setFiles([...dataTransfer.files]);
|
||||
navigate(`/chat/dm/${data.uid}`);
|
||||
navigate(`/chat/dm/${uid}`);
|
||||
// 重置
|
||||
setTimeout(() => {
|
||||
setFiles([]);
|
||||
@@ -25,7 +32,7 @@ const NavItem = ({ data, setFiles }) => {
|
||||
isActive: monitor.canDrop() && monitor.isOver(),
|
||||
}),
|
||||
}));
|
||||
const { uid, user, lastMsg, unreads } = data;
|
||||
if (!currUser || !currMsg) return null;
|
||||
return (
|
||||
<NavLink
|
||||
ref={drop}
|
||||
@@ -33,15 +40,15 @@ const NavItem = ({ data, setFiles }) => {
|
||||
className={`session ${isActive ? "drop_over" : ""}`}
|
||||
to={`/chat/dm/${uid}`}
|
||||
>
|
||||
<Contact compact interactive={false} className="avatar" uid={user.uid} />
|
||||
<Contact compact interactive={false} className="avatar" uid={uid} />
|
||||
<div className="details">
|
||||
<div className="up">
|
||||
<span className="name">{user.name}</span>
|
||||
<time>{dayjs(lastMsg.created_at).fromNow()}</time>
|
||||
<span className="name">{currUser.name}</span>
|
||||
{currMsg && <time>{dayjs(currMsg.created_at).fromNow()}</time>}
|
||||
</div>
|
||||
|
||||
<div className="down">
|
||||
<div className="msg">{lastMsg.content}</div>
|
||||
{currMsg && <div className="msg">{currMsg.content}</div>}
|
||||
{unreads > 0 && <i className="badge">{unreads}</i>}
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,12 +56,14 @@ const NavItem = ({ data, setFiles }) => {
|
||||
);
|
||||
};
|
||||
export default function DMList({ sessions, setDropFiles }) {
|
||||
return sessions.map(({ uid, user, lastMsg, unreads } = {}) => {
|
||||
if (!user) return null;
|
||||
return sessions.map(({ uid, lastMid, unreads } = {}) => {
|
||||
if (!uid) return null;
|
||||
return (
|
||||
<NavItem
|
||||
key={uid}
|
||||
data={{ uid, user, lastMsg, unreads }}
|
||||
uid={uid}
|
||||
mid={lastMid}
|
||||
unreads={unreads}
|
||||
setFiles={setDropFiles}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
const getUnreadCount = (mids, messageData) => {
|
||||
if (!mids || !messageData) return 0;
|
||||
let unreads = 0;
|
||||
mids.forEach((id) => {
|
||||
if (!messageData[id].read) {
|
||||
unreads++;
|
||||
}
|
||||
});
|
||||
return unreads;
|
||||
};
|
||||
|
||||
export default getUnreadCount;
|
||||
+18
-36
@@ -16,20 +16,18 @@ import ChannelList from "./ChannelList";
|
||||
import ContactsModal from "../../common/component/ContactsModal";
|
||||
import ChannelModal from "../../common/component/ChannelModal";
|
||||
import DMList from "./DMList";
|
||||
import getUnreadCount from "./getUnreadCount";
|
||||
|
||||
export default function ChatPage() {
|
||||
const [channelDropFiles, setChannelDropFiles] = useState([]);
|
||||
const [userDropFiles, setUserDropFiles] = useState([]);
|
||||
const { contacts, channels, UserMsgData, ChannelMsgData } = useSelector(
|
||||
(store) => {
|
||||
return {
|
||||
contacts: store.contacts,
|
||||
channels: store.channels,
|
||||
UserMsgData: store.userMessage,
|
||||
ChannelMsgData: store.channelMessage,
|
||||
};
|
||||
}
|
||||
);
|
||||
const { contactsData, UserMsgData, messageData } = useSelector((store) => {
|
||||
return {
|
||||
contactsData: store.contacts.byId,
|
||||
UserMsgData: store.userMessage,
|
||||
messageData: store.message,
|
||||
};
|
||||
});
|
||||
const [channelModalVisible, setChannelModalVisible] = useState(false);
|
||||
const [contactsModalVisible, setContactsModalVisible] = useState(false);
|
||||
const { channel_id, user_id } = useParams();
|
||||
@@ -39,31 +37,19 @@ export default function ChatPage() {
|
||||
const toggleChannelModalVisible = () => {
|
||||
setChannelModalVisible((prev) => !prev);
|
||||
};
|
||||
const getUnreadCount = (gid) => {
|
||||
return Object.values(ChannelMsgData[gid] || {}).filter((m) => m.unread)
|
||||
.length;
|
||||
};
|
||||
// const getUnreadCount = (gid) => {
|
||||
// return Object.values(ChannelMsgData[gid] || {}).filter((m) => m.read)
|
||||
// .length;
|
||||
// };
|
||||
const handleToggleExpand = (evt) => {
|
||||
const { currentTarget } = evt;
|
||||
const listEle = currentTarget.parentElement.parentElement;
|
||||
listEle.classList.toggle("collapse");
|
||||
};
|
||||
if (!contacts) return null;
|
||||
const tmpSessionUser = contacts.find((c) => c.uid == user_id);
|
||||
const transformedChannels = Object.entries(channels).map(([key, obj]) => {
|
||||
const unreads = Object.values(ChannelMsgData[key] || {}).filter(
|
||||
(m) => m.unread
|
||||
).length;
|
||||
return { id: key, ...obj, unreads };
|
||||
});
|
||||
const sessions = Object.keys(UserMsgData).map((uid) => {
|
||||
let currUser = contacts.find((c) => c.uid == uid);
|
||||
if (!currUser) return undefined;
|
||||
let lastMid = Object.keys(UserMsgData[uid]).sort().pop();
|
||||
let unreads = Object.values(UserMsgData[uid] || {}).filter((m) => m.unread)
|
||||
.length;
|
||||
let lastMsg = UserMsgData[uid][lastMid];
|
||||
return { user: currUser, unreads, uid, lastMsg };
|
||||
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 (
|
||||
<>
|
||||
@@ -93,10 +79,7 @@ export default function ChatPage() {
|
||||
/>
|
||||
</h3>
|
||||
<nav className="nav">
|
||||
<ChannelList
|
||||
channels={transformedChannels}
|
||||
setDropFiles={setChannelDropFiles}
|
||||
/>
|
||||
<ChannelList setDropFiles={setChannelDropFiles} />
|
||||
</nav>
|
||||
</div>
|
||||
<div className="list dms">
|
||||
@@ -117,7 +100,7 @@ export default function ChatPage() {
|
||||
</h3>
|
||||
<nav className="nav">
|
||||
<DMList sessions={sessions} setDropFiles={setUserDropFiles} />
|
||||
{user_id && !Object.keys(UserMsgData).includes(user_id) && (
|
||||
{user_id && UserMsgData.ids.findIndex((i) => i == user_id) == -1 && (
|
||||
<NavLink className="session" to={`/chat/dm/${user_id}`}>
|
||||
<Contact
|
||||
compact
|
||||
@@ -147,7 +130,6 @@ export default function ChatPage() {
|
||||
<ChannelChat
|
||||
unreads={getUnreadCount(channel_id)}
|
||||
cid={channel_id}
|
||||
data={channels[channel_id]}
|
||||
dropFiles={channelDropFiles}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user