Refactor dm and private chat creation (#133)

This commit is contained in:
Szymon Szlachtowicz 2021-11-18 19:23:33 +01:00 committed by GitHub
parent 81a14fcb9a
commit 7922343fa6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 165 additions and 233 deletions

View File

@ -1,4 +1,4 @@
import React, { useEffect, useMemo } from "react";
import React, { useEffect } from "react";
import styled from "styled-components";
import { useMessengerContext } from "../../contexts/messengerProvider";
@ -7,45 +7,30 @@ import { CreateIcon } from "../Icons/CreateIcon";
import { Channel } from "./Channel";
interface ChannelsProps {
membersList: string[];
groupList: string[][];
setCreateChat: (val: boolean) => void;
onCommunityClick?: () => void;
}
export function Channels({
membersList,
groupList,
setCreateChat,
onCommunityClick,
}: ChannelsProps) {
const {
clearNotifications,
clearMentions,
mentions,
notifications,
activeChannel,
setActiveChannel,
channels,
} = useMessengerContext();
const activeChannelId = useMemo(() => activeChannel.id, [activeChannel]);
useEffect(() => {
const channel = channels.find((channel) => channel.id === activeChannelId);
if (channel) {
if (notifications[channel.id] > 0) {
clearNotifications(channel.id);
clearMentions(channel.id);
}
}
}, [notifications, activeChannelId]);
type GenerateChannelsProps = ChannelsProps & {
type: string;
};
function GenerateChannels({
type,
onCommunityClick,
setCreateChat,
}: GenerateChannelsProps) {
const { mentions, notifications, activeChannel, setActiveChannel, channels } =
useMessengerContext();
return (
<ChannelList>
{channels.map((channel) => (
<>
{Object.values(channels)
.filter((channel) => channel.type === type)
.map((channel) => (
<Channel
key={channel.id}
channel={channel}
isActive={channel.id === activeChannelId}
isActive={channel.id === activeChannel.id}
isMuted={channel.isMuted || false}
notification={
notifications[channel.id] > 0 && !channel.isMuted
@ -66,6 +51,29 @@ export function Channels({
}}
/>
))}
</>
);
}
export function Channels({ setCreateChat, onCommunityClick }: ChannelsProps) {
const { clearNotifications, clearMentions, notifications, activeChannel } =
useMessengerContext();
useEffect(() => {
if (activeChannel) {
if (notifications[activeChannel.id] > 0) {
clearNotifications(activeChannel.id);
clearMentions(activeChannel.id);
}
}
}, [notifications, activeChannel]);
return (
<ChannelList>
<GenerateChannels
type={"channel"}
onCommunityClick={onCommunityClick}
setCreateChat={setCreateChat}
/>
<Chats>
<ChatsBar>
@ -75,56 +83,16 @@ export function Channels({
</EditBtn>
</ChatsBar>
<ChatsList>
{groupList.length > 0 &&
groupList.map((group) => (
<Channel
key={group.join("")}
channel={{
id: group.join(""),
name: group.join(", "),
type: "group",
}}
isActive={group.join("") === activeChannelId}
isMuted={false}
onClick={() => {
setActiveChannel({
id: group.join(""),
name: group.join(", "),
type: "group",
});
setCreateChat(false);
if (onCommunityClick) {
onCommunityClick();
}
}}
<GenerateChannels
type={"group"}
onCommunityClick={onCommunityClick}
setCreateChat={setCreateChat}
/>
))}
{membersList.length > 0 &&
membersList.map((member) => (
<Channel
key={member}
channel={{
id: member,
name: member,
type: "dm",
description: "Contact",
}}
isActive={member === activeChannelId}
isMuted={false}
onClick={() => {
setActiveChannel({
id: member,
name: member.slice(0, 10),
type: "dm",
description: "Contact",
});
if (onCommunityClick) {
onCommunityClick();
}
setCreateChat(false);
}}
<GenerateChannels
type={"dm"}
onCommunityClick={onCommunityClick}
setCreateChat={setCreateChat}
/>
))}
</ChatsList>
</Chats>
</ChannelList>

View File

@ -12,10 +12,18 @@ import { CommunityModal } from "./Modals/CommunityModal";
import { EditModal } from "./Modals/EditModal";
import { ProfileModal } from "./Modals/ProfileModal";
function Modals() {
return (
<>
<CommunityModal subtitle="Public Community" />
<EditModal />
<ProfileModal />
</>
);
}
export function Chat() {
const [showMembers, setShowMembers] = useState(true);
const [membersList, setMembersList] = useState([]);
const [groupList, setGroupList] = useState([]);
const [createChat, setCreateChat] = useState(false);
const narrow = useNarrow();
@ -25,38 +33,19 @@ export function Chat() {
{!narrow && (
<ChannelsWrapper>
<StyledCommunity />
<Channels
membersList={membersList}
groupList={groupList}
setCreateChat={setCreateChat}
/>
<Channels setCreateChat={setCreateChat} />
</ChannelsWrapper>
)}
{!createChat && (
<ChatBody
onClick={() => setShowMembers(!showMembers)}
showMembers={showMembers}
membersList={membersList}
groupList={groupList}
setMembersList={setMembersList}
setGroupList={setGroupList}
setCreateChat={setCreateChat}
/>
)}
{showMembers && !narrow && !createChat && (
<Members setMembersList={setMembersList} />
)}
{createChat && (
<ChatCreation
setMembersList={setMembersList}
setGroupList={setGroupList}
setCreateChat={setCreateChat}
/>
)}
<CommunityModal subtitle="Public Community" />
<EditModal />
<ProfileModal />
{showMembers && !narrow && !createChat && <Members />}
{createChat && <ChatCreation setCreateChat={setCreateChat} />}
<Modals />
</ChatWrapper>
);
}

View File

@ -27,30 +27,22 @@ enum ChatBodyState {
interface ChatBodyProps {
onClick: () => void;
showMembers: boolean;
membersList: string[];
groupList: [][];
setMembersList: any;
setGroupList: any;
setCreateChat: (val: boolean) => void;
}
export function ChatBody({
onClick,
showMembers,
membersList,
groupList,
setMembersList,
setGroupList,
setCreateChat,
}: ChatBodyProps) {
const { messenger, activeChannel, communityData } = useMessengerContext();
const narrow = useNarrow();
const [showChannelMenu, setShowChannelMenu] = useState(false);
const [showState, setShowState] = useState<ChatBodyState>(ChatBodyState.Chat);
const [editGroup, setEditGroup] = useState(false);
const className = useMemo(() => (narrow ? "narrow" : ""), [narrow]);
const [showState, setShowState] = useState<ChatBodyState>(ChatBodyState.Chat);
const switchShowState = useCallback(
(state: ChatBodyState) => {
if (narrow) {
@ -69,12 +61,7 @@ export function ChatBody({
return (
<ChatBodyWrapper className={className}>
{editGroup && communityData ? (
<ChatCreation
setMembersList={setMembersList}
setGroupList={setGroupList}
setCreateChat={setCreateChat}
editGroup={editGroup}
/>
<ChatCreation setCreateChat={setCreateChat} editGroup={editGroup} />
) : (
<ChatTopbar
className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""}
@ -125,7 +112,6 @@ export function ChatBody({
switchMemberList={() => switchShowState(ChatBodyState.Members)}
setShowChannelMenu={setShowChannelMenu}
setEditGroup={setEditGroup}
setGroupList={setGroupList}
/>
)}
</ChatTopbar>
@ -146,8 +132,6 @@ export function ChatBody({
{showState === ChatBodyState.Channels && (
<NarrowChannels
setShowChannels={() => switchShowState(ChatBodyState.Channels)}
membersList={membersList}
groupList={groupList}
setCreateChat={setCreateChat}
/>
)}
@ -156,7 +140,6 @@ export function ChatBody({
switchShowMembersList={() =>
switchShowState(ChatBodyState.Members)
}
setMembersList={setMembersList}
/>
)}
</>

View File

@ -10,23 +10,16 @@ import { Member } from "../Members/Member";
import { SearchBlock } from "../SearchBlock";
import { textMediumStyles } from "../Text";
interface ChatCreationProps {
setMembersList: any;
setGroupList: any;
setCreateChat: (val: boolean) => void;
editGroup?: boolean;
}
export function ChatCreation({
setMembersList,
setGroupList,
setCreateChat,
editGroup,
}: ChatCreationProps) {
export function ChatCreation({ setCreateChat, editGroup }: ChatCreationProps) {
const identity = useIdentity();
const [query, setQuery] = useState("");
const [styledGroup, setStyledGroup] = useState<string[]>([]);
const { contacts, setActiveChannel } = useMessengerContext();
const { contacts, setChannel } = useMessengerContext();
const addMember = useCallback(
(member: string) => {
@ -47,28 +40,17 @@ export function ChatCreation({
const createChat = (group: string[]) => {
group.length > 1
? (setGroupList((prevGroups: string[][]) => {
prevGroups.push(group);
return prevGroups;
}),
setActiveChannel({
? setChannel({
id: group.join(""),
name: group.join(", "),
type: "group",
}))
: (setMembersList((prevMembers: string[]) => {
if (prevMembers.find((chat) => chat === group[0])) {
return prevMembers;
} else {
return [...prevMembers, group[0]];
}
}),
setActiveChannel({
})
: setChannel({
id: group[0],
name: group[0],
type: "dm",
description: "Contact",
}));
});
setCreateChat(false);
};
@ -112,9 +94,7 @@ export function ChatCreation({
</InputBar>
<CreationBtn
disabled={styledGroup.length === 0}
onClick={() =>
editGroup ? setMembersList(styledGroup) : createChat(styledGroup)
}
onClick={() => createChat(styledGroup)}
>
Confirm
</CreationBtn>

View File

@ -20,7 +20,6 @@ interface ChannelMenuProps {
switchMemberList: () => void;
setShowChannelMenu: (val: boolean) => void;
setEditGroup: (val: boolean) => void;
setGroupList: any;
}
export const ChannelMenu = ({
@ -28,11 +27,9 @@ export const ChannelMenu = ({
switchMemberList,
setShowChannelMenu,
setEditGroup,
setGroupList,
}: ChannelMenuProps) => {
const narrow = useNarrow();
const { clearNotifications, setActiveChannel, channels } =
useMessengerContext();
const { clearNotifications, removeChannel } = useMessengerContext();
const { setModal } = useModal(EditModalName);
return (
<DropdownMenu>
@ -77,16 +74,12 @@ export const ChannelMenu = ({
<CheckSvg width={16} height={16} />
<MenuText>Mark as Read</MenuText>
</MenuItem>
{channel.type === "group" && (
{(channel.type === "group" || channel.type === "dm") && (
<MenuSection>
{" "}
<MenuItem
onClick={() => {
setGroupList((prevGroups: string[][]) => {
const idx = prevGroups.indexOf(channel.name.split(", "));
return idx >= 0 ? prevGroups.splice(idx, 1) : [];
});
setActiveChannel(channels[0]);
removeChannel(channel.id);
setShowChannelMenu(false);
}}
>

View File

@ -1,6 +1,7 @@
import React, { useState } from "react";
import styled from "styled-components";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { Contact } from "../../models/Contact";
import { Icon } from "../Chat/ChatMessages";
import { ContactMenu } from "../Form/ContactMenu";
@ -10,7 +11,6 @@ interface MemberProps {
contact: Contact;
isOnline?: boolean;
switchShowMembers?: () => void;
setMembersList?: any;
onClick?: () => void;
}
@ -18,24 +18,21 @@ export function Member({
contact,
isOnline,
switchShowMembers,
setMembersList,
onClick,
}: MemberProps) {
const startDialog = (member: string) => {
setMembersList((prevMembers: string[]) => {
if (prevMembers.find((chat) => chat === member)) {
return prevMembers;
} else {
return [...prevMembers, member];
}
});
};
const { setChannel } = useMessengerContext();
const [showMenu, setShowMenu] = useState(false);
const onMemberClick = () => {
switchShowMembers?.();
startDialog(contact.id);
setChannel({
id: contact.id,
name: contact.customName ?? contact.trueName,
type: "dm",
description: "DM",
members: [contact],
});
};
return (

View File

@ -3,15 +3,11 @@ import styled from "styled-components";
import { MembersList } from "./MembersList";
interface MembersProps {
setMembersList: any;
}
export function Members({ setMembersList }: MembersProps) {
export function Members() {
return (
<MembersWrapper>
<MemberHeading>Members</MemberHeading>
<MembersList setMembersList={setMembersList} />
<MembersList />
</MembersWrapper>
);
}

View File

@ -11,13 +11,9 @@ import { Member, MemberData, MemberIcon } from "./Member";
interface MembersListProps {
switchShowMembers?: () => void;
setMembersList: any;
}
export function MembersList({
switchShowMembers,
setMembersList,
}: MembersListProps) {
export function MembersList({ switchShowMembers }: MembersListProps) {
const { contacts } = useMessengerContext();
const identity = useIdentity();
@ -43,7 +39,6 @@ export function MembersList({
contact={contact}
isOnline={contact.online}
switchShowMembers={switchShowMembers}
setMembersList={setMembersList}
/>
))}
</MemberCategory>
@ -58,7 +53,6 @@ export function MembersList({
contact={contact}
isOnline={contact.online}
switchShowMembers={switchShowMembers}
setMembersList={setMembersList}
/>
))}
</MemberCategory>

View File

@ -89,7 +89,7 @@ export const ProfileModal = () => {
<NameInputWrapper>
<NameInput
placeholder="Only you will see this nickname"
value={contact.customName}
value={customNameInput}
onChange={(e) => setCustomNameInput(e.currentTarget.value)}
/>
{contact.customName && (

View File

@ -7,15 +7,11 @@ import { NarrowTopbar } from "./NarrowTopbar";
interface NarrowChannelsProps {
setShowChannels: (val: boolean) => void;
membersList: string[];
groupList: string[][];
setCreateChat: (val: boolean) => void;
}
export function NarrowChannels({
setShowChannels,
membersList,
groupList,
setCreateChat,
}: NarrowChannelsProps) {
return (
@ -23,8 +19,6 @@ export function NarrowChannels({
<NarrowTopbar list="Channels" />
<Channels
onCommunityClick={() => setShowChannels(false)}
membersList={membersList}
groupList={groupList}
setCreateChat={setCreateChat}
/>
</ListWrapper>

View File

@ -7,20 +7,13 @@ import { NarrowTopbar } from "./NarrowTopbar";
interface NarrowMembersProps {
switchShowMembersList: () => void;
setMembersList: any;
}
export function NarrowMembers({
switchShowMembersList,
setMembersList,
}: NarrowMembersProps) {
export function NarrowMembers({ switchShowMembersList }: NarrowMembersProps) {
return (
<ListWrapper>
<NarrowTopbar list="Community members" />
<MembersList
switchShowMembers={switchShowMembersList}
setMembersList={setMembersList}
/>
<MembersList switchShowMembers={switchShowMembersList} />
</ListWrapper>
);
}

View File

@ -20,7 +20,9 @@ const MessengerContext = createContext<MessengerType>({
id: "",
name: "",
},
channels: [],
channels: {},
setChannel: () => undefined,
removeChannel: () => undefined,
setActiveChannel: () => undefined,
});

View File

@ -7,7 +7,7 @@ import {
Messenger,
} from "status-communities/dist/cjs";
import { ChannelData } from "../../models/ChannelData";
import { ChannelData, ChannelsData } from "../../models/ChannelData";
import { ChatMessage } from "../../models/ChatMessage";
import { CommunityData } from "../../models/CommunityData";
import { Contacts } from "../../models/Contact";
@ -34,7 +34,9 @@ export type MessengerType = {
communityData: CommunityData | undefined;
contacts: Contacts;
setContacts: React.Dispatch<React.SetStateAction<Contacts>>;
channels: ChannelData[];
channels: ChannelsData;
setChannel: (channel: ChannelData) => void;
removeChannel: (channelId: string) => void;
activeChannel: ChannelData;
setActiveChannel: (channel: ChannelData) => void;
};
@ -148,24 +150,56 @@ export function useMessenger(
[chatId, messenger]
);
const channels = useMemo<ChannelData[]>(() => {
const [channels, setChannels] = useState<ChannelsData>({});
const setChannel = useCallback((channel: ChannelData) => {
setChannels((prev) => {
return { ...prev, [channel.id]: channel };
});
setActiveChannel(channel);
}, []);
const removeChannel = useCallback(
(channelId: string) => {
setChannels((prev) => {
delete prev[channelId];
return prev;
});
const newActiveChannel: ChannelData = Object.values(channels)?.[0] ?? {
id: "",
name: "",
};
setActiveChannel(newActiveChannel);
},
[channels]
);
useEffect(() => {
if (community?.chats) {
return Array.from(community.chats.values()).map((chat) => {
return {
for (const chat of community.chats.values()) {
setChannel({
id: chat.id,
name: chat.communityChat?.identity?.displayName ?? "",
description: chat.communityChat?.identity?.description ?? "",
type: "channel",
};
});
} else {
return [];
}
}
}, [community]);
useEffect(() => {
if (channels.length > 0) setActiveChannel(channels[0]);
}, [channels]);
Object.values(channels)
.filter((channel) => channel.type === "dm")
.forEach((channel) => {
const contact = contacts?.[channel?.members?.[0]?.id ?? ""];
if (contact && channel.name !== (contact?.customName ?? channel.name)) {
setChannel({
...channel,
name: contact?.customName ?? channel.name,
});
}
});
}, [contacts]);
const communityData = useMemo(() => {
if (community?.description) {
@ -200,6 +234,8 @@ export function useMessenger(
contacts,
setContacts,
channels,
setChannel,
removeChannel,
activeChannel,
setActiveChannel,
mentions,

View File

@ -1,3 +1,5 @@
import { Contact } from "./Contact";
export type ChannelData = {
id: string;
name: string;
@ -5,4 +7,9 @@ export type ChannelData = {
description?: string;
icon?: string;
isMuted?: boolean;
members?: Contact[];
};
export type ChannelsData = {
[id: string]: ChannelData;
};