refactor: stash long list updates
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
// import { useRef, useEffect } from "react";
|
||||
import { useRef, useEffect } from "react";
|
||||
import styled from "styled-components";
|
||||
import { Waveform } from "@uiball/loaders";
|
||||
|
||||
const Styled = styled.div`
|
||||
margin-top: 80px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -10,35 +11,35 @@ const Styled = styled.div`
|
||||
padding: 30px 0;
|
||||
/* background-color: #eee; */
|
||||
`;
|
||||
export default function LoadMore() {
|
||||
// const ref = useRef(undefined);
|
||||
// useEffect(() => {
|
||||
// const observer = new IntersectionObserver(
|
||||
// (entries) => {
|
||||
// entries.forEach((entry) => {
|
||||
// const intersecting = entry.isIntersecting;
|
||||
// // const currEle = entry.target;
|
||||
// if (intersecting && loadMore) {
|
||||
// // load more
|
||||
// console.log("inview");
|
||||
// loadMore();
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
// { threshold: 0 }
|
||||
// );
|
||||
// const currEle = ref?.current;
|
||||
// if (currEle) {
|
||||
// observer.observe(ref.current);
|
||||
// }
|
||||
// return () => {
|
||||
// if (currEle) {
|
||||
// observer.unobserve(currEle);
|
||||
// }
|
||||
// };
|
||||
// }, [ref]);
|
||||
export default function LoadMore({ pullDown = null }) {
|
||||
const ref = useRef(undefined);
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
const intersecting = entry.isIntersecting;
|
||||
// const currEle = entry.target;
|
||||
if (intersecting && pullDown) {
|
||||
// load more
|
||||
console.log("inview");
|
||||
pullDown();
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0 }
|
||||
);
|
||||
const currEle = ref?.current;
|
||||
if (currEle) {
|
||||
observer.observe(ref.current);
|
||||
}
|
||||
return () => {
|
||||
if (currEle) {
|
||||
observer.unobserve(currEle);
|
||||
}
|
||||
};
|
||||
}, [ref, pullDown]);
|
||||
return (
|
||||
<Styled>
|
||||
<Styled ref={ref}>
|
||||
<Waveform
|
||||
className="loading"
|
||||
size={24}
|
||||
|
||||
@@ -3,11 +3,14 @@ import { useDebounce } from "rooks";
|
||||
import { NavLink, useLocation } from "react-router-dom";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
// import InfiniteScroll from "react-infinite-scroll-component";
|
||||
import PinList from "./PinList";
|
||||
import FavList from "../FavList";
|
||||
import { useReadMessageMutation } from "../../../app/services/message";
|
||||
import { updateRemeberedNavs } from "../../../app/slices/ui";
|
||||
import useChatScroll from "../../../common/hook/useChatScroll";
|
||||
// import useChatScroll from "../../../common/hook/useChatScroll";
|
||||
import useMessageFeed from "../../../common/hook/useMessageFeed";
|
||||
|
||||
import ChannelIcon from "../../../common/component/ChannelIcon";
|
||||
import Tooltip from "../../../common/component/Tooltip";
|
||||
import Contact from "../../../common/component/Contact";
|
||||
@@ -30,8 +33,13 @@ import {
|
||||
StyledHeader,
|
||||
} from "./styled";
|
||||
import InviteModal from "../../../common/component/InviteModal";
|
||||
import LoadMore from "./LoadMore";
|
||||
|
||||
export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
const { list: msgIds, prepends, hasMore, pullDown } = useMessageFeed({
|
||||
context: "channel",
|
||||
id: cid,
|
||||
});
|
||||
const [toolVisible, setToolVisible] = useState("");
|
||||
const { pathname } = useLocation();
|
||||
const dispatch = useDispatch();
|
||||
@@ -41,7 +49,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
const [addMemberModalVisible, setAddMemberModalVisible] = useState(false);
|
||||
const {
|
||||
selects,
|
||||
msgIds,
|
||||
// msgIds,
|
||||
userIds,
|
||||
data,
|
||||
messageData,
|
||||
@@ -54,13 +62,13 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
footprint: store.footprint,
|
||||
loginUser: store.contacts.byId[store.authData.uid],
|
||||
loginUid: store.authData.uid,
|
||||
msgIds: store.channelMessage[cid] || [],
|
||||
// msgIds: store.channelMessage[cid] || [],
|
||||
userIds: store.contacts.ids,
|
||||
data: store.channels.byId[cid] || {},
|
||||
messageData: store.message || {},
|
||||
};
|
||||
});
|
||||
const ref = useChatScroll(msgIds);
|
||||
// const ref = useChatScroll(msgIds);
|
||||
// const handleClearUnreads = () => {
|
||||
// dispatch(readMessage(msgIds));
|
||||
// };
|
||||
@@ -86,6 +94,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
console.log("channel message list", msgIds);
|
||||
const readIndex = footprint.readChannels[cid];
|
||||
const pinCount = data?.pinned_messages?.length || 0;
|
||||
const feeds = [...prepends, ...msgIds];
|
||||
return (
|
||||
<>
|
||||
{addMemberModalVisible && (
|
||||
@@ -223,41 +232,42 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<StyledChannelChat ref={ref}>
|
||||
<div className="info">
|
||||
<h2 className="title">Welcome to #{name} !</h2>
|
||||
<p className="desc">This is the start of the #{name} channel. </p>
|
||||
<NavLink
|
||||
to={`/setting/channel/${cid}?f=${pathname}`}
|
||||
className="edit"
|
||||
>
|
||||
<EditIcon className="icon" />
|
||||
Edit Channel
|
||||
</NavLink>
|
||||
</div>
|
||||
<div className="feed">
|
||||
{[...msgIds]
|
||||
.sort((a, b) => {
|
||||
return Number(a) - Number(b);
|
||||
})
|
||||
.map((mid, idx) => {
|
||||
const curr = messageData[mid];
|
||||
if (!curr) return null;
|
||||
const isFirst = idx == 0;
|
||||
const prev = idx == 0 ? null : messageData[msgIds[idx - 1]];
|
||||
const read = curr?.from_uid == loginUid || mid <= readIndex;
|
||||
return renderMessageFragment({
|
||||
selectMode: !!selects,
|
||||
updateReadIndex: updateReadDebounced,
|
||||
read,
|
||||
isFirst,
|
||||
prev,
|
||||
curr,
|
||||
contextId: cid,
|
||||
context: "channel",
|
||||
});
|
||||
})}
|
||||
</div>
|
||||
<StyledChannelChat id={`RUSTCHAT_FEED_channel_${cid}`}>
|
||||
{/* <div className="feed"> */}
|
||||
{feeds.map((mid, idx) => {
|
||||
const curr = messageData[mid];
|
||||
if (!curr) return null;
|
||||
const isFirst = idx == 0;
|
||||
const prev =
|
||||
idx == feeds.length - 1 ? null : messageData[feeds[idx + 1]];
|
||||
const read = curr?.from_uid == loginUid || mid <= readIndex;
|
||||
return renderMessageFragment({
|
||||
selectMode: !!selects,
|
||||
updateReadIndex: updateReadDebounced,
|
||||
read,
|
||||
isFirst,
|
||||
prev,
|
||||
curr,
|
||||
contextId: cid,
|
||||
context: "channel",
|
||||
});
|
||||
})}
|
||||
{hasMore ? (
|
||||
<LoadMore pullDown={pullDown} />
|
||||
) : (
|
||||
<div className="info">
|
||||
<h2 className="title">Welcome to #{name} !</h2>
|
||||
<p className="desc">This is the start of the #{name} channel. </p>
|
||||
<NavLink
|
||||
to={`/setting/channel/${cid}?f=${pathname}`}
|
||||
className="edit"
|
||||
>
|
||||
<EditIcon className="icon" />
|
||||
Edit Channel
|
||||
</NavLink>
|
||||
</div>
|
||||
)}
|
||||
{/* </div> */}
|
||||
</StyledChannelChat>
|
||||
{/* {unreads != 0 && (
|
||||
<StyledNotification>
|
||||
|
||||
+47
-56
@@ -2,15 +2,12 @@ import { useState, useEffect } from "react";
|
||||
import { useDebounce } from "rooks";
|
||||
import { NavLink, useLocation } from "react-router-dom";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import InfiniteScroll from "react-infinite-scroller";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import PinList from "./PinList";
|
||||
import LoadMore from "./LoadMore";
|
||||
import FavList from "../FavList";
|
||||
import { useReadMessageMutation } from "../../../app/services/message";
|
||||
import { updateRemeberedNavs } from "../../../app/slices/ui";
|
||||
// import useChatScroll from "../../../common/hook/useChatScroll";
|
||||
import useMessageFeed from "../../../common/hook/useMessageFeed";
|
||||
import useChatScroll from "../../../common/hook/useChatScroll";
|
||||
import ChannelIcon from "../../../common/component/ChannelIcon";
|
||||
import Tooltip from "../../../common/component/Tooltip";
|
||||
import Contact from "../../../common/component/Contact";
|
||||
@@ -26,14 +23,15 @@ import IconHeadphone from "../../../assets/icons/headphone.svg";
|
||||
import boardosIcon from "../../../assets/icons/app.boardos.svg?url";
|
||||
import webrowseIcon from "../../../assets/icons/app.webrowse.svg?url";
|
||||
import addIcon from "../../../assets/icons/add.svg?url";
|
||||
import { StyledContacts, StyledChannelChat, StyledHeader } from "./styled";
|
||||
import {
|
||||
// StyledNotification,
|
||||
StyledContacts,
|
||||
StyledChannelChat,
|
||||
StyledHeader,
|
||||
} from "./styled";
|
||||
import InviteModal from "../../../common/component/InviteModal";
|
||||
|
||||
export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
const { list: msgIdList, appends, hasMore, pullUp } = useMessageFeed({
|
||||
context: "channel",
|
||||
id: cid,
|
||||
});
|
||||
const [toolVisible, setToolVisible] = useState("");
|
||||
const { pathname } = useLocation();
|
||||
const dispatch = useDispatch();
|
||||
@@ -43,6 +41,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
const [addMemberModalVisible, setAddMemberModalVisible] = useState(false);
|
||||
const {
|
||||
selects,
|
||||
msgIds,
|
||||
userIds,
|
||||
data,
|
||||
messageData,
|
||||
@@ -55,16 +54,16 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
footprint: store.footprint,
|
||||
loginUser: store.contacts.byId[store.authData.uid],
|
||||
loginUid: store.authData.uid,
|
||||
msgIds: store.channelMessage[cid] || [],
|
||||
userIds: store.contacts.ids,
|
||||
data: store.channels.byId[cid] || {},
|
||||
messageData: store.message || {},
|
||||
};
|
||||
});
|
||||
// const ref = useChatScroll(mids);
|
||||
const ref = useChatScroll(msgIds);
|
||||
// const handleClearUnreads = () => {
|
||||
// dispatch(readMessage(msgIds));
|
||||
// };
|
||||
// remember the route while switching out
|
||||
useEffect(() => {
|
||||
dispatch(updateRemeberedNavs());
|
||||
return () => {
|
||||
@@ -84,10 +83,9 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
? userIds
|
||||
: members.slice(0).sort((n) => (n == owner ? -1 : 0));
|
||||
const addVisible = loginUser?.is_admin || owner == loginUid;
|
||||
console.log("channel message list", msgIds);
|
||||
const readIndex = footprint.readChannels[cid];
|
||||
const pinCount = data?.pinned_messages?.length || 0;
|
||||
// const finalHasMore = selects ? false : hasMore;
|
||||
const msgs = [...msgIdList, ...appends];
|
||||
return (
|
||||
<>
|
||||
{addMemberModalVisible && (
|
||||
@@ -211,10 +209,10 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
return (
|
||||
<Contact
|
||||
enableContextMenu={true}
|
||||
cid={cid}
|
||||
owner={owner == uid}
|
||||
key={uid}
|
||||
uid={uid}
|
||||
cid={cid}
|
||||
dm
|
||||
popover
|
||||
/>
|
||||
@@ -225,48 +223,41 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<StyledChannelChat id={`RUSTCHAT_FEED_channel_${cid}`}>
|
||||
{!hasMore && (
|
||||
<div className="info">
|
||||
<h2 className="title">Welcome to #{name} !</h2>
|
||||
<p className="desc">This is the start of the #{name} channel. </p>
|
||||
<NavLink
|
||||
to={`/setting/channel/${cid}?f=${pathname}`}
|
||||
className="edit"
|
||||
>
|
||||
<EditIcon className="icon" />
|
||||
Edit Channel
|
||||
</NavLink>
|
||||
</div>
|
||||
)}
|
||||
{/* <div className="feed"> */}
|
||||
<InfiniteScroll
|
||||
threshold={100}
|
||||
hasMore={hasMore}
|
||||
useWindow={false}
|
||||
loader={<LoadMore />}
|
||||
isReverse={true}
|
||||
loadMore={pullUp}
|
||||
>
|
||||
{msgs.map((mid, idx) => {
|
||||
const curr = messageData[mid];
|
||||
if (!curr) return null;
|
||||
const isFirst = idx == 0;
|
||||
const prev = idx == 0 ? null : messageData[msgs[idx - 1]];
|
||||
const read = curr?.from_uid == loginUid || mid <= readIndex;
|
||||
return renderMessageFragment({
|
||||
selectMode: !!selects,
|
||||
updateReadIndex: updateReadDebounced,
|
||||
read,
|
||||
isFirst,
|
||||
prev,
|
||||
curr,
|
||||
contextId: cid,
|
||||
context: "channel",
|
||||
});
|
||||
})}
|
||||
</InfiniteScroll>
|
||||
{/* </div> */}
|
||||
<StyledChannelChat ref={ref}>
|
||||
<div className="info">
|
||||
<h2 className="title">Welcome to #{name} !</h2>
|
||||
<p className="desc">This is the start of the #{name} channel. </p>
|
||||
<NavLink
|
||||
to={`/setting/channel/${cid}?f=${pathname}`}
|
||||
className="edit"
|
||||
>
|
||||
<EditIcon className="icon" />
|
||||
Edit Channel
|
||||
</NavLink>
|
||||
</div>
|
||||
<div className="feed">
|
||||
{[...msgIds]
|
||||
.sort((a, b) => {
|
||||
return Number(a) - Number(b);
|
||||
})
|
||||
.map((mid, idx) => {
|
||||
const curr = messageData[mid];
|
||||
if (!curr) return null;
|
||||
const isFirst = idx == 0;
|
||||
const prev = idx == 0 ? null : messageData[msgIds[idx - 1]];
|
||||
const read = curr?.from_uid == loginUid || mid <= readIndex;
|
||||
return renderMessageFragment({
|
||||
selectMode: !!selects,
|
||||
updateReadIndex: updateReadDebounced,
|
||||
read,
|
||||
isFirst,
|
||||
prev,
|
||||
curr,
|
||||
contextId: cid,
|
||||
context: "channel",
|
||||
});
|
||||
})}
|
||||
</div>
|
||||
</StyledChannelChat>
|
||||
{/* {unreads != 0 && (
|
||||
<StyledNotification>
|
||||
+5
-4
@@ -36,7 +36,7 @@ import InviteModal from "../../../common/component/InviteModal";
|
||||
import LoadMore from "./LoadMore";
|
||||
|
||||
export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
const { list: msgIds, appends, hasMore, pullDown } = useMessageFeed({
|
||||
const { list: msgIds, prepends, hasMore, pullDown } = useMessageFeed({
|
||||
context: "channel",
|
||||
id: cid,
|
||||
});
|
||||
@@ -94,6 +94,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
console.log("channel message list", msgIds);
|
||||
const readIndex = footprint.readChannels[cid];
|
||||
const pinCount = data?.pinned_messages?.length || 0;
|
||||
const feeds = [...prepends, ...msgIds];
|
||||
return (
|
||||
<>
|
||||
{addMemberModalVisible && (
|
||||
@@ -231,14 +232,14 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<StyledChannelChat id="ScrollFeedWrapper">
|
||||
<StyledChannelChat id={`RUSTCHAT_FEED_channel_${cid}`}>
|
||||
{/* <div className="feed"> */}
|
||||
{[...msgIds].map((mid, idx) => {
|
||||
{feeds.map((mid, idx) => {
|
||||
const curr = messageData[mid];
|
||||
if (!curr) return null;
|
||||
const isFirst = idx == 0;
|
||||
const prev =
|
||||
idx == msgIds.length - 1 ? null : messageData[msgIds[idx + 1]];
|
||||
idx == feeds.length - 1 ? null : messageData[feeds[idx + 1]];
|
||||
const read = curr?.from_uid == loginUid || mid <= readIndex;
|
||||
return renderMessageFragment({
|
||||
selectMode: !!selects,
|
||||
@@ -88,6 +88,15 @@ export const StyledChannelChat = styled.article`
|
||||
height: -webkit-fill-available;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
/* pagination start */
|
||||
transform: rotate(180deg);
|
||||
direction: rtl;
|
||||
> div,
|
||||
> hr {
|
||||
direction: ltr;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
/* pagination end */
|
||||
> .info {
|
||||
padding-top: 62px;
|
||||
display: flex;
|
||||
@@ -129,9 +138,5 @@ export const StyledChannelChat = styled.article`
|
||||
}
|
||||
}
|
||||
/* > .feed {
|
||||
overflow-anchor: none;
|
||||
> div {
|
||||
overflow-anchor: auto;
|
||||
}
|
||||
} */
|
||||
`;
|
||||
|
||||
@@ -128,10 +128,10 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
|
||||
title: muted ? "Unmute" : "Mute",
|
||||
handler: handleMute,
|
||||
},
|
||||
{
|
||||
title: "Notification Settings",
|
||||
underline: true,
|
||||
},
|
||||
// {
|
||||
// title: "Notification Settings",
|
||||
// underline: true,
|
||||
// },
|
||||
{
|
||||
title: "Invite People",
|
||||
handler: toggleInviteModalVisible,
|
||||
|
||||
@@ -179,10 +179,9 @@ export const renderMessageFragment = ({
|
||||
}
|
||||
}
|
||||
const _key = local_id || mid;
|
||||
// console.log("_key", _key, local_id, mid);
|
||||
console.log("_key", _key, local_id, mid);
|
||||
return (
|
||||
<React.Fragment key={_key}>
|
||||
{divider && <Divider content={divider}></Divider>}
|
||||
<MessageWrapper
|
||||
key={_key}
|
||||
data-key={_key}
|
||||
@@ -202,8 +201,17 @@ export const renderMessageFragment = ({
|
||||
contextId={contextId}
|
||||
/>
|
||||
</MessageWrapper>
|
||||
{divider && <Divider content={divider}></Divider>}
|
||||
</React.Fragment>
|
||||
);
|
||||
// React.memo(
|
||||
// (prevs, nexts) => {
|
||||
// // curr.properties?.local_id
|
||||
// const prevObj = prevs.curr || undefined;
|
||||
// const nextObj = nexts.curr || undefined;
|
||||
// return prevObj?.properties?.local_id === nextObj?.properties?.local_id;
|
||||
// }
|
||||
// );
|
||||
};
|
||||
|
||||
export default getUnreadCount;
|
||||
|
||||
Reference in New Issue
Block a user