refactor: session message count badge and DnD files

This commit is contained in:
zerosoul
2022-06-14 20:55:49 +08:00
parent 405824d582
commit 75ba278618
5 changed files with 104 additions and 47 deletions
+13 -10
View File
@@ -148,16 +148,19 @@ export default function useMessageFeed({ context = "channel", id = null }) {
}
pageRef.current = pageInfo;
listRef.current = [...pageInfo.ids, ...listRef.current];
setTimeout(() => {
setItems(listRef.current);
console.log("pull up", currPageInfo, listRef.current);
setHasMore(pageInfo.pageNumber !== 1);
const container = containerRef.current;
if (container) {
curScrollPos = container.scrollTop;
oldScroll = container.scrollHeight - container.clientHeight;
}
}, 800);
setTimeout(
() => {
setItems(listRef.current);
console.log("pull up", currPageInfo, listRef.current);
setHasMore(pageInfo.pageNumber !== 1);
const container = containerRef.current;
if (container) {
curScrollPos = container.scrollTop;
oldScroll = container.scrollHeight - container.clientHeight;
}
},
currPageInfo.isLast ? 10 : 800
);
};
const pullDown = () => {
// 向下加载
+9 -3
View File
@@ -6,9 +6,10 @@ import { useUpdateMuteSettingMutation } from "../../../app/services/contact";
import { useReadMessageMutation } from "../../../app/services/message";
import { removeUserSession } from "../../../app/slices/message.user";
import ContextMenu from "../../../common/component/ContextMenu";
import useContactOperation from "../../../common/hook/useContactOperation";
export default function SessionContextMenu({
context,
context = "user",
id,
visible,
mid,
@@ -17,6 +18,7 @@ export default function SessionContextMenu({
setInviteChannelId,
children
}) {
const { canCopyEmail, copyEmail } = useContactOperation({ uid: context == "user" ? id : null });
const [muteChannel] = useUpdateMuteSettingMutation();
const [updateReadIndex] = useReadMessageMutation();
const pathMatched = useMatch(`/chat/dm/${id}`);
@@ -35,7 +37,7 @@ export default function SessionContextMenu({
// console.log("last mid", mids, lastMid);
if (mid) {
const param =
context == "dm" ? { users: [{ uid: +id, mid }] } : { groups: [{ gid: +id, mid }] };
context == "user" ? { users: [{ uid: +id, mid }] } : { groups: [{ gid: +id, mid }] };
updateReadIndex(param);
}
};
@@ -50,12 +52,16 @@ export default function SessionContextMenu({
muteChannel(data);
};
const items =
context == "dm"
context == "user"
? [
{
title: "Mark As Read",
handler: handleReadAll
},
canCopyEmail && {
title: "Copy Email",
handler: copyEmail
},
{
title: "Hide Session",
danger: true,
+53 -31
View File
@@ -5,63 +5,80 @@ import { useDrop } from "react-dnd";
import { NativeTypes } from "react-dnd-html5-backend";
import relativeTime from "dayjs/plugin/relativeTime";
import ContextMenu from "./ContextMenu";
import { renderPreviewMessage } from "../utils";
import getUnreadCount, { renderPreviewMessage } from "../utils";
import Contact from "../../../common/component/Contact";
import iconChannel from "../../../assets/icons/channel.svg?url";
import IconLock from "../../../assets/icons/lock.svg";
import useContextMenu from "../../../common/hook/useContextMenu";
import { useNavigate, NavLink } from "react-router-dom";
import useUploadFile from "../../../common/hook/useUploadFile";
dayjs.extend(relativeTime);
export default function Session({
type = "dm",
type = "user",
id,
mid,
setFiles,
setDeleteChannelId,
setInviteChannelId
}) {
const navigate = useNavigate();
const [{ isActive }, drop] = useDrop(() => ({
accept: [NativeTypes.FILE],
drop({ dataTransfer }) {
if (dataTransfer.files.length) {
// console.log(files, rest);
setFiles([...dataTransfer.files]);
navigate(type == "dm" ? `/chat/dm/${id}` : `/chat/channel/${id}`);
// 重置
setTimeout(() => {
setFiles([]);
}, 300);
}
},
collect: (monitor) => ({
isActive: monitor.canDrop() && monitor.isOver()
})
}));
const { addStageFile } = useUploadFile({ context: type, id });
const [{ isActive }, drop] = useDrop(
() => ({
accept: [NativeTypes.FILE],
drop({ files }) {
if (files.length) {
// console.log(files, rest);
const filesData = files.map((file) => {
const { size, type, name } = file;
const url = URL.createObjectURL(file);
return { size, type, name, url };
});
addStageFile(filesData);
navigate(type == "user" ? `/chat/dm/${id}` : `/chat/channel/${id}`);
}
},
collect: (monitor) => ({
isActive: monitor.canDrop() && monitor.isOver()
})
}),
[type, id]
);
const { visible: contextMenuVisible, handleContextMenuEvent, hideContextMenu } = useContextMenu();
const [data, setData] = useState(null);
const { messageData, contactData, channelData } = useSelector((store) => {
return {
messageData: store.message,
contactData: store.contacts.byId,
channelData: store.channels.byId
};
});
const { messageData, contactData, channelData, readIndex, loginUid, mids } = useSelector(
(store) => {
return {
mids: type == "user" ? store.userMessage.byId[id] : store.channelMessage[id],
loginUid: store.authData.uid,
readIndex:
type == "user" ? store.footprint.readUsers[id] : store.footprint.readChannels[id],
messageData: store.message,
contactData: store.contacts.byId,
channelData: store.channels.byId
};
}
);
const handleImageError = (evt) => {
evt.target.classList.add("channel_default");
evt.target.src = iconChannel;
};
useEffect(() => {
const tmp = type == "dm" ? contactData[id] : channelData[id];
const tmp = type == "user" ? contactData[id] : channelData[id];
if (!tmp) return;
const { name, icon, avatar, is_public = true } = tmp;
const session =
type == "dm" ? { name, icon: avatar, mid, is_public } : { name, icon, mid, is_public };
type == "user" ? { name, icon: avatar, mid, is_public } : { name, icon, mid, is_public };
setData(session);
}, [id, mid, type, contactData, channelData]);
if (!data) return null;
const previewMsg = messageData[mid] || {};
const { name, icon, is_public } = data;
const { unreads = 0 } = getUnreadCount({
mids,
readIndex,
messageData,
loginUid
});
return (
<li className="session">
<ContextMenu
@@ -76,11 +93,11 @@ export default function Session({
<NavLink
ref={drop}
className={`nav ${isActive ? "drop_over" : ""}`}
to={type == "dm" ? `/chat/dm/${id}` : `/chat/channel/${id}`}
to={type == "user" ? `/chat/dm/${id}` : `/chat/channel/${id}`}
onContextMenu={handleContextMenuEvent}
>
<div className="icon">
{type == "dm" ? (
{type == "user" ? (
<Contact avatarSize={40} compact interactive={false} className="avatar" uid={id} />
) : (
<img
@@ -101,6 +118,11 @@ export default function Session({
</div>
<div className="down">
<span className="msg">{renderPreviewMessage(previewMsg)}</span>
{unreads > 0 && (
<i className={`badge ${unreads > 99 ? "dot" : ""}`}>
{unreads > 99 ? null : unreads}
</i>
)}
</div>
</div>
</NavLink>
+2 -2
View File
@@ -32,10 +32,10 @@ export default function SessionList() {
const uSessions = DMs.map((id) => {
const mids = userMessage[id];
if (!mids || mids.length == 0) {
return { mid: null, unreads: 0, id, type: "dm" };
return { mid: null, unreads: 0, id, type: "user" };
}
const mid = [...mids].pop();
return { key: `dm_${id}`, type: "dm", id, mid };
return { key: `user_${id}`, type: "user", id, mid };
});
setSessions(
+27 -1
View File
@@ -17,6 +17,9 @@ const Styled = styled.ul`
&:hover {
background: rgba(116, 127, 141, 0.2);
}
&.drop_over {
box-shadow: inset 0 0 0 2px #52edff;
}
.icon {
flex: 1;
background-color: #eee;
@@ -63,7 +66,8 @@ const Styled = styled.ul`
.down {
display: flex;
align-items: center;
.msg {
justify-content: space-between;
> .msg {
font-weight: 400;
font-size: 12px;
line-height: 18px;
@@ -73,6 +77,28 @@ const Styled = styled.ul`
width: 140px;
text-overflow: ellipsis;
}
> .badge {
color: #fff;
height: 20px;
min-width: 20px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
background: #1fe1f9;
font-weight: 900;
font-size: 10px;
line-height: 10px;
&.dot {
min-width: unset;
width: 6px;
height: 6px;
padding: 0;
}
&.mute {
background: #bfbfbf;
}
}
}
}
}