mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-22 17:33:23 +01:00
Implement asset page (#8696)
A new page has been created for viewing assets. This replaces the old `selectedToken` state, which previously would augment the home page to show token-specific information. The new asset page shows the standard token overview as seen previously on the home page, plus a history filtered to show just transactions relevant to that token. The actions that were available in the old token list menu have been moved to a "Token Options" menu that mirrors the "Account Options" menu. The `selectedTokenAddress` state has been removed, as it is no longer being used for anything. `getMetaMetricState` has been renamed to `getBackgroundMetaMetricState` because its sole purpose is extracting data from the background state to send metrics from the background. It's not really a selector, but it was convenient for it to use the same selectors the UI uses to extract background data, so I left it there for now. A new Redux store has been added to track state related to browser history. The most recent "overview" page (i.e. the home page or the asset page) is currently being tracked, so that actions taken from the asset page can return the user back to the asset page when the action has finished.
This commit is contained in:
parent
ec2e5c848b
commit
df85ab6e10
@ -519,9 +519,6 @@
|
||||
"hide": {
|
||||
"message": "ደብቅ"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "ተለዋጭ ስም ደብቅ"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "ተለዋጭ ስም ይደበቅ?"
|
||||
},
|
||||
|
@ -515,9 +515,6 @@
|
||||
"hide": {
|
||||
"message": "إخفاء"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "إخفاء الرمز"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "أتريد إخفاء العملة الرمزية؟"
|
||||
},
|
||||
|
@ -515,9 +515,6 @@
|
||||
"hide": {
|
||||
"message": "Скриване"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Скриване на жетон"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Скриване на жетон?"
|
||||
},
|
||||
|
@ -519,9 +519,6 @@
|
||||
"hide": {
|
||||
"message": "লুকান"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "টোকেন লুকান"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "টোকেন লুকাবেন?"
|
||||
},
|
||||
|
@ -506,9 +506,6 @@
|
||||
"hide": {
|
||||
"message": "Amaga"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Amagar Fitxa"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Amagar fitxa?"
|
||||
},
|
||||
|
@ -197,9 +197,6 @@
|
||||
"hide": {
|
||||
"message": "Skrýt"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Skrýt token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Skrýt token?"
|
||||
},
|
||||
|
@ -512,9 +512,6 @@
|
||||
"hide": {
|
||||
"message": "Skjul"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Skjul token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Skjul Token?"
|
||||
},
|
||||
|
@ -504,9 +504,6 @@
|
||||
"hide": {
|
||||
"message": "Ausblenden"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Token ausblenden"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Token ausblenden?"
|
||||
},
|
||||
|
@ -516,9 +516,6 @@
|
||||
"hide": {
|
||||
"message": "Απόκρυψη"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Απόκρυψη Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Απόκρυψη του Token;"
|
||||
},
|
||||
|
@ -759,8 +759,9 @@
|
||||
"hide": {
|
||||
"message": "Hide"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Hide Token"
|
||||
"hideTokenSymbol": {
|
||||
"message": "Hide $1",
|
||||
"description": "$1 is the symbol for a token (e.g. 'DAI')"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Hide Token?"
|
||||
@ -1544,6 +1545,9 @@
|
||||
"tokenContractAddress": {
|
||||
"message": "Token Contract Address"
|
||||
},
|
||||
"tokenOptions": {
|
||||
"message": "Token options"
|
||||
},
|
||||
"tokenSymbol": {
|
||||
"message": "Token Symbol"
|
||||
},
|
||||
|
@ -419,9 +419,6 @@
|
||||
"hide": {
|
||||
"message": "Ocultar"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Ocultar token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "¿Ocultar token?"
|
||||
},
|
||||
|
@ -510,9 +510,6 @@
|
||||
"hide": {
|
||||
"message": "Ocultar"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Ocultar token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "¿Ocultar token?"
|
||||
},
|
||||
|
@ -515,9 +515,6 @@
|
||||
"hide": {
|
||||
"message": "Peida"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Peida luba"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Peida luba?"
|
||||
},
|
||||
|
@ -519,9 +519,6 @@
|
||||
"hide": {
|
||||
"message": "عدم نمایش"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "مخفی سازی رمزیاب"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "آیا رمزیاب مخفی شود؟"
|
||||
},
|
||||
|
@ -516,9 +516,6 @@
|
||||
"hide": {
|
||||
"message": "Piilota"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Piilota tietue"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Piilotetaanko tietue?"
|
||||
},
|
||||
|
@ -479,9 +479,6 @@
|
||||
"hide": {
|
||||
"message": "Itago"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Itago ang Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Itago ang Token?"
|
||||
},
|
||||
|
@ -504,9 +504,6 @@
|
||||
"hide": {
|
||||
"message": "Cacher"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Masquer le jeton"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Masquer le jeton?"
|
||||
},
|
||||
|
@ -519,9 +519,6 @@
|
||||
"hide": {
|
||||
"message": "הסתר"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "הסתר טוקן"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "להסתיר טוקן?"
|
||||
},
|
||||
|
@ -519,9 +519,6 @@
|
||||
"hide": {
|
||||
"message": "छुपाएं"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "टोकन छिपाएँ?"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "टोकन छिपाएँ?"
|
||||
},
|
||||
|
@ -173,9 +173,6 @@
|
||||
"hide": {
|
||||
"message": "छुपाएं"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "टोकन छिपाएं"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "टोकन छिपाएंn?"
|
||||
},
|
||||
|
@ -515,9 +515,6 @@
|
||||
"hide": {
|
||||
"message": "Sakrij preglednik"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Sakrij token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Sakriti token?"
|
||||
},
|
||||
|
@ -287,9 +287,6 @@
|
||||
"hide": {
|
||||
"message": "Kache"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Kache Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Kache Token?"
|
||||
},
|
||||
|
@ -515,9 +515,6 @@
|
||||
"hide": {
|
||||
"message": "Elrejtés"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Token elrejtése"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Elrejted a tokent?"
|
||||
},
|
||||
|
@ -506,9 +506,6 @@
|
||||
"hide": {
|
||||
"message": "Sembunyikan"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Sembunyikan Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Sembunyikan Token?"
|
||||
},
|
||||
|
@ -633,9 +633,6 @@
|
||||
"hide": {
|
||||
"message": "Nascondi"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Nascondi Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Nascondi Token?"
|
||||
},
|
||||
|
@ -242,9 +242,6 @@
|
||||
"hide": {
|
||||
"message": "隠す"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "トークンを隠す"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "トークンを隠しますか?"
|
||||
},
|
||||
|
@ -519,9 +519,6 @@
|
||||
"hide": {
|
||||
"message": "ಮರೆಮಾಡಿ"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "ಟೋಕನ್ ಮರೆಮಾಡಿ"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "ಟೋಕನ್ ಮರೆಮಾಡುವುದೇ?"
|
||||
},
|
||||
|
@ -513,9 +513,6 @@
|
||||
"hide": {
|
||||
"message": "숨기기"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "토큰 숨기기"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "토큰 숨기기?"
|
||||
},
|
||||
|
@ -519,9 +519,6 @@
|
||||
"hide": {
|
||||
"message": "Slėpti"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Slėpti prieigos raktą"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Slėpti prieigos raktą?"
|
||||
},
|
||||
|
@ -515,9 +515,6 @@
|
||||
"hide": {
|
||||
"message": "Slēpt"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Paslēpt marķieri"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Paslēpt žetonu?"
|
||||
},
|
||||
|
@ -503,9 +503,6 @@
|
||||
"hide": {
|
||||
"message": "Sembunyikan"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Sembunyikan Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Sembunyikan Token?"
|
||||
},
|
||||
|
@ -167,9 +167,6 @@
|
||||
"hide": {
|
||||
"message": "Verbergen"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Token verbergen"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Token verbergen?"
|
||||
},
|
||||
|
@ -509,9 +509,6 @@
|
||||
"hide": {
|
||||
"message": "Skjul"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Skjul tokenet"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Skjul sjetonger?"
|
||||
},
|
||||
|
@ -137,9 +137,6 @@
|
||||
"hide": {
|
||||
"message": "Itago"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Itago ang Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Itago ang Token?"
|
||||
},
|
||||
|
@ -516,9 +516,6 @@
|
||||
"hide": {
|
||||
"message": "Schowaj"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Schowaj token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Schować token?"
|
||||
},
|
||||
|
@ -173,9 +173,6 @@
|
||||
"hide": {
|
||||
"message": "Ocultar"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Ocultar Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Ocultar Token?"
|
||||
},
|
||||
|
@ -513,9 +513,6 @@
|
||||
"hide": {
|
||||
"message": "Ocultar"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Ocultar Token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Esconder token?"
|
||||
},
|
||||
|
@ -509,9 +509,6 @@
|
||||
"hide": {
|
||||
"message": "Ascunde"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Ascunde tokenul"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Ascunde simbol?"
|
||||
},
|
||||
|
@ -203,9 +203,6 @@
|
||||
"hide": {
|
||||
"message": "Скрыть"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Скрыть токен"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Скрыть токен?"
|
||||
},
|
||||
|
@ -507,9 +507,6 @@
|
||||
"hide": {
|
||||
"message": "Skrýt"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Skrýt token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Skrýt token?"
|
||||
},
|
||||
|
@ -510,9 +510,6 @@
|
||||
"hide": {
|
||||
"message": "Skrij"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Skrij žeton"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Skrijem žeton?"
|
||||
},
|
||||
|
@ -516,9 +516,6 @@
|
||||
"hide": {
|
||||
"message": "Сакриј"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Sakrij token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Da li želite da sakrijete token?"
|
||||
},
|
||||
|
@ -509,9 +509,6 @@
|
||||
"hide": {
|
||||
"message": "Dölj"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Göm token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Göm token?"
|
||||
},
|
||||
|
@ -506,9 +506,6 @@
|
||||
"hide": {
|
||||
"message": "Ficha"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Ficha Kianzio"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Ungependa Kianzio?"
|
||||
},
|
||||
|
@ -194,9 +194,6 @@
|
||||
"hide": {
|
||||
"message": "மறை"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "டோக்கனை மறை"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "டோக்கனை மறை?"
|
||||
},
|
||||
|
@ -248,9 +248,6 @@
|
||||
"hide": {
|
||||
"message": "ซ่อน"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "ซ่อนโทเค็น"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "ซ่อนโทเค็นหรือไม่?"
|
||||
},
|
||||
|
@ -200,9 +200,6 @@
|
||||
"hide": {
|
||||
"message": "Gizle"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Jetonu gizle"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Jetonu gizle?"
|
||||
},
|
||||
|
@ -519,9 +519,6 @@
|
||||
"hide": {
|
||||
"message": "Сховати"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Приховати токен"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Приховати токен?"
|
||||
},
|
||||
|
@ -149,9 +149,6 @@
|
||||
"hide": {
|
||||
"message": "Ẩn"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Ẩn mã token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Ẩn mã token?"
|
||||
},
|
||||
|
@ -513,9 +513,6 @@
|
||||
"hide": {
|
||||
"message": "隐藏"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "隐藏代币"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "隐藏代币?"
|
||||
},
|
||||
|
@ -516,9 +516,6 @@
|
||||
"hide": {
|
||||
"message": "隱藏"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "隱藏代幣"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "隱藏代幣?"
|
||||
},
|
||||
|
@ -102,7 +102,6 @@ initialize().catch(log.error)
|
||||
* @property {Object} unapprovedTxs - An object mapping transaction hashes to unapproved transactions.
|
||||
* @property {Array} frequentRpcList - A list of frequently used RPCs, including custom user-provided ones.
|
||||
* @property {Array} addressBook - A list of previously sent to addresses.
|
||||
* @property {address} selectedTokenAddress - Used to indicate if a token is globally selected. Should be deprecated in favor of UI-centric token selection.
|
||||
* @property {Object} contractExchangeRates - Info about current token prices.
|
||||
* @property {Array} tokens - Tokens held by the current user, including their balances.
|
||||
* @property {Object} send - TODO: Document
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getMetaMetricState } from '../../../ui/app/selectors'
|
||||
import { getBackgroundMetaMetricState } from '../../../ui/app/selectors'
|
||||
import { sendMetaMetricsEvent } from '../../../ui/app/helpers/utils/metametrics.util'
|
||||
|
||||
const inDevelopment = process.env.NODE_ENV === 'development'
|
||||
@ -8,7 +8,7 @@ const METAMETRICS_TRACKING_URL = inDevelopment
|
||||
: 'http://www.metamask.io/metametrics-prod'
|
||||
|
||||
export default function backEndMetaMetricsEvent (metaMaskState, eventData) {
|
||||
const stateEventData = getMetaMetricState({ metamask: metaMaskState })
|
||||
const stateEventData = getBackgroundMetaMetricState({ metamask: metaMaskState })
|
||||
|
||||
if (stateEventData.participateInMetaMetrics) {
|
||||
sendMetaMetricsEvent({
|
||||
|
@ -527,5 +527,8 @@
|
||||
},
|
||||
"unconnectedAccount": {
|
||||
"state": "CLOSED"
|
||||
},
|
||||
"history": {
|
||||
"mostRecentOverviewPage": "/"
|
||||
}
|
||||
}
|
||||
|
@ -478,5 +478,8 @@
|
||||
},
|
||||
"unconnectedAccount": {
|
||||
"state": "CLOSED"
|
||||
},
|
||||
"history": {
|
||||
"mostRecentOverviewPage": "/"
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"selectedTokenAddress": "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d",
|
||||
"unapprovedMsgs": {},
|
||||
"unapprovedMsgCount": 0,
|
||||
"unapprovedPersonalMsgs": {},
|
||||
|
@ -903,7 +903,6 @@ describe('MetaMask', function () {
|
||||
})
|
||||
|
||||
it('finds the transaction in the transactions list', async function () {
|
||||
await driver.clickElement(By.css(`[data-testid="home__history-tab"]`))
|
||||
await driver.wait(async () => {
|
||||
const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item'))
|
||||
return confirmedTxes.length === 1
|
||||
@ -996,13 +995,6 @@ describe('MetaMask', function () {
|
||||
const txStatuses = await driver.findElements(By.css('.list-item__heading'))
|
||||
await driver.wait(until.elementTextMatches(txStatuses[0], /Send\sTST/), 10000)
|
||||
|
||||
await driver.clickElement(By.css('[data-testid="home__asset-tab"]'))
|
||||
|
||||
await driver.clickElement(By.css('[data-testid="wallet-balance"]'))
|
||||
|
||||
await driver.clickElement(By.css('.token-cell'))
|
||||
await driver.delay(1000)
|
||||
|
||||
const tokenBalanceAmount = await driver.findElements(By.css('.token-overview__primary-balance'))
|
||||
await driver.wait(until.elementTextMatches(tokenBalanceAmount[0], /7.500\s*TST/), 10000)
|
||||
})
|
||||
@ -1025,8 +1017,6 @@ describe('MetaMask', function () {
|
||||
await driver.switchToWindow(extension)
|
||||
await driver.delay(regularDelayMs)
|
||||
|
||||
await driver.clickElement(By.css('[data-testid="home__history-tab"]'))
|
||||
|
||||
await driver.wait(async () => {
|
||||
const pendingTxes = await driver.findElements(By.css('.transaction-list__pending-transactions .transaction-list-item'))
|
||||
return pendingTxes.length === 1
|
||||
@ -1227,12 +1217,9 @@ describe('MetaMask', function () {
|
||||
|
||||
describe('Hide token', function () {
|
||||
it('hides the token when clicked', async function () {
|
||||
await driver.clickElement(By.css('[data-testid="home__asset-tab"]'))
|
||||
await driver.clickElement(By.css('[data-testid="token-options__button"]'))
|
||||
|
||||
await driver.clickElement(By.css('.token-cell__ellipsis'))
|
||||
|
||||
const byTokenMenuDropdownOption = By.css('.menu__item--clickable')
|
||||
await driver.clickElement(byTokenMenuDropdownOption)
|
||||
await driver.clickElement(By.css('[data-testid="token-options__hide"]'))
|
||||
|
||||
const confirmHideModal = await driver.findElement(By.css('span .modal'))
|
||||
|
||||
@ -1245,6 +1232,7 @@ describe('MetaMask', function () {
|
||||
|
||||
describe('Add existing token using search', function () {
|
||||
it('clicks on the Add Token button', async function () {
|
||||
await driver.clickElement(By.css('[data-testid="asset__back"]'))
|
||||
await driver.clickElement(By.xpath(`//button[contains(text(), 'Add Token')]`))
|
||||
await driver.delay(regularDelayMs)
|
||||
})
|
||||
|
@ -52,15 +52,6 @@ describe('MetaMask Reducers', function () {
|
||||
assert.equal(state.selectedAddress, 'test address')
|
||||
})
|
||||
|
||||
it('sets select ', function () {
|
||||
const state = reduceMetamask({}, {
|
||||
type: actionConstants.SET_SELECTED_TOKEN,
|
||||
value: 'test token',
|
||||
})
|
||||
|
||||
assert.equal(state.selectedTokenAddress, 'test token')
|
||||
})
|
||||
|
||||
it('sets account label', function () {
|
||||
const state = reduceMetamask({}, {
|
||||
type: actionConstants.SET_ACCOUNT_LABEL,
|
||||
|
@ -4,12 +4,10 @@ import classnames from 'classnames'
|
||||
import Identicon from '../../ui/identicon'
|
||||
|
||||
const AssetListItem = ({
|
||||
active,
|
||||
children,
|
||||
className,
|
||||
'data-testid': dataTestId,
|
||||
iconClassName,
|
||||
menu,
|
||||
onClick,
|
||||
tokenAddress,
|
||||
tokenImage,
|
||||
@ -17,9 +15,7 @@ const AssetListItem = ({
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={classnames('asset-list-item__container', className, {
|
||||
'asset-list-item__container--active': active,
|
||||
})}
|
||||
className={classnames('asset-list-item__container', className)}
|
||||
data-testid={dataTestId}
|
||||
onClick={onClick}
|
||||
>
|
||||
@ -35,18 +31,16 @@ const AssetListItem = ({
|
||||
{ children }
|
||||
</div>
|
||||
{ warning }
|
||||
{ menu }
|
||||
<i className="fas fa-chevron-right asset-list-item__chevron-right" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
AssetListItem.propTypes = {
|
||||
active: PropTypes.bool,
|
||||
children: PropTypes.node.isRequired,
|
||||
className: PropTypes.string,
|
||||
'data-testid': PropTypes.string,
|
||||
iconClassName: PropTypes.string,
|
||||
menu: PropTypes.node,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
tokenAddress: PropTypes.string,
|
||||
tokenImage: PropTypes.string,
|
||||
@ -54,10 +48,8 @@ AssetListItem.propTypes = {
|
||||
}
|
||||
|
||||
AssetListItem.defaultProps = {
|
||||
active: undefined,
|
||||
className: undefined,
|
||||
'data-testid': undefined,
|
||||
menu: undefined,
|
||||
iconClassName: undefined,
|
||||
tokenAddress: undefined,
|
||||
tokenImage: undefined,
|
||||
|
@ -3,9 +3,12 @@
|
||||
display: flex;
|
||||
padding: 24px 16px;
|
||||
align-items: center;
|
||||
border-top: 1px solid $mercury;
|
||||
border-bottom: 1px solid $mercury;
|
||||
cursor: pointer;
|
||||
|
||||
&--active {
|
||||
background: #D9D7DA;
|
||||
&:hover {
|
||||
background-color: $Grey-000;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,4 +19,8 @@
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__chevron-right {
|
||||
color: $Grey-500;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import AddTokenButton from '../add-token-button'
|
||||
import TokenList from '../token-list'
|
||||
@ -9,14 +10,12 @@ import CurrencyDisplay from '../../ui/currency-display'
|
||||
import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'
|
||||
import { useMetricEvent } from '../../../hooks/useMetricEvent'
|
||||
import { useUserPreferencedCurrency } from '../../../hooks/useUserPreferencedCurrency'
|
||||
import { getCurrentAccountWithSendEtherInfo, getShouldShowFiat } from '../../../selectors/selectors'
|
||||
import { setSelectedToken } from '../../../store/actions'
|
||||
import { getCurrentAccountWithSendEtherInfo, getNativeCurrency, getShouldShowFiat } from '../../../selectors'
|
||||
|
||||
const AssetList = () => {
|
||||
const dispatch = useDispatch()
|
||||
const AssetList = ({ onClickAsset }) => {
|
||||
const history = useHistory()
|
||||
const selectedAccountBalance = useSelector((state) => getCurrentAccountWithSendEtherInfo(state).balance)
|
||||
const selectedTokenAddress = useSelector((state) => state.metamask.selectedTokenAddress)
|
||||
const nativeCurrency = useSelector(getNativeCurrency)
|
||||
const showFiat = useSelector(getShouldShowFiat)
|
||||
const selectTokenEvent = useMetricEvent({
|
||||
eventOpts: {
|
||||
@ -45,8 +44,7 @@ const AssetList = () => {
|
||||
return (
|
||||
<>
|
||||
<AssetListItem
|
||||
active={!selectedTokenAddress}
|
||||
onClick={() => dispatch(setSelectedToken())}
|
||||
onClick={() => onClickAsset(nativeCurrency)}
|
||||
data-testid="wallet-balance"
|
||||
>
|
||||
<CurrencyDisplay
|
||||
@ -68,7 +66,7 @@ const AssetList = () => {
|
||||
</AssetListItem>
|
||||
<TokenList
|
||||
onTokenClick={(tokenAddress) => {
|
||||
dispatch(setSelectedToken(tokenAddress))
|
||||
onClickAsset(tokenAddress)
|
||||
selectTokenEvent()
|
||||
}}
|
||||
/>
|
||||
@ -82,4 +80,8 @@ const AssetList = () => {
|
||||
)
|
||||
}
|
||||
|
||||
AssetList.propTypes = {
|
||||
onClickAsset: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default AssetList
|
||||
|
@ -1,67 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import * as actions from '../../../store/actions'
|
||||
import { createAccountLink as genAccountLink } from '@metamask/etherscan-link'
|
||||
import { Menu, Item, CloseArea } from './components/menu'
|
||||
|
||||
class TokenMenuDropdown extends Component {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
showHideTokenConfirmationModal: PropTypes.func.isRequired,
|
||||
token: PropTypes.object.isRequired,
|
||||
network: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
onClose = (e) => {
|
||||
e.stopPropagation()
|
||||
this.props.onClose()
|
||||
}
|
||||
|
||||
render () {
|
||||
const { showHideTokenConfirmationModal } = this.props
|
||||
|
||||
return (
|
||||
<Menu className="token-menu-dropdown" isShowing>
|
||||
<CloseArea onClick={this.onClose} />
|
||||
<Item
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
showHideTokenConfirmationModal(this.props.token)
|
||||
this.props.onClose()
|
||||
}}
|
||||
text={this.context.t('hideToken')}
|
||||
/>
|
||||
<Item
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
const url = genAccountLink(this.props.token.address, this.props.network)
|
||||
global.platform.openTab({ url })
|
||||
this.props.onClose()
|
||||
}}
|
||||
text={this.context.t('viewOnEtherscan')}
|
||||
/>
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TokenMenuDropdown)
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
network: state.metamask.network,
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
showHideTokenConfirmationModal: (token) => {
|
||||
dispatch(actions.showModal({ name: 'HIDE_TOKEN_CONFIRMATION', token }))
|
||||
},
|
||||
}
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
display: grid;
|
||||
grid-template-columns: 30% minmax(30%, 1fr) 30%;
|
||||
column-gap: 5px;
|
||||
|
||||
margin-bottom: 24px;
|
||||
padding: 0 8px;
|
||||
border-bottom: 1px solid $Grey-100;
|
||||
|
||||
|
@ -10,7 +10,6 @@ import Identicon from '../../ui/identicon'
|
||||
import AccountListItem from '../../../pages/send/account-list-item/account-list-item.component'
|
||||
import { conversionUtil } from '../../../helpers/utils/conversion-util'
|
||||
import Button from '../../ui/button'
|
||||
import { DEFAULT_ROUTE } from '../../../helpers/constants/routes'
|
||||
|
||||
export default class SignatureRequestOriginal extends Component {
|
||||
static contextTypes = {
|
||||
@ -28,6 +27,7 @@ export default class SignatureRequestOriginal extends Component {
|
||||
clearConfirmTransaction: PropTypes.func.isRequired,
|
||||
conversionRate: PropTypes.number,
|
||||
history: PropTypes.object.isRequired,
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
requesterAddress: PropTypes.string,
|
||||
sign: PropTypes.func.isRequired,
|
||||
txData: PropTypes.object.isRequired,
|
||||
@ -268,7 +268,7 @@ export default class SignatureRequestOriginal extends Component {
|
||||
}
|
||||
|
||||
renderFooter = () => {
|
||||
const { cancel, sign } = this.props
|
||||
const { cancel, clearConfirmTransaction, history, mostRecentOverviewPage, sign } = this.props
|
||||
|
||||
return (
|
||||
<div className="request-signature__footer">
|
||||
@ -286,8 +286,8 @@ export default class SignatureRequestOriginal extends Component {
|
||||
name: 'Cancel',
|
||||
},
|
||||
})
|
||||
this.props.clearConfirmTransaction()
|
||||
this.props.history.push(DEFAULT_ROUTE)
|
||||
clearConfirmTransaction()
|
||||
history.push(mostRecentOverviewPage)
|
||||
}}
|
||||
>
|
||||
{ this.context.t('cancel') }
|
||||
@ -306,8 +306,8 @@ export default class SignatureRequestOriginal extends Component {
|
||||
name: 'Confirm',
|
||||
},
|
||||
})
|
||||
this.props.clearConfirmTransaction()
|
||||
this.props.history.push(DEFAULT_ROUTE)
|
||||
clearConfirmTransaction()
|
||||
history.push(mostRecentOverviewPage)
|
||||
}}
|
||||
>
|
||||
{ this.context.t('sign') }
|
||||
|
@ -10,12 +10,14 @@ import {
|
||||
import { getAccountByAddress } from '../../../helpers/utils/util'
|
||||
import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck'
|
||||
import SignatureRequestOriginal from './signature-request-original.component'
|
||||
import { getMostRecentOverviewPage } from '../../../ducks/history/history'
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
requester: null,
|
||||
requesterAddress: null,
|
||||
conversionRate: conversionRateSelector(state),
|
||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||
// not passed to component
|
||||
allAccounts: accountsWithSendEtherInfoSelector(state),
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import classnames from 'classnames'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { Component } from 'react'
|
||||
import { conversionUtil, multiplyCurrencies } from '../../../helpers/utils/conversion-util'
|
||||
import TokenMenuDropdown from '../dropdowns/token-menu-dropdown.js'
|
||||
import Tooltip from '../../ui/tooltip-v2'
|
||||
import { I18nContext } from '../../../contexts/i18n'
|
||||
import AssetListItem from '../asset-list-item'
|
||||
@ -15,7 +14,6 @@ export default class TokenCell extends Component {
|
||||
outdatedBalance: PropTypes.bool,
|
||||
symbol: PropTypes.string,
|
||||
string: PropTypes.string,
|
||||
selectedTokenAddress: PropTypes.string,
|
||||
contractExchangeRates: PropTypes.object,
|
||||
conversionRate: PropTypes.number,
|
||||
currentCurrency: PropTypes.string,
|
||||
@ -28,18 +26,12 @@ export default class TokenCell extends Component {
|
||||
outdatedBalance: false,
|
||||
}
|
||||
|
||||
state = {
|
||||
tokenMenuOpen: false,
|
||||
}
|
||||
|
||||
render () {
|
||||
const t = this.context
|
||||
const { tokenMenuOpen } = this.state
|
||||
const {
|
||||
address,
|
||||
symbol,
|
||||
string,
|
||||
selectedTokenAddress,
|
||||
contractExchangeRates,
|
||||
conversionRate,
|
||||
onClick,
|
||||
@ -71,26 +63,6 @@ export default class TokenCell extends Component {
|
||||
|
||||
const showFiat = Boolean(currentTokenInFiat) && currentCurrency.toUpperCase() !== symbol
|
||||
|
||||
const menu = (
|
||||
<>
|
||||
<div>
|
||||
<i
|
||||
className="fa fa-ellipsis-h fa-lg token-cell__ellipsis cursor-pointer"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
this.setState({ tokenMenuOpen: true })
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{tokenMenuOpen && (
|
||||
<TokenMenuDropdown
|
||||
onClose={() => this.setState({ tokenMenuOpen: false })}
|
||||
token={{ symbol, address }}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
const warning = outdatedBalance
|
||||
? (
|
||||
<Tooltip
|
||||
@ -117,10 +89,8 @@ export default class TokenCell extends Component {
|
||||
|
||||
return (
|
||||
<AssetListItem
|
||||
active={selectedTokenAddress === address}
|
||||
className={classnames('token-cell', { 'token-cell--outdated': outdatedBalance })}
|
||||
iconClassName="token-cell__icon"
|
||||
menu={menu}
|
||||
onClick={onClick.bind(null, address)}
|
||||
tokenAddress={address}
|
||||
tokenImage={image}
|
||||
|
@ -7,7 +7,6 @@ function mapStateToProps (state) {
|
||||
contractExchangeRates: state.metamask.contractExchangeRates,
|
||||
conversionRate: state.metamask.conversionRate,
|
||||
currentCurrency: state.metamask.currentCurrency,
|
||||
selectedTokenAddress: state.metamask.selectedTokenAddress,
|
||||
userAddress: getSelectedAddress(state),
|
||||
}
|
||||
}
|
||||
|
@ -34,10 +34,6 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
|
||||
opacity: 0.5
|
||||
}
|
||||
|
||||
&__ellipsis {
|
||||
line-height: 38px;
|
||||
}
|
||||
|
||||
&__balance-wrapper {
|
||||
flex: 1;
|
||||
flex-flow: row wrap;
|
||||
|
@ -15,7 +15,6 @@ describe('Token Cell', function () {
|
||||
const state = {
|
||||
metamask: {
|
||||
currentCurrency: 'usd',
|
||||
selectedTokenAddress: '0xToken',
|
||||
selectedAddress: '0xAddress',
|
||||
contractExchangeRates: {
|
||||
'0xAnotherToken': 0.015,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { useContext } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import classnames from 'classnames'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
@ -15,7 +16,7 @@ import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'
|
||||
import { showModal } from '../../../store/actions'
|
||||
import { isBalanceCached, getSelectedAccount, getShouldShowFiat } from '../../../selectors/selectors'
|
||||
|
||||
const EthOverview = () => {
|
||||
const EthOverview = ({ className }) => {
|
||||
const dispatch = useDispatch()
|
||||
const t = useContext(I18nContext)
|
||||
const sendEvent = useMetricEvent({
|
||||
@ -99,13 +100,18 @@ const EthOverview = () => {
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
icon={<Identicon diameter={50} />}
|
||||
className={className}
|
||||
icon={<Identicon diameter={32} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
EthOverview.propTypes = {
|
||||
className: PropTypes.string,
|
||||
}
|
||||
|
||||
EthOverview.defaultProps = {
|
||||
className: undefined,
|
||||
}
|
||||
|
||||
export default EthOverview
|
||||
|
@ -3,11 +3,12 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
height: 54px;
|
||||
height: 209px;
|
||||
min-width: 0;
|
||||
|
||||
padding-top: 10px;
|
||||
|
||||
flex-direction: column;
|
||||
height: initial;
|
||||
width: 100%;
|
||||
|
||||
&__balance {
|
||||
@ -21,7 +22,8 @@
|
||||
&__buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 16px;
|
||||
height: 44px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,9 @@ import WalletOverview from './wallet-overview'
|
||||
import { SEND_ROUTE } from '../../../helpers/constants/routes'
|
||||
import { useMetricEvent } from '../../../hooks/useMetricEvent'
|
||||
import { getAssetImages } from '../../../selectors/selectors'
|
||||
import { updateSend } from '../../../store/actions'
|
||||
import { updateSendToken } from '../../../store/actions'
|
||||
|
||||
const TokenOverview = ({ token }) => {
|
||||
const TokenOverview = ({ className, token }) => {
|
||||
const dispatch = useDispatch()
|
||||
const t = useContext(I18nContext)
|
||||
const sendTokenEvent = useMetricEvent({
|
||||
@ -43,16 +43,17 @@ const TokenOverview = ({ token }) => {
|
||||
className="token-overview__button"
|
||||
onClick={() => {
|
||||
sendTokenEvent()
|
||||
dispatch(updateSend({ token }))
|
||||
dispatch(updateSendToken(token))
|
||||
history.push(SEND_ROUTE)
|
||||
}}
|
||||
>
|
||||
{ t('send') }
|
||||
</Button>
|
||||
)}
|
||||
className={className}
|
||||
icon={(
|
||||
<Identicon
|
||||
diameter={50}
|
||||
diameter={32}
|
||||
address={token.address}
|
||||
image={assetImages[token.address]}
|
||||
/>
|
||||
@ -62,6 +63,7 @@ const TokenOverview = ({ token }) => {
|
||||
}
|
||||
|
||||
TokenOverview.propTypes = {
|
||||
className: PropTypes.string,
|
||||
token: PropTypes.shape({
|
||||
address: PropTypes.string.isRequired,
|
||||
decimals: PropTypes.number,
|
||||
@ -69,4 +71,8 @@ TokenOverview.propTypes = {
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
TokenOverview.defaultProps = {
|
||||
className: undefined,
|
||||
}
|
||||
|
||||
export default TokenOverview
|
||||
|
@ -1,9 +1,10 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
|
||||
const WalletOverview = ({ balance, buttons, icon }) => {
|
||||
const WalletOverview = ({ balance, buttons, className, icon }) => {
|
||||
return (
|
||||
<div className="wallet-overview">
|
||||
<div className={classnames('wallet-overview', className)}>
|
||||
<div className="wallet-overview__balance">
|
||||
{ icon }
|
||||
{ balance }
|
||||
@ -18,7 +19,12 @@ const WalletOverview = ({ balance, buttons, icon }) => {
|
||||
WalletOverview.propTypes = {
|
||||
balance: PropTypes.element.isRequired,
|
||||
buttons: PropTypes.element.isRequired,
|
||||
className: PropTypes.string,
|
||||
icon: PropTypes.element.isRequired,
|
||||
}
|
||||
|
||||
WalletOverview.defaultProps = {
|
||||
className: undefined,
|
||||
}
|
||||
|
||||
export default WalletOverview
|
||||
|
@ -6,11 +6,11 @@ import { captureException } from '@sentry/browser'
|
||||
|
||||
import {
|
||||
getCurrentNetworkId,
|
||||
getSelectedAsset,
|
||||
getAccountType,
|
||||
getNumberOfAccounts,
|
||||
getNumberOfTokens,
|
||||
} from '../selectors/selectors'
|
||||
import { getSendToken } from '../selectors/send'
|
||||
import {
|
||||
txDataSelector,
|
||||
} from '../selectors/confirm-transaction'
|
||||
@ -31,7 +31,7 @@ export function MetaMetricsProvider ({ children }) {
|
||||
const txData = useSelector(txDataSelector) || {}
|
||||
const network = useSelector(getCurrentNetworkId)
|
||||
const environmentType = getEnvironmentType()
|
||||
const activeCurrency = useSelector(getSelectedAsset)
|
||||
const activeCurrency = useSelector(getSendToken)?.symbol
|
||||
const accountType = useSelector(getAccountType)
|
||||
const confirmTransactionOrigin = txData.origin
|
||||
const metaMetricsId = useSelector((state) => state.metamask.metaMetricsId)
|
||||
|
38
ui/app/ducks/history/history.js
Normal file
38
ui/app/ducks/history/history.js
Normal file
@ -0,0 +1,38 @@
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
import { ASSET_ROUTE, DEFAULT_ROUTE } from '../../helpers/constants/routes'
|
||||
|
||||
// Constants
|
||||
|
||||
const initialState = {
|
||||
mostRecentOverviewPage: DEFAULT_ROUTE,
|
||||
}
|
||||
|
||||
const name = 'history'
|
||||
|
||||
// Slice (reducer plus auto-generated actions and action creators)
|
||||
|
||||
const slice = createSlice({
|
||||
name,
|
||||
initialState,
|
||||
reducers: {
|
||||
pageChanged: (state, action) => {
|
||||
const path = action.payload
|
||||
if (path === DEFAULT_ROUTE || path.startsWith(ASSET_ROUTE)) {
|
||||
state.mostRecentOverviewPage = path
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const { actions, reducer } = slice
|
||||
|
||||
export default reducer
|
||||
|
||||
// Selectors
|
||||
|
||||
export const getMostRecentOverviewPage = (state) => state[name].mostRecentOverviewPage
|
||||
|
||||
// Actions / action-creators
|
||||
|
||||
export const { pageChanged } = actions
|
@ -6,6 +6,7 @@ import appStateReducer from './app/app'
|
||||
import confirmTransactionReducer from './confirm-transaction/confirm-transaction.duck'
|
||||
import gasReducer from './gas/gas.duck'
|
||||
import { switchToConnected, unconnectedAccount } from './alerts'
|
||||
import historyReducer from './history/history'
|
||||
import { ALERT_TYPES } from '../../../app/scripts/controllers/alert'
|
||||
|
||||
export default combineReducers({
|
||||
@ -14,6 +15,7 @@ export default combineReducers({
|
||||
activeTab: (s) => (s === undefined ? null : s),
|
||||
metamask: metamaskReducer,
|
||||
appState: appStateReducer,
|
||||
history: historyReducer,
|
||||
send: sendReducer,
|
||||
confirmTransaction: confirmTransactionReducer,
|
||||
gas: gasReducer,
|
||||
|
@ -11,7 +11,6 @@ export default function reduceMetamask (state = {}, action) {
|
||||
unapprovedTxs: {},
|
||||
frequentRpcList: [],
|
||||
addressBook: [],
|
||||
selectedTokenAddress: null,
|
||||
contractExchangeRates: {},
|
||||
tokens: [],
|
||||
pendingTokens: {},
|
||||
@ -87,33 +86,6 @@ export default function reduceMetamask (state = {}, action) {
|
||||
selectedAddress: action.value,
|
||||
}
|
||||
|
||||
case actionConstants.SET_SELECTED_TOKEN: {
|
||||
const newState = {
|
||||
...metamaskState,
|
||||
selectedTokenAddress: action.value,
|
||||
}
|
||||
const newSend = { ...metamaskState.send }
|
||||
|
||||
if (metamaskState.send.editingTransactionId && !action.value) {
|
||||
delete newSend.token
|
||||
const unapprovedTx = newState.unapprovedTxs[newSend.editingTransactionId] || {}
|
||||
const txParams = unapprovedTx.txParams || {}
|
||||
newState.unapprovedTxs = {
|
||||
...newState.unapprovedTxs,
|
||||
[newSend.editingTransactionId]: {
|
||||
...unapprovedTx,
|
||||
txParams: { ...txParams, data: '' },
|
||||
},
|
||||
}
|
||||
newSend.tokenBalance = null
|
||||
newSend.balance = '0'
|
||||
newSend.from = unapprovedTx.from || ''
|
||||
}
|
||||
|
||||
newState.send = newSend
|
||||
return newState
|
||||
}
|
||||
|
||||
case actionConstants.SET_ACCOUNT_LABEL:
|
||||
const account = action.value.account
|
||||
const name = action.value.label
|
||||
@ -227,6 +199,35 @@ export default function reduceMetamask (state = {}, action) {
|
||||
},
|
||||
})
|
||||
|
||||
case actionConstants.UPDATE_SEND_TOKEN:
|
||||
const newSend = {
|
||||
...metamaskState.send,
|
||||
token: action.value,
|
||||
}
|
||||
// erase token-related state when switching back to native currency
|
||||
if (newSend.editingTransactionId && !newSend.token) {
|
||||
const unapprovedTx = newSend?.unapprovedTxs?.[newSend.editingTransactionId] || {}
|
||||
const txParams = unapprovedTx.txParams || {}
|
||||
Object.assign(newSend, {
|
||||
tokenBalance: null,
|
||||
balance: '0',
|
||||
from: unapprovedTx.from || '',
|
||||
unapprovedTxs: {
|
||||
...newSend.unapprovedTxs,
|
||||
[newSend.editingTransactionId]: {
|
||||
...unapprovedTx,
|
||||
txParams: {
|
||||
...txParams,
|
||||
data: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return Object.assign(metamaskState, {
|
||||
send: newSend,
|
||||
})
|
||||
|
||||
case actionConstants.UPDATE_SEND_ENS_RESOLUTION:
|
||||
return {
|
||||
...metamaskState,
|
||||
|
@ -1,6 +1,7 @@
|
||||
const DEFAULT_ROUTE = '/'
|
||||
const UNLOCK_ROUTE = '/unlock'
|
||||
const LOCK_ROUTE = '/lock'
|
||||
const ASSET_ROUTE = '/asset'
|
||||
const SETTINGS_ROUTE = '/settings'
|
||||
const GENERAL_ROUTE = '/settings/general'
|
||||
const CONNECTIONS_ROUTE = '/settings/connections'
|
||||
@ -57,6 +58,7 @@ const ENCRYPTION_PUBLIC_KEY_REQUEST_PATH = '/encryption-public-key-request'
|
||||
export {
|
||||
DEFAULT_ROUTE,
|
||||
ALERTS_ROUTE,
|
||||
ASSET_ROUTE,
|
||||
UNLOCK_ROUTE,
|
||||
LOCK_ROUTE,
|
||||
SETTINGS_ROUTE,
|
||||
|
@ -256,10 +256,6 @@ export function exportAsFile (filename, data, type = 'text/csv') {
|
||||
}
|
||||
}
|
||||
|
||||
export function getTokenAddressFromTokenObject (token) {
|
||||
return Object.values(token)[0].address.toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely checksumms a potentially-null address
|
||||
*
|
||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
|
||||
import ethUtil from 'ethereumjs-util'
|
||||
import { checkExistingAddresses } from './util'
|
||||
import { tokenInfoGetter } from '../../helpers/utils/token-util'
|
||||
import { DEFAULT_ROUTE, CONFIRM_ADD_TOKEN_ROUTE } from '../../helpers/constants/routes'
|
||||
import { CONFIRM_ADD_TOKEN_ROUTE } from '../../helpers/constants/routes'
|
||||
import TextField from '../../components/ui/text-field'
|
||||
import TokenList from './token-list'
|
||||
import TokenSearch from './token-search'
|
||||
@ -24,6 +24,7 @@ class AddToken extends Component {
|
||||
clearPendingTokens: PropTypes.func,
|
||||
tokens: PropTypes.array,
|
||||
identities: PropTypes.object,
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
@ -307,7 +308,7 @@ class AddToken extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { history, clearPendingTokens } = this.props
|
||||
const { history, clearPendingTokens, mostRecentOverviewPage } = this.props
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
@ -317,7 +318,7 @@ class AddToken extends Component {
|
||||
disabled={this.hasError() || !this.hasSelected()}
|
||||
onCancel={() => {
|
||||
clearPendingTokens()
|
||||
history.push(DEFAULT_ROUTE)
|
||||
history.push(mostRecentOverviewPage)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -2,11 +2,13 @@ import { connect } from 'react-redux'
|
||||
import AddToken from './add-token.component'
|
||||
|
||||
import { setPendingTokens, clearPendingTokens } from '../../store/actions'
|
||||
import { getMostRecentOverviewPage } from '../../ducks/history/history'
|
||||
|
||||
const mapStateToProps = ({ metamask }) => {
|
||||
const { identities, tokens, pendingTokens } = metamask
|
||||
const mapStateToProps = (state) => {
|
||||
const { metamask: { identities, tokens, pendingTokens } } = state
|
||||
return {
|
||||
identities,
|
||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||
tokens,
|
||||
pendingTokens,
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ describe('Add Token', function () {
|
||||
clearPendingTokens: sinon.spy(),
|
||||
tokens: [],
|
||||
identities: {},
|
||||
mostRecentOverviewPage: '/',
|
||||
}
|
||||
|
||||
describe('Add Token', function () {
|
||||
|
65
ui/app/pages/asset/asset.js
Normal file
65
ui/app/pages/asset/asset.js
Normal file
@ -0,0 +1,65 @@
|
||||
import React from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { Redirect, useHistory, useParams } from 'react-router-dom'
|
||||
import { createAccountLink } from '@metamask/etherscan-link'
|
||||
|
||||
import TransactionList from '../../components/app/transaction-list'
|
||||
import { EthOverview, TokenOverview } from '../../components/app/wallet-overview'
|
||||
import { getCurrentNetworkId, getSelectedIdentity } from '../../selectors/selectors'
|
||||
import { getTokens } from '../../ducks/metamask/metamask'
|
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes'
|
||||
import { showModal } from '../../store/actions'
|
||||
|
||||
import AssetNavigation from './components/asset-navigation'
|
||||
import TokenOptions from './components/token-options'
|
||||
|
||||
const Asset = () => {
|
||||
const dispatch = useDispatch()
|
||||
const network = useSelector(getCurrentNetworkId)
|
||||
const selectedAccountName = useSelector((state) => getSelectedIdentity(state).name)
|
||||
const nativeCurrency = useSelector((state) => state.metamask.nativeCurrency)
|
||||
const tokens = useSelector(getTokens)
|
||||
const history = useHistory()
|
||||
const { asset } = useParams()
|
||||
|
||||
const token = tokens.find((token) => token.address === asset)
|
||||
|
||||
let assetName
|
||||
let optionsButton
|
||||
|
||||
if (token) {
|
||||
assetName = token.symbol
|
||||
optionsButton = (
|
||||
<TokenOptions
|
||||
onRemove={() => dispatch(showModal({ name: 'HIDE_TOKEN_CONFIRMATION', token }))}
|
||||
onViewEtherscan={() => {
|
||||
const url = createAccountLink(token.address, network)
|
||||
global.platform.openTab({ url })
|
||||
}}
|
||||
tokenSymbol={token.symbol}
|
||||
/>
|
||||
)
|
||||
} else if (asset === nativeCurrency) {
|
||||
assetName = nativeCurrency
|
||||
} else {
|
||||
return <Redirect to={{ pathname: DEFAULT_ROUTE }} />
|
||||
}
|
||||
|
||||
const overview = token
|
||||
? <TokenOverview className="asset__overview" token={token} />
|
||||
: <EthOverview className="asset__overview" />
|
||||
return (
|
||||
<div className="main-container asset__container">
|
||||
<AssetNavigation
|
||||
accountName={selectedAccountName}
|
||||
assetName={assetName}
|
||||
onBack={() => history.push(DEFAULT_ROUTE)}
|
||||
optionsButton={optionsButton}
|
||||
/>
|
||||
{ overview }
|
||||
<TransactionList tokenAddress={token?.address} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Asset
|
45
ui/app/pages/asset/asset.scss
Normal file
45
ui/app/pages/asset/asset.scss
Normal file
@ -0,0 +1,45 @@
|
||||
.asset {
|
||||
&__container {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
&__overview {
|
||||
box-shadow: 0px 3px 4px rgba(135, 134, 134, 0.16);
|
||||
}
|
||||
}
|
||||
|
||||
.asset-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
height: 54px;
|
||||
}
|
||||
|
||||
.asset-breadcrumb {
|
||||
font-size: 14px;
|
||||
color: $Black-100;
|
||||
|
||||
&__chevron {
|
||||
padding: 0 10px 0 2px;
|
||||
font-size: 16px;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
&__asset {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.token-options {
|
||||
&__button {
|
||||
font-size: 20px;
|
||||
color: $Black-100;
|
||||
background-color: inherit;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
25
ui/app/pages/asset/components/asset-breadcrumb.js
Normal file
25
ui/app/pages/asset/components/asset-breadcrumb.js
Normal file
@ -0,0 +1,25 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const AssetBreadcrumb = ({ accountName, assetName, onBack }) => {
|
||||
return (
|
||||
<div className="asset-breadcrumb">
|
||||
<button className="fas fa-chevron-left asset-breadcrumb__chevron" data-testid="asset__back" onClick={onBack} />
|
||||
<span>
|
||||
{accountName}
|
||||
</span>
|
||||
/
|
||||
<span className="asset-breadcrumb__asset">
|
||||
{ assetName }
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
AssetBreadcrumb.propTypes = {
|
||||
accountName: PropTypes.string.isRequired,
|
||||
assetName: PropTypes.string.isRequired,
|
||||
onBack: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default AssetBreadcrumb
|
26
ui/app/pages/asset/components/asset-navigation.js
Normal file
26
ui/app/pages/asset/components/asset-navigation.js
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import AssetBreadcrumb from './asset-breadcrumb'
|
||||
|
||||
const AssetNavigation = ({ accountName, assetName, onBack, optionsButton }) => {
|
||||
return (
|
||||
<div className="asset-navigation">
|
||||
<AssetBreadcrumb accountName={accountName} assetName={assetName} onBack={onBack} />
|
||||
{ optionsButton }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
AssetNavigation.propTypes = {
|
||||
accountName: PropTypes.string.isRequired,
|
||||
assetName: PropTypes.string.isRequired,
|
||||
onBack: PropTypes.func.isRequired,
|
||||
optionsButton: PropTypes.element,
|
||||
}
|
||||
|
||||
AssetNavigation.defaultProps = {
|
||||
optionsButton: undefined,
|
||||
}
|
||||
|
||||
export default AssetNavigation
|
59
ui/app/pages/asset/components/token-options.js
Normal file
59
ui/app/pages/asset/components/token-options.js
Normal file
@ -0,0 +1,59 @@
|
||||
import React, { useContext, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { I18nContext } from '../../../contexts/i18n'
|
||||
import { Menu, MenuItem } from '../../../components/ui/menu'
|
||||
|
||||
const TokenOptions = ({ onRemove, onViewEtherscan, tokenSymbol }) => {
|
||||
const t = useContext(I18nContext)
|
||||
const [tokenOptionsButtonElement, setTokenOptionsButtonElement] = useState(null)
|
||||
const [tokenOptionsOpen, setTokenOptionsOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="fas fa-ellipsis-v token-options__button"
|
||||
data-testid="token-options__button"
|
||||
onClick={() => setTokenOptionsOpen(true)}
|
||||
ref={setTokenOptionsButtonElement}
|
||||
title={t('tokenOptions')}
|
||||
/>
|
||||
{
|
||||
tokenOptionsOpen
|
||||
? (
|
||||
<Menu anchorElement={tokenOptionsButtonElement} onHide={() => setTokenOptionsOpen(false)} >
|
||||
<MenuItem
|
||||
iconClassName="fas fa-external-link-alt token-options__icon"
|
||||
data-testid="token-options__etherscan"
|
||||
onClick={() => {
|
||||
setTokenOptionsOpen(false)
|
||||
onViewEtherscan()
|
||||
}}
|
||||
>
|
||||
{ t('viewOnEtherscan') }
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
iconClassName="fas fa-trash-alt token-options__icon"
|
||||
data-testid="token-options__hide"
|
||||
onClick={() => {
|
||||
setTokenOptionsOpen(false)
|
||||
onRemove()
|
||||
}}
|
||||
>
|
||||
{ t('hideTokenSymbol', [tokenSymbol]) }
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
)
|
||||
: null
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
TokenOptions.propTypes = {
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
onViewEtherscan: PropTypes.func.isRequired,
|
||||
tokenSymbol: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export default TokenOptions
|
1
ui/app/pages/asset/index.js
Normal file
1
ui/app/pages/asset/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './asset'
|
@ -1,6 +1,5 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes'
|
||||
import Button from '../../components/ui/button'
|
||||
import Identicon from '../../components/ui/identicon'
|
||||
import TokenBalance from '../../components/ui/token-balance'
|
||||
@ -13,16 +12,17 @@ export default class ConfirmAddSuggestedToken extends Component {
|
||||
static propTypes = {
|
||||
history: PropTypes.object,
|
||||
addToken: PropTypes.func,
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
pendingTokens: PropTypes.object,
|
||||
removeSuggestedTokens: PropTypes.func,
|
||||
tokens: PropTypes.array,
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { pendingTokens = {}, history } = this.props
|
||||
const { mostRecentOverviewPage, pendingTokens = {}, history } = this.props
|
||||
|
||||
if (Object.keys(pendingTokens).length === 0) {
|
||||
history.push(DEFAULT_ROUTE)
|
||||
history.push(mostRecentOverviewPage)
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ export default class ConfirmAddSuggestedToken extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { addToken, pendingTokens, tokens, removeSuggestedTokens, history } = this.props
|
||||
const { addToken, pendingTokens, tokens, removeSuggestedTokens, history, mostRecentOverviewPage } = this.props
|
||||
const pendingTokenKey = Object.keys(pendingTokens)[0]
|
||||
const pendingToken = pendingTokens[pendingTokenKey]
|
||||
const hasTokenDuplicates = this.checkTokenDuplicates(pendingTokens, tokens)
|
||||
@ -113,7 +113,7 @@ export default class ConfirmAddSuggestedToken extends Component {
|
||||
className="page-container__footer-button"
|
||||
onClick={() => {
|
||||
removeSuggestedTokens()
|
||||
.then(() => history.push(DEFAULT_ROUTE))
|
||||
.then(() => history.push(mostRecentOverviewPage))
|
||||
}}
|
||||
>
|
||||
{ this.context.t('cancel') }
|
||||
@ -125,7 +125,7 @@ export default class ConfirmAddSuggestedToken extends Component {
|
||||
onClick={() => {
|
||||
addToken(pendingToken)
|
||||
.then(() => removeSuggestedTokens())
|
||||
.then(() => history.push(DEFAULT_ROUTE))
|
||||
.then(() => history.push(mostRecentOverviewPage))
|
||||
}}
|
||||
>
|
||||
{ this.context.t('addToken') }
|
||||
|
@ -3,12 +3,14 @@ import { compose } from 'redux'
|
||||
import ConfirmAddSuggestedToken from './confirm-add-suggested-token.component'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { addToken, removeSuggestedTokens } from '../../store/actions'
|
||||
import { getMostRecentOverviewPage } from '../../ducks/history/history'
|
||||
|
||||
const mapStateToProps = ({ metamask }) => {
|
||||
const { pendingTokens, suggestedTokens, tokens } = metamask
|
||||
const mapStateToProps = (state) => {
|
||||
const { metamask: { pendingTokens, suggestedTokens, tokens } } = state
|
||||
const params = { ...pendingTokens, ...suggestedTokens }
|
||||
|
||||
return {
|
||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||
pendingTokens: params,
|
||||
tokens,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { DEFAULT_ROUTE, ADD_TOKEN_ROUTE } from '../../helpers/constants/routes'
|
||||
import { ASSET_ROUTE, ADD_TOKEN_ROUTE } from '../../helpers/constants/routes'
|
||||
import Button from '../../components/ui/button'
|
||||
import Identicon from '../../components/ui/identicon'
|
||||
import TokenBalance from '../../components/ui/token-balance'
|
||||
@ -14,14 +14,15 @@ export default class ConfirmAddToken extends Component {
|
||||
history: PropTypes.object,
|
||||
clearPendingTokens: PropTypes.func,
|
||||
addTokens: PropTypes.func,
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
pendingTokens: PropTypes.object,
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { pendingTokens = {}, history } = this.props
|
||||
const { mostRecentOverviewPage, pendingTokens = {}, history } = this.props
|
||||
|
||||
if (Object.keys(pendingTokens).length === 0) {
|
||||
history.push(DEFAULT_ROUTE)
|
||||
history.push(mostRecentOverviewPage)
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +33,7 @@ export default class ConfirmAddToken extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { history, addTokens, clearPendingTokens, pendingTokens } = this.props
|
||||
const { history, addTokens, clearPendingTokens, mostRecentOverviewPage, pendingTokens } = this.props
|
||||
|
||||
return (
|
||||
<div className="page-container">
|
||||
@ -103,7 +104,12 @@ export default class ConfirmAddToken extends Component {
|
||||
addTokens(pendingTokens)
|
||||
.then(() => {
|
||||
clearPendingTokens()
|
||||
history.push(DEFAULT_ROUTE)
|
||||
const firstTokenAddress = Object.values(pendingTokens)?.[0].address?.toLowerCase()
|
||||
if (firstTokenAddress) {
|
||||
history.push(`${ASSET_ROUTE}/${firstTokenAddress}`)
|
||||
} else {
|
||||
history.push(mostRecentOverviewPage)
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
|
@ -2,10 +2,12 @@ import { connect } from 'react-redux'
|
||||
import ConfirmAddToken from './confirm-add-token.component'
|
||||
|
||||
import { addTokens, clearPendingTokens } from '../../store/actions'
|
||||
import { getMostRecentOverviewPage } from '../../ducks/history/history'
|
||||
|
||||
const mapStateToProps = ({ metamask }) => {
|
||||
const { pendingTokens } = metamask
|
||||
const mapStateToProps = (state) => {
|
||||
const { metamask: { pendingTokens } } = state
|
||||
return {
|
||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||
pendingTokens,
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import Tooltip from '../../components/ui/tooltip-v2'
|
||||
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums'
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
|
||||
import { conversionUtil } from '../../helpers/utils/conversion-util'
|
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes'
|
||||
|
||||
export default class ConfirmDecryptMessage extends Component {
|
||||
static contextTypes = {
|
||||
@ -31,6 +30,7 @@ export default class ConfirmDecryptMessage extends Component {
|
||||
decryptMessageInline: PropTypes.func.isRequired,
|
||||
conversionRate: PropTypes.number,
|
||||
history: PropTypes.object.isRequired,
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
requesterAddress: PropTypes.string,
|
||||
txData: PropTypes.object,
|
||||
domainMetadata: PropTypes.object,
|
||||
@ -278,7 +278,14 @@ export default class ConfirmDecryptMessage extends Component {
|
||||
}
|
||||
|
||||
renderFooter = () => {
|
||||
const { txData } = this.props
|
||||
const {
|
||||
cancelDecryptMessage,
|
||||
clearConfirmTransaction,
|
||||
decryptMessage,
|
||||
history,
|
||||
mostRecentOverviewPage,
|
||||
txData,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="request-decrypt-message__footer">
|
||||
@ -288,7 +295,7 @@ export default class ConfirmDecryptMessage extends Component {
|
||||
className="request-decrypt-message__footer__cancel-button"
|
||||
onClick={async (event) => {
|
||||
this._removeBeforeUnload()
|
||||
await this.props.cancelDecryptMessage(txData, event)
|
||||
await cancelDecryptMessage(txData, event)
|
||||
this.context.metricsEvent({
|
||||
eventOpts: {
|
||||
category: 'Messages',
|
||||
@ -296,8 +303,8 @@ export default class ConfirmDecryptMessage extends Component {
|
||||
name: 'Cancel',
|
||||
},
|
||||
})
|
||||
this.props.clearConfirmTransaction()
|
||||
this.props.history.push(DEFAULT_ROUTE)
|
||||
clearConfirmTransaction()
|
||||
history.push(mostRecentOverviewPage)
|
||||
}}
|
||||
>
|
||||
{ this.context.t('cancel') }
|
||||
@ -308,7 +315,7 @@ export default class ConfirmDecryptMessage extends Component {
|
||||
className="request-decrypt-message__footer__sign-button"
|
||||
onClick={async (event) => {
|
||||
this._removeBeforeUnload()
|
||||
await this.props.decryptMessage(txData, event)
|
||||
await decryptMessage(txData, event)
|
||||
this.context.metricsEvent({
|
||||
eventOpts: {
|
||||
category: 'Messages',
|
||||
@ -316,8 +323,8 @@ export default class ConfirmDecryptMessage extends Component {
|
||||
name: 'Confirm',
|
||||
},
|
||||
})
|
||||
this.props.clearConfirmTransaction()
|
||||
this.props.history.push(DEFAULT_ROUTE)
|
||||
clearConfirmTransaction()
|
||||
history.push(mostRecentOverviewPage)
|
||||
}}
|
||||
>
|
||||
{ this.context.t('decrypt') }
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
} from '../../selectors'
|
||||
import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck'
|
||||
import ConfirmDecryptMessage from './confirm-decrypt-message.component'
|
||||
import { getMostRecentOverviewPage } from '../../ducks/history/history'
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { confirmTransaction,
|
||||
@ -35,6 +36,7 @@ function mapStateToProps (state) {
|
||||
requester: null,
|
||||
requesterAddress: null,
|
||||
conversionRate: conversionRateSelector(state),
|
||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import Identicon from '../../components/ui/identicon'
|
||||
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums'
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
|
||||
import { conversionUtil } from '../../helpers/utils/conversion-util'
|
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes'
|
||||
|
||||
export default class ConfirmEncryptionPublicKey extends Component {
|
||||
static contextTypes = {
|
||||
@ -30,6 +29,7 @@ export default class ConfirmEncryptionPublicKey extends Component {
|
||||
requesterAddress: PropTypes.string,
|
||||
txData: PropTypes.object,
|
||||
domainMetadata: PropTypes.object,
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
@ -183,7 +183,14 @@ export default class ConfirmEncryptionPublicKey extends Component {
|
||||
}
|
||||
|
||||
renderFooter = () => {
|
||||
const { txData } = this.props
|
||||
const {
|
||||
cancelEncryptionPublicKey,
|
||||
clearConfirmTransaction,
|
||||
encryptionPublicKey,
|
||||
history,
|
||||
mostRecentOverviewPage,
|
||||
txData,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="request-encryption-public-key__footer">
|
||||
@ -193,7 +200,7 @@ export default class ConfirmEncryptionPublicKey extends Component {
|
||||
className="request-encryption-public-key__footer__cancel-button"
|
||||
onClick={async (event) => {
|
||||
this._removeBeforeUnload()
|
||||
await this.props.cancelEncryptionPublicKey(txData, event)
|
||||
await cancelEncryptionPublicKey(txData, event)
|
||||
this.context.metricsEvent({
|
||||
eventOpts: {
|
||||
category: 'Messages',
|
||||
@ -201,8 +208,8 @@ export default class ConfirmEncryptionPublicKey extends Component {
|
||||
name: 'Cancel',
|
||||
},
|
||||
})
|
||||
this.props.clearConfirmTransaction()
|
||||
this.props.history.push(DEFAULT_ROUTE)
|
||||
clearConfirmTransaction()
|
||||
history.push(mostRecentOverviewPage)
|
||||
}}
|
||||
>
|
||||
{ this.context.t('cancel') }
|
||||
@ -213,7 +220,7 @@ export default class ConfirmEncryptionPublicKey extends Component {
|
||||
className="request-encryption-public-key__footer__sign-button"
|
||||
onClick={async (event) => {
|
||||
this._removeBeforeUnload()
|
||||
await this.props.encryptionPublicKey(txData, event)
|
||||
await encryptionPublicKey(txData, event)
|
||||
this.context.metricsEvent({
|
||||
eventOpts: {
|
||||
category: 'Messages',
|
||||
@ -221,8 +228,8 @@ export default class ConfirmEncryptionPublicKey extends Component {
|
||||
name: 'Confirm',
|
||||
},
|
||||
})
|
||||
this.props.clearConfirmTransaction()
|
||||
this.props.history.push(DEFAULT_ROUTE)
|
||||
clearConfirmTransaction()
|
||||
history.push(mostRecentOverviewPage)
|
||||
}}
|
||||
>
|
||||
{ this.context.t('provide') }
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
|
||||
import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck'
|
||||
import ConfirmEncryptionPublicKey from './confirm-encryption-public-key.component'
|
||||
import { getMostRecentOverviewPage } from '../../ducks/history/history'
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { confirmTransaction,
|
||||
@ -36,6 +37,7 @@ function mapStateToProps (state) {
|
||||
requester: null,
|
||||
requesterAddress: null,
|
||||
conversionRate: conversionRateSelector(state),
|
||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
|
||||
import ConfirmPageContainer, { ConfirmDetailRow } from '../../components/app/confirm-page-container'
|
||||
import { isBalanceSufficient } from '../send/send.utils'
|
||||
import { DEFAULT_ROUTE, CONFIRM_TRANSACTION_ROUTE } from '../../helpers/constants/routes'
|
||||
import { CONFIRM_TRANSACTION_ROUTE } from '../../helpers/constants/routes'
|
||||
import {
|
||||
INSUFFICIENT_FUNDS_ERROR_KEY,
|
||||
TRANSACTION_ERROR_KEY,
|
||||
@ -96,6 +96,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
tryReverseResolveAddress: PropTypes.func.isRequired,
|
||||
hideSenderToRecipient: PropTypes.bool,
|
||||
showAccountInHeader: PropTypes.bool,
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
@ -110,6 +111,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
showTransactionConfirmedModal,
|
||||
history,
|
||||
clearConfirmTransaction,
|
||||
mostRecentOverviewPage,
|
||||
nextNonce,
|
||||
customNonceValue,
|
||||
toAddress,
|
||||
@ -136,7 +138,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
showTransactionConfirmedModal({
|
||||
onSubmit: () => {
|
||||
clearConfirmTransaction()
|
||||
history.push(DEFAULT_ROUTE)
|
||||
history.push(mostRecentOverviewPage)
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -383,6 +385,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
cancelAllTransactions,
|
||||
clearConfirmTransaction,
|
||||
history,
|
||||
mostRecentOverviewPage,
|
||||
showRejectTransactionsConfirmationModal,
|
||||
unapprovedTxCount,
|
||||
} = this.props
|
||||
@ -393,7 +396,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
this._removeBeforeUnload()
|
||||
await cancelAllTransactions()
|
||||
clearConfirmTransaction()
|
||||
history.push(DEFAULT_ROUTE)
|
||||
history.push(mostRecentOverviewPage)
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -405,6 +408,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
txData,
|
||||
cancelTransaction,
|
||||
history,
|
||||
mostRecentOverviewPage,
|
||||
clearConfirmTransaction,
|
||||
actionKey,
|
||||
txData: { origin },
|
||||
@ -432,7 +436,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
cancelTransaction(txData)
|
||||
.then(() => {
|
||||
clearConfirmTransaction()
|
||||
history.push(DEFAULT_ROUTE)
|
||||
history.push(mostRecentOverviewPage)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -447,6 +451,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
history,
|
||||
onSubmit,
|
||||
actionKey,
|
||||
mostRecentOverviewPage,
|
||||
metaMetricsSendCount = 0,
|
||||
setMetaMetricsSendCount,
|
||||
methodData = {},
|
||||
@ -493,7 +498,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
this.setState({
|
||||
submitting: false,
|
||||
}, () => {
|
||||
history.push(DEFAULT_ROUTE)
|
||||
history.push(mostRecentOverviewPage)
|
||||
updateCustomNonce('')
|
||||
})
|
||||
})
|
||||
|
@ -37,6 +37,7 @@ import {
|
||||
getPreferences,
|
||||
transactionFeeSelector,
|
||||
} from '../../selectors'
|
||||
import { getMostRecentOverviewPage } from '../../ducks/history/history'
|
||||
|
||||
const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
|
||||
return {
|
||||
@ -178,6 +179,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
metaMetricsSendCount,
|
||||
transactionCategory,
|
||||
nextNonce,
|
||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import R from 'ramda'
|
||||
import SignatureRequest from '../../components/app/signature-request'
|
||||
import SignatureRequestOriginal from '../../components/app/signature-request-original'
|
||||
import Loading from '../../components/ui/loading-screen'
|
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes'
|
||||
import { getMostRecentOverviewPage } from '../../ducks/history/history'
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { metamask, appState } = state
|
||||
@ -25,6 +25,7 @@ function mapStateToProps (state) {
|
||||
|
||||
return {
|
||||
identities: state.metamask.identities,
|
||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||
unapprovedTxs: state.metamask.unapprovedTxs,
|
||||
unapprovedMsgs: state.metamask.unapprovedMsgs,
|
||||
unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs,
|
||||
@ -45,6 +46,7 @@ function mapStateToProps (state) {
|
||||
|
||||
class ConfirmTxScreen extends Component {
|
||||
static propTypes = {
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
unapprovedMsgCount: PropTypes.number,
|
||||
unapprovedPersonalMsgCount: PropTypes.number,
|
||||
unapprovedTypedMessagesCount: PropTypes.number,
|
||||
@ -167,13 +169,15 @@ class ConfirmTxScreen extends Component {
|
||||
componentDidMount () {
|
||||
const {
|
||||
unapprovedTxs = {},
|
||||
history,
|
||||
mostRecentOverviewPage,
|
||||
network,
|
||||
send,
|
||||
} = this.props
|
||||
const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network)
|
||||
|
||||
if (unconfTxList.length === 0 && !send.to && this.getUnapprovedMessagesTotal() === 0) {
|
||||
this.props.history.push(DEFAULT_ROUTE)
|
||||
history.push(mostRecentOverviewPage)
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,6 +189,7 @@ class ConfirmTxScreen extends Component {
|
||||
send,
|
||||
history,
|
||||
match: { params: { id: transactionId } = {} },
|
||||
mostRecentOverviewPage,
|
||||
} = this.props
|
||||
|
||||
let prevTx
|
||||
@ -203,14 +208,14 @@ class ConfirmTxScreen extends Component {
|
||||
if (prevTx && prevTx.status === 'dropped') {
|
||||
this.props.dispatch(actions.showModal({
|
||||
name: 'TRANSACTION_CONFIRMED',
|
||||
onSubmit: () => history.push(DEFAULT_ROUTE),
|
||||
onSubmit: () => history.push(mostRecentOverviewPage),
|
||||
}))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (unconfTxList.length === 0 && !send.to && this.getUnapprovedMessagesTotal() === 0) {
|
||||
this.props.history.push(DEFAULT_ROUTE)
|
||||
this.props.history.push(mostRecentOverviewPage)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ import ConfirmDecryptMessage from '../confirm-decrypt-message'
|
||||
import ConfirmEncryptionPublicKey from '../confirm-encryption-public-key'
|
||||
|
||||
import {
|
||||
DEFAULT_ROUTE,
|
||||
CONFIRM_TRANSACTION_ROUTE,
|
||||
CONFIRM_DEPLOY_CONTRACT_PATH,
|
||||
CONFIRM_SEND_ETHER_PATH,
|
||||
@ -39,6 +38,7 @@ export default class ConfirmTransaction extends Component {
|
||||
setTransactionToConfirm: PropTypes.func,
|
||||
clearConfirmTransaction: PropTypes.func,
|
||||
fetchBasicGasAndTimeEstimates: PropTypes.func,
|
||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||
transaction: PropTypes.object,
|
||||
getContractMethodData: PropTypes.func,
|
||||
transactionId: PropTypes.string,
|
||||
@ -52,6 +52,7 @@ export default class ConfirmTransaction extends Component {
|
||||
totalUnapprovedCount = 0,
|
||||
send = {},
|
||||
history,
|
||||
mostRecentOverviewPage,
|
||||
transaction: { txParams: { data, to } = {} } = {},
|
||||
fetchBasicGasAndTimeEstimates,
|
||||
getContractMethodData,
|
||||
@ -62,7 +63,7 @@ export default class ConfirmTransaction extends Component {
|
||||
} = this.props
|
||||
|
||||
if (!totalUnapprovedCount && !send.to) {
|
||||
history.replace(DEFAULT_ROUTE)
|
||||
history.replace(mostRecentOverviewPage)
|
||||
return
|
||||
}
|
||||
|
||||
@ -86,6 +87,7 @@ export default class ConfirmTransaction extends Component {
|
||||
paramsTransactionId,
|
||||
transactionId,
|
||||
history,
|
||||
mostRecentOverviewPage,
|
||||
totalUnapprovedCount,
|
||||
} = this.props
|
||||
|
||||
@ -95,10 +97,10 @@ export default class ConfirmTransaction extends Component {
|
||||
setTransactionToConfirm(paramsTransactionId)
|
||||
return
|
||||
} else if (prevProps.transactionId && !transactionId && !totalUnapprovedCount) {
|
||||
history.replace(DEFAULT_ROUTE)
|
||||
history.replace(mostRecentOverviewPage)
|
||||
return
|
||||
} else if (prevProps.transactionId && transactionId && prevProps.transactionId !== transactionId) {
|
||||
history.replace(DEFAULT_ROUTE)
|
||||
history.replace(mostRecentOverviewPage)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user