Refactor hooks and add reducers (#208)
This commit is contained in:
parent
f2aa41309a
commit
21e49cb7bf
|
@ -3,8 +3,8 @@ import React, { useMemo } from "react";
|
|||
import styled from "styled-components";
|
||||
|
||||
import { useIdentity } from "../../contexts/identityProvider";
|
||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||
import { useModal } from "../../contexts/modalProvider";
|
||||
import { useManageContact } from "../../hooks/useManageContact";
|
||||
import { AddContactIcon } from "../Icons/AddContactIcon";
|
||||
import { BlockSvg } from "../Icons/BlockIcon";
|
||||
import { ChatSvg } from "../Icons/ChatIcon";
|
||||
|
@ -26,6 +26,8 @@ type ContactMenuProps = {
|
|||
|
||||
export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
|
||||
const identity = useIdentity();
|
||||
const { contacts, contactsDispatch } = useMessengerContext();
|
||||
const contact = useMemo(() => contacts[id], [id, contacts]);
|
||||
const isUser = useMemo(() => {
|
||||
if (identity) {
|
||||
return id === bufToHex(identity.publicKey);
|
||||
|
@ -35,7 +37,6 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
|
|||
}, [id, identity]);
|
||||
|
||||
const { setModal } = useModal(ProfileModalName);
|
||||
const { contact, setBlocked, setIsUntrustworthy } = useManageContact(id);
|
||||
|
||||
if (!contact) return null;
|
||||
return (
|
||||
|
@ -88,7 +89,11 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
|
|||
</MenuItem>
|
||||
</MenuSection>
|
||||
<MenuSection>
|
||||
<MenuItem onClick={() => setIsUntrustworthy(!contact.isUntrustworthy)}>
|
||||
<MenuItem
|
||||
onClick={() =>
|
||||
contactsDispatch({ type: "toggleTrustworthy", payload: { id } })
|
||||
}
|
||||
>
|
||||
<WarningSvg
|
||||
width={16}
|
||||
height={16}
|
||||
|
@ -104,7 +109,7 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
|
|||
{!contact.isFriend && !isUser && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
setBlocked(!contact.blocked);
|
||||
contactsDispatch({ type: "toggleBlocked", payload: { id } });
|
||||
setShowMenu(false);
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -4,9 +4,9 @@ import styled from "styled-components";
|
|||
|
||||
import { useActivities } from "../../contexts/activityProvider";
|
||||
import { useIdentity } from "../../contexts/identityProvider";
|
||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||
import { useModal } from "../../contexts/modalProvider";
|
||||
import { useToasts } from "../../contexts/toastProvider";
|
||||
import { useManageContact } from "../../hooks/useManageContact";
|
||||
import { copy } from "../../utils";
|
||||
import { buttonStyles } from "../Buttons/buttonStyle";
|
||||
import {
|
||||
|
@ -75,13 +75,8 @@ export const ProfileModal = () => {
|
|||
setRequestCreation(requestState ?? false);
|
||||
}, [requestState]);
|
||||
|
||||
const {
|
||||
contact,
|
||||
setBlocked,
|
||||
setCustomName,
|
||||
setIsUntrustworthy,
|
||||
setIsUserFriend,
|
||||
} = useManageContact(id);
|
||||
const { contacts, contactsDispatch } = useMessengerContext();
|
||||
const contact = useMemo(() => contacts[id], [id, contacts]);
|
||||
const [customNameInput, setCustomNameInput] = useState("");
|
||||
|
||||
if (!contact) return null;
|
||||
|
@ -129,7 +124,10 @@ export const ProfileModal = () => {
|
|||
{customNameInput && (
|
||||
<ClearBtn
|
||||
onClick={() => {
|
||||
setCustomName(undefined);
|
||||
contactsDispatch({
|
||||
type: "setCustomName",
|
||||
payload: { id, customName: undefined },
|
||||
});
|
||||
setCustomNameInput("");
|
||||
}}
|
||||
>
|
||||
|
@ -184,7 +182,10 @@ export const ProfileModal = () => {
|
|||
<Btn
|
||||
disabled={!customNameInput}
|
||||
onClick={() => {
|
||||
setCustomName(customNameInput);
|
||||
contactsDispatch({
|
||||
type: "setCustomName",
|
||||
payload: { id, customName: customNameInput },
|
||||
});
|
||||
setRenaming(false);
|
||||
}}
|
||||
>
|
||||
|
@ -234,7 +235,7 @@ export const ProfileModal = () => {
|
|||
<ProfileBtn
|
||||
className={contact.blocked ? "" : "red"}
|
||||
onClick={() => {
|
||||
setBlocked(!contact.blocked);
|
||||
contactsDispatch({ type: "toggleBlocked", payload: { id } });
|
||||
}}
|
||||
>
|
||||
{contact.blocked ? "Unblock" : "Block"}
|
||||
|
@ -243,14 +244,21 @@ export const ProfileModal = () => {
|
|||
{contact.isFriend && (
|
||||
<ProfileBtn
|
||||
className="red"
|
||||
onClick={() => setIsUserFriend(false)}
|
||||
onClick={() =>
|
||||
contactsDispatch({
|
||||
type: "setIsFriend",
|
||||
payload: { id, isFriend: false },
|
||||
})
|
||||
}
|
||||
>
|
||||
Remove Contact
|
||||
</ProfileBtn>
|
||||
)}
|
||||
<ProfileBtn
|
||||
className={contact.isUntrustworthy ? "" : "red"}
|
||||
onClick={() => setIsUntrustworthy(!contact.isUntrustworthy)}
|
||||
onClick={() =>
|
||||
contactsDispatch({ type: "toggleTrustworthy", payload: { id } })
|
||||
}
|
||||
>
|
||||
{contact.isUntrustworthy
|
||||
? "Remove Untrustworthy Mark"
|
||||
|
|
|
@ -17,7 +17,7 @@ const MessengerContext = createContext<MessengerType>({
|
|||
loadingMessenger: true,
|
||||
communityData: undefined,
|
||||
contacts: {},
|
||||
setContacts: () => undefined,
|
||||
contactsDispatch: () => undefined,
|
||||
activeChannel: undefined,
|
||||
channels: {},
|
||||
channelsDispatch: () => undefined,
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
import { useReducer } from "react";
|
||||
|
||||
import { ChannelData, ChannelsData } from "../../models/ChannelData";
|
||||
|
||||
export type ChannelsState = {
|
||||
channels: ChannelsData;
|
||||
activeChannel: ChannelData;
|
||||
};
|
||||
|
||||
export type ChannelAction =
|
||||
| { type: "AddChannel"; payload: ChannelData }
|
||||
| { type: "UpdateActive"; payload: ChannelData }
|
||||
| { type: "ChangeActive"; payload: string }
|
||||
| { type: "ToggleMuted"; payload: string }
|
||||
| { type: "RemoveChannel"; payload: string };
|
||||
|
||||
function channelReducer(
|
||||
state: ChannelsState,
|
||||
action: ChannelAction
|
||||
): ChannelsState {
|
||||
switch (action.type) {
|
||||
case "AddChannel": {
|
||||
const channels = {
|
||||
...state.channels,
|
||||
[action.payload.id]: action.payload,
|
||||
};
|
||||
return { channels, activeChannel: action.payload };
|
||||
}
|
||||
case "UpdateActive": {
|
||||
const activeChannel = state.activeChannel;
|
||||
if (activeChannel) {
|
||||
return {
|
||||
channels: { ...state.channels, [activeChannel.id]: action.payload },
|
||||
activeChannel: action.payload,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "ChangeActive": {
|
||||
const newActive = state.channels[action.payload];
|
||||
if (newActive) {
|
||||
return { ...state, activeChannel: newActive };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "ToggleMuted": {
|
||||
const channel = state.channels[action.payload];
|
||||
if (channel) {
|
||||
const updatedChannel: ChannelData = {
|
||||
...channel,
|
||||
isMuted: !channel.isMuted,
|
||||
};
|
||||
return {
|
||||
channels: { ...state.channels, [channel.id]: updatedChannel },
|
||||
activeChannel: updatedChannel,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "RemoveChannel": {
|
||||
const channelsCopy = { ...state.channels };
|
||||
delete channelsCopy[action.payload];
|
||||
let newActive = { id: "", name: "", type: "channel" } as ChannelData;
|
||||
if (Object.values(channelsCopy).length > 0) {
|
||||
newActive = Object.values(channelsCopy)[0];
|
||||
}
|
||||
return { channels: channelsCopy, activeChannel: newActive };
|
||||
}
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
export function useChannelsReducer() {
|
||||
return useReducer(channelReducer, {
|
||||
channels: {},
|
||||
activeChannel: { id: "", name: "", type: "channel" },
|
||||
} as ChannelsState);
|
||||
}
|
|
@ -4,36 +4,116 @@ import {
|
|||
Messenger,
|
||||
} from "@waku/status-communities/dist/cjs";
|
||||
import { bufToHex } from "@waku/status-communities/dist/cjs/utils";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useMemo, useReducer, useState } from "react";
|
||||
|
||||
import { Contacts } from "../../models/Contact";
|
||||
|
||||
export type ContactsAction =
|
||||
| { type: "updateOnline"; payload: { id: string; clock: number } }
|
||||
| { type: "setTrueName"; payload: { id: string; trueName: string } }
|
||||
| {
|
||||
type: "setCustomName";
|
||||
payload: { id: string; customName: string | undefined };
|
||||
}
|
||||
| {
|
||||
type: "setIsUntrustworthy";
|
||||
payload: { id: string; isUntrustworthy: boolean };
|
||||
}
|
||||
| { type: "setIsFriend"; payload: { id: string; isFriend: boolean } }
|
||||
| { type: "setBlocked"; payload: { id: string; blocked: boolean } }
|
||||
| { type: "toggleBlocked"; payload: { id: string } }
|
||||
| { type: "toggleTrustworthy"; payload: { id: string } };
|
||||
|
||||
function contactsReducer(state: Contacts, action: ContactsAction): Contacts {
|
||||
const id = action.payload.id;
|
||||
const prev = state[id];
|
||||
|
||||
switch (action.type) {
|
||||
case "updateOnline": {
|
||||
const now = Date.now();
|
||||
const clock = action.payload.clock;
|
||||
if (prev) {
|
||||
return { ...state, [id]: { ...prev, online: clock > now - 301000 } };
|
||||
}
|
||||
return { ...state, [id]: { id, trueName: id.slice(0, 10) } };
|
||||
}
|
||||
case "setTrueName": {
|
||||
const trueName = action.payload.trueName;
|
||||
if (prev) {
|
||||
return { ...state, [id]: { ...prev, trueName } };
|
||||
}
|
||||
return { ...state, [id]: { id, trueName } };
|
||||
}
|
||||
case "setCustomName": {
|
||||
const customName = action.payload.customName;
|
||||
if (prev) {
|
||||
return { ...state, [id]: { ...prev, customName } };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "setIsUntrustworthy": {
|
||||
const isUntrustworthy = action.payload.isUntrustworthy;
|
||||
if (prev) {
|
||||
return { ...state, [id]: { ...prev, isUntrustworthy } };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "setIsFriend": {
|
||||
const isFriend = action.payload.isFriend;
|
||||
if (prev) {
|
||||
return { ...state, [id]: { ...prev, isFriend } };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "setBlocked": {
|
||||
const blocked = action.payload.blocked;
|
||||
if (prev) {
|
||||
return { ...state, [id]: { ...prev, blocked } };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "toggleBlocked": {
|
||||
if (prev) {
|
||||
return { ...state, [id]: { ...prev, blocked: !prev.blocked } };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "toggleTrustworthy": {
|
||||
if (prev) {
|
||||
return {
|
||||
...state,
|
||||
[id]: { ...prev, isUntrustworthy: !prev.isUntrustworthy },
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
export function useContacts(
|
||||
messenger: Messenger | undefined,
|
||||
identity: Identity | undefined,
|
||||
newNickname: string | undefined
|
||||
) {
|
||||
const [nickname, setNickname] = useState<string | undefined>(undefined);
|
||||
const [internalContacts, setInternalContacts] = useState<{
|
||||
[id: string]: { clock: number; nickname?: string };
|
||||
}>({});
|
||||
const [contacts, contactsDispatch] = useReducer(contactsReducer, {});
|
||||
|
||||
const contactsClass = useMemo(() => {
|
||||
if (messenger) {
|
||||
const newContacts = new ContactsClass(
|
||||
identity,
|
||||
messenger.waku,
|
||||
(id, clock) => {
|
||||
setInternalContacts((prev) => {
|
||||
return { ...prev, [id]: { ...prev[id], clock } };
|
||||
});
|
||||
},
|
||||
(id, clock) =>
|
||||
contactsDispatch({ type: "updateOnline", payload: { id, clock } }),
|
||||
(id, nickname) => {
|
||||
setInternalContacts((prev) => {
|
||||
if (identity?.publicKey && id === bufToHex(identity.publicKey)) {
|
||||
setNickname(nickname);
|
||||
}
|
||||
return { ...prev, [id]: { ...prev[id], nickname } };
|
||||
if (identity?.publicKey && id === bufToHex(identity.publicKey)) {
|
||||
setNickname(nickname);
|
||||
}
|
||||
contactsDispatch({
|
||||
type: "setTrueName",
|
||||
payload: { id, trueName: nickname },
|
||||
});
|
||||
},
|
||||
newNickname
|
||||
|
@ -42,27 +122,5 @@ export function useContacts(
|
|||
}
|
||||
}, [messenger, identity]);
|
||||
|
||||
const [contacts, setContacts] = useState<Contacts>({});
|
||||
|
||||
useEffect(() => {
|
||||
const now = Date.now();
|
||||
setContacts((prev) => {
|
||||
const newContacts: Contacts = {};
|
||||
Object.entries(internalContacts).forEach(([id, { clock, nickname }]) => {
|
||||
newContacts[id] = {
|
||||
id,
|
||||
online: clock > now - 301000,
|
||||
trueName: nickname ?? id.slice(0, 10),
|
||||
isUntrustworthy: false,
|
||||
blocked: false,
|
||||
};
|
||||
if (prev[id]) {
|
||||
newContacts[id] = { ...prev[id], ...newContacts[id] };
|
||||
}
|
||||
});
|
||||
return newContacts;
|
||||
});
|
||||
}, [internalContacts]);
|
||||
|
||||
return { contacts, setContacts, contactsClass, nickname };
|
||||
return { contacts, contactsDispatch, contactsClass, nickname };
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import { ChatMessage } from "../../models/ChatMessage";
|
|||
import { Contact } from "../../models/Contact";
|
||||
import { uintToImgUrl } from "../../utils";
|
||||
|
||||
import { ChannelAction } from "./useMessenger";
|
||||
import { ChannelAction } from "./useChannelsReducer";
|
||||
|
||||
const contactFromId = (member: string): Contact => {
|
||||
return {
|
||||
|
@ -43,13 +43,14 @@ export function useGroupChats(
|
|||
name: chat.name ?? chat.chatId.slice(0, 10),
|
||||
type: "group",
|
||||
description: `${chat.members.length} members`,
|
||||
members: members,
|
||||
members,
|
||||
}
|
||||
: {
|
||||
id: chat.chatId,
|
||||
name: chat.members[0].id,
|
||||
type: "dm",
|
||||
description: `Chatkey: ${chat.members[0].id}`,
|
||||
members,
|
||||
};
|
||||
dispatch({ type: "AddChannel", payload: channel });
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
Identity,
|
||||
Messenger,
|
||||
} from "@waku/status-communities/dist/cjs";
|
||||
import { useCallback, useEffect, useMemo, useReducer, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
|
||||
import { useConfig } from "../../contexts/configProvider";
|
||||
import { ChannelData, ChannelsData } from "../../models/ChannelData";
|
||||
|
@ -17,7 +17,8 @@ import { createCommunity } from "../../utils/createCommunity";
|
|||
import { createMessenger } from "../../utils/createMessenger";
|
||||
import { uintToImgUrl } from "../../utils/uintToImgUrl";
|
||||
|
||||
import { useContacts } from "./useContacts";
|
||||
import { ChannelAction, useChannelsReducer } from "./useChannelsReducer";
|
||||
import { ContactsAction, useContacts } from "./useContacts";
|
||||
import { useGroupChats } from "./useGroupChats";
|
||||
import { useLoadPrevDay } from "./useLoadPrevDay";
|
||||
import { useMessages } from "./useMessages";
|
||||
|
@ -39,7 +40,7 @@ export type MessengerType = {
|
|||
loadingMessenger: boolean;
|
||||
communityData: CommunityData | undefined;
|
||||
contacts: Contacts;
|
||||
setContacts: React.Dispatch<React.SetStateAction<Contacts>>;
|
||||
contactsDispatch: (action: ContactsAction) => void;
|
||||
channels: ChannelsData;
|
||||
channelsDispatch: (action: ChannelAction) => void;
|
||||
removeChannel: (channelId: string) => void;
|
||||
|
@ -78,9 +79,12 @@ function useCreateCommunity(
|
|||
|
||||
const communityData = useMemo(() => {
|
||||
if (community?.description) {
|
||||
Object.keys(community.description.proto.members).forEach((contact) =>
|
||||
contactsClass?.addContact(contact)
|
||||
);
|
||||
const membersList = Object.keys(community.description.proto.members);
|
||||
|
||||
if (contactsClass) {
|
||||
membersList.forEach(contactsClass.addContact, contactsClass);
|
||||
}
|
||||
|
||||
return {
|
||||
id: community.publicKeyStr,
|
||||
name: community.description.identity?.displayName ?? "",
|
||||
|
@ -88,8 +92,8 @@ function useCreateCommunity(
|
|||
community.description?.identity?.images?.thumbnail?.payload ??
|
||||
new Uint8Array()
|
||||
),
|
||||
members: 0,
|
||||
membersList: Object.keys(community.description.proto.members),
|
||||
members: membersList.length,
|
||||
membersList,
|
||||
description: community.description.identity?.description ?? "",
|
||||
};
|
||||
} else {
|
||||
|
@ -100,88 +104,14 @@ function useCreateCommunity(
|
|||
return { community, communityData };
|
||||
}
|
||||
|
||||
export type ChannelsState = {
|
||||
channels: ChannelsData;
|
||||
activeChannel: ChannelData;
|
||||
};
|
||||
|
||||
export type ChannelAction =
|
||||
| { type: "AddChannel"; payload: ChannelData }
|
||||
| { type: "UpdateActive"; payload: ChannelData }
|
||||
| { type: "ChangeActive"; payload: string }
|
||||
| { type: "ToggleMuted"; payload: string }
|
||||
| { type: "RemoveChannel"; payload: string };
|
||||
|
||||
function channelReducer(
|
||||
state: ChannelsState,
|
||||
action: ChannelAction
|
||||
): ChannelsState {
|
||||
switch (action.type) {
|
||||
case "AddChannel": {
|
||||
const channels = {
|
||||
...state.channels,
|
||||
[action.payload.id]: action.payload,
|
||||
};
|
||||
return { channels, activeChannel: action.payload };
|
||||
}
|
||||
case "UpdateActive": {
|
||||
const activeChannel = state.activeChannel;
|
||||
if (activeChannel) {
|
||||
return {
|
||||
channels: { ...state.channels, [activeChannel.id]: action.payload },
|
||||
activeChannel: action.payload,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "ChangeActive": {
|
||||
const newActive = state.channels[action.payload];
|
||||
if (newActive) {
|
||||
return { ...state, activeChannel: newActive };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "ToggleMuted": {
|
||||
const channel = state.channels[action.payload];
|
||||
if (channel) {
|
||||
const updatedChannel: ChannelData = {
|
||||
...channel,
|
||||
isMuted: !channel.isMuted,
|
||||
};
|
||||
return {
|
||||
channels: { ...state.channels, [channel.id]: updatedChannel },
|
||||
activeChannel: updatedChannel,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case "RemoveChannel": {
|
||||
const channelsCopy = { ...state.channels };
|
||||
delete channelsCopy[action.payload];
|
||||
let newActive = { id: "", name: "", type: "channel" } as ChannelData;
|
||||
if (Object.values(channelsCopy).length > 0) {
|
||||
newActive = Object.values(channelsCopy)[0];
|
||||
}
|
||||
return { channels: channelsCopy, activeChannel: newActive };
|
||||
}
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
export function useMessenger(
|
||||
communityKey: string,
|
||||
identity: Identity | undefined,
|
||||
newNickname: string | undefined
|
||||
) {
|
||||
const [channelsState, channelsDispatch] = useReducer(channelReducer, {
|
||||
channels: {},
|
||||
activeChannel: { id: "", name: "", type: "channel" },
|
||||
} as ChannelsState);
|
||||
|
||||
const [channelsState, channelsDispatch] = useChannelsReducer();
|
||||
const messenger = useCreateMessenger(identity);
|
||||
|
||||
const { contacts, setContacts, contactsClass, nickname } = useContacts(
|
||||
const { contacts, contactsDispatch, contactsClass, nickname } = useContacts(
|
||||
messenger,
|
||||
identity,
|
||||
newNickname
|
||||
|
@ -224,18 +154,21 @@ export function useMessenger(
|
|||
Object.values(channelsState.channels)
|
||||
.filter((channel) => channel.type === "dm")
|
||||
.forEach((channel) => {
|
||||
const contact = contacts?.[channel?.members?.[0]?.id ?? ""];
|
||||
if (contact && channel.name !== (contact?.customName ?? channel.name)) {
|
||||
const contact = contacts?.[channel?.members?.[1]?.id ?? ""];
|
||||
if (
|
||||
contact &&
|
||||
channel.name !== (contact?.customName ?? contact.trueName)
|
||||
) {
|
||||
channelsDispatch({
|
||||
type: "AddChannel",
|
||||
payload: {
|
||||
...channel,
|
||||
name: contact?.customName ?? channel.name,
|
||||
name: contact?.customName ?? contact.trueName,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [contacts]);
|
||||
}, [contacts, channelsState.channels]);
|
||||
|
||||
const {
|
||||
groupChat,
|
||||
|
@ -276,7 +209,7 @@ export function useMessenger(
|
|||
};
|
||||
}
|
||||
if (content) {
|
||||
if (channelsState.activeChannel.type === "group") {
|
||||
if (channelsState.activeChannel.type !== "channel") {
|
||||
await groupChat?.sendMessage(
|
||||
channelsState.activeChannel.id,
|
||||
content,
|
||||
|
@ -318,7 +251,7 @@ export function useMessenger(
|
|||
loadingMessenger,
|
||||
communityData,
|
||||
contacts,
|
||||
setContacts,
|
||||
contactsDispatch,
|
||||
channels: channelsState.channels,
|
||||
channelsDispatch,
|
||||
removeChannel,
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
import { useCallback, useMemo } from "react";
|
||||
|
||||
import { useMessengerContext } from "../contexts/messengerProvider";
|
||||
|
||||
export function useManageContact(id: string) {
|
||||
const { contacts, setContacts } = useMessengerContext();
|
||||
const contact = useMemo(() => contacts[id], [id, contacts]);
|
||||
|
||||
const setCustomName = useCallback(
|
||||
(customName: string | undefined) => {
|
||||
setContacts((prev) => {
|
||||
const prevUser = prev[id];
|
||||
if (!prevUser) return prev;
|
||||
return { ...prev, [id]: { ...prevUser, customName } };
|
||||
});
|
||||
},
|
||||
[id]
|
||||
);
|
||||
|
||||
const setBlocked = useCallback(
|
||||
(blocked: boolean) => {
|
||||
setContacts((prev) => {
|
||||
const prevUser = prev[id];
|
||||
if (!prevUser) return prev;
|
||||
return { ...prev, [id]: { ...prevUser, blocked } };
|
||||
});
|
||||
},
|
||||
[id]
|
||||
);
|
||||
|
||||
const setIsUntrustworthy = useCallback(
|
||||
(isUntrustworthy: boolean) => {
|
||||
setContacts((prev) => {
|
||||
const prevUser = prev[id];
|
||||
if (!prevUser) return prev;
|
||||
return { ...prev, [id]: { ...prevUser, isUntrustworthy } };
|
||||
});
|
||||
},
|
||||
[id]
|
||||
);
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
|
@ -32,12 +32,34 @@ export type GroupChatsType = {
|
|||
};
|
||||
/* TODO: add chat messages encryption */
|
||||
|
||||
class GroupChatUsers {
|
||||
private users: { [id: string]: GroupMember } = {};
|
||||
private identity: Identity;
|
||||
|
||||
public constructor(_identity: Identity) {
|
||||
this.identity = _identity;
|
||||
}
|
||||
|
||||
public async getUser(id: string): Promise<GroupMember> {
|
||||
if (this.users[id]) {
|
||||
return this.users[id];
|
||||
}
|
||||
const topic = await getNegotiatedTopic(this.identity, id);
|
||||
const symKey = await createSymKeyFromPassword(topic);
|
||||
const partitionedTopic = getPartitionedTopic(id);
|
||||
const groupUser: GroupMember = { topic, symKey, id, partitionedTopic };
|
||||
this.users[id] = groupUser;
|
||||
return groupUser;
|
||||
}
|
||||
}
|
||||
|
||||
export class GroupChats {
|
||||
waku: Waku;
|
||||
identity: Identity;
|
||||
private callback: (chats: GroupChat) => void;
|
||||
private removeCallback: (chats: GroupChat) => void;
|
||||
private addMessage: (message: ChatMessage, sender: string) => void;
|
||||
private groupChatUsers;
|
||||
|
||||
public chats: GroupChatsType = {};
|
||||
/**
|
||||
|
@ -62,6 +84,7 @@ export class GroupChats {
|
|||
) {
|
||||
this.waku = waku;
|
||||
this.identity = identity;
|
||||
this.groupChatUsers = new GroupChatUsers(identity);
|
||||
this.callback = callback;
|
||||
this.removeCallback = removeCallback;
|
||||
this.addMessage = addMessage;
|
||||
|
@ -117,10 +140,7 @@ export class GroupChats {
|
|||
const members: GroupMember[] = [];
|
||||
await Promise.all(
|
||||
event.event.members.map(async (member) => {
|
||||
const topic = await getNegotiatedTopic(this.identity, member);
|
||||
const symKey = await createSymKeyFromPassword(topic);
|
||||
const partitionedTopic = getPartitionedTopic(member);
|
||||
members.push({ topic, symKey, id: member, partitionedTopic });
|
||||
members.push(await this.groupChatUsers.getUser(member));
|
||||
})
|
||||
);
|
||||
await this.addChat(
|
||||
|
@ -160,10 +180,7 @@ export class GroupChats {
|
|||
const members: GroupMember[] = [];
|
||||
await Promise.all(
|
||||
event.event.members.map(async (member) => {
|
||||
const topic = await getNegotiatedTopic(this.identity, member);
|
||||
const symKey = await createSymKeyFromPassword(topic);
|
||||
const partitionedTopic = getPartitionedTopic(member);
|
||||
members.push({ topic, symKey, id: member, partitionedTopic });
|
||||
members.push(await this.groupChatUsers.getUser(member));
|
||||
})
|
||||
);
|
||||
chat.members.push(...members);
|
||||
|
@ -353,10 +370,7 @@ export class GroupChats {
|
|||
!chat.members.map((chatMember) => chatMember.id).includes(member)
|
||||
)
|
||||
.map(async (member) => {
|
||||
const topic = await getNegotiatedTopic(this.identity, member);
|
||||
const symKey = await createSymKeyFromPassword(topic);
|
||||
const partitionedTopic = getPartitionedTopic(member);
|
||||
newMembers.push({ topic, symKey, id: member, partitionedTopic });
|
||||
newMembers.push(await this.groupChatUsers.getUser(member));
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -383,10 +397,7 @@ export class GroupChats {
|
|||
|
||||
await Promise.all(
|
||||
members.map(async (member) => {
|
||||
const topic = await getNegotiatedTopic(this.identity, member);
|
||||
const symKey = await createSymKeyFromPassword(topic);
|
||||
const partitionedTopic = getPartitionedTopic(member);
|
||||
newMembers.push({ topic, symKey, id: member, partitionedTopic });
|
||||
newMembers.push(await this.groupChatUsers.getUser(member));
|
||||
})
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue