1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-22 17:33:23 +01:00

[MMI] Added note to trader code fencing (#18051)

* Added note to trader code fencing

* Started adding code fences in signature-request

* Finished code fencing

* Improving code

* adds check and runs prettier

* Fixed storybook and code fences bundle

* Added missing dependency

* updates fences

* fewer lines

* undo previously merged PR

* ran lavamoat auto

* adds test

* prettier

---------

Co-authored-by: António Regadas <apregadas@gmail.com>
Co-authored-by: Antonio Regadas <antonio.regadas@consensys.net>
Co-authored-by: Brad Decker <bhdecker84@gmail.com>
This commit is contained in:
Albert Olivé 2023-05-16 17:44:08 +02:00 committed by GitHub
parent b982bea130
commit a017a1bae0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 218 additions and 52 deletions

View File

@ -2519,6 +2519,12 @@
"notEnoughGas": {
"message": "Not enough gas"
},
"note": {
"message": "Note"
},
"notePlaceholder": {
"message": "The approver will see this note when approving the transaction at the custodian."
},
"notifications": {
"message": "Notifications"
},
@ -4675,6 +4681,9 @@
"transactionHistoryTotalGasFee": {
"message": "Total gas fee"
},
"transactionNote": {
"message": "Transaction note"
},
"transactionResubmitted": {
"message": "Transaction resubmitted with estimated gas fee increased to $1 at $2"
},

View File

@ -18,6 +18,9 @@ import { ConfirmPageContainerSummary, ConfirmPageContainerWarning } from '.';
export default class ConfirmPageContainerContent extends Component {
static contextTypes = {
t: PropTypes.func.isRequired,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
trackEvent: PropTypes.func,
///: END:ONLY_INCLUDE_IN
};
static propTypes = {
@ -55,6 +58,9 @@ export default class ConfirmPageContainerContent extends Component {
transactionType: PropTypes.string,
isBuyableChain: PropTypes.bool,
txData: PropTypes.object,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteComponent: PropTypes.node,
///: END:ONLY_INCLUDE_IN
metaMetricsId: PropTypes.string,
};
@ -69,6 +75,14 @@ export default class ConfirmPageContainerContent extends Component {
}
///: END:ONLY_INCLUDE_IN
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const { noteComponent } = this.props;
if (noteComponent) {
return this.renderTabs();
}
///: END:ONLY_INCLUDE_IN
if (detailsComponent && dataComponent) {
return this.renderTabs();
}
@ -91,6 +105,9 @@ export default class ConfirmPageContainerContent extends Component {
///: BEGIN:ONLY_INCLUDE_IN(snaps)
insightComponent,
///: END:ONLY_INCLUDE_IN
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteComponent,
///: END:ONLY_INCLUDE_IN
} = this.props;
return (
@ -102,6 +119,25 @@ export default class ConfirmPageContainerContent extends Component {
>
{detailsComponent}
</Tab>
{
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteComponent && (
<Tab
className="confirm-page-container-content__tab"
name={t('note')}
pillText={t('new')}
onClick={() => {
this.context.trackEvent({
category: 'Note to trader',
event: 'Clicked on Notes tab on a transaction window',
});
}}
>
{noteComponent}
</Tab>
)
///: END:ONLY_INCLUDE_IN
}
{dataComponent && (
<Tab
className="confirm-page-container-content__tab"
@ -221,6 +257,7 @@ export default class ConfirmPageContainerContent extends Component {
{t('insufficientCurrencyBuyOrDeposit', [
nativeCurrency,
networkName,
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
<Button
type="inline"
className="confirm-page-container-content__link"
@ -237,6 +274,7 @@ export default class ConfirmPageContainerContent extends Component {
>
{t('buyAsset', [nativeCurrency])}
</Button>,
///: END:ONLY_INCLUDE_IN
])}
</Typography>
) : (

View File

@ -99,6 +99,9 @@ const ConfirmPageContainer = (props) => {
txData,
assetStandard,
isApprovalOrRejection,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteComponent,
///: END:ONLY_INCLUDE_IN
} = props;
const t = useI18nContext();
@ -238,6 +241,9 @@ const ConfirmPageContainer = (props) => {
transactionType={currentTransaction.type}
isBuyableChain={isBuyableChain}
txData={txData}
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteComponent={noteComponent}
///: END:ONLY_INCLUDE_IN
/>
)}
{shouldDisplayWarning && errorKey === INSUFFICIENT_FUNDS_ERROR_KEY && (
@ -398,6 +404,9 @@ ConfirmPageContainer.propTypes = {
supportsEIP1559: PropTypes.bool,
nativeCurrency: PropTypes.string,
isApprovalOrRejection: PropTypes.bool,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteComponent: PropTypes.node,
///: END:ONLY_INCLUDE_IN
};
export default ConfirmPageContainer;

View File

@ -3,33 +3,41 @@
exports[`NoteToTrader should render the Note to trader component 1`] = `
<div>
<div
class="box note-header box--display-flex box--flex-direction-row box--justify-content-space-between"
class="box confirm-page-container-content__data box--flex-direction-row"
>
<label
class="box mm-text mm-label mm-label--html-for mm-text--body-md mm-text--font-weight-bold box--display-inline-flex box--flex-direction-row box--align-items-center box--color-text-default"
for="transaction-note"
<div
class="box box--display-flex box--flex-direction-row"
>
Transaction note
</label>
<p
class="box mm-text note-header__counter mm-text--body-md box--flex-direction-row box--color-text-default"
>
9
/
280
</p>
</div>
<div
class="box note-field box--display-flex box--flex-direction-column"
>
<textarea
data-testid="transaction-note"
id="transaction-note"
maxlength="280"
placeholder=""
>
some text
</textarea>
<div
class="box note-header box--display-flex box--flex-direction-row box--justify-content-space-between"
>
<label
class="box mm-text mm-label mm-label--html-for mm-text--body-md mm-text--font-weight-bold box--display-inline-flex box--flex-direction-row box--align-items-center box--color-text-default"
for="transaction-note"
>
Transaction note
</label>
<p
class="box mm-text note-header__counter mm-text--body-md box--flex-direction-row box--color-text-default"
>
9
/
280
</p>
</div>
<div
class="box note-field box--display-flex box--flex-direction-column"
>
<textarea
data-testid="transaction-note"
id="transaction-note"
maxlength="280"
placeholder=""
>
some text
</textarea>
</div>
</div>
</div>
</div>
`;

View File

@ -12,33 +12,35 @@ const NoteToTrader = (props) => {
const { placeholder, maxLength, onChange, noteText, labelText } = props;
return (
<>
<Box
className="note-header"
display={DISPLAY.FLEX}
justifyContent={JustifyContent.spaceBetween}
>
<Label htmlFor="transaction-note">{labelText}</Label>
<Text className="note-header__counter">
{noteText.length}/{maxLength}
</Text>
<Box className="confirm-page-container-content__data">
<Box display={DISPLAY.FLEX} flexDirection={FLEX_DIRECTION.ROW}>
<Box
className="note-header"
display={DISPLAY.FLEX}
justifyContent={JustifyContent.spaceBetween}
>
<Label htmlFor="transaction-note">{labelText}</Label>
<Text className="note-header__counter">
{noteText.length}/{maxLength}
</Text>
</Box>
<Box
display={DISPLAY.FLEX}
flexDirection={FLEX_DIRECTION.COLUMN}
className="note-field"
>
<textarea
id="transaction-note"
data-testid="transaction-note"
onChange={({ target: { value } }) => onChange(value)}
autoFocus
maxLength={maxLength}
placeholder={placeholder}
value={noteText}
/>
</Box>
</Box>
<Box
display={DISPLAY.FLEX}
flexDirection={FLEX_DIRECTION.COLUMN}
className="note-field"
>
<textarea
id="transaction-note"
data-testid="transaction-note"
onChange={({ target: { value } }) => onChange(value)}
autoFocus
maxLength={maxLength}
placeholder={placeholder}
value={noteText}
/>
</Box>
</>
</Box>
);
};

View File

@ -25,6 +25,10 @@ import {
isLegacyTransaction,
} from '../../helpers/utils/transactions.util';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import NoteToTrader from '../../components/institutional/note-to-trader';
///: END:ONLY_INCLUDE_IN
import { TransactionModalContextProvider } from '../../contexts/transaction-modal';
import TransactionDetail from '../../components/app/transaction-detail/transaction-detail.component';
import TransactionDetailItem from '../../components/app/transaction-detail-item/transaction-detail-item.component';
@ -129,6 +133,10 @@ export default class ConfirmTransactionBase extends Component {
hardwareWalletRequiresConnection: PropTypes.bool,
isMultiLayerFeeNetwork: PropTypes.bool,
isBuyableChain: PropTypes.bool,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType: PropTypes.string,
isNoteToTraderSupported: PropTypes.bool,
///: END:ONLY_INCLUDE_IN
isApprovalOrRejection: PropTypes.bool,
assetStandard: PropTypes.string,
useCurrencyRateCheck: PropTypes.bool,
@ -142,6 +150,9 @@ export default class ConfirmTransactionBase extends Component {
editingGas: false,
userAcknowledgedGasMissing: false,
showWarningModal: false,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteText: '',
///: END:ONLY_INCLUDE_IN
};
componentDidUpdate(prevProps) {
@ -594,10 +605,31 @@ export default class ConfirmTransactionBase extends Component {
addToAddressBookIfNew,
toAccounts,
toAddress,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType,
isNoteToTraderSupported,
///: END:ONLY_INCLUDE_IN
} = this.props;
const { submitting } = this.state;
const {
submitting,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteText,
///: END:ONLY_INCLUDE_IN
} = this.state;
const { name } = methodData;
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
if (accountType === 'custody') {
txData.custodyStatus = 'created';
if (isNoteToTraderSupported) {
txData.metadata = {
note: noteText,
};
}
}
///: END:ONLY_INCLUDE_IN
if (txData.type === TransactionType.simpleSend) {
addToAddressBookIfNew(toAddress, toAccounts);
}
@ -802,6 +834,9 @@ export default class ConfirmTransactionBase extends Component {
isApprovalOrRejection,
assetStandard,
title,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
isNoteToTraderSupported,
///: END:ONLY_INCLUDE_IN
} = this.props;
const {
submitting,
@ -869,6 +904,19 @@ export default class ConfirmTransactionBase extends Component {
dataComponent={this.renderData(functionType)}
dataHexComponent={this.renderDataHex(functionType)}
contentComponent={contentComponent}
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteComponent={
isNoteToTraderSupported && (
<NoteToTrader
maxLength="280"
placeholder={t('notePlaceholder')}
onChange={(value) => this.setState({ noteText: value })}
noteText={this.state.noteText}
labelText={t('transactionNote')}
/>
)
}
///: END:ONLY_INCLUDE_IN
nonce={customNonceValue || nonce}
unapprovedTxCount={unapprovedTxCount}
tokenAddress={tokenAddress}

View File

@ -60,6 +60,9 @@ import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils';
import { getGasLoadingAnimationIsShowing } from '../../ducks/app/app';
import { isLegacyTransaction } from '../../helpers/utils/transactions.util';
import { CUSTOM_GAS_ESTIMATE } from '../../../shared/constants/gas';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import { getAccountType } from '../../selectors/selectors';
///: END:ONLY_INCLUDE_IN
import {
TransactionStatus,
TransactionType,
@ -196,6 +199,23 @@ const mapStateToProps = (state, ownProps) => {
const isMultiLayerFeeNetwork = getIsMultiLayerFeeNetwork(state);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const accountType = getAccountType(state);
const fromChecksumHexAddress = toChecksumHexAddress(fromAddress);
let isNoteToTraderSupported = false;
if (
state.metamask.custodyAccountDetails &&
state.metamask.custodyAccountDetails[fromChecksumHexAddress]
) {
const { custodianName } =
state.metamask.custodyAccountDetails[fromChecksumHexAddress];
isNoteToTraderSupported = state.metamask.mmiConfiguration?.custodians?.find(
(custodian) => custodian.name === custodianName,
)?.isNoteToTraderSupported;
}
///: END:ONLY_INCLUDE_IN
return {
balance,
fromAddress,
@ -246,6 +266,10 @@ const mapStateToProps = (state, ownProps) => {
chainId,
isBuyableChain,
useCurrencyRateCheck: getUseCurrencyRateCheck(state),
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType,
isNoteToTraderSupported,
///: END:ONLY_INCLUDE_IN
};
};

View File

@ -166,4 +166,32 @@ describe('Confirm Transaction Base', () => {
expect(getByText('Layer 1 fees')).toBeInTheDocument();
expect(getByText('Layer 2 gas fee')).toBeInTheDocument();
});
it('should render NoteToTrader when isNoteToTraderSupported is true', () => {
baseStore.metamask.custodyAccountDetails = {
'0x0': {
address: '0x0',
details: 'details',
custodyType: 'testCustody - Saturn',
custodianName: 'saturn-dev',
},
};
baseStore.metamask.mmiConfiguration = {
custodians: [
{
name: 'saturn-dev',
displayName: 'Saturn Custody',
isNoteToTraderSupported: true,
},
],
};
const store = configureMockStore(middleware)(baseStore);
const { getByTestId } = renderWithProvider(
<ConfirmTransactionBase actionKey="confirm" />,
store,
);
expect(getByTestId('transaction-note')).toBeInTheDocument();
});
});