session-desktop/ts/components/conversation/ModeratorsRemoveDialog.tsx

227 lines
6.8 KiB
TypeScript

import React from 'react';
import { DefaultTheme } from 'styled-components';
import { ConversationModel } from '../../models/conversation';
import { ApiV2 } from '../../opengroup/opengroupV2';
import { ConversationController } from '../../session/conversations';
import { PubKey } from '../../session/types';
import { ToastUtils } from '../../session/utils';
import { Flex } from '../session/Flex';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../session/SessionButton';
import { ContactType, SessionMemberListItem } from '../session/SessionMemberListItem';
import { SessionModal } from '../session/SessionModal';
import { SessionSpinner } from '../session/SessionSpinner';
import _ from 'lodash';
interface Props {
convo: ConversationModel;
onClose: any;
theme: DefaultTheme;
}
interface State {
modList: Array<ContactType>;
removingInProgress: boolean;
firstLoading: boolean;
}
export class RemoveModeratorsDialog extends React.Component<Props, State> {
private channelAPI: any;
constructor(props: any) {
super(props);
this.onModClicked = this.onModClicked.bind(this);
this.closeDialog = this.closeDialog.bind(this);
this.removeThem = this.removeThem.bind(this);
this.state = {
modList: [],
removingInProgress: false,
firstLoading: true,
};
}
public async componentDidMount() {
if (this.props.convo.isOpenGroupV1()) {
this.channelAPI = await this.props.convo.getPublicSendData();
}
void this.refreshModList();
}
public render() {
const { i18n } = window;
const { removingInProgress, firstLoading } = this.state;
const hasMods = this.state.modList.length !== 0;
const chatName = this.props.convo.get('name');
const title = `${i18n('removeModerators')}: ${chatName}`;
const renderContent = !firstLoading;
return (
<SessionModal title={title} onClose={this.closeDialog} theme={this.props.theme}>
<Flex container={true} flexDirection="column" alignItems="center">
{renderContent && (
<>
<p>Existing moderators:</p>
<div className="contact-selection-list">{this.renderMemberList()}</div>
{hasMods ? null : <p>{i18n('noModeratorsToRemove')}</p>}
<SessionSpinner loading={removingInProgress} />
<div className="session-modal__button-group">
<SessionButton
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
onClick={this.removeThem}
disabled={removingInProgress}
text={i18n('ok')}
/>
<SessionButton
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Primary}
onClick={this.closeDialog}
disabled={removingInProgress}
text={i18n('cancel')}
/>
</div>
</>
)}
<SessionSpinner loading={firstLoading} />
</Flex>
</SessionModal>
);
}
private closeDialog() {
this.props.onClose();
}
private renderMemberList() {
const members = this.state.modList;
const selectedContacts = members.filter(d => d.checkmarked).map(d => d.id);
return members.map((member: ContactType, index: number) => (
<SessionMemberListItem
member={member}
key={index}
index={index}
isSelected={selectedContacts.some(m => m === member.id)}
onSelect={(selectedMember: ContactType) => {
this.onModClicked(selectedMember);
}}
onUnselect={(selectedMember: ContactType) => {
this.onModClicked(selectedMember);
}}
theme={this.props.theme}
/>
));
}
private onModClicked(selected: ContactType) {
const updatedContacts = this.state.modList.map(member => {
if (member.id === selected.id) {
return { ...member, checkmarked: !member.checkmarked };
} else {
return member;
}
});
this.setState(state => {
return {
...state,
modList: updatedContacts,
};
});
}
private async refreshModList() {
let modPubKeys: Array<string> = [];
if (this.props.convo.isOpenGroupV1()) {
// get current list of moderators
modPubKeys = (await this.channelAPI.getModerators()) as Array<string>;
} else if (this.props.convo.isOpenGroupV2()) {
modPubKeys = this.props.convo.getGroupAdmins() || [];
}
const convos = ConversationController.getInstance().getConversations();
const moderatorsConvos = modPubKeys
.map(
pubKey =>
convos.find(c => c.id === pubKey) || {
id: pubKey, // memberList need a key
authorPhoneNumber: pubKey,
}
)
.filter(c => !!c);
const mods = moderatorsConvos.map((d: any) => {
let name = '';
if (d.getLokiProfile) {
const lokiProfile = d.getLokiProfile();
name = lokiProfile ? lokiProfile.displayName : 'Anonymous';
}
// TODO: should take existing members into account
const existingMember = false;
return {
id: d.id,
authorPhoneNumber: d.id,
authorProfileName: name,
selected: false,
authorAvatarPath: '',
authorName: name,
checkmarked: true,
existingMember,
};
});
this.setState({
modList: mods,
firstLoading: false,
removingInProgress: false,
});
}
private async removeThem() {
const removedMods = this.state.modList.filter(d => !d.checkmarked).map(d => d.id);
if (removedMods.length === 0) {
window.log.info('No moderators removed. Nothing todo');
return;
}
window.log.info(`asked to remove moderator: ${removedMods}`);
try {
this.setState({
removingInProgress: true,
});
let res;
if (this.props.convo.isOpenGroupV1()) {
res = await this.channelAPI.serverAPI.removeModerators(removedMods);
} else if (this.props.convo.isOpenGroupV2()) {
const roomInfos = this.props.convo.toOpenGroupV2();
const modsToRemove = _.compact(removedMods.map(m => PubKey.from(m)));
res = await Promise.all(
modsToRemove.map(async m => {
return ApiV2.removeModerator(m, roomInfos);
})
);
// all moderators are removed means all promise resolved with bool= true
res = res.every(r => !!r);
}
if (!res) {
window.log.warn('failed to remove moderators:', res);
ToastUtils.pushUserNeedsToHaveJoined();
} else {
window.log.info(`${removedMods} removed from moderators...`);
ToastUtils.pushUserRemovedFromModerators();
}
} catch (e) {
window.log.error('Got error while adding moderator:', e);
} finally {
await this.refreshModList();
}
}
}