feat(Community/FinaliseOwnership): Added finalise flow in the app

- Button from community column.
- Button from community overview.
- Updated storybook pages (settings overview related) according to new components requirements.

Part of #12174
This commit is contained in:
Noelia 2023-09-28 12:09:47 +02:00 committed by Noelia
parent 862d4f3add
commit 15927b0705
15 changed files with 377 additions and 154 deletions

View File

@ -1,6 +1,6 @@
import QtQuick 2.14 import QtQuick 2.15
import QtQuick.Controls 2.14 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.14 import QtQuick.Layouts 1.15
import Storybook 1.0 import Storybook 1.0
import Models 1.0 import Models 1.0
@ -40,7 +40,6 @@ SplitView {
communityName: communityNameText.text communityName: communityNameText.text
onCancelClicked: logs.logEvent("FinaliseOwnershipDeclinePopup::onCancelClicked")
onDeclineClicked: logs.logEvent("FinaliseOwnershipDeclinePopup::onDeclineClicked") onDeclineClicked: logs.logEvent("FinaliseOwnershipDeclinePopup::onDeclineClicked")
} }
} }

View File

@ -1,6 +1,6 @@
import QtQuick 2.14 import QtQuick 2.15
import QtQuick.Controls 2.14 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.14 import QtQuick.Layouts 1.15
import Storybook 1.0 import Storybook 1.0
import Models 1.0 import Models 1.0

View File

@ -6,19 +6,44 @@ import AppLayouts.Communities.panels 1.0
import utils 1.0 import utils 1.0
import Storybook 1.0
SplitView { SplitView {
id: root id: root
Item { Logs { id: logs }
id: wrapper
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.fillHeight: true Item {
OverviewSettingsFooter { id: wrapper
id: footer SplitView.fillWidth: true
width: parent.width SplitView.fillHeight: true
anchors.centerIn: parent
isControlNode: controlNodeSwitch.checked OverviewSettingsFooter {
communityName: "Socks" id: footer
width: parent.width
anchors.centerIn: parent
isControlNode: controlNodeSwitch.checked
isPendingOwnershipRequest: pendingOwnershipSwitch.checked
communityName: "Socks"
communityColor: "orange"
onExportControlNodeClicked: logs.logEvent("OverviewSettingsFooter::onExportControlNodeClicked")
onImportControlNodeClicked: logs.logEvent("OverviewSettingsFooter::onImportControlNodeClicked")
onLearnMoreClicked: logs.logEvent("OverviewSettingsFooter::onLearnMoreClicked")
onFinaliseOwnershipTransferClicked: logs.logEvent("OverviewSettingsFooter::onFinaliseOwnershipTransferClicked")
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: 150
logsView.logText: logs.logText
} }
} }
@ -32,6 +57,12 @@ SplitView {
text: "Control node on/off" text: "Control node on/off"
checked: true checked: true
} }
Switch {
id: pendingOwnershipSwitch
text: "Is there a pending transfer ownership request?"
checked: true
}
} }
} }
} }

View File

@ -24,15 +24,26 @@ SplitView {
communityShardingEnabled: communityEditor.shardingEnabled communityShardingEnabled: communityEditor.shardingEnabled
communityShardIndex: communityEditor.shardIndex communityShardIndex: communityEditor.shardIndex
isPendingOwnershipRequest: pendingOwnershipSwitch.checked
finaliseOwnershipTransferPopup: undefined
} }
Pane { Pane {
SplitView.minimumWidth: 300 SplitView.minimumWidth: 300
SplitView.preferredWidth: 300 SplitView.preferredWidth: 300
CommunityInfoEditor { ColumnLayout {
id: communityEditor CommunityInfoEditor{
anchors.fill: parent id: communityEditor
anchors.fill: parent
}
Switch {
id: pendingOwnershipSwitch
text: "Is there a pending transfer ownership request?"
checked: true
}
} }
} }
} }

View File

@ -6,13 +6,17 @@ import utils 1.0
import shared.popups 1.0 import shared.popups 1.0
import "views" import "views"
import AppLayouts.Communities.views 1.0
import "stores" import "stores"
import AppLayouts.Communities.views 1.0
import AppLayouts.Communities.popups 1.0 import AppLayouts.Communities.popups 1.0
import AppLayouts.Communities.helpers 1.0
import AppLayouts.Chat.stores 1.0 import AppLayouts.Chat.stores 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStore import AppLayouts.Wallet.stores 1.0 as WalletStore
import StatusQ.Core.Utils 0.1
StackLayout { StackLayout {
id: root id: root
@ -38,6 +42,11 @@ StackLayout {
signal profileButtonClicked() signal profileButtonClicked()
signal openAppSearch() signal openAppSearch()
// Community transfer ownership related props/signals:
// TODO: Backend integrations:
property bool isPendingOwnershipRequest: false
signal ownershipDeclined()
onCurrentIndexChanged: { onCurrentIndexChanged: {
Global.closeCreateChatView() Global.closeCreateChatView()
} }
@ -134,6 +143,9 @@ StackLayout {
collectiblesModel: root.rootStore.collectiblesModel collectiblesModel: root.rootStore.collectiblesModel
isInvitationPending: root.rootStore.isCommunityRequestPending(chatView.communityId) isInvitationPending: root.rootStore.isCommunityRequestPending(chatView.communityId)
finaliseOwnershipTransferPopup: finaliseOwnershipPopup
isPendingOwnershipRequest: root.isPendingOwnershipRequest
onCommunityInfoButtonClicked: root.currentIndex = 1 onCommunityInfoButtonClicked: root.currentIndex = 1
onCommunityManageButtonClicked: root.currentIndex = 1 onCommunityManageButtonClicked: root.currentIndex = 1
@ -170,6 +182,9 @@ StackLayout {
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
sendModalPopup: root.sendModalPopup sendModalPopup: root.sendModalPopup
finaliseOwnershipTransferPopup: finaliseOwnershipPopup
isPendingOwnershipRequest: root.isPendingOwnershipRequest
chatCommunitySectionModule: root.rootStore.chatCommunitySectionModule chatCommunitySectionModule: root.rootStore.chatCommunitySectionModule
community: sectionItemModel community: sectionItemModel
communitySettingsDisabled: root.communitySettingsDisabled communitySettingsDisabled: root.communitySettingsDisabled
@ -223,6 +238,94 @@ StackLayout {
} }
} }
// Components related to transfer community ownership flow:
Component {
id: finaliseOwnershipPopup
FinaliseOwnershipPopup {
id: finalisePopup
readonly property var communityData: root.sectionItemModel
readonly property var ownerToken: ModelUtils.getByKey(communityData.communityTokens,
"privilegesLevel",
Constants.TokenPrivilegesLevel.Owner)
communityName: communityData.name
communityLogo: communityData.image
communityColor: communityData.color
tokenSymbol: ownerToken.symbol
tokenChainName: ownerToken.chainName
accounts: WalletStore.RootStore.nonWatchAccounts
feeText: feeSubscriber.feeText
feeErrorText: feeSubscriber.feeErrorText
isFeeLoading: !feeSubscriber.feesResponse
onRejectClicked: Global.openPopup(declineOwnershipPopup)
onFinaliseOwnershipClicked: signPopup.open()
onVisitCommunityClicked: rootStore.setActiveCommunity(communityData.id)
onOpenControlNodeDocClicked: Global.openLink(link)
DeployFeesSubscriber {
id: feeSubscriber
readonly property TransactionFeesBroker feesBroker: TransactionFeesBroker {
communityTokensStore: root.rootStore.communityTokensStore
}
chainId: finalisePopup.ownerToken.chainId
tokenType: finalisePopup.ownerToken.type
isOwnerDeployment: true
accountAddress: finalisePopup.ownerToken.accountAddress
enabled: finalisePopup.visible || signPopup.visible
Component.onCompleted: feesBroker.registerDeployFeesSubscriber(feeSubscriber)
}
SignTransactionsPopup {
id: signPopup
title: qsTr("Sign transaction - update %1 smart contract").arg(finalisePopup.communityData.name)
totalFeeText: finalisePopup.isFeeLoading ? "" : finalisePopup.feeText
errorText: finalisePopup.feeErrorText
accountName: finalisePopup.ownerToken.accountName
model: QtObject {
readonly property string title: finalisePopup.feeLabel
readonly property string feeText: signPopup.totalFeeText
readonly property bool error: finalisePopup.feeErrorText !== ""
}
onSignTransactionClicked: {
root.rootStore.communityTokensStore.updateSmartContract(finalisePopup.communityData.id, finalisePopup.ownerToken)
close()
}
}
Connections {
target: root
onOwnershipDeclined: finalisePopup.close()
}
}
}
Component {
id: declineOwnershipPopup
FinaliseOwnershipDeclinePopup {
readonly property var communityData: root.sectionItemModel
communityName: communityData.name
onDeclineClicked: {
console.warn("TODO: Backend update notification center and display a toast: Ownership Declined!")
root.ownershipDeclined()
}
}
}
// End of components related to transfer community ownership flow.
Connections { Connections {
target: root.rootStore target: root.rootStore
enabled: mainViewLoader.item enabled: mainViewLoader.item

View File

@ -74,6 +74,10 @@ StatusSectionLayout {
return false return false
} }
// Community transfer ownership related props:
required property var finaliseOwnershipTransferPopup
required property bool isPendingOwnershipRequest
signal communityInfoButtonClicked() signal communityInfoButtonClicked()
signal communityManageButtonClicked() signal communityManageButtonClicked()
signal profileButtonClicked() signal profileButtonClicked()
@ -242,6 +246,8 @@ StatusSectionLayout {
communitiesStore: root.communitiesStore communitiesStore: root.communitiesStore
emojiPopup: root.emojiPopup emojiPopup: root.emojiPopup
hasAddedContacts: root.hasAddedContacts hasAddedContacts: root.hasAddedContacts
finaliseOwnershipTransferPopup: root.finaliseOwnershipTransferPopup
isPendingOwnershipRequest: root.isPendingOwnershipRequest
onInfoButtonClicked: root.communityInfoButtonClicked() onInfoButtonClicked: root.communityInfoButtonClicked()
onManageButtonClicked: root.communityManageButtonClicked() onManageButtonClicked: root.communityManageButtonClicked()
} }

View File

@ -6,11 +6,12 @@ import utils 1.0
/*! /*!
\qmltype SingleFeeSubscriber \qmltype SingleFeeSubscriber
\inherits QtObject \inherits QtObject
\brief Helper object that parses fees response and provides fee text and error text for single fee respnse \brief Helper object that parses fees response and provides fee text and error text for single fee response
*/ */
QtObject { QtObject {
id: root id: root
// Published properties // Published properties
property var feesResponse property var feesResponse

View File

@ -112,6 +112,7 @@ QtObject {
function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode, responseId) { function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode, responseId) {
d.feesBroker.response(responseId, { ethCurrency: ethCurrency, fiatCurrency: fiatCurrency, errorCode: errorCode }) d.feesBroker.response(responseId, { ethCurrency: ethCurrency, fiatCurrency: fiatCurrency, errorCode: errorCode })
} }
function onAirdropFeeUpdated(response) { function onAirdropFeeUpdated(response) {
d.feesBroker.response(response.requestId, response) d.feesBroker.response(response.requestId, response)
} }

View File

@ -12,12 +12,18 @@ import utils 1.0
Control { Control {
id: root id: root
property bool isControlNode: true property bool isControlNode: true
property string communityName: "" property string communityName: ""
property string communityColor: ""
// Community transfer ownership related props:
required property bool isPendingOwnershipRequest
signal exportControlNodeClicked signal exportControlNodeClicked
signal importControlNodeClicked signal importControlNodeClicked
signal learnMoreClicked signal learnMoreClicked
signal finaliseOwnershipTransferClicked
QtObject { QtObject {
id: d id: d
@ -31,6 +37,7 @@ Control {
property string secondaryButtonText property string secondaryButtonText
property string indicatorBgColor property string indicatorBgColor
property string indicatorColor property string indicatorColor
property string indicatorName
property var primaryButtonAction: root.exportControlNodeClicked property var primaryButtonAction: root.exportControlNodeClicked
} }
@ -45,7 +52,7 @@ Control {
Layout.column: 0 Layout.column: 0
color: d.indicatorBgColor color: d.indicatorBgColor
asset.color: d.indicatorColor asset.color: d.indicatorColor
asset.name: "desktop" asset.name: d.indicatorName
} }
ColumnLayout { ColumnLayout {
@ -103,25 +110,38 @@ Control {
// Behavior // Behavior
states: [ states: [
State {
name: "isPendingOwnershipRequest"
when: root.isPendingOwnershipRequest
PropertyChanges { target: d; indicatorBgColor: Theme.palette.alphaColor(root.communityColor, 0.1) }
PropertyChanges { target: d; indicatorColor: root.communityColor }
PropertyChanges { target: d; paragraphTitle: qsTr("Finalise your ownership of the %1 Community").arg(root.communityName) }
PropertyChanges { target: d; paragraphSubtitle: qsTr("You currently hodl the Owner token for %1. Make your device the control node to finalise ownership.").arg(root.communityName) }
PropertyChanges { target: d; primaryButtonText: qsTr("Finalise %1 ownership").arg(root.communityName) }
PropertyChanges { target: d; primaryButtonAction: root.finaliseOwnershipTransferClicked }
PropertyChanges { target: d; indicatorName: "crown" }
},
State { State {
name: "isControlNode" name: "isControlNode"
when: root.isControlNode when: root.isControlNode && !root.isPendingOwnershipRequest
PropertyChanges { target: d; indicatorBgColor: Theme.palette.successColor2 } PropertyChanges { target: d; indicatorBgColor: Theme.palette.successColor2 }
PropertyChanges { target: d; indicatorColor: Theme.palette.successColor1 } PropertyChanges { target: d; indicatorColor: Theme.palette.successColor1 }
PropertyChanges { target: d; paragraphTitle: qsTr("This device is currently the control node for the %1 Community").arg(root.communityName) } PropertyChanges { target: d; paragraphTitle: qsTr("This device is currently the control node for the %1 Community").arg(root.communityName) }
PropertyChanges { target: d; paragraphSubtitle: qsTr("For your Community to function correctly keep this device online with Status running as much as possible.") } PropertyChanges { target: d; paragraphSubtitle: qsTr("For your Community to function correctly keep this device online with Status running as much as possible.") }
PropertyChanges { target: d; primaryButtonText: qsTr("How to move control node") } PropertyChanges { target: d; primaryButtonText: qsTr("How to move control node") }
PropertyChanges { target: d; primaryButtonAction: root.exportControlNodeClicked } PropertyChanges { target: d; primaryButtonAction: root.exportControlNodeClicked }
PropertyChanges { target: d; indicatorName: "desktop" }
}, },
State { State {
name: "isNotControlNode" name: "isNotControlNode"
when: !root.isControlNode when: !root.isControlNode && !root.isPendingOwnershipRequest
PropertyChanges { target: d; indicatorBgColor: Theme.palette.primaryColor3 } PropertyChanges { target: d; indicatorBgColor: Theme.palette.primaryColor3 }
PropertyChanges { target: d; indicatorColor: Theme.palette.primaryColor1 } PropertyChanges { target: d; indicatorColor: Theme.palette.primaryColor1 }
PropertyChanges { target: d; paragraphTitle: qsTr("Make this device the control node for the %1 Community").arg(root.communityName) } PropertyChanges { target: d; paragraphTitle: qsTr("Make this device the control node for the %1 Community").arg(root.communityName) }
PropertyChanges { target: d; paragraphSubtitle: qsTr("Ensure this is a device you can keep online with Status running.") } PropertyChanges { target: d; paragraphSubtitle: qsTr("Ensure this is a device you can keep online with Status running.") }
PropertyChanges { target: d; primaryButtonText: qsTr("Make this device the control node") } PropertyChanges { target: d; primaryButtonText: qsTr("Make this device the control node") }
PropertyChanges { target: d; primaryButtonAction: root.importControlNodeClicked } PropertyChanges { target: d; primaryButtonAction: root.importControlNodeClicked }
PropertyChanges { target: d; indicatorName: "desktop" }
} }
] ]
} }

View File

@ -53,6 +53,10 @@ StackLayout {
property bool communityShardingEnabled property bool communityShardingEnabled
property int communityShardIndex: -1 property int communityShardIndex: -1
// Community transfer ownership related props:
required property var finaliseOwnershipTransferPopup
required property bool isPendingOwnershipRequest
function navigateBack() { function navigateBack() {
if (editSettingsPanelLoader.item.dirty) if (editSettingsPanelLoader.item.dirty)
settingsDirtyToastMessage.notifyDirty() settingsDirtyToastMessage.notifyDirty()
@ -176,13 +180,17 @@ StackLayout {
Component { Component {
id: overviewSettingsFooterComp id: overviewSettingsFooterComp
OverviewSettingsFooter { OverviewSettingsFooter {
rightPadding: 64 rightPadding: 64
leftPadding: 64 leftPadding: 64
bottomPadding: 64 bottomPadding: 64
topPadding: 0 topPadding: 0
communityName: root.name communityName: root.name
communityColor: root.color
isControlNode: root.isControlNode isControlNode: root.isControlNode
isPendingOwnershipRequest: root.isPendingOwnershipRequest
onExportControlNodeClicked:{ onExportControlNodeClicked:{
if(!!root.ownerToken && root.ownerToken.deployState === Constants.ContractTransactionStatus.Completed) { if(!!root.ownerToken && root.ownerToken.deployState === Constants.ContractTransactionStatus.Completed) {
root.exportControlNodeClicked() root.exportControlNodeClicked()
@ -191,6 +199,7 @@ StackLayout {
} }
} }
onImportControlNodeClicked: root.importControlNodeClicked() onImportControlNodeClicked: root.importControlNodeClicked()
onFinaliseOwnershipTransferClicked: Global.openPopup(root.finaliseOwnershipTransferPopup)
//TODO update once the domain changes //TODO update once the domain changes
onLearnMoreClicked: Global.openLink(Constants.statusHelpLinkPrefix + "status-communities/about-the-control-node-in-status-communities") onLearnMoreClicked: Global.openLink(Constants.statusHelpLinkPrefix + "status-communities/about-the-control-node-in-status-communities")
} }

View File

@ -20,27 +20,20 @@ StatusDialog {
width: 480 // by design width: 480 // by design
padding: Style.current.padding padding: Style.current.padding
title: qsTr("Are you sure you dont want to be the owner?")
contentItem: StatusBaseText { contentItem: StatusBaseText {
wrapMode: Text.WrapAtWordBoundaryOrAnywhere wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: qsTr("If you dont want to be the owner of the %1 Community it is important that you let the previous owner know so they can organise another owner to take over. You will have to send the Owner token back to them or on to the next designated owner.").arg(root.communityName) text: qsTr("If you dont want to be the owner of the %1 Community it is important that you let the previous owner know so they can organise another owner to take over. You will have to send the Owner token back to them or on to the next designated owner.").arg(root.communityName)
lineHeight: 1.2 lineHeight: 1.2
} }
header: StatusDialogHeader {
headline.title: qsTr("Are you sure you dont want to be the owner?")
actions.closeButton.onClicked: root.close()
}
footer: StatusDialogFooter { footer: StatusDialogFooter {
spacing: Style.current.padding spacing: Style.current.padding
rightButtons: ObjectModel { rightButtons: ObjectModel {
StatusFlatButton { StatusFlatButton {
text: qsTr("Cancel") text: qsTr("Cancel")
onClicked: { onClicked: close()
root.cancelClicked()
close()
}
} }
StatusButton { StatusButton {

View File

@ -43,7 +43,7 @@ StatusDialog {
QtObject { QtObject {
id: d id: d
readonly property string controlNodeLink: "https://help.status.im/en/status-communities/about-the-control-node-in-status-communities/" readonly property string controlNodeLink: Constants.statusHelpLinkPrefix + "status-communities/about-the-control-node-in-status-communities/"
readonly property int init: 0 readonly property int init: 0
readonly property int finalise: 1 readonly property int finalise: 1
@ -149,8 +149,6 @@ StatusDialog {
StatusButton { StatusButton {
id: acceptBtn id: acceptBtn
type: StatusBaseButton.Type.Normal
} }
} }
leftButtons: ObjectModel { leftButtons: ObjectModel {
@ -171,7 +169,7 @@ StatusDialog {
CustomText { CustomText {
textFormat: Text.RichText textFormat: Text.RichText
text: qsTr("To finalise your ownership and assume ultimate admin rights for the %1 Community, you need to make your device the Community's <a style=\"color: inherit;\" href=\"%2\">control node</a><a style=\"color: inherit;text-decoration: none\" href=\"%2\">↗</a>. You will also need to sign a small transaction to update the %1 Community smart contract to make you the official signatory for all Community changes.").arg(root.communityName).arg(d.controlNodeLink) text: qsTr("To finalise your ownership and assume ultimate admin rights for the %1 Community, you need to make your device the Community's <a style=\"color:%3;\" href=\"%2\">control node</a><a style=\"color:%3;text-decoration: none\" href=\"%2\">↗</a>. You will also need to sign a small transaction to update the %1 Community smart contract to make you the official signatory for all Community changes.").arg(root.communityName).arg(d.controlNodeLink).arg(color)
onLinkActivated: root.openControlNodeDocClicked(link) onLinkActivated: root.openControlNodeDocClicked(link)
} }
@ -196,6 +194,7 @@ StatusDialog {
radius: 8 radius: 8
border.color: Theme.palette.baseColor2 border.color: Theme.palette.baseColor2
color: "transparent"
ColumnLayout { ColumnLayout {
id: boxContent id: boxContent

View File

@ -40,6 +40,10 @@ Item {
property bool hasAddedContacts: false property bool hasAddedContacts: false
property var communityData property var communityData
// Community transfer ownership related props:
required property var finaliseOwnershipTransferPopup
required property bool isPendingOwnershipRequest
readonly property bool isSectionAdmin: readonly property bool isSectionAdmin:
communityData.memberRole === Constants.memberRole.owner || communityData.memberRole === Constants.memberRole.owner ||
communityData.memberRole === Constants.memberRole.admin || communityData.memberRole === Constants.memberRole.admin ||
@ -48,6 +52,13 @@ Item {
signal infoButtonClicked signal infoButtonClicked
signal manageButtonClicked signal manageButtonClicked
QtObject {
id: d
readonly property bool showJoinButton: !communityData.joined || root.communityData.amIBanned
readonly property bool showFinaliseOwnershipButton: root.isPendingOwnershipRequest
}
ColumnHeaderPanel { ColumnHeaderPanel {
id: communityHeader id: communityHeader
@ -64,98 +75,21 @@ Item {
onAdHocChatButtonClicked: root.store.openCloseCreateChatView() onAdHocChatButtonClicked: root.store.openCloseCreateChatView()
} }
StatusButton { Loader {
id: joinCommunityButton id: columnHeaderButton
property bool invitationPending: root.store.isCommunityRequestPending(communityData.id)
anchors.top: communityHeader.bottom anchors.top: communityHeader.bottom
anchors.topMargin: Style.current.halfPadding anchors.topMargin: Style.current.halfPadding
anchors.bottomMargin: Style.current.halfPadding anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
enabled: !root.communityData.amIBanned sourceComponent: d.showFinaliseOwnershipButton ? finaliseCommunityOwnershipBtn :
d.showJoinButton ? joinCommunityButton : undefined
visible: !communityData.joined || root.communityData.amIBanned
text: {
if (root.communityData.amIBanned) return qsTr("You were banned from community")
if (invitationPending) return qsTr("Membership request pending...")
return root.communityData.access === Constants.communityChatOnRequestAccess ?
qsTr("Request to join") : qsTr("Join Community")
}
onClicked: {
Global.openPopup(communityIntroDialog);
}
Connections {
enabled: joinCommunityButton.loading
target: root.store.communitiesModuleInst
function onCommunityAccessRequested(communityId: string) {
if (communityId === communityData.id) {
joinCommunityButton.invitationPending = root.store.isCommunityRequestPending(communityData.id)
joinCommunityButton.loading = false
}
}
function onCommunityAccessFailed(communityId: string) {
if (communityId === communityData.id) {
joinCommunityButton.invitationPending = false
joinCommunityButton.loading = false
Global.displayToastMessage(qsTr("Request to join failed"),
qsTr("Please try again later"),
"",
false,
Constants.ephemeralNotificationType.normal,
"")
}
}
function onUserAuthenticationCanceled() {
joinCommunityButton.invitationPending = false
joinCommunityButton.loading = false
}
}
Component {
id: communityIntroDialog
CommunityIntroDialog {
isInvitationPending: joinCommunityButton.invitationPending
requirementsCheckPending: root.store.requirementsCheckPending
name: communityData.name
introMessage: communityData.introMessage
imageSrc: communityData.image
accessType: communityData.access
loginType: root.store.loginType
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
permissionsModel: {
root.store.prepareTokenModelForCommunity(communityData.id)
return root.store.permissionsModel
}
assetsModel: root.store.assetsModel
collectiblesModel: root.store.collectiblesModel
onJoined: {
joinCommunityButton.loading = true
root.store.requestToJoinCommunityWithAuthentication(communityData.id, root.store.userProfileInst.name, sharedAddresses, airdropAddress)
}
onCancelMembershipRequest: {
root.store.cancelPendingRequest(communityData.id)
joinCommunityButton.invitationPending = root.store.isCommunityRequestPending(communityData.id)
}
onSharedAddressesUpdated: {
root.store.updatePermissionsModel(communityData.id, sharedAddresses)
}
onClosed: destroy()
}
}
} }
ChatsLoadingPanel { ChatsLoadingPanel {
chatSectionModule: root.communitySectionModule chatSectionModule: root.communitySectionModule
width: parent.width width: parent.width
anchors.top: joinCommunityButton.visible ? joinCommunityButton.bottom : communityHeader.bottom anchors.top: columnHeaderButton.sourceComponent !== undefined ? columnHeaderButton.bottom : communityHeader.bottom
anchors.topMargin: active ? Style.current.halfPadding : 0 anchors.topMargin: active ? Style.current.halfPadding : 0
} }
@ -208,7 +142,8 @@ Item {
StatusScrollView { StatusScrollView {
id: scrollView id: scrollView
anchors.top: joinCommunityButton.visible ? joinCommunityButton.bottom : communityHeader.bottom
anchors.top: columnHeaderButton.sourceComponent !== undefined ? columnHeaderButton.bottom : communityHeader.bottom
anchors.topMargin: Style.current.halfPadding anchors.topMargin: Style.current.halfPadding
anchors.bottom: createChatOrCommunity.top anchors.bottom: createChatOrCommunity.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@ -246,8 +181,8 @@ Item {
onChatListCategoryReordered: root.store.reorderCommunityCategories(categoryId, to) onChatListCategoryReordered: root.store.reorderCommunityCategories(categoryId, to)
onCategoryAddButtonClicked: Global.openPopup(createChannelPopup, { onCategoryAddButtonClicked: Global.openPopup(createChannelPopup, {
categoryId: id categoryId: id
}) })
popupMenu: StatusMenu { popupMenu: StatusMenu {
StatusAction { StatusAction {
@ -314,12 +249,12 @@ Item {
text: qsTr("Edit Category") text: qsTr("Edit Category")
icon.name: "edit" icon.name: "edit"
onTriggered: { onTriggered: {
Global.openPopup(createCategoryPopup, { Global.openPopup(createCategoryPopup, {
isEdit: true, isEdit: true,
channels: [], channels: [],
categoryId: categoryItem.itemId, categoryId: categoryItem.itemId,
categoryName: categoryItem.name categoryName: categoryItem.name
}) })
} }
} }
@ -335,11 +270,11 @@ Item {
type: StatusAction.Type.Danger type: StatusAction.Type.Danger
onTriggered: { onTriggered: {
Global.openPopup(deleteCategoryConfirmationDialogComponent, { Global.openPopup(deleteCategoryConfirmationDialogComponent, {
"headerSettings.title": qsTr("Delete '%1' category").arg(categoryItem.name), "headerSettings.title": qsTr("Delete '%1' category").arg(categoryItem.name),
confirmationText: qsTr("Are you sure you want to delete '%1' category? Channels inside the category won't be deleted.") confirmationText: qsTr("Are you sure you want to delete '%1' category? Channels inside the category won't be deleted.")
.arg(categoryItem.name), .arg(categoryItem.name),
categoryId: categoryItem.itemId categoryId: categoryItem.itemId
}) })
} }
} }
} }
@ -415,14 +350,14 @@ Item {
onEditCommunityChannel: { onEditCommunityChannel: {
communitySectionModule.editCommunityChannel( communitySectionModule.editCommunityChannel(
chatId, chatId,
newName, newName,
newDescription, newDescription,
newEmoji, newEmoji,
newColor, newColor,
newCategory, newCategory,
channelPosition // TODO change this to the signal once it is modifiable channelPosition // TODO change this to the signal once it is modifiable
) )
} }
} }
} }
@ -458,16 +393,16 @@ Item {
width: parent.width width: parent.width
height: item.height height: item.height
sourceComponent: Component { sourceComponent: Component {
ChannelsAndCategoriesBannerPanel { ChannelsAndCategoriesBannerPanel {
id: channelsAndCategoriesBanner id: channelsAndCategoriesBanner
communityId: communityData.id communityId: communityData.id
onAddMembersClicked: { onAddMembersClicked: {
Global.openPopup(createChannelPopup); Global.openPopup(createChannelPopup);
}
onAddCategoriesClicked: {
Global.openPopup(createCategoryPopup);
}
} }
onAddCategoriesClicked: {
Global.openPopup(createCategoryPopup);
}
}
} }
} // Loader } // Loader
} // Column } // Column
@ -510,22 +445,126 @@ Item {
adminPopupMenu.showInviteButton = false adminPopupMenu.showInviteButton = false
adminPopupMenu.popup() adminPopupMenu.popup()
adminPopupMenu.y = Qt.binding(() => root.height - adminPopupMenu.height adminPopupMenu.y = Qt.binding(() => root.height - adminPopupMenu.height
- createChannelOrCategoryBtn.height - 20) - createChannelOrCategoryBtn.height - 20)
} }
} }
} }
} }
} }
Component {
id: joinCommunityButton
StatusButton {
property bool invitationPending: root.store.isCommunityRequestPending(communityData.id)
anchors.top: communityHeader.bottom
anchors.topMargin: Style.current.halfPadding
anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
enabled: !root.communityData.amIBanned
text: {
if (root.communityData.amIBanned) return qsTr("You were banned from community")
if (invitationPending) return qsTr("Membership request pending...")
return root.communityData.access === Constants.communityChatOnRequestAccess ?
qsTr("Request to join") : qsTr("Join Community")
}
onClicked: {
Global.openPopup(communityIntroDialog);
}
Connections {
enabled: joinCommunityButton.loading
target: root.store.communitiesModuleInst
function onCommunityAccessRequested(communityId: string) {
if (communityId === communityData.id) {
joinCommunityButton.invitationPending = root.store.isCommunityRequestPending(communityData.id)
joinCommunityButton.loading = false
}
}
function onCommunityAccessFailed(communityId: string) {
if (communityId === communityData.id) {
joinCommunityButton.invitationPending = false
joinCommunityButton.loading = false
Global.displayToastMessage(qsTr("Request to join failed"),
qsTr("Please try again later"),
"",
false,
Constants.ephemeralNotificationType.normal,
"")
}
}
function onUserAuthenticationCanceled() {
joinCommunityButton.invitationPending = false
joinCommunityButton.loading = false
}
}
Component {
id: communityIntroDialog
CommunityIntroDialog {
isInvitationPending: joinCommunityButton.invitationPending
requirementsCheckPending: root.store.requirementsCheckPending
name: communityData.name
introMessage: communityData.introMessage
imageSrc: communityData.image
accessType: communityData.access
loginType: root.store.loginType
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
permissionsModel: {
root.store.prepareTokenModelForCommunity(communityData.id)
return root.store.permissionsModel
}
assetsModel: root.store.assetsModel
collectiblesModel: root.store.collectiblesModel
onJoined: {
joinCommunityButton.loading = true
root.store.requestToJoinCommunityWithAuthentication(communityData.id, root.store.userProfileInst.name, sharedAddresses, airdropAddress)
}
onCancelMembershipRequest: {
root.store.cancelPendingRequest(communityData.id)
joinCommunityButton.invitationPending = root.store.isCommunityRequestPending(communityData.id)
}
onSharedAddressesUpdated: {
root.store.updatePermissionsModel(communityData.id, sharedAddresses)
}
onClosed: destroy()
}
}
}
}
Component {
id: finaliseCommunityOwnershipBtn
StatusButton {
anchors.top: communityHeader.bottom
anchors.topMargin: Style.current.halfPadding
anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
text: communityData.joined ? qsTr("Finalise community ownership") : qsTr("To join, finalise community ownership")
onClicked: Global.openPopup(root.finaliseOwnershipTransferPopup)
}
}
Component { Component {
id: createChannelPopup id: createChannelPopup
CreateChannelPopup { CreateChannelPopup {
communitiesStore: root.communitiesStore communitiesStore: root.communitiesStore
emojiPopup: root.emojiPopup emojiPopup: root.emojiPopup
onCreateCommunityChannel: function (chName, chDescription, chEmoji, chColor, onCreateCommunityChannel: function (chName, chDescription, chEmoji, chColor,
chCategoryId) { chCategoryId) {
root.store.createCommunityChannel(chName, chDescription, chEmoji, chColor, root.store.createCommunityChannel(chName, chDescription, chEmoji, chColor,
chCategoryId) chCategoryId)
} }
onClosed: { onClosed: {
destroy() destroy()

View File

@ -44,6 +44,10 @@ StatusSectionLayout {
readonly property bool isTokenMasterOwner: community.memberRole === Constants.memberRole.tokenMaster readonly property bool isTokenMasterOwner: community.memberRole === Constants.memberRole.tokenMaster
readonly property bool isControlNode: community.isControlNode readonly property bool isControlNode: community.isControlNode
// Community transfer ownership related props:
required property var finaliseOwnershipTransferPopup
required property bool isPendingOwnershipRequest
readonly property string filteredSelectedTags: { readonly property string filteredSelectedTags: {
let tagsArray = [] let tagsArray = []
if (community && community.tags) { if (community && community.tags) {
@ -187,6 +191,9 @@ StatusSectionLayout {
tokensModel: root.community.communityTokens tokensModel: root.community.communityTokens
accounts: root.walletAccountsModel accounts: root.walletAccountsModel
finaliseOwnershipTransferPopup: root.finaliseOwnershipTransferPopup
isPendingOwnershipRequest: root.isPendingOwnershipRequest
onCollectCommunityMetricsMessagesCount: { onCollectCommunityMetricsMessagesCount: {
rootStore.collectCommunityMetricsMessagesCount(intervals) rootStore.collectCommunityMetricsMessagesCount(intervals)
} }

View File

@ -60,6 +60,10 @@ QtObject {
communityTokensModuleInst.removeCommunityToken(communityId, parts[0], parts[1]) communityTokensModuleInst.removeCommunityToken(communityId, parts[0], parts[1])
} }
function updateSmartContract(communityId, collectibleItem) {
console.warn("TODO: Backend to update smart contract and finalise community transfer ownership! The token owner is: " + collectibleItem.symbol)
}
readonly property Connections connections: Connections { readonly property Connections connections: Connections {
target: communityTokensModuleInst target: communityTokensModuleInst