1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-29 15:50:28 +01:00
metamask-extension/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js

259 lines
9.1 KiB
JavaScript
Raw Normal View History

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import log from 'loglevel';
import classnames from 'classnames';
import BigNumber from 'bignumber.js';
import Modal from '../../modal';
import Identicon from '../../../ui/identicon';
import TextField from '../../../ui/text-field';
import {
calcTokenAmount,
toPrecisionWithoutTrailingZeros,
} from '../../../../../shared/lib/transactions-controller-utils';
import {
ButtonIcon,
ButtonIconSize,
IconName,
} from '../../../component-library';
const MAX_UNSIGNED_256_INT = new BigNumber(2).pow(256).minus(1).toString(10);
export default class EditApprovalPermission extends PureComponent {
static propTypes = {
decimals: PropTypes.number,
hideModal: PropTypes.func.isRequired,
selectedIdentity: PropTypes.object,
tokenAmount: PropTypes.string,
customTokenAmount: PropTypes.string,
tokenSymbol: PropTypes.string,
tokenBalance: PropTypes.string,
setCustomAmount: PropTypes.func,
origin: PropTypes.string.isRequired,
2020-10-06 20:28:38 +02:00
requiredMinimum: PropTypes.instanceOf(BigNumber),
};
static contextTypes = {
t: PropTypes.func,
};
state = {
2020-10-06 20:28:38 +02:00
// This is used as a TextField value, which should be a string.
customSpendLimit: this.props.customTokenAmount || '',
selectedOptionIsUnlimited: !this.props.customTokenAmount,
};
2020-11-03 00:41:28 +01:00
renderModalContent(error) {
const { t } = this.context;
const {
hideModal,
selectedIdentity,
tokenAmount,
tokenSymbol,
tokenBalance,
customTokenAmount,
origin,
} = this.props;
const { name, address } = selectedIdentity || {};
const { selectedOptionIsUnlimited } = this.state;
return (
<div className="edit-approval-permission">
<div className="edit-approval-permission__header">
<div className="edit-approval-permission__title">
2020-11-03 00:41:28 +01:00
{t('editPermission')}
</div>
2023-02-27 17:42:02 +01:00
<ButtonIcon
iconName={IconName.Close}
size={ButtonIconSize.Lg}
2023-02-27 17:42:02 +01:00
className="edit-approval-permission__header__close"
onClick={hideModal}
/>
</div>
<div className="edit-approval-permission__account-info">
<div className="edit-approval-permission__account-info__account">
2020-11-03 00:41:28 +01:00
<Identicon address={address} diameter={32} />
2020-10-06 20:28:38 +02:00
<div className="edit-approval-permission__name-and-balance-container">
2020-11-03 00:41:28 +01:00
<div className="edit-approval-permission__account-info__name">
{name}
</div>
<div>{t('balance')}</div>
2020-10-06 20:28:38 +02:00
</div>
</div>
<div className="edit-approval-permission__account-info__balance">
{`${toPrecisionWithoutTrailingZeros(
tokenBalance,
9,
)} ${tokenSymbol}`}
</div>
</div>
<div className="edit-approval-permission__edit-section">
<div className="edit-approval-permission__edit-section__title">
2020-11-03 00:41:28 +01:00
{t('spendLimitPermission')}
</div>
<div className="edit-approval-permission__edit-section__description">
2020-11-03 00:41:28 +01:00
{t('allowWithdrawAndSpend', [origin])}
</div>
<div className="edit-approval-permission__edit-section__option">
<div
className="edit-approval-permission__edit-section__radio-button"
onClick={() => this.setState({ selectedOptionIsUnlimited: true })}
>
<div
className={classnames({
2022-07-31 20:26:40 +02:00
'edit-approval-permission__edit-section__radio-button-outline':
!selectedOptionIsUnlimited,
'edit-approval-permission__edit-section__radio-button-outline--selected':
selectedOptionIsUnlimited,
})}
/>
<div className="edit-approval-permission__edit-section__radio-button-fill" />
2020-11-03 00:41:28 +01:00
{selectedOptionIsUnlimited && (
<div className="edit-approval-permission__edit-section__radio-button-dot" />
)}
</div>
<div className="edit-approval-permission__edit-section__option-text">
<div
className={classnames({
2022-07-31 20:26:40 +02:00
'edit-approval-permission__edit-section__option-label':
!selectedOptionIsUnlimited,
'edit-approval-permission__edit-section__option-label--selected':
selectedOptionIsUnlimited,
})}
>
{new BigNumber(tokenAmount).equals(
new BigNumber(MAX_UNSIGNED_256_INT),
2020-11-03 00:41:28 +01:00
)
? t('unlimited')
: t('proposedApprovalLimit')}
</div>
2020-11-03 00:41:28 +01:00
<div className="edit-approval-permission__edit-section__option-description">
{t('spendLimitRequestedBy', [origin])}
</div>
2020-11-03 00:41:28 +01:00
<div className="edit-approval-permission__edit-section__option-value">
{`${Number(tokenAmount)} ${tokenSymbol}`}
</div>
</div>
</div>
<div className="edit-approval-permission__edit-section__option">
<div
className="edit-approval-permission__edit-section__radio-button"
2020-11-03 00:41:28 +01:00
onClick={() =>
this.setState({ selectedOptionIsUnlimited: false })
}
>
<div
className={classnames({
2022-07-31 20:26:40 +02:00
'edit-approval-permission__edit-section__radio-button-outline':
selectedOptionIsUnlimited,
'edit-approval-permission__edit-section__radio-button-outline--selected':
!selectedOptionIsUnlimited,
})}
/>
<div className="edit-approval-permission__edit-section__radio-button-fill" />
2020-11-03 00:41:28 +01:00
{!selectedOptionIsUnlimited && (
<div className="edit-approval-permission__edit-section__radio-button-dot" />
)}
</div>
<div className="edit-approval-permission__edit-section__option-text">
<div
className={classnames({
2022-07-31 20:26:40 +02:00
'edit-approval-permission__edit-section__option-label':
selectedOptionIsUnlimited,
'edit-approval-permission__edit-section__option-label--selected':
!selectedOptionIsUnlimited,
})}
>
2020-11-03 00:41:28 +01:00
{t('customSpendLimit')}
</div>
2020-11-03 00:41:28 +01:00
<div className="edit-approval-permission__edit-section__option-description">
{t('enterMaxSpendLimit')}
</div>
2020-11-03 00:41:28 +01:00
<div className="edit-approval-permission__edit-section__option-input">
<TextField
type="number"
2020-11-03 00:41:28 +01:00
placeholder={`${Number(
customTokenAmount || tokenAmount,
)} ${tokenSymbol}`}
onChange={(event) => {
this.setState({ customSpendLimit: event.target.value });
if (selectedOptionIsUnlimited) {
this.setState({ selectedOptionIsUnlimited: false });
}
}}
fullWidth
margin="dense"
2020-11-03 00:41:28 +01:00
value={this.state.customSpendLimit}
error={error}
/>
</div>
</div>
</div>
</div>
</div>
);
}
2020-11-03 00:41:28 +01:00
validateSpendLimit() {
const { t } = this.context;
const { decimals, requiredMinimum } = this.props;
const { selectedOptionIsUnlimited, customSpendLimit } = this.state;
if (selectedOptionIsUnlimited || !customSpendLimit) {
return undefined;
}
let customSpendLimitNumber;
try {
customSpendLimitNumber = new BigNumber(customSpendLimit);
} catch (error) {
log.debug(`Error converting '${customSpendLimit}' to BigNumber:`, error);
return t('spendLimitInvalid');
}
if (customSpendLimitNumber.isNegative()) {
return t('spendLimitInvalid');
}
const maxTokenAmount = calcTokenAmount(MAX_UNSIGNED_256_INT, decimals);
if (customSpendLimitNumber.greaterThan(maxTokenAmount)) {
return t('spendLimitTooLarge');
}
2020-10-06 20:28:38 +02:00
if (
requiredMinimum !== undefined &&
customSpendLimitNumber.lessThan(requiredMinimum)
) {
return t('spendLimitInsufficient');
2020-10-06 20:28:38 +02:00
}
return undefined;
}
2020-11-03 00:41:28 +01:00
render() {
const { t } = this.context;
const { setCustomAmount, hideModal, customTokenAmount } = this.props;
const { selectedOptionIsUnlimited, customSpendLimit } = this.state;
const error = this.validateSpendLimit();
const disabled = Boolean(
(customSpendLimit === customTokenAmount && !selectedOptionIsUnlimited) ||
2020-11-03 00:41:28 +01:00
error,
);
return (
<Modal
onSubmit={() => {
setCustomAmount(selectedOptionIsUnlimited ? '' : customSpendLimit);
hideModal();
}}
submitText={t('save')}
contentClass="edit-approval-permission-modal-content"
containerClass="edit-approval-permission-modal-container"
submitDisabled={disabled}
>
2020-11-03 00:41:28 +01:00
{this.renderModalContent(error)}
</Modal>
);
}
}