/* Copyright 2024 New Vector Ltd. Copyright 2019-2021 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ import React, { ChangeEvent, SyntheticEvent } from "react"; import { logger } from "matrix-js-sdk/src/logger"; import { _t } from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; import { Mjolnir } from "../../../../../mjolnir/Mjolnir"; import { ListRule } from "../../../../../mjolnir/ListRule"; import { BanList, RULE_SERVER, RULE_USER } from "../../../../../mjolnir/BanList"; import Modal from "../../../../../Modal"; import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import ErrorDialog from "../../../dialogs/ErrorDialog"; import QuestionDialog from "../../../dialogs/QuestionDialog"; import AccessibleButton from "../../../elements/AccessibleButton"; import Field from "../../../elements/Field"; import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection"; interface IState { busy: boolean; newPersonalRule: string; newList: string; } export default class MjolnirUserSettingsTab extends React.Component<{}, IState> { public constructor(props: {}) { super(props); this.state = { busy: false, newPersonalRule: "", newList: "", }; } private onPersonalRuleChanged = (e: ChangeEvent): void => { this.setState({ newPersonalRule: e.target.value }); }; private onNewListChanged = (e: ChangeEvent): void => { this.setState({ newList: e.target.value }); }; private onAddPersonalRule = async (e: SyntheticEvent): Promise => { e.preventDefault(); e.stopPropagation(); let kind = RULE_SERVER; if (this.state.newPersonalRule.startsWith("@")) { kind = RULE_USER; } this.setState({ busy: true }); try { const list = await Mjolnir.sharedInstance().getOrCreatePersonalList(); await list.banEntity(kind, this.state.newPersonalRule, _t("labs_mjolnir|ban_reason")); this.setState({ newPersonalRule: "" }); // this will also cause the new rule to be rendered } catch (e) { logger.error(e); Modal.createDialog(ErrorDialog, { title: _t("labs_mjolnir|error_adding_ignore"), description: _t("labs_mjolnir|something_went_wrong"), }); } finally { this.setState({ busy: false }); } }; private onSubscribeList = async (e: SyntheticEvent): Promise => { e.preventDefault(); e.stopPropagation(); this.setState({ busy: true }); try { const room = await MatrixClientPeg.safeGet().joinRoom(this.state.newList); await Mjolnir.sharedInstance().subscribeToList(room.roomId); this.setState({ newList: "" }); // this will also cause the new rule to be rendered } catch (e) { logger.error(e); Modal.createDialog(ErrorDialog, { title: _t("labs_mjolnir|error_adding_list_title"), description: _t("labs_mjolnir|error_adding_list_description"), }); } finally { this.setState({ busy: false }); } }; private async removePersonalRule(rule: ListRule): Promise { this.setState({ busy: true }); try { const list = Mjolnir.sharedInstance().getPersonalList(); await list!.unbanEntity(rule.kind, rule.entity); } catch (e) { logger.error(e); Modal.createDialog(ErrorDialog, { title: _t("labs_mjolnir|error_removing_ignore"), description: _t("labs_mjolnir|something_went_wrong"), }); } finally { this.setState({ busy: false }); } } private async unsubscribeFromList(list: BanList): Promise { this.setState({ busy: true }); try { await Mjolnir.sharedInstance().unsubscribeFromList(list.roomId); await MatrixClientPeg.safeGet().leave(list.roomId); } catch (e) { logger.error(e); Modal.createDialog(ErrorDialog, { title: _t("labs_mjolnir|error_removing_list_title"), description: _t("labs_mjolnir|error_removing_list_description"), }); } finally { this.setState({ busy: false }); } } private viewListRules(list: BanList): void { const room = MatrixClientPeg.safeGet().getRoom(list.roomId); const name = room ? room.name : list.roomId; const renderRules = (rules: ListRule[]): JSX.Element => { if (rules.length === 0) return {_t("labs_mjolnir|rules_empty")}; const tiles: JSX.Element[] = []; for (const rule of rules) { tiles.push(
  • {rule.entity}
  • , ); } return
      {tiles}
    ; }; Modal.createDialog(QuestionDialog, { title: _t("labs_mjolnir|rules_title", { roomName: name }), description: (

    {_t("labs_mjolnir|rules_server")}

    {renderRules(list.serverRules)}

    {_t("labs_mjolnir|rules_user")}

    {renderRules(list.userRules)}
    ), button: _t("action|close"), hasCancelButton: false, }); } private renderPersonalBanListRules(): JSX.Element { const list = Mjolnir.sharedInstance().getPersonalList(); const rules = list ? [...list.userRules, ...list.serverRules] : []; if (!list || rules.length <= 0) return {_t("labs_mjolnir|personal_empty")}; const tiles: JSX.Element[] = []; for (const rule of rules) { tiles.push(
  • this.removePersonalRule(rule)} disabled={this.state.busy} > {_t("action|remove")}   {rule.entity}
  • , ); } return (

    {_t("labs_mjolnir|personal_section")}

      {tiles}
    ); } private renderSubscribedBanLists(): JSX.Element { const personalList = Mjolnir.sharedInstance().getPersonalList(); const lists = Mjolnir.sharedInstance().lists.filter((b) => { return personalList ? personalList.roomId !== b.roomId : true; }); if (!lists || lists.length <= 0) return {_t("labs_mjolnir|no_lists")}; const tiles: JSX.Element[] = []; for (const list of lists) { const room = MatrixClientPeg.safeGet().getRoom(list.roomId); const name = room ? ( {room.name} ({list.roomId}) ) : ( list.roomId ); tiles.push(
  • this.unsubscribeFromList(list)} disabled={this.state.busy} > {_t("action|unsubscribe")}   this.viewListRules(list)} disabled={this.state.busy} > {_t("labs_mjolnir|view_rules")}   {name}
  • , ); } return (

    {_t("labs_mjolnir|lists")}

      {tiles}
    ); } public render(): React.ReactNode { const brand = SdkConfig.get().brand; return ( {_t("labs_mjolnir|advanced_warning")}

    {_t("labs_mjolnir|explainer_1", { brand }, { code: (s) => {s} })}

    {_t("labs_mjolnir|explainer_2")}

    {this.renderPersonalBanListRules()}
    {_t("action|ignore")}
    {_t("labs_mjolnir|lists_description_1")}   {_t("labs_mjolnir|lists_description_2")} } > {this.renderSubscribedBanLists()}
    {_t("action|subscribe")}
    ); } }