refactor: session message count badge and DnD files
This commit is contained in:
@@ -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 = () => {
|
||||
// 向下加载
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user