diff --git a/storybook/pages/TokenMasterActionPopupPage.qml b/storybook/pages/TokenMasterActionPopupPage.qml
new file mode 100644
index 0000000000..4919c14550
--- /dev/null
+++ b/storybook/pages/TokenMasterActionPopupPage.qml
@@ -0,0 +1,147 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+import Qt.labs.settings 1.0
+
+import Storybook 1.0
+import Models 1.0
+
+import AppLayouts.Communities.popups 1.0
+
+
+SplitView {
+ orientation: Qt.Vertical
+
+ Logs { id: logs }
+
+ ListModel {
+ id: accountsModel
+
+ ListElement {
+ name: "Test account"
+ emoji: "😋"
+ address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
+ color: "red"
+ }
+
+ ListElement {
+ name: "Another account - generated"
+ emoji: "🚗"
+ address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8888"
+ color: "blue"
+ }
+ }
+
+ Item {
+ id: content
+
+ SplitView.fillWidth: true
+ SplitView.fillHeight: true
+
+ PopupBackground {
+ anchors.fill: parent
+ }
+
+ Button {
+ anchors.centerIn: parent
+ text: "Reopen"
+
+ onClicked: dialog.open()
+ }
+
+ TokenMasterActionPopup {
+ id: dialog
+
+ parent: content
+ visible: true
+ closePolicy: Popup.NoAutoClose
+ anchors.centerIn: parent
+ modal: false
+
+ actionType: actionTypesRadioButtonGroup.checkedButton.actionType
+
+ accountsModel: accountsModel
+ communityName: "Doodles"
+ userName: "simon"
+ networkName: "Optimism"
+
+ isFeeLoading: feeLoadingCheckBox.checked
+ feeText: "0.0015 ETH ($75.43)"
+ feeErrorText: feeErrorCheckBox.checked ? "Some fee error" : ""
+
+ onRemotelyDestructClicked: logs.logEvent("onRemotelyDestructClicked")
+ onBanClicked: logs.logEvent("onBanClicked")
+ onKickClicked: logs.logEvent("onKickClicked")
+ }
+ }
+
+ LogsAndControlsPanel {
+ SplitView.minimumHeight: 100
+ SplitView.preferredHeight: 150
+
+ logsView.logText: logs.logText
+
+ ColumnLayout {
+ RowLayout {
+ CheckBox {
+ id: feeLoadingCheckBox
+
+ text: "Loading fee"
+ }
+
+ CheckBox {
+ id: feeErrorCheckBox
+
+ text: "Fee error"
+ }
+ }
+
+ ButtonGroup {
+ id: actionTypesRadioButtonGroup
+
+ buttons: actionTypesRow.children
+ }
+
+ RowLayout {
+ id: actionTypesRow
+
+ RadioButton {
+ id: remotelyDestructRadioButton
+
+ readonly property int actionType:
+ TokenMasterActionPopup.ActionType.RemotelyDestruct
+
+ text: "Remotely destruct"
+ checked: true
+ }
+
+ RadioButton {
+ id: kickRadioButton
+
+ readonly property int actionType:
+ TokenMasterActionPopup.ActionType.Kick
+
+ text: "Kick"
+ }
+
+ RadioButton {
+ id: banRadioButton
+
+ readonly property int actionType:
+ TokenMasterActionPopup.ActionType.Ban
+
+ text: "Ban"
+ }
+ }
+ }
+ }
+
+ Settings {
+ property alias remotelyDestructRadioButtonChecked: remotelyDestructRadioButton.checked
+ property alias kickRadioButtonChecked: kickRadioButton.checked
+ property alias banRadioButtonChecked: banRadioButton.checked
+ }
+}
+
+// category: Popups
diff --git a/ui/app/AppLayouts/Communities/popups/TokenMasterActionPopup.qml b/ui/app/AppLayouts/Communities/popups/TokenMasterActionPopup.qml
new file mode 100644
index 0000000000..ddf66b912a
--- /dev/null
+++ b/ui/app/AppLayouts/Communities/popups/TokenMasterActionPopup.qml
@@ -0,0 +1,182 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import QtQml.Models 2.15
+
+import StatusQ.Core 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Popups.Dialog 0.1
+import StatusQ.Core.Theme 0.1
+
+import AppLayouts.Communities.panels 1.0
+
+import utils 1.0
+
+
+StatusDialog {
+ id: root
+
+ enum ActionType {
+ RemotelyDestruct, Kick, Ban
+ }
+
+ title: {
+ if (actionType === TokenMasterActionPopup.ActionType.Ban)
+ return qsTr("Ban %1").arg(userName)
+ if (actionType === TokenMasterActionPopup.ActionType.Kick)
+ return qsTr("Kick %1").arg(userName)
+
+ return qsTr("Remotely destruct TokenMaster token")
+ }
+
+ implicitWidth: 600
+
+ property int actionType: TokenMasterActionPopup.ActionType.RemotelyDestruct
+
+ property string communityName
+ property string userName
+ property string networkName
+
+ property string feeText
+ property string feeErrorText
+ property bool isFeeLoading
+ property var accountsModel
+
+ readonly property string feeLabel: qsTr("Remotely destruct 1 TokenMaster token on %1").arg(
+ root.networkName)
+
+ signal remotelyDestructClicked
+ signal kickClicked
+ signal banClicked
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 20
+
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: {
+ if (root.actionType === TokenMasterActionPopup.ActionType.RemotelyDestruct)
+ return qsTr('Continuing will destroy the TokenMaster token held by %1 and revoke the permissions they have by virtue of holding this token.')
+ .arg(root.userName)
+
+ if (root.actionType === TokenMasterActionPopup.ActionType.Kick)
+ return qsTr('Are you sure you kick %1 from %2? %1 is a TokenMaster hodler. In order to kick them you must also remotely destruct their TokenMaster token to revoke the permissions they have by virtue of holding this token.')
+ .arg(root.userName).arg(root.communityName)
+
+ if (root.actionType === TokenMasterActionPopup.ActionType.Ban)
+ return qsTr('Are you sure you ban %1 from %2? %1 is a TokenMaster hodler. In order to kick them you must also remotely destruct their TokenMaster token to revoke the permissions they have by virtue of holding this token.')
+ .arg(root.userName).arg(root.communityName)
+ }
+
+ textFormat: Text.RichText
+ wrapMode: Text.Wrap
+ lineHeight: 22
+ lineHeightMode: Text.FixedHeight
+ }
+
+ Rectangle {
+ Layout.bottomMargin: 2
+ Layout.preferredHeight: 1
+ Layout.fillWidth: true
+
+ visible: root.actionType
+ !== TokenMasterActionPopup.ActionType.RemotelyDestruct
+ color: Theme.palette.baseColor2
+ }
+
+ RowLayout {
+ visible: root.actionType === TokenMasterActionPopup.ActionType.Ban
+
+ StatusBaseText {
+ Layout.fillWidth: true
+
+ text: qsTr("Delete all messages posted by the user")
+ color: Theme.palette.directColor1
+ font.pixelSize: Theme.primaryTextFontSize
+ }
+
+ StatusSwitch {
+ id: deleteMessagesSwitch
+
+ checked: true
+ verticalPadding: 2
+ }
+ }
+
+ RowLayout {
+ Layout.bottomMargin: 2
+
+ visible: root.actionType
+ !== TokenMasterActionPopup.ActionType.RemotelyDestruct
+
+ StatusBaseText {
+ Layout.fillWidth: true
+
+ text: qsTr("Remotely destruct 1 TokenMaster token")
+ color: Theme.palette.directColor1
+ font.pixelSize: Theme.primaryTextFontSize
+ }
+
+ StatusSwitch {
+ id: remotelyDestructSwitch
+
+ checked: true
+ enabled: false
+ verticalPadding: 2
+ }
+ }
+
+ FeesBox {
+ Layout.fillWidth: true
+
+ implicitWidth: 0
+
+ accountsSelector.model: root.accountsModel
+ accountErrorText: root.feeErrorText
+
+ model: QtObject {
+ id: singleFeeModel
+
+ readonly property string title: root.feeLabel
+ readonly property string feeText: root.isFeeLoading ?
+ "" : root.feeText
+ readonly property bool error: root.feeErrorText !== ""
+ }
+ }
+ }
+
+ footer: StatusDialogFooter {
+ spacing: Style.current.padding
+
+ rightButtons: ObjectModel {
+ StatusFlatButton {
+ text: qsTr("Cancel")
+ onClicked: close()
+ }
+ StatusButton {
+ enabled: !root.isFeeLoading && root.feeErrorText === ""
+ && root.feeText !== ""
+ text: {
+ if (root.actionType === TokenMasterActionPopup.ActionType.Ban)
+ return qsTr("Ban %1 and remotely destruct 1 token").arg(root.userName)
+
+ if (root.actionType === TokenMasterActionPopup.ActionType.Kick)
+ return qsTr("Kick %1 and remotely destruct 1 token").arg(root.userName)
+
+ return qsTr("Remotely destruct 1 token")
+ }
+
+ type: StatusBaseButton.Type.Danger
+ onClicked: {
+ if (root.actionType === TokenMasterActionPopup.ActionType.RemotelyDestruct)
+ root.remotelyDestructClicked()
+ else if (root.actionType === TokenMasterActionPopup.ActionType.Ban)
+ root.banClicked()
+ else if (root.actionType === TokenMasterActionPopup.ActionType.Kick)
+ root.kickClicked()
+ }
+ }
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Communities/popups/qmldir b/ui/app/AppLayouts/Communities/popups/qmldir
index a1759c74bc..2e72ad691c 100644
--- a/ui/app/AppLayouts/Communities/popups/qmldir
+++ b/ui/app/AppLayouts/Communities/popups/qmldir
@@ -1,7 +1,6 @@
AlertPopup 1.0 AlertPopup.qml
BurnTokensPopup 1.0 BurnTokensPopup.qml
CommunityProfilePopup 1.0 CommunityProfilePopup.qml
-TokenPermissionsPopup 1.0 TokenPermissionsPopup.qml
CreateCategoryPopup 1.0 CreateCategoryPopup.qml
CreateChannelPopup 1.0 CreateChannelPopup.qml
CreateCommunityPopup 1.0 CreateCommunityPopup.qml
@@ -15,7 +14,9 @@ MembersDropdown 1.0 MembersDropdown.qml
PermissionsDropdown 1.0 PermissionsDropdown.qml
RecipientTypeSelectionDropdown 1.0 RecipientTypeSelectionDropdown.qml
RemotelyDestructPopup 1.0 RemotelyDestructPopup.qml
+SharedAddressesPopup 1.0 SharedAddressesPopup.qml
SignMultiTokenTransactionsPopup 1.0 SignMultiTokenTransactionsPopup.qml
SignTokenTransactionsPopup 1.0 SignTokenTransactionsPopup.qml
+TokenMasterActionPopup 1.0 TokenMasterActionPopup.qml
+TokenPermissionsPopup 1.0 TokenPermissionsPopup.qml
TransferOwnershipPopup 1.0 TransferOwnershipPopup.qml
-SharedAddressesPopup 1.0 SharedAddressesPopup.qml