Refactor channels and providers (#134)

This commit is contained in:
Szymon Szlachtowicz 2021-11-19 09:31:49 +01:00 committed by GitHub
parent 7922343fa6
commit 4852d90546
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 178 additions and 216 deletions

View File

@ -1,4 +1,4 @@
import React, { useMemo } from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useNarrow } from "../../contexts/narrowProvider"; import { useNarrow } from "../../contexts/narrowProvider";
@ -7,12 +7,51 @@ import { GroupIcon } from "../Icons/GroupIcon";
import { MutedIcon } from "../Icons/MutedIcon"; import { MutedIcon } from "../Icons/MutedIcon";
import { textMediumStyles } from "../Text"; import { textMediumStyles } from "../Text";
function RenderChannelName({
channel,
className,
}: {
channel: ChannelData;
className?: string;
}) {
switch (channel.type) {
case "group":
return (
<div className={className}>
<GroupIcon />
{channel.name}
</div>
);
case "channel":
return <div className={className}>{`# ${channel.name}`}</div>;
case "dm":
return <div className={className}>{channel.name}</div>;
}
}
function ChannelIcon({
channel,
activeView,
}: {
channel: ChannelData;
activeView?: boolean;
}) {
const narrow = useNarrow();
return (
<ChannelLogo
icon={channel.icon}
className={activeView ? "active" : narrow ? "narrow" : ""}
>
{!channel.icon && channel.name.slice(0, 1).toUpperCase()}
</ChannelLogo>
);
}
interface ChannelProps { interface ChannelProps {
channel: ChannelData; channel: ChannelData;
notification?: number; notified?: boolean;
mention?: number; mention?: number;
isActive: boolean; isActive: boolean;
isMuted: boolean;
activeView?: boolean; activeView?: boolean;
onClick?: () => void; onClick?: () => void;
} }
@ -20,75 +59,48 @@ interface ChannelProps {
export function Channel({ export function Channel({
channel, channel,
isActive, isActive,
isMuted,
activeView, activeView,
onClick, onClick,
notification, notified,
mention, mention,
}: ChannelProps) { }: ChannelProps) {
const narrow = useNarrow(); const narrow = useNarrow();
const className = useMemo(
() => (narrow && !activeView ? "narrow" : activeView ? "active" : ""),
[narrow]
);
return ( return (
<ChannelWrapper <ChannelWrapper
className={ className={`${isActive && "active"}`}
(isActive && !activeView) || (isActive && narrow) ? "active" : "" isNarrow={narrow && activeView}
}
style={{ width: narrow && activeView ? "calc(100% - 162px)" : "100%" }}
onClick={onClick} onClick={onClick}
> >
<ChannelInfo> <ChannelInfo>
<ChannelLogo <ChannelIcon channel={channel} activeView={activeView} />
style={{
backgroundImage: channel.icon ? `url(${channel.icon}` : "",
}}
className={className}
>
{!channel.icon && channel.name.slice(0, 1).toUpperCase()}
</ChannelLogo>
<ChannelTextInfo> <ChannelTextInfo>
<ChannelName <ChannelName
className={ channel={channel}
isActive || narrow active={isActive || narrow}
? "active" muted={channel?.isMuted}
: notification && notification > 0 notified={notified}
? "notified" />
: isMuted
? "muted"
: ""
}
>
{channel.type && channel.type === "group" ? (
<GroupIcon />
) : channel.type === "dm" ? (
""
) : (
"#"
)}{" "}
{channel.name}
</ChannelName>
{activeView && ( {activeView && (
<ChannelDescription> {channel.description}</ChannelDescription> <ChannelDescription>{channel.description}</ChannelDescription>
)} )}
</ChannelTextInfo> </ChannelTextInfo>
</ChannelInfo> </ChannelInfo>
{notification && notification > 0 && !activeView && mention && ( {!activeView && !!mention && mention > 0 && !channel?.isMuted && (
<NotificationBagde>{mention}</NotificationBagde> <NotificationBagde>{mention}</NotificationBagde>
)} )}
{isMuted && !notification && <MutedIcon />} {channel?.isMuted && <MutedIcon />}
</ChannelWrapper> </ChannelWrapper>
); );
} }
const ChannelWrapper = styled.div` const ChannelWrapper = styled.div<{ isNarrow?: boolean }>`
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 8px; padding: 8px;
cursor: pointer; cursor: pointer;
width: ${({ isNarrow }) => (isNarrow ? "calc(100% - 162px)" : "100%")};
&.active { &.active {
background-color: ${({ theme }) => theme.activeChannelBackground}; background-color: ${({ theme }) => theme.activeChannelBackground};
border-radius: 8px; border-radius: 8px;
@ -109,7 +121,7 @@ const ChannelTextInfo = styled.div`
white-space: nowrap; white-space: nowrap;
`; `;
export const ChannelLogo = styled.div` export const ChannelLogo = styled.div<{ icon?: string }>`
width: 24px; width: 24px;
height: 24px; height: 24px;
display: flex; display: flex;
@ -124,45 +136,37 @@ export const ChannelLogo = styled.div`
background-color: ${({ theme }) => theme.iconColor}; background-color: ${({ theme }) => theme.iconColor};
background-size: cover; background-size: cover;
background-repeat: no-repeat; background-repeat: no-repeat;
backgroundimage: ${({ icon }) => icon && `url(${icon}`};
color: ${({ theme }) => theme.iconTextColor}; color: ${({ theme }) => theme.iconTextColor};
&.active { &.active {
width: 36px; width: 36px;
height: 36px; height: 36px;
font-size: 20px; font-size: 20px;
line-height: 20px;
} }
&.narrow { &.narrow {
width: 40px; width: 40px;
height: 40px; height: 40px;
font-size: 20px; font-size: 20px;
line-height: 20px;
} }
`; `;
export const ChannelName = styled.div` export const ChannelName = styled(RenderChannelName)<{
font-weight: 500; muted?: boolean;
opacity: 0.7; notified?: boolean;
active?: boolean;
}>`
font-weight: ${({ notified, muted, active }) =>
notified && !muted && !active ? "600" : "500"};
opacity: ${({ notified, muted, active }) =>
muted ? "0.4" : notified || active ? "1.0" : "0.7"};
color: ${({ theme }) => theme.primary}; color: ${({ theme }) => theme.primary};
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
${textMediumStyles} ${textMediumStyles}
&.active,
&.notified {
opacity: 1;
}
&.muted {
opacity: 0.4;
}
&.notified {
font-weight: 600;
}
`; `;
const ChannelDescription = styled.p` const ChannelDescription = styled.p`

View File

@ -1,13 +1,13 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { ChatState, useChatState } from "../../contexts/chatStateProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { CreateIcon } from "../Icons/CreateIcon"; import { CreateIcon } from "../Icons/CreateIcon";
import { Channel } from "./Channel"; import { Channel } from "./Channel";
interface ChannelsProps { interface ChannelsProps {
setCreateChat: (val: boolean) => void;
onCommunityClick?: () => void; onCommunityClick?: () => void;
} }
@ -15,13 +15,10 @@ type GenerateChannelsProps = ChannelsProps & {
type: string; type: string;
}; };
function GenerateChannels({ function GenerateChannels({ type, onCommunityClick }: GenerateChannelsProps) {
type,
onCommunityClick,
setCreateChat,
}: GenerateChannelsProps) {
const { mentions, notifications, activeChannel, setActiveChannel, channels } = const { mentions, notifications, activeChannel, setActiveChannel, channels } =
useMessengerContext(); useMessengerContext();
const setChatState = useChatState()[1];
return ( return (
<> <>
{Object.values(channels) {Object.values(channels)
@ -31,23 +28,14 @@ function GenerateChannels({
key={channel.id} key={channel.id}
channel={channel} channel={channel}
isActive={channel.id === activeChannel.id} isActive={channel.id === activeChannel.id}
isMuted={channel.isMuted || false} notified={notifications?.[channel.id] > 0}
notification={ mention={mentions?.[channel.id]}
notifications[channel.id] > 0 && !channel.isMuted
? notifications[channel.id]
: undefined
}
mention={
mentions[channel.id] > 0 && !channel.isMuted
? mentions[channel.id]
: undefined
}
onClick={() => { onClick={() => {
setActiveChannel(channel); setActiveChannel(channel);
if (onCommunityClick) { if (onCommunityClick) {
onCommunityClick(); onCommunityClick();
} }
setCreateChat(false); setChatState(ChatState.ChatBody);
}} }}
/> />
))} ))}
@ -55,7 +43,7 @@ function GenerateChannels({
); );
} }
export function Channels({ setCreateChat, onCommunityClick }: ChannelsProps) { export function Channels({ onCommunityClick }: ChannelsProps) {
const { clearNotifications, clearMentions, notifications, activeChannel } = const { clearNotifications, clearMentions, notifications, activeChannel } =
useMessengerContext(); useMessengerContext();
useEffect(() => { useEffect(() => {
@ -66,19 +54,15 @@ export function Channels({ setCreateChat, onCommunityClick }: ChannelsProps) {
} }
} }
}, [notifications, activeChannel]); }, [notifications, activeChannel]);
const setChatState = useChatState()[1];
return ( return (
<ChannelList> <ChannelList>
<GenerateChannels <GenerateChannels type={"channel"} onCommunityClick={onCommunityClick} />
type={"channel"}
onCommunityClick={onCommunityClick}
setCreateChat={setCreateChat}
/>
<Chats> <Chats>
<ChatsBar> <ChatsBar>
<Heading>Chat</Heading> <Heading>Chat</Heading>
<EditBtn onClick={() => setCreateChat(true)}> <EditBtn onClick={() => setChatState(ChatState.ChatCreation)}>
<CreateIcon /> <CreateIcon />
</EditBtn> </EditBtn>
</ChatsBar> </ChatsBar>
@ -86,13 +70,8 @@ export function Channels({ setCreateChat, onCommunityClick }: ChannelsProps) {
<GenerateChannels <GenerateChannels
type={"group"} type={"group"}
onCommunityClick={onCommunityClick} onCommunityClick={onCommunityClick}
setCreateChat={setCreateChat}
/>
<GenerateChannels
type={"dm"}
onCommunityClick={onCommunityClick}
setCreateChat={setCreateChat}
/> />
<GenerateChannels type={"dm"} onCommunityClick={onCommunityClick} />
</ChatsList> </ChatsList>
</Chats> </Chats>
</ChannelList> </ChannelList>

View File

@ -16,17 +16,11 @@ export function EmptyChannel({ channel }: EmptyChannelProps) {
return ( return (
<Wrapper> <Wrapper>
<ChannelInfoEmpty> <ChannelInfoEmpty>
<ChannelLogoEmpty <ChannelLogoEmpty icon={channel.icon}>
style={{
backgroundImage: channel.icon ? `url(${channel.icon}` : "",
}}
>
{" "} {" "}
{!channel.icon && channel.name.slice(0, 1).toUpperCase()} {!channel.icon && channel.name.slice(0, 1).toUpperCase()}
</ChannelLogoEmpty> </ChannelLogoEmpty>
<ChannelNameEmpty className={"active"}> <ChannelNameEmpty active={true} channel={channel} />
{channel.name.slice(0, 10)}
</ChannelNameEmpty>
</ChannelInfoEmpty> </ChannelInfoEmpty>
{channel.type === "dm" ? ( {channel.type === "dm" ? (

View File

@ -1,6 +1,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { ChatState, useChatState } from "../contexts/chatStateProvider";
import { useNarrow } from "../contexts/narrowProvider"; import { useNarrow } from "../contexts/narrowProvider";
import { Channels } from "./Channels/Channels"; import { Channels } from "./Channels/Channels";
@ -23,9 +24,8 @@ function Modals() {
} }
export function Chat() { export function Chat() {
const [showMembers, setShowMembers] = useState(true); const [state] = useChatState();
const [createChat, setCreateChat] = useState(false); const [showMembers, setShowMembers] = useState(false);
const narrow = useNarrow(); const narrow = useNarrow();
return ( return (
@ -33,18 +33,17 @@ export function Chat() {
{!narrow && ( {!narrow && (
<ChannelsWrapper> <ChannelsWrapper>
<StyledCommunity /> <StyledCommunity />
<Channels setCreateChat={setCreateChat} /> <Channels />
</ChannelsWrapper> </ChannelsWrapper>
)} )}
{!createChat && ( {state === ChatState.ChatBody && (
<ChatBody <ChatBody
onClick={() => setShowMembers(!showMembers)} onClick={() => setShowMembers(!showMembers)}
showMembers={showMembers} showMembers={showMembers}
setCreateChat={setCreateChat}
/> />
)} )}
{showMembers && !narrow && !createChat && <Members />} {showMembers && !narrow && state === ChatState.ChatBody && <Members />}
{createChat && <ChatCreation setCreateChat={setCreateChat} />} {state === ChatState.ChatCreation && <ChatCreation />}
<Modals /> <Modals />
</ChatWrapper> </ChatWrapper>
); );

View File

@ -27,14 +27,9 @@ enum ChatBodyState {
interface ChatBodyProps { interface ChatBodyProps {
onClick: () => void; onClick: () => void;
showMembers: boolean; showMembers: boolean;
setCreateChat: (val: boolean) => void;
} }
export function ChatBody({ export function ChatBody({ onClick, showMembers }: ChatBodyProps) {
onClick,
showMembers,
setCreateChat,
}: ChatBodyProps) {
const { messenger, activeChannel, communityData } = useMessengerContext(); const { messenger, activeChannel, communityData } = useMessengerContext();
const narrow = useNarrow(); const narrow = useNarrow();
const [showChannelMenu, setShowChannelMenu] = useState(false); const [showChannelMenu, setShowChannelMenu] = useState(false);
@ -61,7 +56,7 @@ export function ChatBody({
return ( return (
<ChatBodyWrapper className={className}> <ChatBodyWrapper className={className}>
{editGroup && communityData ? ( {editGroup && communityData ? (
<ChatCreation setCreateChat={setCreateChat} editGroup={editGroup} /> <ChatCreation editGroup={editGroup} />
) : ( ) : (
<ChatTopbar <ChatTopbar
className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""} className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""}
@ -78,10 +73,9 @@ export function ChatBody({
<Channel <Channel
channel={activeChannel} channel={activeChannel}
isActive={ isActive={
narrow ? showState === ChatBodyState.Channels : true narrow ? showState === ChatBodyState.Channels : false
} }
activeView={true} activeView={true}
isMuted={false}
onClick={() => switchShowState(ChatBodyState.Channels)} onClick={() => switchShowState(ChatBodyState.Channels)}
/> />
</> </>
@ -132,7 +126,6 @@ export function ChatBody({
{showState === ChatBodyState.Channels && ( {showState === ChatBodyState.Channels && (
<NarrowChannels <NarrowChannels
setShowChannels={() => switchShowState(ChatBodyState.Channels)} setShowChannels={() => switchShowState(ChatBodyState.Channels)}
setCreateChat={setCreateChat}
/> />
)} )}
{showState === ChatBodyState.Members && ( {showState === ChatBodyState.Members && (

View File

@ -2,6 +2,7 @@ import React, { useCallback, useState } from "react";
import { bufToHex } from "status-communities/dist/cjs/utils"; import { bufToHex } from "status-communities/dist/cjs/utils";
import styled from "styled-components"; import styled from "styled-components";
import { ChatState, useChatState } from "../../contexts/chatStateProvider";
import { useIdentity } from "../../contexts/identityProvider"; import { useIdentity } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { buttonStyles } from "../Buttons/buttonStyle"; import { buttonStyles } from "../Buttons/buttonStyle";
@ -10,16 +11,16 @@ import { Member } from "../Members/Member";
import { SearchBlock } from "../SearchBlock"; import { SearchBlock } from "../SearchBlock";
import { textMediumStyles } from "../Text"; import { textMediumStyles } from "../Text";
interface ChatCreationProps { interface ChatCreationProps {
setCreateChat: (val: boolean) => void;
editGroup?: boolean; editGroup?: boolean;
} }
export function ChatCreation({ setCreateChat, editGroup }: ChatCreationProps) { export function ChatCreation({ editGroup }: ChatCreationProps) {
const identity = useIdentity(); const identity = useIdentity();
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const [styledGroup, setStyledGroup] = useState<string[]>([]); const [styledGroup, setStyledGroup] = useState<string[]>([]);
const { contacts, setChannel } = useMessengerContext(); const { contacts, setChannel } = useMessengerContext();
const setChatState = useChatState()[1];
const addMember = useCallback( const addMember = useCallback(
(member: string) => { (member: string) => {
@ -51,7 +52,7 @@ export function ChatCreation({ setCreateChat, editGroup }: ChatCreationProps) {
type: "dm", type: "dm",
description: "Contact", description: "Contact",
}); });
setCreateChat(false); setChatState(ChatState.ChatBody);
}; };
return ( return (

View File

@ -1,6 +1,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Identity } from "status-communities/dist/cjs"; import { Identity } from "status-communities/dist/cjs";
import { ChatStateProvider } from "../contexts/chatStateProvider";
import { IdentityProvider } from "../contexts/identityProvider"; import { IdentityProvider } from "../contexts/identityProvider";
import { MessengerProvider } from "../contexts/messengerProvider"; import { MessengerProvider } from "../contexts/messengerProvider";
@ -18,7 +19,9 @@ export function ChatLoader({ communityKey }: ChatLoaderProps) {
return ( return (
<IdentityProvider identity={identity}> <IdentityProvider identity={identity}>
<MessengerProvider identity={identity} communityKey={communityKey}> <MessengerProvider identity={identity} communityKey={communityKey}>
<Chat /> <ChatStateProvider>
<Chat />
</ChatStateProvider>
</MessengerProvider> </MessengerProvider>
</IdentityProvider> </IdentityProvider>
); );

View File

@ -2,7 +2,6 @@ import React, { useMemo } from "react";
import { bufToHex } from "status-communities/dist/cjs/utils"; import { bufToHex } from "status-communities/dist/cjs/utils";
import styled from "styled-components"; import styled from "styled-components";
import { useFriends } from "../../contexts/friendsProvider";
import { useIdentity } from "../../contexts/identityProvider"; import { useIdentity } from "../../contexts/identityProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
import { useManageContact } from "../../hooks/useManageContact"; import { useManageContact } from "../../hooks/useManageContact";
@ -33,10 +32,8 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
); );
const { setModal } = useModal(ProfileModalName); const { setModal } = useModal(ProfileModalName);
const { friends, setFriends } = useFriends(); const { contact, setBlocked, setIsUntrustworthy, setIsUserFriend } =
useManageContact(id);
const userIsFriend = useMemo(() => friends.includes(id), [friends, id]);
const { contact, setBlocked, setIsUntrustworthy } = useManageContact(id);
if (!contact) return null; if (!contact) return null;
return ( return (
@ -63,13 +60,13 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
<ProfileSvg width={16} height={16} /> <ProfileSvg width={16} height={16} />
<MenuText>View Profile</MenuText> <MenuText>View Profile</MenuText>
</MenuItem> </MenuItem>
{!userIsFriend && ( {!contact.isFriend && (
<MenuItem onClick={() => setFriends((prev) => [...prev, id])}> <MenuItem onClick={() => setIsUserFriend(true)}>
<AddContactSvg width={16} height={16} /> <AddContactSvg width={16} height={16} />
<MenuText>Send Contact Request</MenuText> <MenuText>Send Contact Request</MenuText>
</MenuItem> </MenuItem>
)} )}
{userIsFriend && ( {contact.isFriend && (
<MenuItem> <MenuItem>
<ChatSvg width={16} height={16} /> <ChatSvg width={16} height={16} />
<MenuText>Send Message</MenuText> <MenuText>Send Message</MenuText>
@ -98,7 +95,7 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
</MenuText> </MenuText>
</MenuItem> </MenuItem>
{!userIsFriend && !isUser && ( {!contact.isFriend && !isUser && (
<MenuItem <MenuItem
onClick={() => { onClick={() => {
setBlocked(!contact.blocked); setBlocked(!contact.blocked);

View File

@ -55,15 +55,7 @@ export const EditModal = () => {
</NameSection> </NameSection>
<LogoSection> <LogoSection>
<Label>Group image</Label> <Label>Group image</Label>
<GroupLogo <GroupLogo icon={image || activeChannel.icon}>
style={{
backgroundImage: image
? `url(${image}`
: activeChannel.icon
? `url(${activeChannel.icon}`
: "",
}}
>
{!activeChannel.icon && {!activeChannel.icon &&
!image && !image &&
activeChannel.name.slice(0, 1).toUpperCase()} activeChannel.name.slice(0, 1).toUpperCase()}

View File

@ -2,7 +2,6 @@ import React, { useEffect, useMemo, useState } from "react";
import { bufToHex } from "status-communities/dist/cjs/utils"; import { bufToHex } from "status-communities/dist/cjs/utils";
import styled from "styled-components"; import styled from "styled-components";
import { useFriends } from "../../contexts/friendsProvider";
import { useIdentity } from "../../contexts/identityProvider"; import { useIdentity } from "../../contexts/identityProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
import { useManageContact } from "../../hooks/useManageContact"; import { useManageContact } from "../../hooks/useManageContact";
@ -40,17 +39,18 @@ export const ProfileModal = () => {
[id, identity] [id, identity]
); );
const { friends, setFriends } = useFriends();
const userIsFriend = useMemo(() => friends.includes(id), [friends, id]);
const [renaming, setRenaming] = useState(renamingState ?? false); const [renaming, setRenaming] = useState(renamingState ?? false);
useEffect(() => { useEffect(() => {
setRenaming(renamingState ?? false); setRenaming(renamingState ?? false);
}, [renamingState]); }, [renamingState]);
const { contact, setBlocked, setCustomName, setIsUntrustworthy } = const {
useManageContact(id); contact,
setBlocked,
setCustomName,
setIsUntrustworthy,
setIsUserFriend,
} = useManageContact(id);
const [customNameInput, setCustomNameInput] = useState(""); const [customNameInput, setCustomNameInput] = useState("");
if (!contact) return null; if (!contact) return null;
@ -134,7 +134,7 @@ export const ProfileModal = () => {
</> </>
) : ( ) : (
<> <>
{!userIsFriend && !isUser && ( {!contact.isFriend && !isUser && (
<ProfileBtn <ProfileBtn
className={contact.blocked ? "" : "red"} className={contact.blocked ? "" : "red"}
onClick={() => { onClick={() => {
@ -144,12 +144,10 @@ export const ProfileModal = () => {
{contact.blocked ? "Unblock" : "Block"} {contact.blocked ? "Unblock" : "Block"}
</ProfileBtn> </ProfileBtn>
)} )}
{userIsFriend && ( {contact.isFriend && (
<ProfileBtn <ProfileBtn
className="red" className="red"
onClick={() => onClick={() => setIsUserFriend(false)}
setFriends((prev) => prev.filter((e) => e != id))
}
> >
Remove Contact Remove Contact
</ProfileBtn> </ProfileBtn>
@ -162,8 +160,8 @@ export const ProfileModal = () => {
? "Remove Untrustworthy Mark" ? "Remove Untrustworthy Mark"
: "Mark as Untrustworthy"} : "Mark as Untrustworthy"}
</ProfileBtn> </ProfileBtn>
{!userIsFriend && ( {!contact.isFriend && (
<Btn onClick={() => setFriends((prev) => [...prev, id])}> <Btn onClick={() => setIsUserFriend(true)}>
Send Contact Request Send Contact Request
</Btn> </Btn>
)} )}

View File

@ -7,20 +7,13 @@ import { NarrowTopbar } from "./NarrowTopbar";
interface NarrowChannelsProps { interface NarrowChannelsProps {
setShowChannels: (val: boolean) => void; setShowChannels: (val: boolean) => void;
setCreateChat: (val: boolean) => void;
} }
export function NarrowChannels({ export function NarrowChannels({ setShowChannels }: NarrowChannelsProps) {
setShowChannels,
setCreateChat,
}: NarrowChannelsProps) {
return ( return (
<ListWrapper> <ListWrapper>
<NarrowTopbar list="Channels" /> <NarrowTopbar list="Channels" />
<Channels <Channels onCommunityClick={() => setShowChannels(false)} />
onCommunityClick={() => setShowChannels(false)}
setCreateChat={setCreateChat}
/>
</ListWrapper> </ListWrapper>
); );
} }

View File

@ -3,7 +3,6 @@ import { ThemeProvider } from "styled-components";
import styled from "styled-components"; import styled from "styled-components";
import { FetchMetadataProvider } from "../contexts/fetchMetadataProvider"; import { FetchMetadataProvider } from "../contexts/fetchMetadataProvider";
import { FriendsProvider } from "../contexts/friendsProvider";
import { ModalProvider } from "../contexts/modalProvider"; import { ModalProvider } from "../contexts/modalProvider";
import { NarrowProvider } from "../contexts/narrowProvider"; import { NarrowProvider } from "../contexts/narrowProvider";
import { Metadata } from "../models/Metadata"; import { Metadata } from "../models/Metadata";
@ -28,15 +27,13 @@ export function ReactChat({
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<NarrowProvider myRef={ref}> <NarrowProvider myRef={ref}>
<FetchMetadataProvider fetchMetadata={fetchMetadata}> <FetchMetadataProvider fetchMetadata={fetchMetadata}>
<FriendsProvider> <ModalProvider>
<ModalProvider> <Wrapper ref={ref}>
<Wrapper ref={ref}> <GlobalStyle />
<GlobalStyle /> <ChatLoader communityKey={communityKey} />
<ChatLoader communityKey={communityKey} /> <div id="modal-root" />
<div id="modal-root" /> </Wrapper>
</Wrapper> </ModalProvider>
</ModalProvider>
</FriendsProvider>
</FetchMetadataProvider> </FetchMetadataProvider>
</NarrowProvider> </NarrowProvider>
</ThemeProvider> </ThemeProvider>

View File

@ -3,8 +3,8 @@ import styled from "styled-components";
import { useMessengerContext } from "../contexts/messengerProvider"; import { useMessengerContext } from "../contexts/messengerProvider";
import { Channel } from "./Channels/Channel";
import { ContactsList } from "./Chat/ChatCreation"; import { ContactsList } from "./Chat/ChatCreation";
import { Member } from "./Members/Member";
interface SearchBlockProps { interface SearchBlockProps {
query: string; query: string;
@ -39,15 +39,9 @@ export const SearchBlock = ({
.filter((member) => member.id.includes(query)) .filter((member) => member.id.includes(query))
.filter((member) => !dsicludeList.includes(member.id)) .filter((member) => !dsicludeList.includes(member.id))
.map((member) => ( .map((member) => (
<Channel <Member
key={member.id} key={member.id}
channel={{ contact={member}
id: member.id,
name: member.id.slice(0, 10),
type: "dm",
}}
isActive={false}
isMuted={false}
onClick={() => onClick(member.id)} onClick={() => onClick(member.id)}
/> />
))} ))}

View File

@ -0,0 +1,25 @@
import React, { createContext, useContext, useState } from "react";
export enum ChatState {
ChatCreation,
ChatBody,
}
type ChatStateContextType = [
ChatState,
React.Dispatch<React.SetStateAction<ChatState>>
];
const ChatStateContext = createContext<ChatStateContextType>([
ChatState.ChatBody,
() => undefined,
]);
export function useChatState() {
return useContext(ChatStateContext);
}
export function ChatStateProvider({ children }: { children: React.ReactNode }) {
const state = useState(ChatState.ChatBody);
return <ChatStateContext.Provider value={state} children={children} />;
}

View File

@ -1,27 +0,0 @@
import React, { createContext, useContext, useState } from "react";
const FriendsContext = createContext<{
friends: string[];
setFriends: React.Dispatch<React.SetStateAction<string[]>>;
}>({
friends: [],
setFriends: () => undefined,
});
export function useFriends() {
return useContext(FriendsContext);
}
interface FriendsProviderProps {
children: React.ReactNode;
}
export function FriendsProvider({ children }: FriendsProviderProps) {
const [friends, setFriends] = useState<string[]>([]);
return (
<FriendsContext.Provider
value={{ friends, setFriends }}
children={children}
/>
);
}

View File

@ -19,6 +19,7 @@ const MessengerContext = createContext<MessengerType>({
activeChannel: { activeChannel: {
id: "", id: "",
name: "", name: "",
type: "channel",
}, },
channels: {}, channels: {},
setChannel: () => undefined, setChannel: () => undefined,

View File

@ -49,6 +49,7 @@ export function useMessenger(
id: "", id: "",
name: "", name: "",
description: "", description: "",
type: "channel",
}); });
const chatId = useMemo(() => activeChannel.id, [activeChannel]); const chatId = useMemo(() => activeChannel.id, [activeChannel]);

View File

@ -38,5 +38,23 @@ export function useManageContact(id: string) {
}, },
[id] [id]
); );
return { contact, setCustomName, setBlocked, setIsUntrustworthy };
const setIsUserFriend = useCallback(
(isFriend: boolean) => {
setContacts((prev) => {
const prevUser = prev[id];
if (!prevUser) return prev;
return { ...prev, [id]: { ...prevUser, isFriend } };
});
},
[id]
);
return {
contact,
setCustomName,
setBlocked,
setIsUntrustworthy,
setIsUserFriend,
};
} }

View File

@ -3,7 +3,7 @@ import { Contact } from "./Contact";
export type ChannelData = { export type ChannelData = {
id: string; id: string;
name: string; name: string;
type?: "channel" | "dm" | "group"; type: "channel" | "dm" | "group";
description?: string; description?: string;
icon?: string; icon?: string;
isMuted?: boolean; isMuted?: boolean;

View File

@ -5,6 +5,7 @@ export type Contact = {
customName?: string; customName?: string;
isUntrustworthy: boolean; isUntrustworthy: boolean;
blocked: boolean; blocked: boolean;
isFriend?: boolean;
}; };
export type Contacts = { export type Contacts = {

View File

@ -14,7 +14,6 @@ export const GlobalStyle = createGlobalStyle`
html { html {
margin: 0; margin: 0;
font-family: 'Inter', sans-serif; font-family: 'Inter', sans-serif;
font-weight: normal;
font-size: 15px; font-size: 15px;
line-height: 22px; line-height: 22px;
} }