diff --git a/ts/components/OnionStatusDialog.tsx b/ts/components/OnionStatusDialog.tsx index 976546d98..686f00a99 100644 --- a/ts/components/OnionStatusDialog.tsx +++ b/ts/components/OnionStatusDialog.tsx @@ -143,7 +143,7 @@ export const ActionPanelOnionStatusLight = (props: { let iconColor = red; //if we are not online or the first path is not valid, we keep red as color if (isOnline && firstPathLength > 1) { - iconColor = onionPathsCount > 2 ? green : onionPathsCount > 1 ? orange : red; + iconColor = onionPathsCount >= 2 ? green : onionPathsCount >= 1 ? orange : red; } return ( diff --git a/ts/components/UserDetailsDialog.tsx b/ts/components/UserDetailsDialog.tsx index 0f7d0737e..e0f523e88 100644 --- a/ts/components/UserDetailsDialog.tsx +++ b/ts/components/UserDetailsDialog.tsx @@ -1,107 +1,80 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Avatar, AvatarSize } from './Avatar'; import { SessionButton, SessionButtonColor, SessionButtonType } from './session/SessionButton'; import { SessionIdEditable } from './session/SessionIdEditable'; import { ConversationController } from '../session/conversations'; -import { ConversationModel, ConversationTypeEnum } from '../models/conversation'; +import { ConversationTypeEnum } from '../models/conversation'; import { SessionWrapperModal } from './session/SessionWrapperModal'; import { SpacerMD } from './basic/Text'; -import autoBind from 'auto-bind'; import { updateUserDetailsModal } from '../state/ducks/modalDialog'; import { openConversationExternal } from '../state/ducks/conversations'; - +// tslint:disable-next-line: no-submodule-imports +import useKey from 'react-use/lib/useKey'; type Props = { conversationId: string; authorAvatarPath?: string; userName: string; }; -interface State { - isEnlargedImageShown: boolean; -} - -export class UserDetailsDialog extends React.Component { - private readonly convo: ConversationModel; - constructor(props: Props) { - super(props); - - autoBind(this); - this.convo = ConversationController.getInstance().get(props.conversationId); - window.addEventListener('keyup', this.onKeyUp); - - this.state = { isEnlargedImageShown: false }; - } - - public render() { - return ( - -
-
{this.renderAvatar()}
-
- - - - -
- -
-
- ); - } - - private renderAvatar() { - const size = this.state.isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL; - const userName = this.props.userName || this.props.conversationId; - - return ( - - ); - } - - private readonly handleShowEnlargedDialog = () => { - this.setState({ isEnlargedImageShown: !this.state.isEnlargedImageShown }); - }; +export const UserDetailsDialog = (props: Props) => { + const [isEnlargedImageShown, setIsEnlargedImageShown] = useState(false); + const convo = ConversationController.getInstance().get(props.conversationId); - private onKeyUp(event: any) { - switch (event.key) { - case 'Enter': - void this.onClickStartConversation(); - break; - case 'Esc': - case 'Escape': - this.closeDialog(); - break; - default: - } - } - - private closeDialog() { - window.removeEventListener('keyup', this.onKeyUp); + const size = isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL; + const userName = props.userName || props.conversationId; + function closeDialog() { window.inboxStore?.dispatch(updateUserDetailsModal(null)); } - private async onClickStartConversation() { - // this.props.onStartConversation(); + async function onClickStartConversation() { const conversation = await ConversationController.getInstance().getOrCreateAndWait( - this.convo.id, + convo.id, ConversationTypeEnum.PRIVATE ); window.inboxStore?.dispatch(openConversationExternal(conversation.id)); - this.closeDialog(); + closeDialog(); } -} + + useKey( + 'Enter', + () => { + void onClickStartConversation(); + }, + undefined, + [props.conversationId] + ); + + return ( + +
+
+ { + setIsEnlargedImageShown(!isEnlargedImageShown); + }} + pubkey={props.conversationId} + /> +
+
+ + + + +
+ +
+
+ ); +}; diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index c882eff8f..3d87c62f7 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -487,7 +487,7 @@ class MessageInner extends React.PureComponent { onAvatarClick={() => { window.inboxStore?.dispatch( updateUserDetailsModal({ - conversationId: this.props.convoId, + conversationId: authorPhoneNumber, userName, authorAvatarPath, }) diff --git a/ts/components/conversation/ModeratorsAddDialog.tsx b/ts/components/conversation/ModeratorsAddDialog.tsx index 33147b940..0f8639287 100644 --- a/ts/components/conversation/ModeratorsAddDialog.tsx +++ b/ts/components/conversation/ModeratorsAddDialog.tsx @@ -10,6 +10,7 @@ import { SessionWrapperModal } from '../session/SessionWrapperModal'; import { ConversationController } from '../../session/conversations'; import { useDispatch } from 'react-redux'; import { updateAddModeratorsModal } from '../../state/ducks/modalDialog'; +import _ from 'lodash'; type Props = { conversationId: string; diff --git a/ts/components/conversation/ModeratorsRemoveDialog.tsx b/ts/components/conversation/ModeratorsRemoveDialog.tsx index 024b68aed..b10e9741a 100644 --- a/ts/components/conversation/ModeratorsRemoveDialog.tsx +++ b/ts/components/conversation/ModeratorsRemoveDialog.tsx @@ -209,9 +209,10 @@ export class RemoveModeratorsDialog extends React.Component { } else { window?.log?.info(`${removedMods} removed from moderators...`); ToastUtils.pushUserRemovedFromModerators(); + this.closeDialog(); } } catch (e) { - window?.log?.error('Got error while adding moderator:', e); + window?.log?.error('Got error while removing moderator:', e); } finally { this.refreshModList(); } diff --git a/ts/components/session/SessionSeedModal.tsx b/ts/components/session/SessionSeedModal.tsx index d6e32d0bc..2ed5c820a 100644 --- a/ts/components/session/SessionSeedModal.tsx +++ b/ts/components/session/SessionSeedModal.tsx @@ -57,7 +57,11 @@ class SessionSeedModalInner extends React.Component<{}, State> { return ( <> {!loading && ( - + {hasPassword && !passwordValid ? ( @@ -111,7 +115,6 @@ class SessionSeedModalInner extends React.Component<{}, State> { const fgColor = '#1B1B1B'; const hexEncodedSeed = mn_decode(this.state.recoveryPhrase, 'english'); - const onClose = () => window.inboxStore?.dispatch(recoveryPhraseModal(null)); return ( <> @@ -133,7 +136,6 @@ class SessionSeedModalInner extends React.Component<{}, State> { this.copyRecoveryPhrase(this.state.recoveryPhrase); }} /> - ); diff --git a/ts/components/session/SessionWrapperModal.tsx b/ts/components/session/SessionWrapperModal.tsx index 5f7d4537a..bc0abea83 100644 --- a/ts/components/session/SessionWrapperModal.tsx +++ b/ts/components/session/SessionWrapperModal.tsx @@ -5,6 +5,9 @@ import { SessionIconButton, SessionIconSize, SessionIconType } from './icon/'; import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton'; import { DefaultTheme, useTheme } from 'styled-components'; +// tslint:disable-next-line: no-submodule-imports +import useKey from 'react-use/lib/useKey'; + type Props = { title: string; onClose: any; @@ -58,21 +61,23 @@ export const SessionWrapperModal = (props: SessionWrapperModalType) => { const theme = useTheme(); - useEffect(() => { - window.addEventListener('keyup', keyUpHandler); - - return () => { - window.removeEventListener('keyup', keyUpHandler); - }; - }, []); + useKey( + 'Esc', + () => { + props.onClose?.(); + }, + undefined, + [props.onClose] + ); - const keyUpHandler = ({ key }: any) => { - if (key === 'Escape') { - if (props.onClose) { - props.onClose(); - } - } - }; + useKey( + 'Escape', + () => { + props.onClose?.(); + }, + undefined, + [props.onClose] + ); return (
diff --git a/ts/interactions/messageInteractions.ts b/ts/interactions/messageInteractions.ts index fe4124735..5103a2e28 100644 --- a/ts/interactions/messageInteractions.ts +++ b/ts/interactions/messageInteractions.ts @@ -149,17 +149,17 @@ export async function removeSenderFromModerator(sender: string, convoId: string) export async function addSenderAsModerator(sender: string, convoId: string) { try { - const pubKeyToRemove = PubKey.cast(sender); + const pubKeyToAdd = PubKey.cast(sender); const convo = ConversationController.getInstance().getOrThrow(convoId); const roomInfo = convo.toOpenGroupV2(); - const res = await ApiV2.addModerator(pubKeyToRemove, roomInfo); + const res = await ApiV2.addModerator(pubKeyToAdd, roomInfo); if (!res) { window?.log?.warn('failed to add moderator:', res); ToastUtils.pushUserNeedsToHaveJoined(); } else { - window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`); + window?.log?.info(`${pubKeyToAdd.key} added to moderators...`); ToastUtils.pushUserAddedToModerators(); } } catch (e) { diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index a68bdb571..076fcf1c1 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -408,8 +408,8 @@ export class ConversationModel extends Backbone.Model { } public async updateGroupAdmins(groupAdmins: Array) { - const existingAdmins = _.sortBy(this.getGroupAdmins()); - const newAdmins = _.sortBy(groupAdmins); + const existingAdmins = _.uniq(_.sortBy(this.getGroupAdmins())); + const newAdmins = _.uniq(_.sortBy(groupAdmins)); if (_.isEqual(existingAdmins, newAdmins)) { // window?.log?.info( diff --git a/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts b/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts index 43f558027..41d60559e 100644 --- a/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts +++ b/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts @@ -448,16 +448,9 @@ const handleCompactPollResults = async ( window?.log?.warn('Could not find convo for compactPoll', convoId); return; } - const existingModerators = convo.get('moderators') || []; - let changeOnConvo = false; - if (!_.isEqual(existingModerators.sort(), res.moderators.sort())) { - convo.set({ moderators: res.moderators }); - changeOnConvo = true; - } - if (changeOnConvo) { - await convo.commit(); - } + // this already do the commit + await convo.updateGroupAdmins(res.moderators); }) ); };