mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Update Confirm Contract screen (#3597)
This commit is contained in:
parent
ad9feee637
commit
6f749e5576
16
app/images/arrow-right.svg
Normal file
16
app/images/arrow-right.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="25px" height="21px" viewBox="0 0 25 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>arrow-right</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Confirm-Send-ETH---V3" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(-500.000000, -235.000000)">
|
||||
<g id="Group-4" transform="translate(312.000000, 99.000000)" fill="#5B5B5B">
|
||||
<g id="Group-18" transform="translate(109.000000, 119.000000)">
|
||||
<g id="arrow-right" transform="translate(78.000000, 17.000000)">
|
||||
<path d="M13.2809946,0.467462271 L13.2809946,0.467462271 C12.6477116,1.09191648 12.6477116,2.10286154 13.2809946,2.72571868 L19.1052554,8.46878095 L2.61883998,8.46878095 C1.72479329,8.46878095 0.999190175,9.18426813 0.999190175,10.0658505 L0.999190175,10.0674476 C0.999190175,10.94903 1.72479329,11.6629201 2.61883998,11.6629201 L19.1052554,11.6629201 L13.2809946,17.4075795 C12.6477116,18.0304366 12.6477116,19.0413817 13.2809946,19.6658359 C13.9126581,20.288693 14.9378964,20.288693 15.5711795,19.6658359 L25.3052748,10.0658505 L15.5711795,0.467462271 C14.9378964,-0.155394872 13.9126581,-0.155394872 13.2809946,0.467462271" id="Fill-1"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -109,7 +109,7 @@ DepositEtherModal.prototype.render = function () {
|
||||
const isTestNetwork = ['3', '4', '42'].find(n => n === network)
|
||||
const networkName = networkNames[network]
|
||||
|
||||
return h('div.page-container.page-container--full-width', {}, [
|
||||
return h('div.page-container.page-container--full-width.page-container--full-height', {}, [
|
||||
|
||||
h('div.page-container__header', [
|
||||
|
||||
|
@ -1,53 +1,29 @@
|
||||
const Component = require('react').Component
|
||||
const { Component } = require('react')
|
||||
const { connect } = require('react-redux')
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const PropTypes = require('prop-types')
|
||||
const actions = require('../../actions')
|
||||
const clone = require('clone')
|
||||
const Identicon = require('../identicon')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const BN = ethUtil.BN
|
||||
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
|
||||
const { conversionUtil } = require('../../conversion-util')
|
||||
const t = require('../../../i18n')
|
||||
const SenderToRecipient = require('../sender-to-recipient')
|
||||
|
||||
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
|
||||
|
||||
class ConfirmDeployContract extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract)
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const {
|
||||
conversionRate,
|
||||
identities,
|
||||
currentCurrency,
|
||||
} = state.metamask
|
||||
const accounts = state.metamask.accounts
|
||||
const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
|
||||
return {
|
||||
currentCurrency,
|
||||
conversionRate,
|
||||
identities,
|
||||
selectedAddress,
|
||||
this.state = {
|
||||
valid: false,
|
||||
submitting: false,
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
|
||||
cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inherits(ConfirmDeployContract, Component)
|
||||
function ConfirmDeployContract () {
|
||||
Component.call(this)
|
||||
this.state = {}
|
||||
this.onSubmit = this.onSubmit.bind(this)
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.onSubmit = function (event) {
|
||||
onSubmit (event) {
|
||||
event.preventDefault()
|
||||
const txMeta = this.gatherTxMeta()
|
||||
const valid = this.checkValidity()
|
||||
@ -56,23 +32,23 @@ ConfirmDeployContract.prototype.onSubmit = function (event) {
|
||||
if (valid && this.verifyGasParams()) {
|
||||
this.props.sendTransaction(txMeta, event)
|
||||
} else {
|
||||
this.props.dispatch(actions.displayWarning(t('invalidGasParams')))
|
||||
this.props.displayWarning('invalidGasParams')
|
||||
this.setState({ submitting: false })
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.cancel = function (event, txMeta) {
|
||||
cancel (event, txMeta) {
|
||||
event.preventDefault()
|
||||
this.props.cancelTransaction(txMeta)
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.checkValidity = function () {
|
||||
checkValidity () {
|
||||
const form = this.getFormEl()
|
||||
const valid = form.checkValidity()
|
||||
return valid
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.getFormEl = function () {
|
||||
getFormEl () {
|
||||
const form = document.querySelector('form#pending-tx-form')
|
||||
// Stub out form for unit tests:
|
||||
if (!form) {
|
||||
@ -82,7 +58,7 @@ ConfirmDeployContract.prototype.getFormEl = function () {
|
||||
}
|
||||
|
||||
// After a customizable state value has been updated,
|
||||
ConfirmDeployContract.prototype.gatherTxMeta = function () {
|
||||
gatherTxMeta () {
|
||||
const props = this.props
|
||||
const state = this.state
|
||||
const txData = clone(state.txData) || clone(props.txData)
|
||||
@ -91,7 +67,7 @@ ConfirmDeployContract.prototype.gatherTxMeta = function () {
|
||||
return txData
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.verifyGasParams = function () {
|
||||
verifyGasParams () {
|
||||
// We call this in case the gas has not been modified at all
|
||||
if (!this.state) { return true }
|
||||
return (
|
||||
@ -100,17 +76,17 @@ ConfirmDeployContract.prototype.verifyGasParams = function () {
|
||||
)
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype._notZeroOrEmptyString = function (obj) {
|
||||
_notZeroOrEmptyString (obj) {
|
||||
return obj !== '' && obj !== '0x0'
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) {
|
||||
bnMultiplyByFraction (targetBN, numerator, denominator) {
|
||||
const numBN = new BN(numerator)
|
||||
const denomBN = new BN(denominator)
|
||||
return targetBN.mul(numBN).div(denomBN)
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.getData = function () {
|
||||
getData () {
|
||||
const { identities } = this.props
|
||||
const txMeta = this.gatherTxMeta()
|
||||
const txParams = txMeta.txParams || {}
|
||||
@ -124,7 +100,7 @@ ConfirmDeployContract.prototype.getData = function () {
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.getAmount = function () {
|
||||
getAmount () {
|
||||
const { conversionRate, currentCurrency } = this.props
|
||||
const txMeta = this.gatherTxMeta()
|
||||
const txParams = txMeta.txParams || {}
|
||||
@ -155,7 +131,7 @@ ConfirmDeployContract.prototype.getAmount = function () {
|
||||
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.getGasFee = function () {
|
||||
getGasFee () {
|
||||
const { conversionRate, currentCurrency } = this.props
|
||||
const txMeta = this.gatherTxMeta()
|
||||
const txParams = txMeta.txParams || {}
|
||||
@ -195,7 +171,7 @@ ConfirmDeployContract.prototype.getGasFee = function () {
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.renderGasFee = function () {
|
||||
renderGasFee () {
|
||||
const { currentCurrency } = this.props
|
||||
const { fiat: fiatGas, eth: ethGas } = this.getGasFee()
|
||||
|
||||
@ -214,7 +190,7 @@ ConfirmDeployContract.prototype.renderGasFee = function () {
|
||||
)
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.renderHeroAmount = function () {
|
||||
renderHeroAmount () {
|
||||
const { currentCurrency } = this.props
|
||||
const { fiat: fiatAmount } = this.getAmount()
|
||||
const txMeta = this.gatherTxMeta()
|
||||
@ -232,13 +208,13 @@ ConfirmDeployContract.prototype.renderHeroAmount = function () {
|
||||
)
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.renderTotalPlusGas = function () {
|
||||
renderTotalPlusGas () {
|
||||
const { currentCurrency } = this.props
|
||||
const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
|
||||
const { fiat: fiatGas, eth: ethGas } = this.getGasFee()
|
||||
|
||||
return (
|
||||
h('section.flex-row.flex-center.confirm-screen-total-box ', [
|
||||
h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
|
||||
h('div.confirm-screen-section-column', [
|
||||
h('span.confirm-screen-label', [ t('total') + ' ' ]),
|
||||
h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]),
|
||||
@ -252,7 +228,7 @@ ConfirmDeployContract.prototype.renderTotalPlusGas = function () {
|
||||
)
|
||||
}
|
||||
|
||||
ConfirmDeployContract.prototype.render = function () {
|
||||
render () {
|
||||
const { backToAccountDetail, selectedAddress } = this.props
|
||||
const txMeta = this.gatherTxMeta()
|
||||
|
||||
@ -266,37 +242,21 @@ ConfirmDeployContract.prototype.render = function () {
|
||||
this.inputs = []
|
||||
|
||||
return (
|
||||
h('div.flex-column.flex-grow.confirm-screen-container', {
|
||||
style: { minWidth: '355px' },
|
||||
}, [
|
||||
// Main Send token Card
|
||||
h('div.confirm-screen-wrapper.flex-column.flex-grow', [
|
||||
h('h3.flex-center.confirm-screen-header', [
|
||||
h('button.confirm-screen-back-button.allcaps', {
|
||||
h('.page-container', [
|
||||
h('.page-container__header', [
|
||||
h('.page-container__back-button', {
|
||||
onClick: () => backToAccountDetail(selectedAddress),
|
||||
}, t('back')),
|
||||
h('div.confirm-screen-title', t('confirmContract')),
|
||||
h('div.confirm-screen-header-tip'),
|
||||
]),
|
||||
h('div.flex-row.flex-center.confirm-screen-identicons', [
|
||||
h('div.confirm-screen-account-wrapper', [
|
||||
h(
|
||||
Identicon,
|
||||
{
|
||||
address: fromAddress,
|
||||
diameter: 60,
|
||||
},
|
||||
),
|
||||
h('span.confirm-screen-account-name', fromName),
|
||||
// h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
|
||||
]),
|
||||
h('i.fa.fa-arrow-right.fa-lg'),
|
||||
h('div.confirm-screen-account-wrapper', [
|
||||
h('i.fa.fa-file-text-o'),
|
||||
h('span.confirm-screen-account-name', t('newContract')),
|
||||
h('span.confirm-screen-account-number', ' '),
|
||||
]),
|
||||
h('.page-container__title', t('confirmContract')),
|
||||
h('.page-container__subtitle', t('pleaseReviewTransaction')),
|
||||
]),
|
||||
// Main Send token Card
|
||||
h('.page-container__content', [
|
||||
|
||||
h(SenderToRecipient, {
|
||||
senderName: fromName,
|
||||
senderAddress: fromAddress,
|
||||
}),
|
||||
|
||||
// h('h3.flex-center.confirm-screen-sending-to-message', {
|
||||
// style: {
|
||||
@ -333,17 +293,58 @@ ConfirmDeployContract.prototype.render = function () {
|
||||
]),
|
||||
|
||||
h('form#pending-tx-form', {
|
||||
onSubmit: this.onSubmit,
|
||||
onClick: event => this.onSubmit(event),
|
||||
}, [
|
||||
h('.page-container__footer', [
|
||||
// Cancel Button
|
||||
h('div.cancel.btn-light.confirm-screen-cancel-button.allcaps', {
|
||||
onClick: (event) => this.cancel(event, txMeta),
|
||||
h('button.btn-cancel.page-container__footer-button.allcaps', {
|
||||
onClick: event => this.cancel(event, txMeta),
|
||||
}, t('cancel')),
|
||||
|
||||
// Accept Button
|
||||
h('button.confirm-screen-confirm-button.allcaps', [t('confirm')]),
|
||||
|
||||
h('button.btn-confirm.page-container__footer-button.allcaps', {
|
||||
onClick: event => this.onSubmit(event),
|
||||
}, t('confirm')),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmDeployContract.propTypes = {
|
||||
sendTransaction: PropTypes.func,
|
||||
cancelTransaction: PropTypes.func,
|
||||
backToAccountDetail: PropTypes.func,
|
||||
displayWarning: PropTypes.func,
|
||||
identities: PropTypes.object,
|
||||
conversionRate: PropTypes.number,
|
||||
currentCurrency: PropTypes.string,
|
||||
selectedAddress: PropTypes.string,
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const {
|
||||
conversionRate,
|
||||
identities,
|
||||
currentCurrency,
|
||||
} = state.metamask
|
||||
const accounts = state.metamask.accounts
|
||||
const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
|
||||
return {
|
||||
currentCurrency,
|
||||
conversionRate,
|
||||
identities,
|
||||
selectedAddress,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
|
||||
cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
|
||||
displayWarning: warning => actions.displayWarning(t(warning)),
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract)
|
||||
|
45
ui/app/components/sender-to-recipient.js
Normal file
45
ui/app/components/sender-to-recipient.js
Normal file
@ -0,0 +1,45 @@
|
||||
const { Component } = require('react')
|
||||
const h = require('react-hyperscript')
|
||||
const PropTypes = require('prop-types')
|
||||
const t = require('../../i18n')
|
||||
const Identicon = require('./identicon')
|
||||
|
||||
class SenderToRecipient extends Component {
|
||||
render () {
|
||||
const { senderName, senderAddress } = this.props
|
||||
|
||||
return (
|
||||
h('.sender-to-recipient__container', [
|
||||
h('.sender-to-recipient__sender', [
|
||||
h('.sender-to-recipient__sender-icon', [
|
||||
h(Identicon, {
|
||||
address: senderAddress,
|
||||
diameter: 20,
|
||||
}),
|
||||
]),
|
||||
h('.sender-to-recipient__name.sender-to-recipient__sender-name', senderName),
|
||||
]),
|
||||
h('.sender-to-recipient__arrow-container', [
|
||||
h('.sender-to-recipient__arrow-circle', [
|
||||
h('img', {
|
||||
height: 15,
|
||||
width: 15,
|
||||
src: '/images/arrow-right.svg',
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
h('.sender-to-recipient__recipient', [
|
||||
h('i.fa.fa-file-text-o'),
|
||||
h('.sender-to-recipient__name.sender-to-recipient__recipient-name', t('newContract')),
|
||||
]),
|
||||
])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SenderToRecipient.propTypes = {
|
||||
senderName: PropTypes.string,
|
||||
senderAddress: PropTypes.string,
|
||||
}
|
||||
|
||||
module.exports = SenderToRecipient
|
@ -45,6 +45,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
background-color: $caribbean-green; // TODO: reusable color in colors.css
|
||||
text-align: center;
|
||||
padding: .8rem 1rem;
|
||||
color: $white;
|
||||
border: 2px solid $caribbean-green;
|
||||
border-radius: 4px;
|
||||
font-size: .85rem;
|
||||
font-weight: 400;
|
||||
transition: border-color .3s ease;
|
||||
}
|
||||
|
||||
// No longer used in flat design, remove when modal buttons done
|
||||
// div.wallet-btn {
|
||||
// border: 1px solid rgb(91, 93, 103);
|
||||
|
@ -202,7 +202,7 @@
|
||||
}
|
||||
|
||||
.confirm-screen-label {
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
line-height: 40px;
|
||||
color: $scorpion;
|
||||
text-align: left;
|
||||
@ -229,7 +229,6 @@ section .confirm-screen-account-number,
|
||||
.confirm-screen-row {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
border-bottom: 1px solid $alto;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
@ -237,6 +236,10 @@ section .confirm-screen-account-number,
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
font-weight: 300;
|
||||
|
||||
&:not(:last-of-type) {
|
||||
border-bottom: 1px solid $alto;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-screen-row-detail {
|
||||
@ -247,12 +250,9 @@ section .confirm-screen-account-number,
|
||||
|
||||
.confirm-screen-total-box {
|
||||
background-color: $wild-sand;
|
||||
padding: 20px;
|
||||
padding-left: 35px;
|
||||
border-bottom: 1px solid $alto;
|
||||
|
||||
.confirm-screen-label {
|
||||
line-height: 18px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.confirm-screen-row-detail {
|
||||
@ -261,7 +261,7 @@ section .confirm-screen-account-number,
|
||||
|
||||
&__subtitle {
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.confirm-screen-row-info {
|
||||
@ -304,21 +304,3 @@ section .confirm-screen-account-number,
|
||||
font-weight: 300;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
#pending-tx-form {
|
||||
flex: 1 0 auto;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
background-color: $white;
|
||||
padding: 12px;
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
width: 100%;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
border-top: 1px solid $alto;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
@ -58,3 +58,4 @@
|
||||
|
||||
@import './welcome-screen.scss';
|
||||
|
||||
@import './sender-to-recipient.scss';
|
||||
|
58
ui/app/css/itcss/components/sender-to-recipient.scss
Normal file
58
ui/app/css/itcss/components/sender-to-recipient.scss
Normal file
@ -0,0 +1,58 @@
|
||||
.sender-to-recipient {
|
||||
&__container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
border-bottom: 1px solid $geyser;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__sender,
|
||||
&__recipient {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
padding: 10px 20px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__sender {
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
&__recipient {
|
||||
border-left: 1px solid $geyser;
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
&__arrow-container {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__arrow-circle {
|
||||
background: $white;
|
||||
padding: 5px;
|
||||
border: 1px solid $geyser;
|
||||
border-radius: 20px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__name {
|
||||
padding-left: 5px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
@ -82,7 +82,6 @@ input.large-input {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
border-radius: 7px;
|
||||
height: 100%;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
@ -116,7 +115,8 @@ input.large-input {
|
||||
flex: 0 0 auto;
|
||||
|
||||
.btn-clear,
|
||||
.btn-cancel {
|
||||
.btn-cancel,
|
||||
.btn-confirm {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
@ -134,9 +134,16 @@ input.large-input {
|
||||
}
|
||||
}
|
||||
|
||||
&__back-button {
|
||||
color: #2f9ae0;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
padding-bottom: 10px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
&__title {
|
||||
color: $black;
|
||||
font-family: Roboto;
|
||||
font-size: 2rem;
|
||||
font-weight: 500;
|
||||
line-height: 2rem;
|
||||
@ -188,6 +195,10 @@ input.large-input {
|
||||
width: initial;
|
||||
}
|
||||
|
||||
&--full-height {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__content {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
Loading…
x
Reference in New Issue
Block a user