-
Notifications
You must be signed in to change notification settings - Fork 5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor and redesign confirm transaction views #4691
Conversation
ce7adb1
to
42ada41
Compare
@alextsg What are your thoughts on adding directory specific My preference is for no selection logic at all in Thoughts? |
t: PropTypes.func, | ||
} | ||
|
||
static propTypes = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps alphabetize this list and put spaces between the sections (by type of source) of props.
} = {}, | ||
} = this.props | ||
|
||
const INSUFFICIENT_FUNDS_ERROR = t('insufficientFunds') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be better to store errors as their translation keys, as opposed to their translations. And then translate them at the point of render.
Reasons:
(1) Data stored will not be a 'view' value, just data that represents the current state of errors
(2) Debugging will be easier if the users state logs are all in english, as opposed to some parts of state that representing error handling being in a different laguage
Also, perhaps these errors should be moved to a constants file
return | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are your thoughts on moving some or all of the logic in getError
and validateEditGas
to either reducers or utils?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think keeping errors in the redux state makes sense when there's an app-wide display for errors (like how GitHub has it under the nav bar) but when the error is localized to a component then I don't think it's necessary, since it's basically up to the component how the error should be handled (displayed somewhere, disable buttons, etc.).
As for utils, I get that by doing so it keeps the component file smaller, but in my opinion the purpose of a util is re-usability. I want to avoid passing in a bunch of arguments into a util function as that just makes the util very specific and hard to use. In this case, I think isBalanceSufficient
is great as a util, but getError
would be too specific to the component. validateEditGas
could probably be moved to the container file, but we should figure out how to deal with the translation of error messages.
if (onEditGas) { | ||
onEditGas() | ||
} else { | ||
showCustomizeGasModal({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe put all of showCustomizeGasModal
in the container?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... maybe not
@@ -399,19 +399,17 @@ class TransactionStateManager extends EventEmitter { | |||
_setTxStatus (txId, status) { | |||
const txMeta = this.getTx(txId) | |||
txMeta.status = status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this change needed?
@@ -705,11 +705,10 @@ function signTypedMsg (msgData) { | |||
|
|||
function signTx (txData) { | |||
return (dispatch) => { | |||
dispatch(actions.showLoadingIndication()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you remove showLoadingIndication
and hideLoadingIndication
here, but not in the other methods edited below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a weird case where the callback passed to ethQuery.sendTransaction
gets called when the tx gets approved or rejected, and not when we'd expect (called after the tx is added to the list of unapproved tx'es). The loading spinner was being hidden unintentionally during approving/rejecting on the confirm step.
}) | ||
.then(() => updateMetamaskStateFromBackground()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not related to this PR, but we should probably rename updateMetamaskStateFromBackground
to something like getUpdatedMetamaskStateFromBackground
. The current name makes it sound like the method does the updating of react state itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving a TODO here for myself to do this after I finish reviwing:
- create github issue to rename updateMetamaskStateFromBackground
@@ -0,0 +1,65 @@ | |||
import { createSelector } from 'reselect' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you prefer to have these here in a general selectors/
directory, as opposed to in one of the confirm-transaction
directories? (As is done, for example, with send)
|
||
renderTabs () { | ||
// const { children } = this.props | ||
const numberOfTabs = React.Children.count(this.props.children) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity why is React.Children
(and not this.props.children
) needed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- remove commented out code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
React.Children
is a set of utils that can be used on this.props.children
https://reactjs.org/docs/react-api.html#reactchildren
const { detailsComponent, dataComponent } = this.props | ||
|
||
return ( | ||
<Tabs> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be nice if the tabs component had an API that allowed:
<Tabs
tabs={
'Details': detailsComponent,
'Data': dataComponent,
}
/>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was actually trying to avoid this so that the elements would be more HTML semantic:
<Tabs>
<Tab />
<Tab />
</Tabs>
{ this.renderContent() } | ||
{ | ||
errorMessage && ( | ||
<div className="confirm-page-container-content__error-container"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we put the <div className="confirm-page-container-content__error-container">
inside the ConfirmPageContainerError
component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not here, because the confirm-page-container-content__error-container
class adds padding around the ConfirmPageContainerError
component. This makes the ConfirmPageContainerError
more reusable and contained since the parent would be responsible for the spacing of the child. I might not want the same spacing/padding used elsewhere.
</div> | ||
</div> | ||
{ | ||
hideSubtitle || <div className="confirm-page-container-summary__subtitle"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be slight improvement on code readability if this was showSubtitle &&
. I say this because the other conditionally rendered elements are rendered if a value is truthy with &&
. Reading the file and then encountering ||
is a little confusing. I say this lightly though, if switching to showSubtitle &&
makes things less readable or intuitive elsewhere, then my suggestion here should be ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did it this way because the default of the summary component is to show the subtitle, and hiding it is the exception. If I used showSubtitle
as the boolean prop then I think it's a less convenient API since I'd have to add that in more places than not.
@@ -267,7 +269,31 @@ const MODALS = { | |||
|
|||
CUSTOMIZE_GAS: { | |||
contents: [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we also need to switch over the modal used on the send screen at some point (but not as part of this PR).
- Create github issue for using new customize gas modal component on send screen.
import ConfirmTransactionSwitch from './confirm-transaction-switch.component' | ||
|
||
const mapStateToProps = state => { | ||
const { confirmTransaction } = state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should map the specific properties within confirmTransaction
to props here. It will simplify the logic within the component.
@@ -0,0 +1,4 @@ | |||
export function isConfirmDeployContract (txData = {}) { | |||
const { txParams = {} } = txData | |||
return !txParams.to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is consistent with current code, but I wonder if there is a more specific check. It seems likely that we will be handling other transactions in the future that don't have a recipient address. Perhaps we can parse something from data
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tools I have for parsing data (abi-decoder and eth-method-registry) don't return anything from the deploy contract data, so I don't think there's a quick fix at our disposal. I asked kumavis about this as well and deploying a contract should be the only case when txParams.to
is not defined.
|
||
if (paramsTransactionId) { | ||
// Check to make sure params ID is valid | ||
const tx = R.find(({ id }) => id + '' === paramsTransactionId)(unconfirmedTransactions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with using ramda, but the code might become a little more accessible if we use the native find
method.
} | ||
} | ||
|
||
setTransactionToConfirm () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this method is another case where the logic could be moved to the .container
component and then to selectors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept this method in the component file since it works with react-router props. I kinda see methods in the container file as having to do with modifying the data the component uses and not anything to do with the view, so I've been keeping react-router/view changes in the component and not the container.
@@ -45,9 +45,9 @@ function calcGasTotal (gasLimit, gasPrice) { | |||
|
|||
function isBalanceSufficient ({ | |||
amount = '0x0', | |||
amountConversionRate = 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why amountConversionRate
was defaulted to 0
before? We should confirm that changing the default to 1
does not break any desired behaviour.
ui/app/conversion-util.js
Outdated
@@ -28,6 +28,8 @@ const BN = ethUtil.BN | |||
const R = require('ramda') | |||
const { stripHexPrefix } = require('ethereumjs-util') | |||
|
|||
global.BigNumber = BigNumber |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why add BigNumber
to global?
@@ -0,0 +1,116 @@ | |||
import currencyFormatter from 'currency-formatter' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I asked a similar question elsewhere. Your thoughts on including this in a general ui/app/helpers/
directory as opposed to within a root directory for confirm-transaction components?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just found myself reusing these in various components and the .duck, and it got annoying having to move these functions/files around based on which component was using a function during debugging/refactoring (up one level when used by a parent, down one level when not used).
@danjm I'm indifferent to using selectors as it has pros and cons, unless it's for more complicated retrieval or using a combination of selectors with As for the folder structure, I think I placed selectors I did use in a top level selectors folder, since I used them in both a |
7380c90
to
c123419
Compare
c123419
to
a2d9c43
Compare
…clicking through. (e2e beta tests)
…n to contain localhost before attempting to click. (e2e beta tests)
…ered before attempting to select the tx-list-item. (e2e beta tests)
…e-upgrades e2e beta test upgrades for confirm refactor
…firmations that have data
What is the process of getting this up into master/production? Didn't see a place to chat with the team (maybe add chat server badge to readme?) |
@1blockologist this will bei n 4.9.0, should be out early next week! thanks for your patience. |
Where are screenshots of before and after? Common, it is just Ctrl+Shift+PrtSc and Ctrl+V on GNOME. ;) |
No description provided.