Refactor and add replies to group chats (#149)
This commit is contained in:
parent
8b79cf397e
commit
44da36dfdf
|
@ -4,22 +4,16 @@ import styled from "styled-components";
|
|||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||
import { useNarrow } from "../../contexts/narrowProvider";
|
||||
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 { NarrowMembers } from "../NarrowMode/NarrowMembers";
|
||||
import { CommunitySkeleton } from "../Skeleton/CommunitySkeleton";
|
||||
import { Loading } from "../Skeleton/Loading";
|
||||
import { LoadingSkeleton } from "../Skeleton/LoadingSkeleton";
|
||||
|
||||
import { ChatCreation } from "./ChatCreation";
|
||||
import { ChatInput } from "./ChatInput";
|
||||
import { ChatMessages } from "./ChatMessages";
|
||||
import { ChatTopbar } from "./ChatTopbar";
|
||||
|
||||
enum ChatBodyState {
|
||||
export enum ChatBodyState {
|
||||
Chat,
|
||||
Channels,
|
||||
Members,
|
||||
|
@ -33,7 +27,6 @@ interface ChatBodyProps {
|
|||
export function ChatBody({ onClick, showMembers }: ChatBodyProps) {
|
||||
const { messenger, activeChannel, communityData } = useMessengerContext();
|
||||
const narrow = useNarrow();
|
||||
const [showChannelMenu, setShowChannelMenu] = useState(false);
|
||||
|
||||
const [editGroup, setEditGroup] = useState(false);
|
||||
const className = useMemo(() => (narrow ? "narrow" : ""), [narrow]);
|
||||
|
@ -65,57 +58,14 @@ export function ChatBody({ onClick, showMembers }: ChatBodyProps) {
|
|||
/>
|
||||
) : (
|
||||
<ChatTopbar
|
||||
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
|
||||
className={className}
|
||||
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}
|
||||
showMembers={showMembers}
|
||||
showState={showState}
|
||||
switchShowState={switchShowState}
|
||||
/>
|
||||
)}
|
||||
</ChatTopbar>
|
||||
)}
|
||||
{messenger ? (
|
||||
<>
|
||||
{showState === ChatBodyState.Chat && (
|
||||
|
@ -164,91 +114,3 @@ const ChatBodyWrapper = styled.div`
|
|||
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};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -79,7 +79,7 @@ export function ChatCreation({
|
|||
{query && (
|
||||
<SearchBlock
|
||||
query={query}
|
||||
dsicludeList={styledGroup}
|
||||
discludeList={styledGroup}
|
||||
onClick={addMember}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -284,7 +284,7 @@ export function ChatInput({ reply, setReply }: ChatInputProps) {
|
|||
{query && (
|
||||
<SearchBlock
|
||||
query={query}
|
||||
dsicludeList={[]}
|
||||
discludeList={[]}
|
||||
onClick={addMention}
|
||||
onBotttom
|
||||
/>
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
`;
|
|
@ -8,14 +8,14 @@ import { Member } from "./Members/Member";
|
|||
|
||||
interface SearchBlockProps {
|
||||
query: string;
|
||||
dsicludeList: string[];
|
||||
discludeList: string[];
|
||||
onClick: (member: string) => void;
|
||||
onBotttom?: boolean;
|
||||
}
|
||||
|
||||
export const SearchBlock = ({
|
||||
query,
|
||||
dsicludeList,
|
||||
discludeList,
|
||||
onClick,
|
||||
onBotttom,
|
||||
}: SearchBlockProps) => {
|
||||
|
@ -24,8 +24,8 @@ export const SearchBlock = ({
|
|||
const searchList = useMemo(() => {
|
||||
return Object.values(contacts)
|
||||
.filter((member) => member.id.includes(query))
|
||||
.filter((member) => !dsicludeList.includes(member.id));
|
||||
}, [query, dsicludeList, contacts]);
|
||||
.filter((member) => !discludeList.includes(member.id));
|
||||
}, [query, discludeList, contacts]);
|
||||
|
||||
if (searchList.length === 0) {
|
||||
return null;
|
||||
|
@ -37,7 +37,7 @@ export const SearchBlock = ({
|
|||
<ContactsList>
|
||||
{Object.values(contacts)
|
||||
.filter((member) => member.id.includes(query))
|
||||
.filter((member) => !dsicludeList.includes(member.id))
|
||||
.filter((member) => !discludeList.includes(member.id))
|
||||
.map((member) => (
|
||||
<Member
|
||||
key={member.id}
|
||||
|
|
|
@ -65,7 +65,8 @@ export function useGroupChats(
|
|||
msg.text ?? "",
|
||||
new Date(msg.clock ?? 0),
|
||||
sender,
|
||||
image
|
||||
image,
|
||||
msg.responseTo
|
||||
),
|
||||
msg.chatId
|
||||
);
|
||||
|
|
|
@ -217,7 +217,7 @@ export function useMessenger(
|
|||
}
|
||||
if (content) {
|
||||
if (activeChannel.type === "group") {
|
||||
await groupChat?.sendMessage(activeChannel.id, content);
|
||||
await groupChat?.sendMessage(activeChannel.id, content, responseTo);
|
||||
} else {
|
||||
await messenger?.sendMessage(activeChannel.id, content, responseTo);
|
||||
}
|
||||
|
|
|
@ -68,7 +68,11 @@ export class GroupChats {
|
|||
*
|
||||
* @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 chat = this.chats[chatId];
|
||||
if (chat) {
|
||||
|
@ -78,7 +82,8 @@ export class GroupChats {
|
|||
now,
|
||||
now,
|
||||
chatId,
|
||||
content
|
||||
content,
|
||||
responseTo
|
||||
);
|
||||
const wakuMessage = await WakuMessage.fromBytes(
|
||||
chatMessage.encode(),
|
||||
|
|
Loading…
Reference in New Issue