Refactor channels and providers (#134)
This commit is contained in:
parent
7922343fa6
commit
4852d90546
|
@ -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`
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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" ? (
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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 && (
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()}
|
||||||
|
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -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} />;
|
||||||
|
}
|
|
@ -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}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -19,6 +19,7 @@ const MessengerContext = createContext<MessengerType>({
|
||||||
activeChannel: {
|
activeChannel: {
|
||||||
id: "",
|
id: "",
|
||||||
name: "",
|
name: "",
|
||||||
|
type: "channel",
|
||||||
},
|
},
|
||||||
channels: {},
|
channels: {},
|
||||||
setChannel: () => undefined,
|
setChannel: () => undefined,
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue