feat(BurnToken): Add fee box with network selector to Burn popup

- It adds fee box into the Burn popup component.
- It updates storybook accordingly.

Closes #11609
This commit is contained in:
Noelia 2023-08-07 15:31:07 +02:00 committed by Noelia
parent 15701e91aa
commit d136d9bb67
5 changed files with 151 additions and 18 deletions

View File

@ -10,6 +10,24 @@ import AppLayouts.Communities.popups 1.0
SplitView { SplitView {
Logs { id: logs } 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"
}
}
SplitView { SplitView {
orientation: Qt.Vertical orientation: Qt.Vertical
SplitView.fillWidth: true SplitView.fillWidth: true
@ -38,6 +56,8 @@ SplitView {
remainingTokens: editorAmount.text remainingTokens: editorAmount.text
isAsset: assetButton.checked isAsset: assetButton.checked
tokenSource: assetButton.checked ? ModelsData.assets.socks : ModelsData.collectibles.kitty1Big tokenSource: assetButton.checked ? ModelsData.assets.socks : ModelsData.collectibles.kitty1Big
accounts: accountsModel
chainName: "Optimism"
onBurnClicked: logs.logEvent("BurnTokensPopup::onBurnClicked --> Burn amount: " + burnAmount) onBurnClicked: logs.logEvent("BurnTokensPopup::onBurnClicked --> Burn amount: " + burnAmount)
onCancelClicked: logs.logEvent("BurnTokensPopup::onCancelClicked") onCancelClicked: logs.logEvent("BurnTokensPopup::onCancelClicked")

View File

@ -66,12 +66,13 @@ StackView {
signal mintOwnerToken(var ownerToken, var tMasterToken) signal mintOwnerToken(var ownerToken, var tMasterToken)
signal deployFeesRequested(int chainId, string accountAddress, int tokenType) signal deployFeesRequested(int chainId, string accountAddress, int tokenType)
signal burnFeesRequested(string tokenKey, int amount, string accountAddress)
signal signRemoteDestructTransactionOpened(var remotelyDestructTokensList, // [key , amount] signal signRemoteDestructTransactionOpened(var remotelyDestructTokensList, // [key , amount]
string tokenKey) string tokenKey)
signal remotelyDestructCollectibles(var remotelyDestructTokensList, // [key , amount] signal remotelyDestructCollectibles(var remotelyDestructTokensList, // [key , amount]
string tokenKey) string tokenKey)
signal signBurnTransactionOpened(string tokenKey, int amount) signal signBurnTransactionOpened(string tokenKey, int amount, string accountAddress)
signal burnToken(string tokenKey, int amount) signal burnToken(string tokenKey, int amount, string accountAddress)
signal airdropToken(string tokenKey, int type, var addresses) signal airdropToken(string tokenKey, int type, var addresses)
signal deleteToken(string tokenKey) signal deleteToken(string tokenKey)
@ -642,6 +643,7 @@ StackView {
// helper properties to pass data through popups // helper properties to pass data through popups
property var remotelyDestructTokensList property var remotelyDestructTokensList
property int burnAmount property int burnAmount
property string accountAddress
RemotelyDestructPopup { RemotelyDestructPopup {
id: remotelyDestructPopup id: remotelyDestructPopup
@ -685,9 +687,9 @@ StackView {
root.remotelyDestructCollectibles( root.remotelyDestructCollectibles(
footer.remotelyDestructTokensList, tokenKey) footer.remotelyDestructTokensList, tokenKey)
else else
root.burnToken(tokenKey, footer.burnAmount) root.burnToken(tokenKey, footer.burnAmount, footer.accountAddress)
footerPanel.closePopups() footer.closePopups()
} }
title: signTransactionPopup.isRemotelyDestructTransaction title: signTransactionPopup.isRemotelyDestructTransaction
@ -705,7 +707,7 @@ StackView {
root.setFeeLoading() root.setFeeLoading()
signTransactionPopup.isRemotelyDestructTransaction signTransactionPopup.isRemotelyDestructTransaction
? root.signRemoteDestructTransactionOpened(footer.remotelyDestructTokensList, tokenKey) ? root.signRemoteDestructTransactionOpened(footer.remotelyDestructTokensList, tokenKey)
: root.signBurnTransactionOpened(tokenKey, footer.burnAmount) : root.signBurnTransactionOpened(tokenKey, footer.burnAmount, footer.accountAddress)
} }
onSignTransactionClicked: signTransaction() onSignTransactionClicked: signTransaction()
} }
@ -717,10 +719,19 @@ StackView {
tokenName: footer.token.name tokenName: footer.token.name
remainingTokens: footer.token.remainingTokens remainingTokens: footer.token.remainingTokens
tokenSource: footer.token.artworkSource tokenSource: footer.token.artworkSource
chainName: footer.token.chainName
feeText: root.feeText
feeErrorText: root.feeErrorText
isFeeLoading: root.isFeeLoading
accounts: root.accounts
onBurnFeesRequested: root.burnFeesRequested(footer.token.key, burnAmount, accountAddress)
onBurnClicked: { onBurnClicked: {
burnTokensPopup.close() burnTokensPopup.close()
footer.burnAmount = burnAmount footer.burnAmount = burnAmount
footer.accountAddress = accountAddress
signTransactionPopup.isRemotelyDestructTransaction = false signTransactionPopup.isRemotelyDestructTransaction = false
signTransactionPopup.open() signTransactionPopup.open()
} }

View File

@ -3,35 +3,52 @@ import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14 import QtQuick.Layouts 1.14
import QtQml.Models 2.14 import QtQml.Models 2.14
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQml 2.15
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Controls.Validators 0.1 import StatusQ.Controls.Validators 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import AppLayouts.Communities.panels 1.0 import AppLayouts.Communities.panels 1.0
import AppLayouts.Communities.helpers 1.0
import utils 1.0 import utils 1.0
import SortFilterProxyModel 0.2
StatusDialog { StatusDialog {
id: root id: root
property string communityName property string communityName
property bool isAsset // If asset isAsset = true; if collectible --> isAsset = false
property string tokenName property string tokenName
property int remainingTokens property int remainingTokens
property url tokenSource property url tokenSource
property bool isAsset // If asset isAsset = true; if collectible --> isAsset = false property string chainName
signal burnClicked(int burnAmount) // Fees related properties:
property string feeText
property string feeErrorText: ""
property bool isFeeLoading
readonly property string feeLabel: qsTr("Burn %1 token on %2").arg(root.tokenName).arg(root.chainName)
// Account expected roles: address, name, color, emoji, walletType
property var accounts
signal burnClicked(int burnAmount, string accountAddress)
signal cancelClicked signal cancelClicked
signal burnFeesRequested(int burnAmount, string accountAddress)
QtObject { QtObject {
id: d id: d
property string accountAddress
property alias amountToBurn: amountToBurnInput.text property alias amountToBurn: amountToBurnInput.text
readonly property bool isFeeError: root.feeErrorText !== ""
readonly property bool isFormValid: specificAmountButton.checked && amountToBurnInput.valid || allTokensButton.checked
function initialize() { function initialize() {
specificAmountButton.checked = true specificAmountButton.checked = true
@ -117,10 +134,85 @@ StatusDialog {
ButtonGroup { id: radioGroup } ButtonGroup { id: radioGroup }
} }
StatusDialogDivider {
Layout.fillWidth: true
}
FeesBox {
id: feesBox
readonly property bool triggerFeeReevaluation: {
specificAmountButton.checked
amountToBurnInput.text
allTokensButton.checked
feesBox.accountsSelector.currentIndex
requestFeeDelayTimer.restart()
return true
}
Layout.fillWidth: true
placeholderText: qsTr("Choose number of tokens to burn to see gas fees")
accountErrorText: root.feeErrorText
implicitWidth: 0
model: d.isFormValid ? singleFeeModel : undefined
accountsSelector.model: SortFilterProxyModel {
sourceModel: root.accounts
proxyRoles: [
ExpressionRole {
name: "color"
function getColor(colorId) {
return Utils.getColorForId(colorId)
}
// Direct call for singleton function is not handled properly by
// SortFilterProxyModel that's why helper function is used instead.
expression: { return getColor(model.colorId) }
}
]
filters: ValueFilter {
roleName: "walletType"
value: Constants.watchWalletType
inverted: true
}
}
accountsSelector.onCurrentIndexChanged: {
if (accountsSelector.currentIndex < 0)
return
const item = SQUtils.ModelUtils.get(accountsSelector.model, accountsSelector.currentIndex)
d.accountAddress = item.address
}
Timer {
id: requestFeeDelayTimer
interval: 500
onTriggered: {
if(specificAmountButton.checked)
root.burnFeesRequested(parseInt(amountToBurnInput.text), d.accountAddress)
else
root.burnFeesRequested(root.remainingTokens, d.accountAddress)
}
}
QtObject {
id: singleFeeModel
readonly property string title: root.feeLabel
readonly property string feeText: root.isFeeLoading ?
"" : root.feeText
readonly property bool error: d.isFeeError
}
}
} }
header: StatusDialogHeader { header: StatusDialogHeader {
headline.title: qsTr("Burn %1 tokens").arg(root.tokenName) headline.title: qsTr("Burn %1 tokens").arg(root.tokenName)
headline.subtitle: qsTr("%n %1 remaining in smart contract", "", root.remainingTokens).arg(root.tokenName) headline.subtitle: qsTr("%n %1 remaining in smart contract", "", root.remainingTokens).arg(root.tokenName)
leftComponent: Rectangle { leftComponent: Rectangle {
height: 40 height: 40
@ -160,14 +252,14 @@ StatusDialog {
} }
StatusButton { StatusButton {
enabled: specificAmountButton.checked && amountToBurnInput.valid || allTokensButton.checked enabled: d.isFormValid && !d.isFeeError && !root.isFeeLoading
text: qsTr("Burn tokens") text: qsTr("Burn tokens")
type: StatusBaseButton.Type.Danger type: StatusBaseButton.Type.Danger
onClicked: { onClicked: {
if(specificAmountButton.checked) if(specificAmountButton.checked)
root.burnClicked(parseInt(amountToBurnInput.text)) root.burnClicked(parseInt(amountToBurnInput.text), d.accountAddress)
else else
root.burnClicked(root.remainingTokens) root.burnClicked(root.remainingTokens, d.accountAddress)
} }
} }
} }

View File

@ -361,6 +361,14 @@ StatusSectionLayout {
chainId, accountAddress, tokenType) chainId, accountAddress, tokenType)
} }
onBurnFeesRequested: {
feeText = ""
feeErrorText = ""
isFeeLoading = true
communityTokensStore.computeBurnFee(tokenKey, amount, accountAddress)
}
onMintCollectible: onMintCollectible:
communityTokensStore.deployCollectible( communityTokensStore.deployCollectible(
root.community.id, collectibleItem) root.community.id, collectibleItem)
@ -381,10 +389,10 @@ StatusSectionLayout {
root.community.id, remotelyDestructTokensList, tokenKey) root.community.id, remotelyDestructTokensList, tokenKey)
onSignBurnTransactionOpened: onSignBurnTransactionOpened:
communityTokensStore.computeBurnFee(tokenKey, amount) communityTokensStore.computeBurnFee(tokenKey, amount, accountAddress)
onBurnToken: onBurnToken:
communityTokensStore.burnToken(root.community.id, tokenKey, amount) communityTokensStore.burnToken(root.community.id, tokenKey, amount, accountAddress)
onDeleteToken: onDeleteToken:
communityTokensStore.deleteToken(root.community.id, tokenKey) communityTokensStore.deleteToken(root.community.id, tokenKey)

View File

@ -109,12 +109,14 @@ QtObject {
} }
// Burn: // Burn:
function computeBurnFee(tokenKey, amount) { function computeBurnFee(tokenKey, amount, accountAddress) {
communityTokensModuleInst.computeBurnFee(tokenKey, amount) // TODO: Backend. It should include the account address in the calculation.
communityTokensModuleInst.computeBurnFee(tokenKey, amount/*, accountAddress*/)
} }
function burnToken(communityId, tokenKey, burnAmount) { function burnToken(communityId, tokenKey, burnAmount, accountAddress) {
communityTokensModuleInst.burnTokens(communityId, tokenKey, burnAmount) // TODO: Backend. It should include the account address in the burn action.
communityTokensModuleInst.burnTokens(communityId, tokenKey, burnAmount/*, accountAddress*/)
} }
// Airdrop tokens: // Airdrop tokens: