Refactor and add replies to group chats (#149)

This commit is contained in:
Szymon Szlachtowicz 2021-12-07 15:26:22 +01:00 committed by GitHub
parent 8b79cf397e
commit 44da36dfdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 199 additions and 158 deletions

View File

@ -4,22 +4,16 @@ import styled from "styled-components";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider"; import { useNarrow } from "../../contexts/narrowProvider";
import { Reply } from "../../hooks/useReply"; import { Reply } from "../../hooks/useReply";
import { Channel } from "../Channels/Channel";
import { Community } from "../Community";
import { ChannelMenu } from "../Form/ChannelMenu";
import { MembersIcon } from "../Icons/MembersIcon";
import { MoreIcon } from "../Icons/MoreIcon";
import { NarrowChannels } from "../NarrowMode/NarrowChannels"; import { NarrowChannels } from "../NarrowMode/NarrowChannels";
import { NarrowMembers } from "../NarrowMode/NarrowMembers"; import { NarrowMembers } from "../NarrowMode/NarrowMembers";
import { CommunitySkeleton } from "../Skeleton/CommunitySkeleton";
import { Loading } from "../Skeleton/Loading";
import { LoadingSkeleton } from "../Skeleton/LoadingSkeleton"; import { LoadingSkeleton } from "../Skeleton/LoadingSkeleton";
import { ChatCreation } from "./ChatCreation"; import { ChatCreation } from "./ChatCreation";
import { ChatInput } from "./ChatInput"; import { ChatInput } from "./ChatInput";
import { ChatMessages } from "./ChatMessages"; import { ChatMessages } from "./ChatMessages";
import { ChatTopbar } from "./ChatTopbar";
enum ChatBodyState { export enum ChatBodyState {
Chat, Chat,
Channels, Channels,
Members, Members,
@ -33,7 +27,6 @@ interface ChatBodyProps {
export function ChatBody({ onClick, showMembers }: ChatBodyProps) { export function ChatBody({ onClick, showMembers }: ChatBodyProps) {
const { messenger, activeChannel, communityData } = useMessengerContext(); const { messenger, activeChannel, communityData } = useMessengerContext();
const narrow = useNarrow(); const narrow = useNarrow();
const [showChannelMenu, setShowChannelMenu] = useState(false);
const [editGroup, setEditGroup] = useState(false); const [editGroup, setEditGroup] = useState(false);
const className = useMemo(() => (narrow ? "narrow" : ""), [narrow]); const className = useMemo(() => (narrow ? "narrow" : ""), [narrow]);
@ -65,57 +58,14 @@ export function ChatBody({ onClick, showMembers }: ChatBodyProps) {
/> />
) : ( ) : (
<ChatTopbar <ChatTopbar
className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""} className={className}
>
<ChannelWrapper className={className}>
{messenger && communityData ? (
<>
{narrow && (
<CommunityWrap className={className}>
<Community />
</CommunityWrap>
)}
<Channel
channel={activeChannel}
isActive={
narrow ? showState === ChatBodyState.Channels : false
}
activeView={true}
onClick={() => switchShowState(ChatBodyState.Channels)}
/>
</>
) : (
<SkeletonWrapper>
<CommunitySkeleton />
</SkeletonWrapper>
)}
</ChannelWrapper>
<MenuWrapper>
{!narrow && (
<MemberBtn
onClick={onClick} onClick={onClick}
className={showMembers ? "active" : ""}
>
<MembersIcon />
</MemberBtn>
)}
<MoreBtn onClick={() => setShowChannelMenu(!showChannelMenu)}>
<MoreIcon />
</MoreBtn>
</MenuWrapper>
{!messenger && !communityData && <Loading />}
{showChannelMenu && (
<ChannelMenu
channel={activeChannel}
switchMemberList={() => switchShowState(ChatBodyState.Members)}
setShowChannelMenu={setShowChannelMenu}
setEditGroup={setEditGroup} setEditGroup={setEditGroup}
showMembers={showMembers}
showState={showState}
switchShowState={switchShowState}
/> />
)} )}
</ChatTopbar>
)}
{messenger ? ( {messenger ? (
<> <>
{showState === ChatBodyState.Chat && ( {showState === ChatBodyState.Chat && (
@ -164,91 +114,3 @@ const ChatBodyWrapper = styled.div`
width: 100%; width: 100%;
} }
`; `;
const ChannelWrapper = styled.div`
display: flex;
align-items: center;
max-width: 85%;
&.narrow {
width: calc(100% - 46px);
}
`;
const SkeletonWrapper = styled.div`
padding: 8px;
`;
const ChatTopbar = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 8px;
background: ${({ theme }) => theme.bodyBackgroundColor};
position: relative;
&.narrow {
width: 100%;
}
`;
const CommunityWrap = styled.div`
padding-right: 10px;
margin-right: 16px;
position: relative;
&.narrow {
margin-right: 8px;
}
&:after {
content: "";
position: absolute;
right: 0;
top: 50%;
width: 2px;
height: 24px;
transform: translateY(-50%);
border-radius: 1px;
background: ${({ theme }) => theme.primary};
opacity: 0.1;
}
`;
const MenuWrapper = styled.div`
display: flex;
align-items: center;
`;
const MemberBtn = styled.button`
width: 32px;
height: 32px;
border-radius: 8px;
padding: 0;
&:hover {
background: ${({ theme }) => theme.border};
}
&:active,
&.active {
background: ${({ theme }) => theme.inputColor};
}
`;
const MoreBtn = styled.button`
width: 32px;
height: 32px;
border-radius: 8px;
padding: 0;
margin: 0 8px;
&:hover {
background: ${({ theme }) => theme.border};
}
&:active,
&.active {
background: ${({ theme }) => theme.inputColor};
}
`;

View File

@ -79,7 +79,7 @@ export function ChatCreation({
{query && ( {query && (
<SearchBlock <SearchBlock
query={query} query={query}
dsicludeList={styledGroup} discludeList={styledGroup}
onClick={addMember} onClick={addMember}
/> />
)} )}

View File

@ -284,7 +284,7 @@ export function ChatInput({ reply, setReply }: ChatInputProps) {
{query && ( {query && (
<SearchBlock <SearchBlock
query={query} query={query}
dsicludeList={[]} discludeList={[]}
onClick={addMention} onClick={addMention}
onBotttom onBotttom
/> />

View File

@ -0,0 +1,173 @@
import React, { useState } from "react";
import styled from "styled-components";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider";
import { Channel } from "../Channels/Channel";
import { Community } from "../Community";
import { ChannelMenu } from "../Form/ChannelMenu";
import { MembersIcon } from "../Icons/MembersIcon";
import { MoreIcon } from "../Icons/MoreIcon";
import { CommunitySkeleton } from "../Skeleton/CommunitySkeleton";
import { Loading } from "../Skeleton/Loading";
import { ChatBodyState } from "./ChatBody";
type ChatTopbarProps = {
showState: ChatBodyState;
className: string;
onClick: () => void;
switchShowState: (state: ChatBodyState) => void;
showMembers: boolean;
setEditGroup: React.Dispatch<React.SetStateAction<boolean>>;
};
export function ChatTopbar({
showState,
className,
onClick,
switchShowState,
showMembers,
setEditGroup,
}: ChatTopbarProps) {
const { messenger, activeChannel, communityData } = useMessengerContext();
const narrow = useNarrow();
const [showChannelMenu, setShowChannelMenu] = useState(false);
return (
<Topbar
className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""}
>
<ChannelWrapper className={className}>
{messenger && communityData ? (
<>
{narrow && (
<CommunityWrap className={className}>
<Community />
</CommunityWrap>
)}
<Channel
channel={activeChannel}
isActive={narrow ? showState === ChatBodyState.Channels : false}
activeView={true}
onClick={() => switchShowState(ChatBodyState.Channels)}
/>
</>
) : (
<SkeletonWrapper>
<CommunitySkeleton />
</SkeletonWrapper>
)}
</ChannelWrapper>
<MenuWrapper>
{!narrow && (
<MemberBtn onClick={onClick} className={showMembers ? "active" : ""}>
<MembersIcon />
</MemberBtn>
)}
<MoreBtn onClick={() => setShowChannelMenu(!showChannelMenu)}>
<MoreIcon />
</MoreBtn>
</MenuWrapper>
{!messenger && !communityData && <Loading />}
{showChannelMenu && (
<ChannelMenu
channel={activeChannel}
switchMemberList={() => switchShowState(ChatBodyState.Members)}
setShowChannelMenu={setShowChannelMenu}
setEditGroup={setEditGroup}
/>
)}
</Topbar>
);
}
const ChannelWrapper = styled.div`
display: flex;
align-items: center;
max-width: 85%;
&.narrow {
width: calc(100% - 46px);
}
`;
const SkeletonWrapper = styled.div`
padding: 8px;
`;
const Topbar = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 8px;
background: ${({ theme }) => theme.bodyBackgroundColor};
position: relative;
&.narrow {
width: 100%;
}
`;
const CommunityWrap = styled.div`
padding-right: 10px;
margin-right: 16px;
position: relative;
&.narrow {
margin-right: 8px;
}
&:after {
content: "";
position: absolute;
right: 0;
top: 50%;
width: 2px;
height: 24px;
transform: translateY(-50%);
border-radius: 1px;
background: ${({ theme }) => theme.primary};
opacity: 0.1;
}
`;
const MenuWrapper = styled.div`
display: flex;
align-items: center;
`;
const MemberBtn = styled.button`
width: 32px;
height: 32px;
border-radius: 8px;
padding: 0;
&:hover {
background: ${({ theme }) => theme.border};
}
&:active,
&.active {
background: ${({ theme }) => theme.inputColor};
}
`;
const MoreBtn = styled.button`
width: 32px;
height: 32px;
border-radius: 8px;
padding: 0;
margin: 0 8px;
&:hover {
background: ${({ theme }) => theme.border};
}
&:active,
&.active {
background: ${({ theme }) => theme.inputColor};
}
`;

View File

@ -8,14 +8,14 @@ import { Member } from "./Members/Member";
interface SearchBlockProps { interface SearchBlockProps {
query: string; query: string;
dsicludeList: string[]; discludeList: string[];
onClick: (member: string) => void; onClick: (member: string) => void;
onBotttom?: boolean; onBotttom?: boolean;
} }
export const SearchBlock = ({ export const SearchBlock = ({
query, query,
dsicludeList, discludeList,
onClick, onClick,
onBotttom, onBotttom,
}: SearchBlockProps) => { }: SearchBlockProps) => {
@ -24,8 +24,8 @@ export const SearchBlock = ({
const searchList = useMemo(() => { const searchList = useMemo(() => {
return Object.values(contacts) return Object.values(contacts)
.filter((member) => member.id.includes(query)) .filter((member) => member.id.includes(query))
.filter((member) => !dsicludeList.includes(member.id)); .filter((member) => !discludeList.includes(member.id));
}, [query, dsicludeList, contacts]); }, [query, discludeList, contacts]);
if (searchList.length === 0) { if (searchList.length === 0) {
return null; return null;
@ -37,7 +37,7 @@ export const SearchBlock = ({
<ContactsList> <ContactsList>
{Object.values(contacts) {Object.values(contacts)
.filter((member) => member.id.includes(query)) .filter((member) => member.id.includes(query))
.filter((member) => !dsicludeList.includes(member.id)) .filter((member) => !discludeList.includes(member.id))
.map((member) => ( .map((member) => (
<Member <Member
key={member.id} key={member.id}

View File

@ -65,7 +65,8 @@ export function useGroupChats(
msg.text ?? "", msg.text ?? "",
new Date(msg.clock ?? 0), new Date(msg.clock ?? 0),
sender, sender,
image image,
msg.responseTo
), ),
msg.chatId msg.chatId
); );

View File

@ -217,7 +217,7 @@ export function useMessenger(
} }
if (content) { if (content) {
if (activeChannel.type === "group") { if (activeChannel.type === "group") {
await groupChat?.sendMessage(activeChannel.id, content); await groupChat?.sendMessage(activeChannel.id, content, responseTo);
} else { } else {
await messenger?.sendMessage(activeChannel.id, content, responseTo); await messenger?.sendMessage(activeChannel.id, content, responseTo);
} }

View File

@ -68,7 +68,11 @@ export class GroupChats {
* *
* @param text text message to send * @param text text message to send
*/ */
public async sendMessage(chatId: string, content: Content): Promise<void> { public async sendMessage(
chatId: string,
content: Content,
responseTo?: string
): Promise<void> {
const now = Date.now(); const now = Date.now();
const chat = this.chats[chatId]; const chat = this.chats[chatId];
if (chat) { if (chat) {
@ -78,7 +82,8 @@ export class GroupChats {
now, now,
now, now,
chatId, chatId,
content content,
responseTo
); );
const wakuMessage = await WakuMessage.fromBytes( const wakuMessage = await WakuMessage.fromBytes(
chatMessage.encode(), chatMessage.encode(),