refactor: lots updates

This commit is contained in:
zerosoul
2022-03-14 11:32:00 +08:00
parent 5d363b5a5f
commit 46cfda76d0
83 changed files with 2018 additions and 1486 deletions
+24 -61
View File
@@ -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>
);
}
+19 -10
View File
@@ -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}
/>
);
+15 -46
View File
@@ -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>
+2 -3
View File
@@ -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
View File
@@ -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}
/>
);
+12
View File
@@ -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
View File
@@ -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}
/>
)}