mirror of
https://github.com/oxen-io/session-desktop.git
synced 2023-12-14 02:12:57 +01:00
fix moderator add/remove
This commit is contained in:
parent
9a08ab68bc
commit
9ed030fac6
|
@ -143,7 +143,7 @@ export const ActionPanelOnionStatusLight = (props: {
|
||||||
let iconColor = red;
|
let iconColor = red;
|
||||||
//if we are not online or the first path is not valid, we keep red as color
|
//if we are not online or the first path is not valid, we keep red as color
|
||||||
if (isOnline && firstPathLength > 1) {
|
if (isOnline && firstPathLength > 1) {
|
||||||
iconColor = onionPathsCount > 2 ? green : onionPathsCount > 1 ? orange : red;
|
iconColor = onionPathsCount >= 2 ? green : onionPathsCount >= 1 ? orange : red;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,107 +1,80 @@
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Avatar, AvatarSize } from './Avatar';
|
import { Avatar, AvatarSize } from './Avatar';
|
||||||
|
|
||||||
import { SessionButton, SessionButtonColor, SessionButtonType } from './session/SessionButton';
|
import { SessionButton, SessionButtonColor, SessionButtonType } from './session/SessionButton';
|
||||||
import { SessionIdEditable } from './session/SessionIdEditable';
|
import { SessionIdEditable } from './session/SessionIdEditable';
|
||||||
import { ConversationController } from '../session/conversations';
|
import { ConversationController } from '../session/conversations';
|
||||||
import { ConversationModel, ConversationTypeEnum } from '../models/conversation';
|
import { ConversationTypeEnum } from '../models/conversation';
|
||||||
import { SessionWrapperModal } from './session/SessionWrapperModal';
|
import { SessionWrapperModal } from './session/SessionWrapperModal';
|
||||||
import { SpacerMD } from './basic/Text';
|
import { SpacerMD } from './basic/Text';
|
||||||
import autoBind from 'auto-bind';
|
|
||||||
import { updateUserDetailsModal } from '../state/ducks/modalDialog';
|
import { updateUserDetailsModal } from '../state/ducks/modalDialog';
|
||||||
import { openConversationExternal } from '../state/ducks/conversations';
|
import { openConversationExternal } from '../state/ducks/conversations';
|
||||||
|
// tslint:disable-next-line: no-submodule-imports
|
||||||
|
import useKey from 'react-use/lib/useKey';
|
||||||
type Props = {
|
type Props = {
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
authorAvatarPath?: string;
|
authorAvatarPath?: string;
|
||||||
userName: string;
|
userName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface State {
|
export const UserDetailsDialog = (props: Props) => {
|
||||||
isEnlargedImageShown: boolean;
|
const [isEnlargedImageShown, setIsEnlargedImageShown] = useState(false);
|
||||||
}
|
const convo = ConversationController.getInstance().get(props.conversationId);
|
||||||
|
|
||||||
export class UserDetailsDialog extends React.Component<Props, State> {
|
const size = isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL;
|
||||||
private readonly convo: ConversationModel;
|
const userName = props.userName || props.conversationId;
|
||||||
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 (
|
|
||||||
<SessionWrapperModal title={this.props.userName} onClose={this.closeDialog}>
|
|
||||||
<div className="avatar-center">
|
|
||||||
<div className="avatar-center-inner">{this.renderAvatar()}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<SpacerMD />
|
|
||||||
<SessionIdEditable editable={false} text={this.convo.id} />
|
|
||||||
|
|
||||||
<div className="session-modal__button-group__center">
|
|
||||||
<SessionButton
|
|
||||||
text={window.i18n('startConversation')}
|
|
||||||
buttonType={SessionButtonType.Default}
|
|
||||||
buttonColor={SessionButtonColor.Primary}
|
|
||||||
onClick={this.onClickStartConversation}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SessionWrapperModal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderAvatar() {
|
|
||||||
const size = this.state.isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL;
|
|
||||||
const userName = this.props.userName || this.props.conversationId;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Avatar
|
|
||||||
avatarPath={this.props.authorAvatarPath}
|
|
||||||
name={userName}
|
|
||||||
size={size}
|
|
||||||
onAvatarClick={this.handleShowEnlargedDialog}
|
|
||||||
pubkey={this.props.conversationId}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly handleShowEnlargedDialog = () => {
|
|
||||||
this.setState({ isEnlargedImageShown: !this.state.isEnlargedImageShown });
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
function closeDialog() {
|
||||||
window.inboxStore?.dispatch(updateUserDetailsModal(null));
|
window.inboxStore?.dispatch(updateUserDetailsModal(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onClickStartConversation() {
|
async function onClickStartConversation() {
|
||||||
// this.props.onStartConversation();
|
|
||||||
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
|
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||||
this.convo.id,
|
convo.id,
|
||||||
ConversationTypeEnum.PRIVATE
|
ConversationTypeEnum.PRIVATE
|
||||||
);
|
);
|
||||||
|
|
||||||
window.inboxStore?.dispatch(openConversationExternal(conversation.id));
|
window.inboxStore?.dispatch(openConversationExternal(conversation.id));
|
||||||
|
|
||||||
this.closeDialog();
|
closeDialog();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
useKey(
|
||||||
|
'Enter',
|
||||||
|
() => {
|
||||||
|
void onClickStartConversation();
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
[props.conversationId]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SessionWrapperModal title={props.userName} onClose={closeDialog} showExitIcon={true}>
|
||||||
|
<div className="avatar-center">
|
||||||
|
<div className="avatar-center-inner">
|
||||||
|
<Avatar
|
||||||
|
avatarPath={props.authorAvatarPath}
|
||||||
|
name={userName}
|
||||||
|
size={size}
|
||||||
|
onAvatarClick={() => {
|
||||||
|
setIsEnlargedImageShown(!isEnlargedImageShown);
|
||||||
|
}}
|
||||||
|
pubkey={props.conversationId}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SpacerMD />
|
||||||
|
<SessionIdEditable editable={false} text={convo.id} />
|
||||||
|
|
||||||
|
<div className="session-modal__button-group__center">
|
||||||
|
<SessionButton
|
||||||
|
text={window.i18n('startConversation')}
|
||||||
|
buttonType={SessionButtonType.Default}
|
||||||
|
buttonColor={SessionButtonColor.Primary}
|
||||||
|
onClick={onClickStartConversation}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SessionWrapperModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -487,7 +487,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
||||||
onAvatarClick={() => {
|
onAvatarClick={() => {
|
||||||
window.inboxStore?.dispatch(
|
window.inboxStore?.dispatch(
|
||||||
updateUserDetailsModal({
|
updateUserDetailsModal({
|
||||||
conversationId: this.props.convoId,
|
conversationId: authorPhoneNumber,
|
||||||
userName,
|
userName,
|
||||||
authorAvatarPath,
|
authorAvatarPath,
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { SessionWrapperModal } from '../session/SessionWrapperModal';
|
||||||
import { ConversationController } from '../../session/conversations';
|
import { ConversationController } from '../../session/conversations';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { updateAddModeratorsModal } from '../../state/ducks/modalDialog';
|
import { updateAddModeratorsModal } from '../../state/ducks/modalDialog';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
|
|
|
@ -209,9 +209,10 @@ export class RemoveModeratorsDialog extends React.Component<Props, State> {
|
||||||
} else {
|
} else {
|
||||||
window?.log?.info(`${removedMods} removed from moderators...`);
|
window?.log?.info(`${removedMods} removed from moderators...`);
|
||||||
ToastUtils.pushUserRemovedFromModerators();
|
ToastUtils.pushUserRemovedFromModerators();
|
||||||
|
this.closeDialog();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
window?.log?.error('Got error while adding moderator:', e);
|
window?.log?.error('Got error while removing moderator:', e);
|
||||||
} finally {
|
} finally {
|
||||||
this.refreshModList();
|
this.refreshModList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,11 @@ class SessionSeedModalInner extends React.Component<{}, State> {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!loading && (
|
{!loading && (
|
||||||
<SessionWrapperModal title={i18n('showRecoveryPhrase')} onClose={onClose}>
|
<SessionWrapperModal
|
||||||
|
title={i18n('showRecoveryPhrase')}
|
||||||
|
onClose={onClose}
|
||||||
|
showExitIcon={true}
|
||||||
|
>
|
||||||
<SpacerSM />
|
<SpacerSM />
|
||||||
|
|
||||||
{hasPassword && !passwordValid ? (
|
{hasPassword && !passwordValid ? (
|
||||||
|
@ -111,7 +115,6 @@ class SessionSeedModalInner extends React.Component<{}, State> {
|
||||||
const fgColor = '#1B1B1B';
|
const fgColor = '#1B1B1B';
|
||||||
|
|
||||||
const hexEncodedSeed = mn_decode(this.state.recoveryPhrase, 'english');
|
const hexEncodedSeed = mn_decode(this.state.recoveryPhrase, 'english');
|
||||||
const onClose = () => window.inboxStore?.dispatch(recoveryPhraseModal(null));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -133,7 +136,6 @@ class SessionSeedModalInner extends React.Component<{}, State> {
|
||||||
this.copyRecoveryPhrase(this.state.recoveryPhrase);
|
this.copyRecoveryPhrase(this.state.recoveryPhrase);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SessionButton text={i18n('cancel')} onClick={onClose} />
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,6 +5,9 @@ import { SessionIconButton, SessionIconSize, SessionIconType } from './icon/';
|
||||||
import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton';
|
import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton';
|
||||||
import { DefaultTheme, useTheme } from 'styled-components';
|
import { DefaultTheme, useTheme } from 'styled-components';
|
||||||
|
|
||||||
|
// tslint:disable-next-line: no-submodule-imports
|
||||||
|
import useKey from 'react-use/lib/useKey';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
onClose: any;
|
onClose: any;
|
||||||
|
@ -58,21 +61,23 @@ export const SessionWrapperModal = (props: SessionWrapperModalType) => {
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
useEffect(() => {
|
useKey(
|
||||||
window.addEventListener('keyup', keyUpHandler);
|
'Esc',
|
||||||
|
() => {
|
||||||
|
props.onClose?.();
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
[props.onClose]
|
||||||
|
);
|
||||||
|
|
||||||
return () => {
|
useKey(
|
||||||
window.removeEventListener('keyup', keyUpHandler);
|
'Escape',
|
||||||
};
|
() => {
|
||||||
}, []);
|
props.onClose?.();
|
||||||
|
},
|
||||||
const keyUpHandler = ({ key }: any) => {
|
undefined,
|
||||||
if (key === 'Escape') {
|
[props.onClose]
|
||||||
if (props.onClose) {
|
);
|
||||||
props.onClose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`loki-dialog modal ${additionalClassName}`}>
|
<div className={`loki-dialog modal ${additionalClassName}`}>
|
||||||
|
|
|
@ -149,17 +149,17 @@ export async function removeSenderFromModerator(sender: string, convoId: string)
|
||||||
|
|
||||||
export async function addSenderAsModerator(sender: string, convoId: string) {
|
export async function addSenderAsModerator(sender: string, convoId: string) {
|
||||||
try {
|
try {
|
||||||
const pubKeyToRemove = PubKey.cast(sender);
|
const pubKeyToAdd = PubKey.cast(sender);
|
||||||
const convo = ConversationController.getInstance().getOrThrow(convoId);
|
const convo = ConversationController.getInstance().getOrThrow(convoId);
|
||||||
|
|
||||||
const roomInfo = convo.toOpenGroupV2();
|
const roomInfo = convo.toOpenGroupV2();
|
||||||
const res = await ApiV2.addModerator(pubKeyToRemove, roomInfo);
|
const res = await ApiV2.addModerator(pubKeyToAdd, roomInfo);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
window?.log?.warn('failed to add moderator:', res);
|
window?.log?.warn('failed to add moderator:', res);
|
||||||
|
|
||||||
ToastUtils.pushUserNeedsToHaveJoined();
|
ToastUtils.pushUserNeedsToHaveJoined();
|
||||||
} else {
|
} else {
|
||||||
window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`);
|
window?.log?.info(`${pubKeyToAdd.key} added to moderators...`);
|
||||||
ToastUtils.pushUserAddedToModerators();
|
ToastUtils.pushUserAddedToModerators();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -408,8 +408,8 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateGroupAdmins(groupAdmins: Array<string>) {
|
public async updateGroupAdmins(groupAdmins: Array<string>) {
|
||||||
const existingAdmins = _.sortBy(this.getGroupAdmins());
|
const existingAdmins = _.uniq(_.sortBy(this.getGroupAdmins()));
|
||||||
const newAdmins = _.sortBy(groupAdmins);
|
const newAdmins = _.uniq(_.sortBy(groupAdmins));
|
||||||
|
|
||||||
if (_.isEqual(existingAdmins, newAdmins)) {
|
if (_.isEqual(existingAdmins, newAdmins)) {
|
||||||
// window?.log?.info(
|
// window?.log?.info(
|
||||||
|
|
|
@ -448,16 +448,9 @@ const handleCompactPollResults = async (
|
||||||
window?.log?.warn('Could not find convo for compactPoll', convoId);
|
window?.log?.warn('Could not find convo for compactPoll', convoId);
|
||||||
return;
|
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) {
|
// this already do the commit
|
||||||
await convo.commit();
|
await convo.updateGroupAdmins(res.moderators);
|
||||||
}
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue