Cleanup loading chat body (#178)
This commit is contained in:
parent
97532cc88d
commit
c170f81054
|
@ -20,7 +20,7 @@ function RenderChannelName({
|
|||
case "group":
|
||||
return (
|
||||
<div className={className}>
|
||||
<GroupIcon activeView={channel.id === activeChannel.id} />
|
||||
<GroupIcon activeView={channel.id === activeChannel?.id} />
|
||||
{` ${channel.name}`}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -29,7 +29,7 @@ function GenerateChannels({ type, onCommunityClick }: GenerateChannelsProps) {
|
|||
<Channel
|
||||
key={channel.id}
|
||||
channel={channel}
|
||||
isActive={channel.id === activeChannel.id}
|
||||
isActive={channel.id === activeChannel?.id}
|
||||
notified={notifications?.[channel.id] > 0}
|
||||
mention={mentions?.[channel.id]}
|
||||
onClick={() => {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { useIdentity } from "../../contexts/identityProvider";
|
||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||
import { useNarrow } from "../../contexts/narrowProvider";
|
||||
import { Reply } from "../../hooks/useReply";
|
||||
import { ChannelData } from "../../models/ChannelData";
|
||||
import { TokenRequirement } from "../Form/TokenRequirement";
|
||||
import { MessagesList } from "../Messages/MessagesList";
|
||||
import { NarrowChannels } from "../NarrowMode/NarrowChannels";
|
||||
|
@ -13,7 +13,7 @@ import { LoadingSkeleton } from "../Skeleton/LoadingSkeleton";
|
|||
|
||||
import { ChatCreation } from "./ChatCreation";
|
||||
import { ChatInput } from "./ChatInput";
|
||||
import { ChatTopbar } from "./ChatTopbar";
|
||||
import { ChatTopbar, ChatTopbarLoading } from "./ChatTopbar";
|
||||
|
||||
export enum ChatBodyState {
|
||||
Chat,
|
||||
|
@ -21,6 +21,55 @@ export enum ChatBodyState {
|
|||
Members,
|
||||
}
|
||||
|
||||
function ChatBodyLoading() {
|
||||
const narrow = useNarrow();
|
||||
return (
|
||||
<Wrapper>
|
||||
<ChatBodyWrapper className={narrow ? "narrow" : ""}>
|
||||
<ChatTopbarLoading />
|
||||
<LoadingSkeleton />
|
||||
<ChatInput reply={undefined} setReply={() => undefined} />
|
||||
</ChatBodyWrapper>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
type ChatBodyContentProps = {
|
||||
showState: ChatBodyState;
|
||||
switchShowState: (state: ChatBodyState) => void;
|
||||
channel: ChannelData;
|
||||
};
|
||||
|
||||
function ChatBodyContent({
|
||||
showState,
|
||||
switchShowState,
|
||||
channel,
|
||||
}: ChatBodyContentProps) {
|
||||
const [reply, setReply] = useState<Reply | undefined>(undefined);
|
||||
|
||||
switch (showState) {
|
||||
case ChatBodyState.Chat:
|
||||
return (
|
||||
<>
|
||||
<MessagesList setReply={setReply} channel={channel} />
|
||||
<ChatInput reply={reply} setReply={setReply} />
|
||||
</>
|
||||
);
|
||||
case ChatBodyState.Channels:
|
||||
return (
|
||||
<NarrowChannels
|
||||
setShowChannels={() => switchShowState(ChatBodyState.Channels)}
|
||||
/>
|
||||
);
|
||||
case ChatBodyState.Members:
|
||||
return (
|
||||
<NarrowMembers
|
||||
switchShowMembersList={() => switchShowState(ChatBodyState.Members)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface ChatBodyProps {
|
||||
onClick: () => void;
|
||||
showMembers: boolean;
|
||||
|
@ -29,9 +78,8 @@ interface ChatBodyProps {
|
|||
|
||||
export function ChatBody({ onClick, showMembers, permission }: ChatBodyProps) {
|
||||
const { messenger, activeChannel, communityData } = useMessengerContext();
|
||||
const narrow = useNarrow();
|
||||
const identity = useIdentity();
|
||||
const [editGroup, setEditGroup] = useState(false);
|
||||
const narrow = useNarrow();
|
||||
const className = useMemo(() => (narrow ? "narrow" : ""), [narrow]);
|
||||
|
||||
const [showState, setShowState] = useState<ChatBodyState>(ChatBodyState.Chat);
|
||||
|
@ -50,8 +98,7 @@ export function ChatBody({ onClick, showMembers, permission }: ChatBodyProps) {
|
|||
}
|
||||
}, [narrow]);
|
||||
|
||||
const [reply, setReply] = useState<Reply | undefined>(undefined);
|
||||
|
||||
if (messenger && communityData && activeChannel) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<ChatBodyWrapper className={className}>
|
||||
|
@ -62,7 +109,6 @@ export function ChatBody({ onClick, showMembers, permission }: ChatBodyProps) {
|
|||
/>
|
||||
) : (
|
||||
<ChatTopbar
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
setEditGroup={setEditGroup}
|
||||
showMembers={showMembers}
|
||||
|
@ -70,42 +116,11 @@ export function ChatBody({ onClick, showMembers, permission }: ChatBodyProps) {
|
|||
switchShowState={switchShowState}
|
||||
/>
|
||||
)}
|
||||
{messenger ? (
|
||||
<>
|
||||
{showState === ChatBodyState.Chat && (
|
||||
<>
|
||||
{messenger && communityData ? (
|
||||
<MessagesList setReply={setReply} />
|
||||
) : (
|
||||
<LoadingSkeleton />
|
||||
)}
|
||||
<ChatInput
|
||||
reply={reply}
|
||||
setReply={setReply}
|
||||
disabled={!identity}
|
||||
<ChatBodyContent
|
||||
showState={showState}
|
||||
switchShowState={switchShowState}
|
||||
channel={activeChannel}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{showState === ChatBodyState.Channels && (
|
||||
<NarrowChannels
|
||||
setShowChannels={() => switchShowState(ChatBodyState.Channels)}
|
||||
/>
|
||||
)}
|
||||
{showState === ChatBodyState.Members && (
|
||||
<NarrowMembers
|
||||
switchShowMembersList={() =>
|
||||
switchShowState(ChatBodyState.Members)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<LoadingSkeleton />
|
||||
<ChatInput reply={reply} setReply={setReply} disabled={!identity} />
|
||||
</>
|
||||
)}
|
||||
</ChatBodyWrapper>
|
||||
{!permission && (
|
||||
<BluredWrapper>
|
||||
|
@ -114,6 +129,9 @@ export function ChatBody({ onClick, showMembers, permission }: ChatBodyProps) {
|
|||
)}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
return <ChatBodyLoading />;
|
||||
}
|
||||
|
||||
const Wrapper = styled.div`
|
||||
|
|
|
@ -7,6 +7,7 @@ import React, {
|
|||
} from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { useIdentity } from "../../contexts/identityProvider";
|
||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||
import { useModal } from "../../contexts/modalProvider";
|
||||
import { Reply } from "../../hooks/useReply";
|
||||
|
@ -27,10 +28,11 @@ import { EmojiPicker } from "./EmojiPicker";
|
|||
interface ChatInputProps {
|
||||
reply: Reply | undefined;
|
||||
setReply: (val: Reply | undefined) => void;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
export function ChatInput({ reply, setReply, disabled }: ChatInputProps) {
|
||||
export function ChatInput({ reply, setReply }: ChatInputProps) {
|
||||
const identity = useIdentity();
|
||||
const disabled = useMemo(() => !identity, [identity]);
|
||||
const { sendMessage, contacts } = useMessengerContext();
|
||||
const [content, setContent] = useState("");
|
||||
const [clearComponent, setClearComponent] = useState("");
|
||||
|
|
|
@ -16,9 +16,38 @@ import { Loading } from "../Skeleton/Loading";
|
|||
|
||||
import { ChatBodyState } from "./ChatBody";
|
||||
|
||||
export function ChatTopbarLoading() {
|
||||
const narrow = useNarrow();
|
||||
|
||||
return (
|
||||
<Topbar className={narrow ? "narrow" : ""}>
|
||||
<ChannelWrapper className={narrow ? "narrow" : ""}>
|
||||
<SkeletonWrapper>
|
||||
<CommunitySkeleton />
|
||||
</SkeletonWrapper>
|
||||
</ChannelWrapper>
|
||||
<MenuWrapper>
|
||||
{!narrow && (
|
||||
<TopBtn>
|
||||
<MembersIcon />
|
||||
</TopBtn>
|
||||
)}
|
||||
<TopBtn>
|
||||
<MoreIcon />
|
||||
</TopBtn>
|
||||
<ActivityWrapper>
|
||||
<TopBtn>
|
||||
<ActivityIcon />
|
||||
</TopBtn>
|
||||
</ActivityWrapper>
|
||||
</MenuWrapper>
|
||||
<Loading />
|
||||
</Topbar>
|
||||
);
|
||||
}
|
||||
|
||||
type ChatTopbarProps = {
|
||||
showState: ChatBodyState;
|
||||
className: string;
|
||||
onClick: () => void;
|
||||
switchShowState: (state: ChatBodyState) => void;
|
||||
showMembers: boolean;
|
||||
|
@ -27,7 +56,6 @@ type ChatTopbarProps = {
|
|||
|
||||
export function ChatTopbar({
|
||||
showState,
|
||||
className,
|
||||
onClick,
|
||||
switchShowState,
|
||||
showMembers,
|
||||
|
@ -39,15 +67,19 @@ export function ChatTopbar({
|
|||
const [showChannelMenu, setShowChannelMenu] = useState(false);
|
||||
const [showActivityCenter, setShowActivityCenter] = useState(false);
|
||||
|
||||
if (!activeChannel) {
|
||||
return <ChatTopbarLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Topbar
|
||||
className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""}
|
||||
>
|
||||
<ChannelWrapper className={className}>
|
||||
<ChannelWrapper className={narrow ? "narrow" : ""}>
|
||||
{messenger && communityData ? (
|
||||
<>
|
||||
{narrow && (
|
||||
<CommunityWrap className={className}>
|
||||
<CommunityWrap className={narrow ? "narrow" : ""}>
|
||||
<Community />
|
||||
</CommunityWrap>
|
||||
)}
|
||||
|
|
|
@ -5,6 +5,7 @@ import { useMessengerContext } from "../../contexts/messengerProvider";
|
|||
import { useModal } from "../../contexts/modalProvider";
|
||||
import { useChatScrollHandle } from "../../hooks/useChatScrollHandle";
|
||||
import { Reply } from "../../hooks/useReply";
|
||||
import { ChannelData } from "../../models/ChannelData";
|
||||
import { EmptyChannel } from "../Channels/EmptyChannel";
|
||||
import { LoadingIcon } from "../Icons/LoadingIcon";
|
||||
import { LinkModal, LinkModalName } from "../Modals/LinkModal";
|
||||
|
@ -14,12 +15,13 @@ import { UiMessage } from "./UiMessage";
|
|||
|
||||
interface MessagesListProps {
|
||||
setReply: (val: Reply | undefined) => void;
|
||||
channel: ChannelData;
|
||||
}
|
||||
|
||||
export function MessagesList({ setReply }: MessagesListProps) {
|
||||
const { messages, activeChannel, contacts } = useMessengerContext();
|
||||
export function MessagesList({ setReply, channel }: MessagesListProps) {
|
||||
const { messages, contacts } = useMessengerContext();
|
||||
const ref = useRef<HTMLHeadingElement>(null);
|
||||
const loadingMessages = useChatScrollHandle(messages, ref, activeChannel);
|
||||
const loadingMessages = useChatScrollHandle(messages, ref);
|
||||
|
||||
const shownMessages = useMemo(
|
||||
() =>
|
||||
|
@ -50,7 +52,7 @@ export function MessagesList({ setReply }: MessagesListProps) {
|
|||
<MessagesWrapper ref={ref}>
|
||||
<PictureModal image={image} />
|
||||
<LinkModal link={link} />
|
||||
<EmptyChannel channel={activeChannel} />
|
||||
<EmptyChannel channel={channel} />
|
||||
{loadingMessages && (
|
||||
<LoadingWrapper>
|
||||
<LoadingIcon className="message" />
|
||||
|
@ -60,7 +62,7 @@ export function MessagesList({ setReply }: MessagesListProps) {
|
|||
<UiMessage
|
||||
key={message.id}
|
||||
message={message}
|
||||
channel={activeChannel}
|
||||
channel={channel}
|
||||
idx={idx}
|
||||
prevMessage={shownMessages[idx - 1]}
|
||||
setLink={setLink}
|
||||
|
|
|
@ -34,9 +34,11 @@ export const EditModal = () => {
|
|||
const { setModal } = useModal(EditModalName);
|
||||
|
||||
const handleUpload = () => {
|
||||
if (activeChannel) {
|
||||
activeChannel.icon = image;
|
||||
changeGroupChatName(groupName, activeChannel.id);
|
||||
setModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -62,10 +64,10 @@ export const EditModal = () => {
|
|||
</NameSection>
|
||||
<LogoSection>
|
||||
<Label>Group image</Label>
|
||||
<GroupLogo icon={image || activeChannel.icon}>
|
||||
{!activeChannel.icon &&
|
||||
<GroupLogo icon={image || activeChannel?.icon}>
|
||||
{!activeChannel?.icon &&
|
||||
!image &&
|
||||
activeChannel.name.slice(0, 1).toUpperCase()}
|
||||
activeChannel?.name?.slice(0, 1)?.toUpperCase()}
|
||||
<AddPictureInputWrapper>
|
||||
<AddIcon />
|
||||
<AddPictureInput
|
||||
|
|
|
@ -17,11 +17,7 @@ const MessengerContext = createContext<MessengerType>({
|
|||
communityData: undefined,
|
||||
contacts: {},
|
||||
setContacts: () => undefined,
|
||||
activeChannel: {
|
||||
id: "",
|
||||
name: "",
|
||||
type: "channel",
|
||||
},
|
||||
activeChannel: undefined,
|
||||
channels: {},
|
||||
setChannel: () => undefined,
|
||||
removeChannel: () => undefined,
|
||||
|
|
|
@ -42,7 +42,7 @@ export type MessengerType = {
|
|||
channels: ChannelsData;
|
||||
setChannel: (channel: ChannelData) => void;
|
||||
removeChannel: (channelId: string) => void;
|
||||
activeChannel: ChannelData;
|
||||
activeChannel: ChannelData | undefined;
|
||||
setActiveChannel: (channel: ChannelData) => void;
|
||||
createGroupChat: (members: string[]) => void;
|
||||
changeGroupChatName: (name: string, chatId: string) => void;
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
import { useEffect, useState } from "react";
|
||||
|
||||
import { useMessengerContext } from "../contexts/messengerProvider";
|
||||
import { ChannelData } from "../models/ChannelData";
|
||||
import { ChatMessage } from "../models/ChatMessage";
|
||||
|
||||
export function useChatScrollHandle(
|
||||
messages: ChatMessage[],
|
||||
ref: React.RefObject<HTMLHeadingElement>,
|
||||
activeChannel: ChannelData
|
||||
ref: React.RefObject<HTMLHeadingElement>
|
||||
) {
|
||||
const { loadPrevDay, loadingMessages } = useMessengerContext();
|
||||
const { loadPrevDay, loadingMessages, activeChannel } = useMessengerContext();
|
||||
const [scrollOnBot, setScrollOnBot] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -19,7 +17,7 @@ export function useChatScrollHandle(
|
|||
}, [messages.length, scrollOnBot]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loadingMessages) {
|
||||
if (!loadingMessages && activeChannel) {
|
||||
if (
|
||||
(ref?.current?.clientHeight ?? 0) >= (ref?.current?.scrollHeight ?? 0)
|
||||
) {
|
||||
|
@ -27,11 +25,11 @@ export function useChatScrollHandle(
|
|||
loadPrevDay(activeChannel.id, activeChannel.type === "group");
|
||||
}
|
||||
}
|
||||
}, [messages.length, loadingMessages]);
|
||||
}, [messages.length, loadingMessages, activeChannel]);
|
||||
|
||||
useEffect(() => {
|
||||
const setScroll = () => {
|
||||
if (ref?.current) {
|
||||
if (ref?.current && activeChannel) {
|
||||
if (ref.current.scrollTop <= 0) {
|
||||
loadPrevDay(activeChannel.id, activeChannel.type === "group");
|
||||
}
|
||||
|
@ -51,6 +49,6 @@ export function useChatScrollHandle(
|
|||
};
|
||||
ref.current?.addEventListener("scroll", setScroll);
|
||||
return () => ref.current?.removeEventListener("scroll", setScroll);
|
||||
}, [ref, scrollOnBot]);
|
||||
}, [ref, scrollOnBot, activeChannel]);
|
||||
return loadingMessages;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue