Add name and member handling in group chats (#144)
This commit is contained in:
parent
daabab46ed
commit
ff733a15fc
|
@ -76,7 +76,7 @@ function DragDiv() {
|
||||||
<ReactChat
|
<ReactChat
|
||||||
theme={theme ? lightTheme : darkTheme}
|
theme={theme ? lightTheme : darkTheme}
|
||||||
communityKey={
|
communityKey={
|
||||||
"0x0235564b1b402e8f6ad540f4da0f6384fb828b8f7bb5a34942aa03719041b8b793"
|
"0x02516353a03fc3892d268a72f4c4b2b0fad179702a996a87346407139949767ba7"
|
||||||
}
|
}
|
||||||
fetchMetadata={fetchMetadata}
|
fetchMetadata={fetchMetadata}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -56,7 +56,10 @@ export function ChatBody({ onClick, showMembers }: ChatBodyProps) {
|
||||||
return (
|
return (
|
||||||
<ChatBodyWrapper className={className}>
|
<ChatBodyWrapper className={className}>
|
||||||
{editGroup && communityData ? (
|
{editGroup && communityData ? (
|
||||||
<ChatCreation editGroup={editGroup} />
|
<ChatCreation
|
||||||
|
setEditGroup={setEditGroup}
|
||||||
|
activeChannel={activeChannel}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ChatTopbar
|
<ChatTopbar
|
||||||
className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""}
|
className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""}
|
||||||
|
|
|
@ -5,20 +5,28 @@ import styled from "styled-components";
|
||||||
import { ChatState, useChatState } from "../../contexts/chatStateProvider";
|
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 { ChannelData } from "../../models/ChannelData";
|
||||||
import { buttonStyles } from "../Buttons/buttonStyle";
|
import { buttonStyles } from "../Buttons/buttonStyle";
|
||||||
import { CrossIcon } from "../Icons/CrossIcon";
|
import { CrossIcon } from "../Icons/CrossIcon";
|
||||||
import { Member } from "../Members/Member";
|
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 {
|
||||||
editGroup?: boolean;
|
setEditGroup?: (val: boolean) => void;
|
||||||
|
activeChannel?: ChannelData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChatCreation({ editGroup }: ChatCreationProps) {
|
export function ChatCreation({
|
||||||
|
setEditGroup,
|
||||||
|
activeChannel,
|
||||||
|
}: 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, createGroupChat } = useMessengerContext();
|
activeChannel?.members?.map((member) => member?.customName ?? member.id) ??
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const { contacts, createGroupChat, addMembers } = useMessengerContext();
|
||||||
const setChatState = useChatState()[1];
|
const setChatState = useChatState()[1];
|
||||||
|
|
||||||
const addMember = useCallback(
|
const addMember = useCallback(
|
||||||
|
@ -33,7 +41,6 @@ export function ChatCreation({ editGroup }: ChatCreationProps) {
|
||||||
},
|
},
|
||||||
[setStyledGroup, styledGroup]
|
[setStyledGroup, styledGroup]
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeMember = (member: string) => {
|
const removeMember = (member: string) => {
|
||||||
setStyledGroup((prev) => prev.filter((e) => e != member));
|
setStyledGroup((prev) => prev.filter((e) => e != member));
|
||||||
};
|
};
|
||||||
|
@ -85,12 +92,19 @@ export function ChatCreation({ editGroup }: ChatCreationProps) {
|
||||||
</InputBar>
|
</InputBar>
|
||||||
<CreationBtn
|
<CreationBtn
|
||||||
disabled={styledGroup.length === 0}
|
disabled={styledGroup.length === 0}
|
||||||
onClick={() => createChat(styledGroup)}
|
onClick={() => {
|
||||||
|
if (!activeChannel) {
|
||||||
|
createChat(styledGroup);
|
||||||
|
} else {
|
||||||
|
addMembers(styledGroup, activeChannel.id);
|
||||||
|
}
|
||||||
|
setEditGroup?.(false);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Confirm
|
Confirm
|
||||||
</CreationBtn>
|
</CreationBtn>
|
||||||
</CreationBar>
|
</CreationBar>
|
||||||
{!editGroup && !query && (
|
{!setEditGroup && !query && (
|
||||||
<Contacts>
|
<Contacts>
|
||||||
<ContactsHeading>Contacts</ContactsHeading>
|
<ContactsHeading>Contacts</ContactsHeading>
|
||||||
<ContactsList>
|
<ContactsList>
|
||||||
|
|
|
@ -27,6 +27,7 @@ const MessengerContext = createContext<MessengerType>({
|
||||||
setActiveChannel: () => undefined,
|
setActiveChannel: () => undefined,
|
||||||
createGroupChat: () => undefined,
|
createGroupChat: () => undefined,
|
||||||
changeGroupChatName: () => undefined,
|
changeGroupChatName: () => undefined,
|
||||||
|
addMembers: () => undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useMessengerContext() {
|
export function useMessengerContext() {
|
||||||
|
|
|
@ -96,5 +96,20 @@ export function useGroupChats(
|
||||||
[channels, groupChat]
|
[channels, groupChat]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { createGroupChat, removeChannel, groupChat, changeGroupChatName };
|
const addMembers = useCallback(
|
||||||
|
(members: string[], chatId: string) => {
|
||||||
|
if (groupChat) {
|
||||||
|
groupChat.addMembers(chatId, members);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[groupChat]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
createGroupChat,
|
||||||
|
removeChannel,
|
||||||
|
groupChat,
|
||||||
|
changeGroupChatName,
|
||||||
|
addMembers,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ export type MessengerType = {
|
||||||
setActiveChannel: (channel: ChannelData) => void;
|
setActiveChannel: (channel: ChannelData) => void;
|
||||||
createGroupChat: (members: string[]) => void;
|
createGroupChat: (members: string[]) => void;
|
||||||
changeGroupChatName: (name: string, chatId: string) => void;
|
changeGroupChatName: (name: string, chatId: string) => void;
|
||||||
|
addMembers: (members: string[], chatId: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function useCreateMessenger(identity: Identity | undefined) {
|
function useCreateMessenger(identity: Identity | undefined) {
|
||||||
|
@ -168,8 +169,13 @@ export function useMessenger(
|
||||||
});
|
});
|
||||||
}, [contacts]);
|
}, [contacts]);
|
||||||
|
|
||||||
const { groupChat, removeChannel, createGroupChat, changeGroupChatName } =
|
const {
|
||||||
useGroupChats(
|
groupChat,
|
||||||
|
removeChannel,
|
||||||
|
createGroupChat,
|
||||||
|
changeGroupChatName,
|
||||||
|
addMembers,
|
||||||
|
} = useGroupChats(
|
||||||
messenger,
|
messenger,
|
||||||
identity,
|
identity,
|
||||||
setChannels,
|
setChannels,
|
||||||
|
@ -235,5 +241,6 @@ export function useMessenger(
|
||||||
clearMentions,
|
clearMentions,
|
||||||
createGroupChat,
|
createGroupChat,
|
||||||
changeGroupChatName,
|
changeGroupChatName,
|
||||||
|
addMembers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ export type GroupChat = {
|
||||||
members: string[];
|
members: string[];
|
||||||
admins?: string[];
|
admins?: string[];
|
||||||
name?: string;
|
name?: string;
|
||||||
|
removed: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GroupChatsType = {
|
export type GroupChatsType = {
|
||||||
|
@ -95,9 +96,11 @@ export class GroupChats {
|
||||||
);
|
);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
membershipUpdate.events.map(async (event) => {
|
membershipUpdate.events.map(async (event) => {
|
||||||
const bufSigner = event.signer;
|
const signer = event.signer ? bufToHex(event.signer) : "";
|
||||||
const signer = bufSigner ? bufToHex(bufSigner) : "";
|
const thisUser = bufToHex(this.identity.publicKey);
|
||||||
const chatId = membershipUpdate.chatId;
|
const chatId = membershipUpdate.chatId;
|
||||||
|
const chat: GroupChat | undefined = this.chats[chatId];
|
||||||
|
|
||||||
if (signer) {
|
if (signer) {
|
||||||
switch (event.event.type) {
|
switch (event.event.type) {
|
||||||
case MembershipUpdateEvent_EventType.CHAT_CREATED: {
|
case MembershipUpdateEvent_EventType.CHAT_CREATED: {
|
||||||
|
@ -106,27 +109,47 @@ export class GroupChats {
|
||||||
chatId: chatId,
|
chatId: chatId,
|
||||||
members: event.event.members,
|
members: event.event.members,
|
||||||
admins: [signer],
|
admins: [signer],
|
||||||
|
removed: false,
|
||||||
},
|
},
|
||||||
useCallback
|
useCallback
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MembershipUpdateEvent_EventType.MEMBER_REMOVED: {
|
case MembershipUpdateEvent_EventType.MEMBER_REMOVED: {
|
||||||
if (
|
if (chat) {
|
||||||
event.event.members[0] == bufToHex(this.identity.publicKey)
|
chat.members = chat.members.filter(
|
||||||
) {
|
(member) => !event.event.members.includes(member)
|
||||||
|
);
|
||||||
|
if (event.event.members.includes(thisUser)) {
|
||||||
await this.removeChat(
|
await this.removeChat(
|
||||||
{
|
{
|
||||||
chatId: chatId,
|
...chat,
|
||||||
members: event.event.members,
|
removed: true,
|
||||||
},
|
},
|
||||||
useCallback
|
useCallback
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
if (!chat.removed && useCallback) {
|
||||||
|
this.callback(this.chats[chatId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MembershipUpdateEvent_EventType.MEMBERS_ADDED: {
|
||||||
|
if (chat) {
|
||||||
|
chat.members.push(...event.event.members);
|
||||||
|
if (
|
||||||
|
chat.members.includes(thisUser) &&
|
||||||
|
chat.admins?.includes(signer)
|
||||||
|
) {
|
||||||
|
chat.removed = false;
|
||||||
|
await this.addChat(chat, useCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MembershipUpdateEvent_EventType.NAME_CHANGED: {
|
case MembershipUpdateEvent_EventType.NAME_CHANGED: {
|
||||||
const chat = this.chats[chatId];
|
|
||||||
if (chat) {
|
if (chat) {
|
||||||
if (chat.admins?.includes(signer)) {
|
if (chat.admins?.includes(signer)) {
|
||||||
chat.name = event.event.name;
|
chat.name = event.event.name;
|
||||||
|
@ -181,20 +204,26 @@ export class GroupChats {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async addChat(chat: GroupChat, useCallback: boolean): Promise<void> {
|
private async addChat(chat: GroupChat, useCallback: boolean): Promise<void> {
|
||||||
|
if (this.chats[chat.chatId]) {
|
||||||
|
this.chats[chat.chatId] = chat;
|
||||||
|
if (useCallback) {
|
||||||
|
this.callback(chat);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
this.chats[chat.chatId] = chat;
|
this.chats[chat.chatId] = chat;
|
||||||
if (useCallback) {
|
if (useCallback) {
|
||||||
await this.handleChatObserver(chat);
|
await this.handleChatObserver(chat);
|
||||||
this.callback(chat);
|
this.callback(chat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async removeChat(
|
private async removeChat(
|
||||||
chat: GroupChat,
|
chat: GroupChat,
|
||||||
useCallback: boolean
|
useCallback: boolean
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
delete this.chats[chat.chatId];
|
this.chats[chat.chatId] = chat;
|
||||||
if (useCallback) {
|
if (useCallback) {
|
||||||
await this.handleChatObserver(chat, true);
|
|
||||||
this.removeCallback(chat);
|
this.removeCallback(chat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,8 +243,10 @@ export class GroupChats {
|
||||||
);
|
);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Object.values(this.chats).map(async (chat) => {
|
Object.values(this.chats).map(async (chat) => {
|
||||||
|
if (!chat?.removed) {
|
||||||
await this.handleChatObserver(chat);
|
await this.handleChatObserver(chat);
|
||||||
this.callback(chat);
|
this.callback(chat);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.waku.relay.addObserver(
|
this.waku.relay.addObserver(
|
||||||
|
@ -246,6 +277,21 @@ export class GroupChats {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async addMembers(chatId: string, members: string[]): Promise<void> {
|
||||||
|
const payload = MembershipUpdateMessage.create(chatId, this.identity);
|
||||||
|
const chat = this.chats[chatId];
|
||||||
|
if (chat && payload) {
|
||||||
|
const newMembers = members.filter(
|
||||||
|
(member) => !chat.members.includes(member)
|
||||||
|
);
|
||||||
|
payload.addMembersAddedEvent(newMembers);
|
||||||
|
await this.sendUpdateMessage(payload.encode(), [
|
||||||
|
...chat.members,
|
||||||
|
...newMembers,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a create group chat membership update message with given members
|
* Sends a create group chat membership update message with given members
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue