mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge branch 'master' into i3725-refactor-send-component
This commit is contained in:
commit
f4d8da9277
16
CHANGELOG.md
16
CHANGELOG.md
@ -1,9 +1,23 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## Current Master
|
## Current Master
|
||||||
- Fix link for 'Learn More' in the Add Token Screen to open to a new tab.
|
|
||||||
|
|
||||||
|
- Improved performance of 3D fox logo.
|
||||||
|
|
||||||
|
## 4.5.5 Fri Apr 06 2018
|
||||||
|
|
||||||
|
- Graceful handling of unknown keys in txParams
|
||||||
|
- Fixes buggy handling of historical transactions with unknown keys in txParams
|
||||||
|
- Fix link for 'Learn More' in the Add Token Screen to open to a new tab.
|
||||||
- Fix Download State Logs button [#3791](https://github.com/MetaMask/metamask-extension/issues/3791)
|
- Fix Download State Logs button [#3791](https://github.com/MetaMask/metamask-extension/issues/3791)
|
||||||
|
- Enhanced migration error handling + reporting
|
||||||
|
|
||||||
|
## 4.5.4 (aborted) Thu Apr 05 2018
|
||||||
|
|
||||||
|
- Graceful handling of unknown keys in txParams
|
||||||
|
- Fix link for 'Learn More' in the Add Token Screen to open to a new tab.
|
||||||
|
- Fix Download State Logs button [#3791](https://github.com/MetaMask/metamask-extension/issues/3791)
|
||||||
|
- Fix migration error reporting
|
||||||
|
|
||||||
## 4.5.3 Wed Apr 04 2018
|
## 4.5.3 Wed Apr 04 2018
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
{ "code": "ru", "name": "Russian" },
|
{ "code": "ru", "name": "Russian" },
|
||||||
{ "code": "sl", "name": "Slovenian" },
|
{ "code": "sl", "name": "Slovenian" },
|
||||||
{ "code": "th", "name": "Thai" },
|
{ "code": "th", "name": "Thai" },
|
||||||
|
{ "code": "tr", "name": "Turkish" },
|
||||||
{ "code": "vi", "name": "Vietnamese" },
|
{ "code": "vi", "name": "Vietnamese" },
|
||||||
{ "code": "zh_CN", "name": "Mandarin" },
|
{ "code": "zh_CN", "name": "Mandarin" },
|
||||||
{ "code": "zh_TW", "name": "Taiwanese" }
|
{ "code": "zh_TW", "name": "Taiwanese" }
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
"addToken": {
|
"addToken": {
|
||||||
"message": "トークンを追加"
|
"message": "トークンを追加"
|
||||||
},
|
},
|
||||||
|
"addTokens": {
|
||||||
|
"message": "トークンを追加"
|
||||||
|
},
|
||||||
"amount": {
|
"amount": {
|
||||||
"message": "金額"
|
"message": "金額"
|
||||||
},
|
},
|
||||||
@ -46,6 +49,9 @@
|
|||||||
"balance": {
|
"balance": {
|
||||||
"message": "残高:"
|
"message": "残高:"
|
||||||
},
|
},
|
||||||
|
"balances": {
|
||||||
|
"message": "トークン残高"
|
||||||
|
},
|
||||||
"balanceIsInsufficientGas": {
|
"balanceIsInsufficientGas": {
|
||||||
"message": "現在のガス総量に対して残高が不足しています"
|
"message": "現在のガス総量に対して残高が不足しています"
|
||||||
},
|
},
|
||||||
@ -63,10 +69,10 @@
|
|||||||
"message": "購入"
|
"message": "購入"
|
||||||
},
|
},
|
||||||
"buyCoinbase": {
|
"buyCoinbase": {
|
||||||
"message": "Coinbaseで購入"
|
"message": "Coinbaseのサイトで購入"
|
||||||
},
|
},
|
||||||
"buyCoinbaseExplainer": {
|
"buyCoinbaseExplainer": {
|
||||||
"message": "Coinbaseは、世界的なBitcoin、Ethereum、そしてLitecoinの取引所です。"
|
"message": "Etherを購入できます。Coinbaseは、世界的なBitcoin、Ethereum、そしてLitecoinの取引所です。"
|
||||||
},
|
},
|
||||||
"cancel": {
|
"cancel": {
|
||||||
"message": "キャンセル"
|
"message": "キャンセル"
|
||||||
@ -90,7 +96,7 @@
|
|||||||
"message": "トランザクションの確認"
|
"message": "トランザクションの確認"
|
||||||
},
|
},
|
||||||
"continueToCoinbase": {
|
"continueToCoinbase": {
|
||||||
"message": "Coinbaseで続行"
|
"message": "Coinbaseを開く"
|
||||||
},
|
},
|
||||||
"contractDeployment": {
|
"contractDeployment": {
|
||||||
"message": "コントラクトのデプロイ"
|
"message": "コントラクトのデプロイ"
|
||||||
@ -138,6 +144,9 @@
|
|||||||
"customGas": {
|
"customGas": {
|
||||||
"message": "ガスのカスタマイズ"
|
"message": "ガスのカスタマイズ"
|
||||||
},
|
},
|
||||||
|
"customToken": {
|
||||||
|
"message": "カスタムトークン"
|
||||||
|
},
|
||||||
"customize": {
|
"customize": {
|
||||||
"message": "カスタマイズ"
|
"message": "カスタマイズ"
|
||||||
},
|
},
|
||||||
@ -154,20 +163,20 @@
|
|||||||
"message": "DENとは、あなたのパスワードが暗号化されたMetaMask内のストレージです。"
|
"message": "DENとは、あなたのパスワードが暗号化されたMetaMask内のストレージです。"
|
||||||
},
|
},
|
||||||
"deposit": {
|
"deposit": {
|
||||||
"message": "受取り"
|
"message": "振込"
|
||||||
},
|
},
|
||||||
"depositBTC": {
|
"depositBTC": {
|
||||||
"message": "あなたのBTCを次のアドレスへデポジット:"
|
"message": "BTCを下記のアドレスへ振込んでください:"
|
||||||
},
|
},
|
||||||
"depositCoin": {
|
"depositCoin": {
|
||||||
"message": "あなたの $1を次のアドレスへデポジット",
|
"message": "$1を下記のアドレスへ振込んでください",
|
||||||
"description": "Tells the user what coin they have selected to deposit with shapeshift"
|
"description": "Tells the user what coin they have selected to deposit with shapeshift"
|
||||||
},
|
},
|
||||||
"depositEth": {
|
"depositEth": {
|
||||||
"message": "ETHをデポジット"
|
"message": "ETHを入金"
|
||||||
},
|
},
|
||||||
"depositEther": {
|
"depositEther": {
|
||||||
"message": "Etherをデポジット"
|
"message": "Etherを振込"
|
||||||
},
|
},
|
||||||
"depositFiat": {
|
"depositFiat": {
|
||||||
"message": "法定通貨でデポジット"
|
"message": "法定通貨でデポジット"
|
||||||
@ -176,10 +185,10 @@
|
|||||||
"message": "別のアカウントから入金"
|
"message": "別のアカウントから入金"
|
||||||
},
|
},
|
||||||
"depositShapeShift": {
|
"depositShapeShift": {
|
||||||
"message": "ShapeShiftで入金"
|
"message": "ShapeShiftで交換"
|
||||||
},
|
},
|
||||||
"depositShapeShiftExplainer": {
|
"depositShapeShiftExplainer": {
|
||||||
"message": "他の暗号通貨をEtherと交換してMetaMaskのウォレットへ入金できます。アカウント作成は不要です。"
|
"message": "他の暗号通貨とEtherを交換して、MetaMaskのウォレットへ入金できます。アカウント作成は不要です。"
|
||||||
},
|
},
|
||||||
"details": {
|
"details": {
|
||||||
"message": "詳細"
|
"message": "詳細"
|
||||||
@ -188,10 +197,10 @@
|
|||||||
"message": "ダイレクトデポジット"
|
"message": "ダイレクトデポジット"
|
||||||
},
|
},
|
||||||
"directDepositEther": {
|
"directDepositEther": {
|
||||||
"message": "Etherを直接受け取り"
|
"message": "Etherを直接入金"
|
||||||
},
|
},
|
||||||
"directDepositEtherExplainer": {
|
"directDepositEtherExplainer": {
|
||||||
"message": "Etherをすでにお持ちなら、MetaMaskの新しいウォレットにEtherを送信することができます。"
|
"message": "既にEtherをお持ちなら、MetaMaskの新しいウォレットにEtherを送信することができます。"
|
||||||
},
|
},
|
||||||
"done": {
|
"done": {
|
||||||
"message": "完了"
|
"message": "完了"
|
||||||
@ -209,7 +218,7 @@
|
|||||||
"message": "パスワードを入力"
|
"message": "パスワードを入力"
|
||||||
},
|
},
|
||||||
"etherscanView": {
|
"etherscanView": {
|
||||||
"message": "Etherscanでアカウントを参照"
|
"message": "Etherscanでアカウントを確認"
|
||||||
},
|
},
|
||||||
"exchangeRate": {
|
"exchangeRate": {
|
||||||
"message": "交換レート"
|
"message": "交換レート"
|
||||||
@ -266,7 +275,7 @@
|
|||||||
"message": "必要ガスプライス"
|
"message": "必要ガスプライス"
|
||||||
},
|
},
|
||||||
"getEther": {
|
"getEther": {
|
||||||
"message": "Etherをゲット"
|
"message": "Etherを取得する"
|
||||||
},
|
},
|
||||||
"getEtherFromFaucet": {
|
"getEtherFromFaucet": {
|
||||||
"message": "フォーセットで $1のEtherを得ることができます。",
|
"message": "フォーセットで $1のEtherを得ることができます。",
|
||||||
@ -287,7 +296,7 @@
|
|||||||
"message": "トークンを隠す"
|
"message": "トークンを隠す"
|
||||||
},
|
},
|
||||||
"hideTokenPrompt": {
|
"hideTokenPrompt": {
|
||||||
"message": "トークンを隠しますか??"
|
"message": "トークンを隠しますか?"
|
||||||
},
|
},
|
||||||
"howToDeposit": {
|
"howToDeposit": {
|
||||||
"message": "どのようにEtherをデポジットしますか?"
|
"message": "どのようにEtherをデポジットしますか?"
|
||||||
@ -300,7 +309,7 @@
|
|||||||
"message": "アカウントのインポート"
|
"message": "アカウントのインポート"
|
||||||
},
|
},
|
||||||
"importAccountMsg": {
|
"importAccountMsg": {
|
||||||
"message":"追加したアカウントはMetaMaskのアカウントシードフレーズとは関連付けられません。インポートしたアカウントについての詳細は"
|
"message":"追加したアカウントはMetaMaskのアカウントパスフレーズとは関連付けられません。インポートしたアカウントについての詳細は"
|
||||||
},
|
},
|
||||||
"importAnAccount": {
|
"importAnAccount": {
|
||||||
"message": "アカウントをインポート"
|
"message": "アカウントをインポート"
|
||||||
@ -334,13 +343,22 @@
|
|||||||
"message": "JSONファイル",
|
"message": "JSONファイル",
|
||||||
"description": "format for importing an account"
|
"description": "format for importing an account"
|
||||||
},
|
},
|
||||||
|
"keepTrackTokens": {
|
||||||
|
"message": "MetaMaskアカウントで入手したトークンを検索できます。"
|
||||||
|
},
|
||||||
"kovan": {
|
"kovan": {
|
||||||
"message": "Kovanテストネットワーク"
|
"message": "Kovanテストネットワーク"
|
||||||
},
|
},
|
||||||
|
"learnMore": {
|
||||||
|
"message": "詳細"
|
||||||
|
},
|
||||||
"lessThanMax": {
|
"lessThanMax": {
|
||||||
"message": " $1以下にして下さい。",
|
"message": " $1以下にして下さい。",
|
||||||
"description": "helper for inputting hex as decimal input"
|
"description": "helper for inputting hex as decimal input"
|
||||||
},
|
},
|
||||||
|
"likeToAddTokens": {
|
||||||
|
"message": "トークンを追加しますか?"
|
||||||
|
},
|
||||||
"limit": {
|
"limit": {
|
||||||
"message": "リミット"
|
"message": "リミット"
|
||||||
},
|
},
|
||||||
@ -371,8 +389,11 @@
|
|||||||
"myAccounts": {
|
"myAccounts": {
|
||||||
"message": "マイアカウント"
|
"message": "マイアカウント"
|
||||||
},
|
},
|
||||||
|
"mustSelectOne": {
|
||||||
|
"message": "一つ以上のトークンを選択してください。"
|
||||||
|
},
|
||||||
"needEtherInWallet": {
|
"needEtherInWallet": {
|
||||||
"message": "MetaMaskを使って分散型アプリケーションを使用するためには、このウォレットにEtherが必要です。"
|
"message": "MetaMaskで分散型アプリケーションを使用するためには、このウォレットにEtherが必要です。"
|
||||||
},
|
},
|
||||||
"needImportFile": {
|
"needImportFile": {
|
||||||
"message": "インポートするファイルを選択してください。",
|
"message": "インポートするファイルを選択してください。",
|
||||||
@ -411,7 +432,7 @@
|
|||||||
"message": "この名前にはアドレスが設定されていません。"
|
"message": "この名前にはアドレスが設定されていません。"
|
||||||
},
|
},
|
||||||
"noDeposits": {
|
"noDeposits": {
|
||||||
"message": "デポジットがありません。"
|
"message": "振込みがありません。"
|
||||||
},
|
},
|
||||||
"noTransactionHistory": {
|
"noTransactionHistory": {
|
||||||
"message": "トランザクション履歴がありません。"
|
"message": "トランザクション履歴がありません。"
|
||||||
@ -445,10 +466,13 @@
|
|||||||
"description": "For importing an account from a private key"
|
"description": "For importing an account from a private key"
|
||||||
},
|
},
|
||||||
"pasteSeed": {
|
"pasteSeed": {
|
||||||
"message": "シードをここにペーストして下さい!"
|
"message": "パスフレーズをここにペーストして下さい!"
|
||||||
},
|
},
|
||||||
"pleaseReviewTransaction": {
|
"pleaseReviewTransaction": {
|
||||||
"message": "トランザクションをレビューして下さい。"
|
"message": "トランザクションを確認して下さい。"
|
||||||
|
},
|
||||||
|
"popularTokens": {
|
||||||
|
"message": "人気のトークン"
|
||||||
},
|
},
|
||||||
"privateKey": {
|
"privateKey": {
|
||||||
"message": "秘密鍵",
|
"message": "秘密鍵",
|
||||||
@ -470,13 +494,13 @@
|
|||||||
"message": "もっと読む"
|
"message": "もっと読む"
|
||||||
},
|
},
|
||||||
"receive": {
|
"receive": {
|
||||||
"message": "受け取る"
|
"message": "受取"
|
||||||
},
|
},
|
||||||
"recipientAddress": {
|
"recipientAddress": {
|
||||||
"message": "受取人アドレス"
|
"message": "受取人アドレス"
|
||||||
},
|
},
|
||||||
"refundAddress": {
|
"refundAddress": {
|
||||||
"message": "あなたの返金先アドレス"
|
"message": "受取アドレス"
|
||||||
},
|
},
|
||||||
"rejected": {
|
"rejected": {
|
||||||
"message": "拒否されました"
|
"message": "拒否されました"
|
||||||
@ -487,12 +511,18 @@
|
|||||||
"restoreFromSeed": {
|
"restoreFromSeed": {
|
||||||
"message": "パスフレーズから復元する"
|
"message": "パスフレーズから復元する"
|
||||||
},
|
},
|
||||||
|
"restoreVault": {
|
||||||
|
"message": "ウォレットを復元する"
|
||||||
|
},
|
||||||
"required": {
|
"required": {
|
||||||
"message": "必要です。"
|
"message": "必要です。"
|
||||||
},
|
},
|
||||||
"retryWithMoreGas": {
|
"retryWithMoreGas": {
|
||||||
"message": "より高いガスプライスで再度試して下さい。"
|
"message": "より高いガスプライスで再度試して下さい。"
|
||||||
},
|
},
|
||||||
|
"walletSeed": {
|
||||||
|
"message": "ウォレットのパスフレーズ"
|
||||||
|
},
|
||||||
"revealSeedWords": {
|
"revealSeedWords": {
|
||||||
"message": "パスフレーズを表示"
|
"message": "パスフレーズを表示"
|
||||||
},
|
},
|
||||||
@ -519,23 +549,35 @@
|
|||||||
"selectService": {
|
"selectService": {
|
||||||
"message": "サービスを選択"
|
"message": "サービスを選択"
|
||||||
},
|
},
|
||||||
|
"selectType": {
|
||||||
|
"message": "キーの種類"
|
||||||
|
},
|
||||||
"send": {
|
"send": {
|
||||||
"message": "送信"
|
"message": "送信"
|
||||||
},
|
},
|
||||||
|
"sendETH": {
|
||||||
|
"message": "ETHの送信"
|
||||||
|
},
|
||||||
"sendTokens": {
|
"sendTokens": {
|
||||||
"message": "トークンを送る"
|
"message": "トークンを送る"
|
||||||
},
|
},
|
||||||
"onlySendToEtherAddress": {
|
"onlySendToEtherAddress": {
|
||||||
"message": "ETHはイーサリウムアカウントのみに送信できます。"
|
"message": "ETHはイーサリウムアカウントのみに送信できます。"
|
||||||
},
|
},
|
||||||
|
"searchTokens": {
|
||||||
|
"message": "トークンの検索"
|
||||||
|
},
|
||||||
"sendTokensAnywhere": {
|
"sendTokensAnywhere": {
|
||||||
"message": "イーサリアムアカウントを持っている人にトークンを送る"
|
"message": "イーサリアムアカウントを持っている人にトークンを送る"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"message": "設定"
|
"message": "設定"
|
||||||
},
|
},
|
||||||
|
"info": {
|
||||||
|
"message": "情報"
|
||||||
|
},
|
||||||
"shapeshiftBuy": {
|
"shapeshiftBuy": {
|
||||||
"message": "Shapeshiftで買う"
|
"message": "Shapeshiftで交換"
|
||||||
},
|
},
|
||||||
"showPrivateKeys": {
|
"showPrivateKeys": {
|
||||||
"message": "秘密鍵を表示"
|
"message": "秘密鍵を表示"
|
||||||
@ -565,13 +607,13 @@
|
|||||||
"message": "送信"
|
"message": "送信"
|
||||||
},
|
},
|
||||||
"takesTooLong": {
|
"takesTooLong": {
|
||||||
"message": "長くかかりすぎていますか?"
|
"message": "送信に時間がかかりますか?"
|
||||||
},
|
},
|
||||||
"testFaucet": {
|
"testFaucet": {
|
||||||
"message": "Faucetをテスト"
|
"message": "Faucetをテスト"
|
||||||
},
|
},
|
||||||
"to": {
|
"to": {
|
||||||
"message": "宛先"
|
"message": "送信先"
|
||||||
},
|
},
|
||||||
"toETHviaShapeShift": {
|
"toETHviaShapeShift": {
|
||||||
"message": "ShapeShiftで $1をETHにする",
|
"message": "ShapeShiftで $1をETHにする",
|
||||||
@ -595,6 +637,9 @@
|
|||||||
"total": {
|
"total": {
|
||||||
"message": "合計"
|
"message": "合計"
|
||||||
},
|
},
|
||||||
|
"transactions": {
|
||||||
|
"message": "トランザクション"
|
||||||
|
},
|
||||||
"transactionMemo": {
|
"transactionMemo": {
|
||||||
"message": "トランザクションメモ (オプション)"
|
"message": "トランザクションメモ (オプション)"
|
||||||
},
|
},
|
||||||
@ -609,7 +654,7 @@
|
|||||||
"description": "Followed by a link (here) to view token balances"
|
"description": "Followed by a link (here) to view token balances"
|
||||||
},
|
},
|
||||||
"typePassword": {
|
"typePassword": {
|
||||||
"message": "パスワードタイプ"
|
"message": "パスワードの入力"
|
||||||
},
|
},
|
||||||
"uiWelcome": {
|
"uiWelcome": {
|
||||||
"message": "新UIへようこそ!(ベータ版)"
|
"message": "新UIへようこそ!(ベータ版)"
|
||||||
@ -646,7 +691,7 @@
|
|||||||
"message": "警告"
|
"message": "警告"
|
||||||
},
|
},
|
||||||
"whatsThis": {
|
"whatsThis": {
|
||||||
"message": "これは何でしょう?"
|
"message": "この機能について"
|
||||||
},
|
},
|
||||||
"yourSigRequested": {
|
"yourSigRequested": {
|
||||||
"message": "あなたの署名がリクエストされています。"
|
"message": "あなたの署名がリクエストされています。"
|
||||||
|
912
app/_locales/tr/messages.json
Normal file
912
app/_locales/tr/messages.json
Normal file
@ -0,0 +1,912 @@
|
|||||||
|
{
|
||||||
|
"accept": {
|
||||||
|
"message": "Kabul et"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"message": "Hesap"
|
||||||
|
},
|
||||||
|
"accountDetails": {
|
||||||
|
"message": "Hesap Detayları"
|
||||||
|
},
|
||||||
|
"accountName": {
|
||||||
|
"message": "Hesap İsmi"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"message": "Adres"
|
||||||
|
},
|
||||||
|
"addCustomToken": {
|
||||||
|
"message": "Özel jeton ekle"
|
||||||
|
},
|
||||||
|
"addToken": {
|
||||||
|
"message": "Jeton ekle"
|
||||||
|
},
|
||||||
|
"addTokens": {
|
||||||
|
"message": "Jetonlar ekle"
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"message": "Tutar"
|
||||||
|
},
|
||||||
|
"amountPlusGas": {
|
||||||
|
"message": "Tutar + Gas"
|
||||||
|
},
|
||||||
|
"appDescription": {
|
||||||
|
"message": "Ethereum Tarayıcı Uzantısı",
|
||||||
|
"description": "Uygulama açıklaması"
|
||||||
|
},
|
||||||
|
"appName": {
|
||||||
|
"message": "MetaMask",
|
||||||
|
"description": "Uygulama ismi"
|
||||||
|
},
|
||||||
|
"approved": {
|
||||||
|
"message": "Onaylandı"
|
||||||
|
},
|
||||||
|
"attemptingConnect": {
|
||||||
|
"message": "Blockchain'e bağlanmayı deniyor"
|
||||||
|
},
|
||||||
|
"attributions": {
|
||||||
|
"message": "Atıflar"
|
||||||
|
},
|
||||||
|
"available": {
|
||||||
|
"message": "Müsait"
|
||||||
|
},
|
||||||
|
"back": {
|
||||||
|
"message": "Geri"
|
||||||
|
},
|
||||||
|
"balance": {
|
||||||
|
"message": "Bakiye:"
|
||||||
|
},
|
||||||
|
"balances": {
|
||||||
|
"message": "Jeton bakiyesi"
|
||||||
|
},
|
||||||
|
"balanceIsInsufficientGas": {
|
||||||
|
"message": "Toplam gas için yetersiz bakiye"
|
||||||
|
},
|
||||||
|
"beta": {
|
||||||
|
"message": "BETA"
|
||||||
|
},
|
||||||
|
"betweenMinAndMax": {
|
||||||
|
"message": "$1'e eşit veya daha büyük olmalı ve $2'den küçük veya eşit olmalı",
|
||||||
|
"description": "Onaltılık sayının ondalık sayı olarak girişi için yardımcı"
|
||||||
|
},
|
||||||
|
"blockiesIdenticon": {
|
||||||
|
"message": "Blockies Identicon kullan"
|
||||||
|
},
|
||||||
|
"borrowDharma": {
|
||||||
|
"message": "Dharma (Beta) ile ödünç al"
|
||||||
|
},
|
||||||
|
"builtInCalifornia": {
|
||||||
|
"message": "MetaMask California'da tasarlandı ve yaratıldı"
|
||||||
|
},
|
||||||
|
"buy": {
|
||||||
|
"message": "Satın al"
|
||||||
|
},
|
||||||
|
"buyCoinbase": {
|
||||||
|
"message": "Coinbase'de satın al"
|
||||||
|
},
|
||||||
|
"buyCoinbaseExplainer": {
|
||||||
|
"message": "Coinbase bitcoin, ethereum, and litecoin alıp satmanın dünyadaki en popüler yolu"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"message": "Tamam"
|
||||||
|
},
|
||||||
|
"cancel": {
|
||||||
|
"message": "Vazgeç"
|
||||||
|
},
|
||||||
|
"classicInterface": {
|
||||||
|
"message": "Klasik arayüzü kullan"
|
||||||
|
},
|
||||||
|
"clickCopy": {
|
||||||
|
"message": "Kopyalamak için tıkla"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"message": "Onayla"
|
||||||
|
},
|
||||||
|
"confirmed": {
|
||||||
|
"message": "Onaylandı"
|
||||||
|
},
|
||||||
|
"confirmContract": {
|
||||||
|
"message": "Sözleşmeyi onayla"
|
||||||
|
},
|
||||||
|
"confirmPassword": {
|
||||||
|
"message": "Şifreyi onayla"
|
||||||
|
},
|
||||||
|
"confirmTransaction": {
|
||||||
|
"message": "İşlemi onayla"
|
||||||
|
},
|
||||||
|
"continue": {
|
||||||
|
"message": "Devam et"
|
||||||
|
},
|
||||||
|
"continueToCoinbase": {
|
||||||
|
"message": "Coinbase'e devam et"
|
||||||
|
},
|
||||||
|
"contractDeployment": {
|
||||||
|
"message": "Sözleşme kurulumu"
|
||||||
|
},
|
||||||
|
"conversionProgress": {
|
||||||
|
"message": "Çevirim devam ediyor"
|
||||||
|
},
|
||||||
|
"copiedButton": {
|
||||||
|
"message": "Kopyalandı"
|
||||||
|
},
|
||||||
|
"copiedClipboard": {
|
||||||
|
"message": "Panoya kopyalandı"
|
||||||
|
},
|
||||||
|
"copiedExclamation": {
|
||||||
|
"message": "Kopyalandı!"
|
||||||
|
},
|
||||||
|
"copiedSafe": {
|
||||||
|
"message": "Güvenli bir yere kopyaladım"
|
||||||
|
},
|
||||||
|
"copy": {
|
||||||
|
"message": "Kopyala"
|
||||||
|
},
|
||||||
|
"copyToClipboard": {
|
||||||
|
"message": "Panoya kopyala"
|
||||||
|
},
|
||||||
|
"copyButton": {
|
||||||
|
"message": " Kopyala "
|
||||||
|
},
|
||||||
|
"copyPrivateKey": {
|
||||||
|
"message": "Bu sizin özel anahtarınız (kopyalamak için tıklayın)"
|
||||||
|
},
|
||||||
|
"create": {
|
||||||
|
"message": "Yarat"
|
||||||
|
},
|
||||||
|
"createAccount": {
|
||||||
|
"message": "Hesap Oluştur"
|
||||||
|
},
|
||||||
|
"createDen": {
|
||||||
|
"message": "Yarat"
|
||||||
|
},
|
||||||
|
"crypto": {
|
||||||
|
"message": "Kripto",
|
||||||
|
"description": "Kambiyo tipi (kripto para)"
|
||||||
|
},
|
||||||
|
"currentConversion": {
|
||||||
|
"message": "Geçerli çevirme"
|
||||||
|
},
|
||||||
|
"currentNetwork": {
|
||||||
|
"message": "Geçerli Ağ"
|
||||||
|
},
|
||||||
|
"customGas": {
|
||||||
|
"message": "Gas'i özelleştir"
|
||||||
|
},
|
||||||
|
"customToken": {
|
||||||
|
"message": "Özel Jeton"
|
||||||
|
},
|
||||||
|
"customize": {
|
||||||
|
"message": "Özelleştir"
|
||||||
|
},
|
||||||
|
"customRPC": {
|
||||||
|
"message": "Özel RPC"
|
||||||
|
},
|
||||||
|
"decimalsMustZerotoTen": {
|
||||||
|
"message": "Ondalıklar en azından 0 olmalı ve 36'dan büyük olmamalı."
|
||||||
|
},
|
||||||
|
"decimal": {
|
||||||
|
"message": "Ondalık hassasiyeti"
|
||||||
|
},
|
||||||
|
"defaultNetwork": {
|
||||||
|
"message": "Ether işlemleri için varsayılan ağ Main Net."
|
||||||
|
},
|
||||||
|
"denExplainer": {
|
||||||
|
"message": "DEN'iniz MetaMask içersinde parola-şifrelenmiş deponuzdur."
|
||||||
|
},
|
||||||
|
"deposit": {
|
||||||
|
"message": "Yatır"
|
||||||
|
},
|
||||||
|
"depositBTC": {
|
||||||
|
"message": "BTC'inizi aşağıdaki adrese yatırın:"
|
||||||
|
},
|
||||||
|
"depositCoin": {
|
||||||
|
"message": "$1'nızı aşağıdaki adrese yatırın",
|
||||||
|
"description": "Kullanıcıya hangi jetonu seçtiyse onu yatırmasını shapeshift ile söyler."
|
||||||
|
},
|
||||||
|
"depositEth": {
|
||||||
|
"message": "Eth yatır"
|
||||||
|
},
|
||||||
|
"depositEther": {
|
||||||
|
"message": "Ether yatır"
|
||||||
|
},
|
||||||
|
"depositFiat": {
|
||||||
|
"message": "Para yatır"
|
||||||
|
},
|
||||||
|
"depositFromAccount": {
|
||||||
|
"message": "Başka bir hesaptan yatır"
|
||||||
|
},
|
||||||
|
"depositShapeShift": {
|
||||||
|
"message": "ShapeShift ile yatır"
|
||||||
|
},
|
||||||
|
"depositShapeShiftExplainer": {
|
||||||
|
"message": "Eğer başka kripto paralara sahipseniz, MetaMask cüzdanınıza direk olarak Ether yatırabilirsiniz. Hesaba gerek yoktur."
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"message": "Ayrıntılar"
|
||||||
|
},
|
||||||
|
"directDeposit": {
|
||||||
|
"message": "Direk Yatırma"
|
||||||
|
},
|
||||||
|
"directDepositEther": {
|
||||||
|
"message": "Direk Ether Yatırma"
|
||||||
|
},
|
||||||
|
"directDepositEtherExplainer": {
|
||||||
|
"message": "Eğer çoktan Etheriniz varsa, yeni hesabınıza Ether aktarmanın en kolay yolu direk yatırmadır."
|
||||||
|
},
|
||||||
|
"done": {
|
||||||
|
"message": "Bitti"
|
||||||
|
},
|
||||||
|
"downloadStateLogs": {
|
||||||
|
"message": "Durum kayıtlarını indir"
|
||||||
|
},
|
||||||
|
"dropped": {
|
||||||
|
"message": "Bırakıldı"
|
||||||
|
},
|
||||||
|
"edit": {
|
||||||
|
"message": "Düzenle"
|
||||||
|
},
|
||||||
|
"editAccountName": {
|
||||||
|
"message": "Hesap ismini düzenle"
|
||||||
|
},
|
||||||
|
"emailUs": {
|
||||||
|
"message": "Bize e-posta atın!"
|
||||||
|
},
|
||||||
|
"encryptNewDen": {
|
||||||
|
"message": "Yeni DEN'inizi şifreleyin"
|
||||||
|
},
|
||||||
|
"enterPassword": {
|
||||||
|
"message": "Parolanızı girin"
|
||||||
|
},
|
||||||
|
"enterPasswordConfirm": {
|
||||||
|
"message": "Onaylamak için parolanızı girin"
|
||||||
|
},
|
||||||
|
"passwordNotLongEnough": {
|
||||||
|
"message": "Parola yeterince uzun değil"
|
||||||
|
},
|
||||||
|
"passwordsDontMatch": {
|
||||||
|
"message": "Parolalar eşleşmiyor"
|
||||||
|
},
|
||||||
|
"etherscanView": {
|
||||||
|
"message": "Hesabı Etherscan üzerinde izle"
|
||||||
|
},
|
||||||
|
"exchangeRate": {
|
||||||
|
"message": "Döviz kuru"
|
||||||
|
},
|
||||||
|
"exportPrivateKey": {
|
||||||
|
"message": "Özel anahtarı ver"
|
||||||
|
},
|
||||||
|
"exportPrivateKeyWarning": {
|
||||||
|
"message": "Özel anahtarınızı vermek sizin sorumluluğunuzdadır."
|
||||||
|
},
|
||||||
|
"failed": {
|
||||||
|
"message": "Başarısız oldu"
|
||||||
|
},
|
||||||
|
"fiat": {
|
||||||
|
"message": "Para",
|
||||||
|
"description": "Döviz türü"
|
||||||
|
},
|
||||||
|
"fileImportFail": {
|
||||||
|
"message": "Dosya alma çalışmıyor mu? Buraya tıklayın!",
|
||||||
|
"description": "Kullanıcıların hesaplarını JSON dosyasından almalarına yardım eder"
|
||||||
|
},
|
||||||
|
"followTwitter": {
|
||||||
|
"message": "Bizi twitter'da takip edin"
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"message": "Kimden"
|
||||||
|
},
|
||||||
|
"fromToSame": {
|
||||||
|
"message": "Kimden ve kime adresi aynı olamaz"
|
||||||
|
},
|
||||||
|
"fromShapeShift": {
|
||||||
|
"message": "ShapeShift'den"
|
||||||
|
},
|
||||||
|
"gas": {
|
||||||
|
"message": "Gas",
|
||||||
|
"description": "Gas maliyetinin kısa indikatörü"
|
||||||
|
},
|
||||||
|
"gasFee": {
|
||||||
|
"message": "Gas Ücreti"
|
||||||
|
},
|
||||||
|
"gasLimit": {
|
||||||
|
"message": "Gas Limiti"
|
||||||
|
},
|
||||||
|
"gasLimitCalculation": {
|
||||||
|
"message": "Önerilen gas limitini ağ başarı oranını baz alarak hesaplıyoruz."
|
||||||
|
},
|
||||||
|
"gasLimitRequired": {
|
||||||
|
"message": "Gas limiti gereklidir"
|
||||||
|
},
|
||||||
|
"gasLimitTooLow": {
|
||||||
|
"message": "Gas limiti en az 21000 olmalıdır"
|
||||||
|
},
|
||||||
|
"generatingSeed": {
|
||||||
|
"message": "Kaynak Oluşturuyor..."
|
||||||
|
},
|
||||||
|
"gasPrice": {
|
||||||
|
"message": "Gas Fiyatı (GWEI)"
|
||||||
|
},
|
||||||
|
"gasPriceCalculation": {
|
||||||
|
"message": "Önerilen gas fiyatını ağ başarı oranını baz alarak hesaplıyoruz."
|
||||||
|
},
|
||||||
|
"gasPriceRequired": {
|
||||||
|
"message": "Gas Fiyatı Gereklidir"
|
||||||
|
},
|
||||||
|
"getEther": {
|
||||||
|
"message": "Ether Al"
|
||||||
|
},
|
||||||
|
"getEtherFromFaucet": {
|
||||||
|
"message": "Musluktan $1 karşılığı Ether alın",
|
||||||
|
"description": "Ether musluğunun ağ ismini gösterir"
|
||||||
|
},
|
||||||
|
"greaterThanMin": {
|
||||||
|
"message": "must be greater than or equal to $1.",
|
||||||
|
"description": "helper for inputting hex as decimal input"
|
||||||
|
},
|
||||||
|
"here": {
|
||||||
|
"message": "burada",
|
||||||
|
"description": "daha fazla bilgi için -buraya tıklayın- (troubleTokenBalances ile gidiyor)"
|
||||||
|
},
|
||||||
|
"hereList": {
|
||||||
|
"message": "İşte bir liste!!!!"
|
||||||
|
},
|
||||||
|
"hide": {
|
||||||
|
"message": "Gizle"
|
||||||
|
},
|
||||||
|
"hideToken": {
|
||||||
|
"message": "Jetonu gizle"
|
||||||
|
},
|
||||||
|
"hideTokenPrompt": {
|
||||||
|
"message": "Jetonu gizle?"
|
||||||
|
},
|
||||||
|
"howToDeposit": {
|
||||||
|
"message": "Ether'i nasıl yatırmak istersiniz?"
|
||||||
|
},
|
||||||
|
"holdEther": {
|
||||||
|
"message": "Ether ve jeton tutmanızı sağlar ve merkezi olmayan uygulamalar ve sizin aranızda köprü vazifesi görür."
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"message": "Al",
|
||||||
|
"description": "Seçilen dosyadan hesap alma düğmesi. "
|
||||||
|
},
|
||||||
|
"importAccount": {
|
||||||
|
"message": "Hesap Al"
|
||||||
|
},
|
||||||
|
"importAccountMsg": {
|
||||||
|
"message":" Alınan hesaplar orjinal kaynakifadenizle yarattığınız MetaMask hesabınızla ilişkilendirilmez. Alınan hesaplar ile ilgili daha fazla bilgi edinin "
|
||||||
|
},
|
||||||
|
"importAnAccount": {
|
||||||
|
"message": "Hesap al"
|
||||||
|
},
|
||||||
|
"importDen": {
|
||||||
|
"message": "Varolan DEN al"
|
||||||
|
},
|
||||||
|
"imported": {
|
||||||
|
"message": "Alındı",
|
||||||
|
"description": "Hesabın keyringe başarı ile alındığını gösteren durum"
|
||||||
|
},
|
||||||
|
"infoHelp": {
|
||||||
|
"message": "Bilgi ve yardım"
|
||||||
|
},
|
||||||
|
"insufficientFunds": {
|
||||||
|
"message": "Yetersiz kaynak."
|
||||||
|
},
|
||||||
|
"insufficientTokens": {
|
||||||
|
"message": "Yetersiz Jeton."
|
||||||
|
},
|
||||||
|
"invalidAddress": {
|
||||||
|
"message": "Geçersiz adres"
|
||||||
|
},
|
||||||
|
"invalidAddressRecipient": {
|
||||||
|
"message": "Alıcı adresi geçersiz"
|
||||||
|
},
|
||||||
|
"invalidGasParams": {
|
||||||
|
"message": "Geçersiz gas parametreleri"
|
||||||
|
},
|
||||||
|
"invalidInput": {
|
||||||
|
"message": "Geçersiz giriş."
|
||||||
|
},
|
||||||
|
"invalidRequest": {
|
||||||
|
"message": "Geçersiz istek"
|
||||||
|
},
|
||||||
|
"invalidRPC": {
|
||||||
|
"message": "Geçersiz RPC URI"
|
||||||
|
},
|
||||||
|
"jsonFail": {
|
||||||
|
"message": "Birşeyler yanlış gitti. JSON dosyanızın düzgün derlendiğinden emin olun."
|
||||||
|
},
|
||||||
|
"jsonFile": {
|
||||||
|
"message": "JSON Dosyası",
|
||||||
|
"description": "Hesap alımı için düzenle"
|
||||||
|
},
|
||||||
|
"keepTrackTokens": {
|
||||||
|
"message": "MetaMask hesabınızla satın aldığınız jetonların kaydını tutun."
|
||||||
|
},
|
||||||
|
"kovan": {
|
||||||
|
"message": "Kovan Test Ağı"
|
||||||
|
},
|
||||||
|
"knowledgeDataBase": {
|
||||||
|
"message": "Bilgi veritabanımızı ziyaret edin"
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
|
"message": "Maksimum"
|
||||||
|
},
|
||||||
|
"learnMore": {
|
||||||
|
"message": "Daha fazla bilgi."
|
||||||
|
},
|
||||||
|
"lessThanMax": {
|
||||||
|
"message": "$1'den az veya eşit olmalıdır.",
|
||||||
|
"description": "Onaltılık sayıyı ondalık olarak girmek için yardımcı"
|
||||||
|
},
|
||||||
|
"likeToAddTokens": {
|
||||||
|
"message": "Bu jetonlara adres eklemek ister misiniz?"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"message": "Bağlantılar"
|
||||||
|
},
|
||||||
|
"limit": {
|
||||||
|
"message": "Limit"
|
||||||
|
},
|
||||||
|
"loading": {
|
||||||
|
"message": "Yükleniyor..."
|
||||||
|
},
|
||||||
|
"loadingTokens": {
|
||||||
|
"message": "Jetonlar yükleniyor..."
|
||||||
|
},
|
||||||
|
"localhost": {
|
||||||
|
"message": "Localhost 8545"
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
"message": "Giriş yap"
|
||||||
|
},
|
||||||
|
"logout": {
|
||||||
|
"message": "Çıkış"
|
||||||
|
},
|
||||||
|
"loose": {
|
||||||
|
"message": "Gevşek"
|
||||||
|
},
|
||||||
|
"loweCaseWords": {
|
||||||
|
"message": "kaynak kelimeleri sadece küçük harflerden oluşabilir."
|
||||||
|
},
|
||||||
|
"mainnet": {
|
||||||
|
"message": "Main Ethereum Ağı"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"message": "Mesaj"
|
||||||
|
},
|
||||||
|
"metamaskDescription": {
|
||||||
|
"message": "MetaMask Ethereum için güvenli bir kimlik kasasıdır."
|
||||||
|
},
|
||||||
|
"min": {
|
||||||
|
"message": "Minimum"
|
||||||
|
},
|
||||||
|
"myAccounts": {
|
||||||
|
"message": "Hesaplarım"
|
||||||
|
},
|
||||||
|
"mustSelectOne": {
|
||||||
|
"message": "En az bir jeton seçilmeli"
|
||||||
|
},
|
||||||
|
"needEtherInWallet": {
|
||||||
|
"message": "MetaMask kullanarak merkezi olamayan uygulamalarla etkileşmek için cüzdanınızda Ether bulunmalıdır."
|
||||||
|
},
|
||||||
|
"needImportFile": {
|
||||||
|
"message": "Almak için bir dosya seçmelisiniz.",
|
||||||
|
"description": "Kullanıcı bir hesap alır ve devam etmek içinbir dosya seçmelidir."
|
||||||
|
},
|
||||||
|
"needImportPassword": {
|
||||||
|
"message": "Seçilen dosya için bir parola girmelisiniz.",
|
||||||
|
"description": "Hesap almak için parola ve dosya gerekiyor."
|
||||||
|
},
|
||||||
|
"negativeETH": {
|
||||||
|
"message": "Negatif ETH miktarları gönderilemez."
|
||||||
|
},
|
||||||
|
"networks": {
|
||||||
|
"message": "Ağlar"
|
||||||
|
},
|
||||||
|
"newAccount": {
|
||||||
|
"message": "Yeni Hesap"
|
||||||
|
},
|
||||||
|
"newAccountNumberName": {
|
||||||
|
"message": "Hesap $1",
|
||||||
|
"description": "Hesap yaratma ekranındaki bir sonraki hesabın varsayılan ismi"
|
||||||
|
},
|
||||||
|
"newContract": {
|
||||||
|
"message": "Yeni Sözleşme"
|
||||||
|
},
|
||||||
|
"newPassword": {
|
||||||
|
"message": "Yeni Parola (min 8 karakter)"
|
||||||
|
},
|
||||||
|
"newRecipient": {
|
||||||
|
"message": "Yeni alıcı"
|
||||||
|
},
|
||||||
|
"newRPC": {
|
||||||
|
"message": "Yeni RPC URL"
|
||||||
|
},
|
||||||
|
"next": {
|
||||||
|
"message": "Sonraki"
|
||||||
|
},
|
||||||
|
"noAddressForName": {
|
||||||
|
"message": "Bu isim için bir adres tanımlanmamış."
|
||||||
|
},
|
||||||
|
"noDeposits": {
|
||||||
|
"message": "Yatırma alınmadı"
|
||||||
|
},
|
||||||
|
"noTransactionHistory": {
|
||||||
|
"message": "İşlem geçmişi yok."
|
||||||
|
},
|
||||||
|
"noTransactions": {
|
||||||
|
"message": "İşlem yok"
|
||||||
|
},
|
||||||
|
"notStarted": {
|
||||||
|
"message": "Başlamadı"
|
||||||
|
},
|
||||||
|
"oldUI": {
|
||||||
|
"message": "Eski UI"
|
||||||
|
},
|
||||||
|
"oldUIMessage": {
|
||||||
|
"message": "Eski UI'a döndünüz. Yeni UI'a üst sağ sekme menüsündeki seçenek ile dönebilirsiniz."
|
||||||
|
},
|
||||||
|
"or": {
|
||||||
|
"message": "veya",
|
||||||
|
"description": "Yeni bir hesap yaratmak veya almak arasındaki seçim"
|
||||||
|
},
|
||||||
|
"passwordCorrect": {
|
||||||
|
"message": "Lütfen parolanın doğru olduğuna emin olun."
|
||||||
|
},
|
||||||
|
"passwordMismatch": {
|
||||||
|
"message": "parolalar eşleşmiyor",
|
||||||
|
"description": "parola yaratma işleminde, iki yeni parola alanı eşleşmiyor."
|
||||||
|
},
|
||||||
|
"passwordShort": {
|
||||||
|
"message": "parola yeterince uzun değil",
|
||||||
|
"description": "parola yaratma işleminde, parola güvenli olacak kadar uzun değil."
|
||||||
|
},
|
||||||
|
"pastePrivateKey": {
|
||||||
|
"message": "Özel anahtar dizinizi buraya yapıştırın:",
|
||||||
|
"description": "Özel anahtardan hesap almak için"
|
||||||
|
},
|
||||||
|
"pasteSeed": {
|
||||||
|
"message": "Kaynak ifadenizi buraya yapıştırın!"
|
||||||
|
},
|
||||||
|
"personalAddressDetected": {
|
||||||
|
"message": "Kişisel adres tespit edilidi. Jeton sözleşme adresini girin."
|
||||||
|
},
|
||||||
|
"pleaseReviewTransaction": {
|
||||||
|
"message": "Lütfen işleminizi gözden geçirin."
|
||||||
|
},
|
||||||
|
"popularTokens": {
|
||||||
|
"message": "Popüler Jetonlar"
|
||||||
|
},
|
||||||
|
"privacyMsg": {
|
||||||
|
"message": "Gizlilik Şartları"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"message": "Özel Anahtar",
|
||||||
|
"description": "Hesap alırken bu tip bir dosya seçin"
|
||||||
|
},
|
||||||
|
"privateKeyWarning": {
|
||||||
|
"message": "Uyarı: Bu anahtarı kimse ile paylaşmayın. Özel anahtarlarınıza sahip herkes hesaplarınızıdaki tüm varlığınızı çalabilir."
|
||||||
|
},
|
||||||
|
"privateNetwork": {
|
||||||
|
"message": "Özel Ağ"
|
||||||
|
},
|
||||||
|
"qrCode": {
|
||||||
|
"message": "QR Kodunu göster"
|
||||||
|
},
|
||||||
|
"readdToken": {
|
||||||
|
"message": "Gelecekte Bu jetonu hesap seçenekleri menüsünde “Jeton ekle”'ye giderek geri ekleyebilirsiniz."
|
||||||
|
},
|
||||||
|
"readMore": {
|
||||||
|
"message": "Burada daha fazla okuyun."
|
||||||
|
},
|
||||||
|
"readMore2": {
|
||||||
|
"message": "Daha fazla okuyun."
|
||||||
|
},
|
||||||
|
"receive": {
|
||||||
|
"message": "Al"
|
||||||
|
},
|
||||||
|
"recipientAddress": {
|
||||||
|
"message": "Alıcı adresi"
|
||||||
|
},
|
||||||
|
"refundAddress": {
|
||||||
|
"message": "İade adresiniz"
|
||||||
|
},
|
||||||
|
"rejected": {
|
||||||
|
"message": "Rededildi"
|
||||||
|
},
|
||||||
|
"resetAccount": {
|
||||||
|
"message": "Hesabı sıfıla"
|
||||||
|
},
|
||||||
|
"restoreFromSeed": {
|
||||||
|
"message": "Kaynak ifadeden geri getir. Restore from seed phrase"
|
||||||
|
},
|
||||||
|
"restoreVault": {
|
||||||
|
"message": "Kasayı geri getir"
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"message": "Gerekli"
|
||||||
|
},
|
||||||
|
"retryWithMoreGas": {
|
||||||
|
"message": "Daha yüksek bir gas fiyatı ile tekrar dene"
|
||||||
|
},
|
||||||
|
"walletSeed": {
|
||||||
|
"message": "Cüzdan Kaynağı"
|
||||||
|
},
|
||||||
|
"revealSeedWords": {
|
||||||
|
"message": "Kaynak kelimelerini göster"
|
||||||
|
},
|
||||||
|
"revealSeedWordsWarning": {
|
||||||
|
"message": "Açık bir yerde kaynak kelimeliriniz geri getirmeyin! Bu kelimeler tüm hesaplarınızı çalmak için kullanılabilir."
|
||||||
|
},
|
||||||
|
"revert": {
|
||||||
|
"message": "Geri döndür"
|
||||||
|
},
|
||||||
|
"rinkeby": {
|
||||||
|
"message": "Rinkeby Test Ağı"
|
||||||
|
},
|
||||||
|
"ropsten": {
|
||||||
|
"message": "Ropsten Test Ağı"
|
||||||
|
},
|
||||||
|
"currentRpc": {
|
||||||
|
"message": "Geçerli RPC"
|
||||||
|
},
|
||||||
|
"connectingToMainnet": {
|
||||||
|
"message": "Main Ethereum Ağına bağlanıyor"
|
||||||
|
},
|
||||||
|
"connectingToRopsten": {
|
||||||
|
"message": "Ropsten Test Ağına bağlanıyor"
|
||||||
|
},
|
||||||
|
"connectingToKovan": {
|
||||||
|
"message": "Kovan Test Ağına bağlanıyor"
|
||||||
|
},
|
||||||
|
"connectingToRinkeby": {
|
||||||
|
"message": "Rinkeby Test Ağına bağlanıyor"
|
||||||
|
},
|
||||||
|
"connectingToUnknown": {
|
||||||
|
"message": "Bilinmeyen Ağa bağlanıyor"
|
||||||
|
},
|
||||||
|
"sampleAccountName": {
|
||||||
|
"message": "E.g. Yeni hesabım",
|
||||||
|
"description": "Kullanıcının hesabına okunabilir isim ekleme konseptini anlamasına yardımcı olmak."
|
||||||
|
},
|
||||||
|
"save": {
|
||||||
|
"message": "Kaydet"
|
||||||
|
},
|
||||||
|
"reprice_title": {
|
||||||
|
"message": "İşlemi Yeniden Fiyatlandır"
|
||||||
|
},
|
||||||
|
"reprice_subtitle": {
|
||||||
|
"message": "İşlemizi hızlandırmayı denemek için gas fiyatınızı yükseltin."
|
||||||
|
},
|
||||||
|
"saveAsFile": {
|
||||||
|
"message": "Dosya olarak kaydet",
|
||||||
|
"description": "Hesap verme işlemi"
|
||||||
|
},
|
||||||
|
"saveSeedAsFile": {
|
||||||
|
"message": "Kaynak Kelimelerini Dosya olarak Kaydet"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"message": "Ara"
|
||||||
|
},
|
||||||
|
"secretPhrase": {
|
||||||
|
"message": "Kasanızı geri getirmek için gizli 12 kelimelik ifadenizi giriniz."
|
||||||
|
},
|
||||||
|
"newPassword8Chars": {
|
||||||
|
"message": "Yeni Parola (minumum 8 karakter)"
|
||||||
|
},
|
||||||
|
"seedPhraseReq": {
|
||||||
|
"message": "Kaynak ifadeleri 12 kelimedir."
|
||||||
|
},
|
||||||
|
"select": {
|
||||||
|
"message": "Seç"
|
||||||
|
},
|
||||||
|
"selectCurrency": {
|
||||||
|
"message": "Döviz Seç"
|
||||||
|
},
|
||||||
|
"selectService": {
|
||||||
|
"message": "Servis Seç"
|
||||||
|
},
|
||||||
|
"selectType": {
|
||||||
|
"message": "Tip Seç"
|
||||||
|
},
|
||||||
|
"send": {
|
||||||
|
"message": "Gönder"
|
||||||
|
},
|
||||||
|
"sendETH": {
|
||||||
|
"message": "ETH Gönder"
|
||||||
|
},
|
||||||
|
"sendTokens": {
|
||||||
|
"message": "Jeton Gönder"
|
||||||
|
},
|
||||||
|
"onlySendToEtherAddress": {
|
||||||
|
"message": "Ethereum adresine sadece ETH gönder."
|
||||||
|
},
|
||||||
|
"searchTokens": {
|
||||||
|
"message": "Jeton ara"
|
||||||
|
},
|
||||||
|
"sendTokensAnywhere": {
|
||||||
|
"message": "Ethereum hesabı olan birine Jeton gönder"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"message": "Ayarlar"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"message": "Bilgi"
|
||||||
|
},
|
||||||
|
"shapeshiftBuy": {
|
||||||
|
"message": "Shapeshift ile satın al"
|
||||||
|
},
|
||||||
|
"showPrivateKeys": {
|
||||||
|
"message": "Özel anahtarları göster"
|
||||||
|
},
|
||||||
|
"showQRCode": {
|
||||||
|
"message": "QR Kodu göster"
|
||||||
|
},
|
||||||
|
"sign": {
|
||||||
|
"message": "İmza"
|
||||||
|
},
|
||||||
|
"signed": {
|
||||||
|
"message": "İmzalandı"
|
||||||
|
},
|
||||||
|
"signMessage": {
|
||||||
|
"message": "Mesajı İmzala"
|
||||||
|
},
|
||||||
|
"signNotice": {
|
||||||
|
"message": "Bu mesajı imzalamanın tehlikeli \nyan etkileri olabilir. Tamamen güvendiğiniz sitelerden \ngelen mesajları hesabınızla imzalayınız.\n Bu tehlikeli metod gelecek versiyonlarda çıkarılacaktır. "
|
||||||
|
},
|
||||||
|
"sigRequest": {
|
||||||
|
"message": "İmza isteği"
|
||||||
|
},
|
||||||
|
"sigRequested": {
|
||||||
|
"message": "İmza isteniyor"
|
||||||
|
},
|
||||||
|
"spaceBetween": {
|
||||||
|
"message": "Kelimeler arası sadece bir boşluk olabilir."
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"message": "Durum"
|
||||||
|
},
|
||||||
|
"stateLogs": {
|
||||||
|
"message": "Durum Kayıtları"
|
||||||
|
},
|
||||||
|
"stateLogsDescription": {
|
||||||
|
"message": "Durum kayıtları açık hesap adresinizi ve gönderilen işlemleri içerir."
|
||||||
|
},
|
||||||
|
"stateLogError": {
|
||||||
|
"message": "Durum kayıtlarını alma hatası"
|
||||||
|
},
|
||||||
|
"submit": {
|
||||||
|
"message": "Gönder"
|
||||||
|
},
|
||||||
|
"submitted": {
|
||||||
|
"message": "Gönderildi"
|
||||||
|
},
|
||||||
|
"supportCenter": {
|
||||||
|
"message": "Destek merkezimizi ziyaret edin"
|
||||||
|
},
|
||||||
|
"symbolBetweenZeroTen": {
|
||||||
|
"message": "Sembol 0 ve 10 karakter aralığında olmalıdır."
|
||||||
|
},
|
||||||
|
"takesTooLong": {
|
||||||
|
"message": "Çok mu uzun sürüyor?"
|
||||||
|
},
|
||||||
|
"terms": {
|
||||||
|
"message": "Kullanım şartları"
|
||||||
|
},
|
||||||
|
"testFaucet": {
|
||||||
|
"message": "Test Musluğu"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"message": "Kime: "
|
||||||
|
},
|
||||||
|
"toETHviaShapeShift": {
|
||||||
|
"message": "ShapeShift üstünden $1'dan ETH'e",
|
||||||
|
"description": "system will fill in deposit type in start of message"
|
||||||
|
},
|
||||||
|
"tokenAddress": {
|
||||||
|
"message": "Jeton Adresi"
|
||||||
|
},
|
||||||
|
"tokenAlreadyAdded": {
|
||||||
|
"message": "Jeton çoktan eklenmiş."
|
||||||
|
},
|
||||||
|
"tokenBalance": {
|
||||||
|
"message": "Jeton bakiyeniz:"
|
||||||
|
},
|
||||||
|
"tokenSelection": {
|
||||||
|
"message": "Jeton arayın veya popüler jeton listemizden seçin."
|
||||||
|
},
|
||||||
|
"tokenSymbol": {
|
||||||
|
"message": "Jeton Sembolü"
|
||||||
|
},
|
||||||
|
"tokenWarning1": {
|
||||||
|
"message": "MetaMask hesabınızla aldığınız jetonların kaydını tutun. Başka bir hesapla jetonlar satın aldıysanız, o jetonlar burada gözükmeyecektir."
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"message": "Toplam"
|
||||||
|
},
|
||||||
|
"transactions": {
|
||||||
|
"message": "işlemler"
|
||||||
|
},
|
||||||
|
"transactionError": {
|
||||||
|
"message": "İşlem Hatası. Sözleşme kodundan kural dışı durum fırlatıldı."
|
||||||
|
},
|
||||||
|
"transactionMemo": {
|
||||||
|
"message": "İşlem notu (opsiyonel)"
|
||||||
|
},
|
||||||
|
"transactionNumber": {
|
||||||
|
"message": "İşlem numarası"
|
||||||
|
},
|
||||||
|
"transfers": {
|
||||||
|
"message": "Transferler"
|
||||||
|
},
|
||||||
|
"troubleTokenBalances": {
|
||||||
|
"message": "Jeton bakiyelerinizi yüklerken sorun yaşadık. Buradan izleyebilirsiniz ",
|
||||||
|
"description": "Jeton bakiyelerini görmek için bir link (burası) ile takip ediliyor"
|
||||||
|
},
|
||||||
|
"twelveWords": {
|
||||||
|
"message": "MetaMask hesaplarınızı geri getirmenin tek yolu bu 12 kelimedir.\nBu kelimeleri güvenli ve gizli bir yerde saklayın."
|
||||||
|
},
|
||||||
|
"typePassword": {
|
||||||
|
"message": "Parolanızı girin"
|
||||||
|
},
|
||||||
|
"uiWelcome": {
|
||||||
|
"message": "Yeni UI (Beta)'ya hoşgeldiniz"
|
||||||
|
},
|
||||||
|
"uiWelcomeMessage": {
|
||||||
|
"message": "Şu anda yeni Metamask UI kullanmaktasınız. Gözatın, jeton gönderme gibi yeni özellikleri deneyin ve herhangi bir sorunlar karşılaşırsanız bize haber verin"
|
||||||
|
},
|
||||||
|
"unapproved": {
|
||||||
|
"message": "Onaylanmadı"
|
||||||
|
},
|
||||||
|
"unavailable": {
|
||||||
|
"message": "Mevcut değil"
|
||||||
|
},
|
||||||
|
"unknown": {
|
||||||
|
"message": "Bilinmeyen"
|
||||||
|
},
|
||||||
|
"unknownNetwork": {
|
||||||
|
"message": "Bilinmeyen özel ağ"
|
||||||
|
},
|
||||||
|
"unknownNetworkId": {
|
||||||
|
"message": "Bilinmeyen ağ IDsi"
|
||||||
|
},
|
||||||
|
"uriErrorMsg": {
|
||||||
|
"message": "URIler için HTTP/HTTPS öneki gerekmektedir."
|
||||||
|
},
|
||||||
|
"usaOnly": {
|
||||||
|
"message": "Sadece ABD",
|
||||||
|
"description": "Bu dövizi sadece ABD ikamet edenler kullanabilir"
|
||||||
|
},
|
||||||
|
"usedByClients": {
|
||||||
|
"message": "Farklı istemciler tarafından kullanılmakta"
|
||||||
|
},
|
||||||
|
"useOldUI": {
|
||||||
|
"message": "Eski UI kullan"
|
||||||
|
},
|
||||||
|
"validFileImport": {
|
||||||
|
"message": "Almak için geçerli bir dosya seçmelisiniz"
|
||||||
|
},
|
||||||
|
"vaultCreated": {
|
||||||
|
"message": "Kasa Yaratıldı"
|
||||||
|
},
|
||||||
|
"viewAccount": {
|
||||||
|
"message": "Hesabı İncele"
|
||||||
|
},
|
||||||
|
"visitWebSite": {
|
||||||
|
"message": "Web sitemizi ziyaret edin"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"message": "Uyarı"
|
||||||
|
},
|
||||||
|
"welcomeBeta": {
|
||||||
|
"message": "MetaMask Beta'ya Hoşgeldiniz"
|
||||||
|
},
|
||||||
|
"whatsThis": {
|
||||||
|
"message": "Bu nedir?"
|
||||||
|
},
|
||||||
|
"yourSigRequested": {
|
||||||
|
"message": "İmzanız isteniyor"
|
||||||
|
},
|
||||||
|
"youSign": {
|
||||||
|
"message": "İmzalıyorsunuz"
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "__MSG_appName__",
|
"name": "__MSG_appName__",
|
||||||
"short_name": "__MSG_appName__",
|
"short_name": "__MSG_appName__",
|
||||||
"version": "4.5.3",
|
"version": "4.5.5",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"author": "https://metamask.io",
|
"author": "https://metamask.io",
|
||||||
"description": "__MSG_appDescription__",
|
"description": "__MSG_appDescription__",
|
||||||
|
@ -78,6 +78,28 @@ async function loadStateFromPersistence () {
|
|||||||
diskStore.getState() ||
|
diskStore.getState() ||
|
||||||
migrator.generateInitialState(firstTimeState)
|
migrator.generateInitialState(firstTimeState)
|
||||||
|
|
||||||
|
// check if somehow state is empty
|
||||||
|
// this should never happen but new error reporting suggests that it has
|
||||||
|
// for a small number of users
|
||||||
|
// https://github.com/metamask/metamask-extension/issues/3919
|
||||||
|
if (versionedData && !versionedData.data) {
|
||||||
|
// try to recover from diskStore incase only localStore is bad
|
||||||
|
const diskStoreState = diskStore.getState()
|
||||||
|
if (diskStoreState && diskStoreState.data) {
|
||||||
|
// we were able to recover (though it might be old)
|
||||||
|
versionedData = diskStoreState
|
||||||
|
const vaultStructure = getObjStructure(versionedData)
|
||||||
|
raven.captureMessage('MetaMask - Empty vault found - recovered from diskStore', {
|
||||||
|
// "extra" key is required by Sentry
|
||||||
|
extra: { vaultStructure },
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// unable to recover, clear state
|
||||||
|
versionedData = migrator.generateInitialState(firstTimeState)
|
||||||
|
raven.captureMessage('MetaMask - Empty vault found - unable to recover')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// report migration errors to sentry
|
// report migration errors to sentry
|
||||||
migrator.on('error', (err) => {
|
migrator.on('error', (err) => {
|
||||||
// get vault structure without secrets
|
// get vault structure without secrets
|
||||||
@ -140,9 +162,9 @@ function setupController (initState, initLangCode) {
|
|||||||
asStream(controller.store),
|
asStream(controller.store),
|
||||||
debounce(1000),
|
debounce(1000),
|
||||||
storeTransform(versionifyData),
|
storeTransform(versionifyData),
|
||||||
storeTransform(syncDataWithExtension),
|
storeTransform(persistData),
|
||||||
(error) => {
|
(error) => {
|
||||||
log.error('pump hit error', error)
|
log.error('MetaMask - Persistence pipeline failed', error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -151,7 +173,13 @@ function setupController (initState, initLangCode) {
|
|||||||
return versionedData
|
return versionedData
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncDataWithExtension(state) {
|
function persistData(state) {
|
||||||
|
if (!state) {
|
||||||
|
throw new Error('MetaMask - updated state is missing', state)
|
||||||
|
}
|
||||||
|
if (!state.data) {
|
||||||
|
throw new Error('MetaMask - updated state does not have data', state)
|
||||||
|
}
|
||||||
if (localStore.isSupported) {
|
if (localStore.isSupported) {
|
||||||
localStore.set(state)
|
localStore.set(state)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -3,7 +3,8 @@ module.exports = function isPopupOrNotification () {
|
|||||||
// if (url.match(/popup.html$/) || url.match(/home.html$/)) {
|
// if (url.match(/popup.html$/) || url.match(/home.html$/)) {
|
||||||
// Below regexes needed for feature toggles (e.g. see line ~340 in ui/app/app.js)
|
// Below regexes needed for feature toggles (e.g. see line ~340 in ui/app/app.js)
|
||||||
// Revert below regexes to above commented out regexes before merge to master
|
// Revert below regexes to above commented out regexes before merge to master
|
||||||
if (url.match(/popup.html(?:\?.+)*$/) || url.match(/home.html(?:\?.+)*$/)) {
|
if (url.match(/popup.html(?:\?.+)*$/) ||
|
||||||
|
url.match(/home.html(?:\?.+)*$/) || url.match(/home.html(?:#.*)*$/)) {
|
||||||
return 'popup'
|
return 'popup'
|
||||||
} else {
|
} else {
|
||||||
return 'notification'
|
return 'notification'
|
||||||
|
@ -92,8 +92,10 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
|||||||
// or rejected tx's.
|
// or rejected tx's.
|
||||||
// not tx's that are pending or unapproved
|
// not tx's that are pending or unapproved
|
||||||
if (txCount > txHistoryLimit - 1) {
|
if (txCount > txHistoryLimit - 1) {
|
||||||
const index = transactions.findIndex((metaTx) => metaTx.status === 'confirmed' || metaTx.status === 'rejected')
|
let index = transactions.findIndex((metaTx) => metaTx.status === 'confirmed' || metaTx.status === 'rejected')
|
||||||
transactions.splice(index, 1)
|
if (index !== -1) {
|
||||||
|
transactions.splice(index, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
transactions.push(txMeta)
|
transactions.push(txMeta)
|
||||||
this._saveTxList(transactions)
|
this._saveTxList(transactions)
|
||||||
|
@ -27,8 +27,11 @@ module.exports = {
|
|||||||
|
|
||||||
function transformState (state) {
|
function transformState (state) {
|
||||||
const newState = state
|
const newState = state
|
||||||
if (newState.config.provider.type === 'testnet') {
|
const { config } = newState
|
||||||
newState.config.provider.type = 'ropsten'
|
if ( config && config.provider ) {
|
||||||
|
if (config.provider.type === 'testnet') {
|
||||||
|
newState.config.provider.type = 'ropsten'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,14 @@ module.exports = {
|
|||||||
|
|
||||||
function transformState (state) {
|
function transformState (state) {
|
||||||
const newState = state
|
const newState = state
|
||||||
const transactions = newState.TransactionController.transactions
|
const { TransactionController } = newState
|
||||||
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
if (TransactionController && TransactionController.transactions) {
|
||||||
if (!txMeta.err) return txMeta
|
const transactions = TransactionController.transactions
|
||||||
else if (txMeta.err.message === 'Gave up submitting tx.') txMeta.status = 'failed'
|
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
||||||
return txMeta
|
if (!txMeta.err) return txMeta
|
||||||
})
|
else if (txMeta.err.message === 'Gave up submitting tx.') txMeta.status = 'failed'
|
||||||
|
return txMeta
|
||||||
|
})
|
||||||
|
}
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,18 @@ module.exports = {
|
|||||||
|
|
||||||
function transformState (state) {
|
function transformState (state) {
|
||||||
const newState = state
|
const newState = state
|
||||||
const transactions = newState.TransactionController.transactions
|
const { TransactionController } = newState
|
||||||
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
if (TransactionController && TransactionController.transactions) {
|
||||||
if (!txMeta.err) return txMeta
|
const transactions = newState.TransactionController.transactions
|
||||||
if (txMeta.err === 'transaction with the same hash was already imported.') {
|
|
||||||
txMeta.status = 'submitted'
|
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
||||||
delete txMeta.err
|
if (!txMeta.err) return txMeta
|
||||||
}
|
if (txMeta.err === 'transaction with the same hash was already imported.') {
|
||||||
return txMeta
|
txMeta.status = 'submitted'
|
||||||
})
|
delete txMeta.err
|
||||||
|
}
|
||||||
|
return txMeta
|
||||||
|
})
|
||||||
|
}
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
@ -27,14 +27,17 @@ module.exports = {
|
|||||||
|
|
||||||
function transformState (state) {
|
function transformState (state) {
|
||||||
const newState = state
|
const newState = state
|
||||||
const transactions = newState.TransactionController.transactions
|
const { TransactionController } = newState
|
||||||
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
if (TransactionController && TransactionController.transactions) {
|
||||||
if (!txMeta.status === 'failed') return txMeta
|
const transactions = newState.TransactionController.transactions
|
||||||
if (txMeta.retryCount > 0 && txMeta.retryCount < 2) {
|
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
||||||
txMeta.status = 'submitted'
|
if (!txMeta.status === 'failed') return txMeta
|
||||||
delete txMeta.err
|
if (txMeta.retryCount > 0 && txMeta.retryCount < 2) {
|
||||||
}
|
txMeta.status = 'submitted'
|
||||||
return txMeta
|
delete txMeta.err
|
||||||
})
|
}
|
||||||
|
return txMeta
|
||||||
|
})
|
||||||
|
}
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
@ -29,24 +29,27 @@ module.exports = {
|
|||||||
|
|
||||||
function transformState (state) {
|
function transformState (state) {
|
||||||
const newState = state
|
const newState = state
|
||||||
const transactions = newState.TransactionController.transactions
|
const { TransactionController } = newState
|
||||||
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
if (TransactionController && TransactionController.transactions) {
|
||||||
// no history: initialize
|
const transactions = newState.TransactionController.transactions
|
||||||
if (!txMeta.history || txMeta.history.length === 0) {
|
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
||||||
const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta)
|
// no history: initialize
|
||||||
txMeta.history = [snapshot]
|
if (!txMeta.history || txMeta.history.length === 0) {
|
||||||
|
const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta)
|
||||||
|
txMeta.history = [snapshot]
|
||||||
|
return txMeta
|
||||||
|
}
|
||||||
|
// has history: migrate
|
||||||
|
const newHistory = (
|
||||||
|
txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history)
|
||||||
|
// remove empty diffs
|
||||||
|
.filter((entry) => {
|
||||||
|
return !Array.isArray(entry) || entry.length > 0
|
||||||
|
})
|
||||||
|
)
|
||||||
|
txMeta.history = newHistory
|
||||||
return txMeta
|
return txMeta
|
||||||
}
|
})
|
||||||
// has history: migrate
|
}
|
||||||
const newHistory = (
|
|
||||||
txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history)
|
|
||||||
// remove empty diffs
|
|
||||||
.filter((entry) => {
|
|
||||||
return !Array.isArray(entry) || entry.length > 0
|
|
||||||
})
|
|
||||||
)
|
|
||||||
txMeta.history = newHistory
|
|
||||||
return txMeta
|
|
||||||
})
|
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
@ -29,32 +29,36 @@ module.exports = {
|
|||||||
|
|
||||||
function transformState (state) {
|
function transformState (state) {
|
||||||
const newState = state
|
const newState = state
|
||||||
const transactions = newState.TransactionController.transactions
|
const { TransactionController } = newState
|
||||||
|
if (TransactionController && TransactionController.transactions) {
|
||||||
|
|
||||||
newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => {
|
const transactions = newState.TransactionController.transactions
|
||||||
if (txMeta.status !== 'submitted') return txMeta
|
|
||||||
|
|
||||||
const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed')
|
newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => {
|
||||||
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
|
if (txMeta.status !== 'submitted') return txMeta
|
||||||
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
|
|
||||||
const highestConfirmedNonce = getHighestNonce(confirmedTxs)
|
|
||||||
|
|
||||||
const pendingTxs = txList.filter((tx) => tx.status === 'submitted')
|
const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed')
|
||||||
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
|
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
|
||||||
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
|
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
|
||||||
const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce)
|
const highestConfirmedNonce = getHighestNonce(confirmedTxs)
|
||||||
|
|
||||||
const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce)
|
const pendingTxs = txList.filter((tx) => tx.status === 'submitted')
|
||||||
|
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
|
||||||
|
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
|
||||||
|
const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce)
|
||||||
|
|
||||||
if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) {
|
const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce)
|
||||||
txMeta.status = 'failed'
|
|
||||||
txMeta.err = {
|
if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) {
|
||||||
message: 'nonce too high',
|
txMeta.status = 'failed'
|
||||||
note: 'migration 019 custom error',
|
txMeta.err = {
|
||||||
|
message: 'nonce too high',
|
||||||
|
note: 'migration 019 custom error',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return txMeta
|
||||||
return txMeta
|
})
|
||||||
})
|
}
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,12 +28,15 @@ module.exports = {
|
|||||||
|
|
||||||
function transformState (state) {
|
function transformState (state) {
|
||||||
const newState = state
|
const newState = state
|
||||||
const transactions = newState.TransactionController.transactions
|
const { TransactionController } = newState
|
||||||
|
if (TransactionController && TransactionController.transactions) {
|
||||||
|
const transactions = newState.TransactionController.transactions
|
||||||
|
|
||||||
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
||||||
if (txMeta.status !== 'submitted' || txMeta.submittedTime) return txMeta
|
if (txMeta.status !== 'submitted' || txMeta.submittedTime) return txMeta
|
||||||
txMeta.submittedTime = (new Date()).getTime()
|
txMeta.submittedTime = (new Date()).getTime()
|
||||||
return txMeta
|
return txMeta
|
||||||
})
|
})
|
||||||
|
}
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
@ -28,23 +28,27 @@ module.exports = {
|
|||||||
|
|
||||||
function transformState (state) {
|
function transformState (state) {
|
||||||
const newState = state
|
const newState = state
|
||||||
const transactions = newState.TransactionController.transactions
|
|
||||||
|
|
||||||
if (transactions.length <= 40) return newState
|
const { TransactionController } = newState
|
||||||
|
if (TransactionController && TransactionController.transactions) {
|
||||||
|
const transactions = newState.TransactionController.transactions
|
||||||
|
|
||||||
let reverseTxList = transactions.reverse()
|
if (transactions.length <= 40) return newState
|
||||||
let stripping = true
|
|
||||||
while (reverseTxList.length > 40 && stripping) {
|
let reverseTxList = transactions.reverse()
|
||||||
let txIndex = reverseTxList.findIndex((txMeta) => {
|
let stripping = true
|
||||||
return (txMeta.status === 'failed' ||
|
while (reverseTxList.length > 40 && stripping) {
|
||||||
txMeta.status === 'rejected' ||
|
let txIndex = reverseTxList.findIndex((txMeta) => {
|
||||||
txMeta.status === 'confirmed' ||
|
return (txMeta.status === 'failed' ||
|
||||||
txMeta.status === 'dropped')
|
txMeta.status === 'rejected' ||
|
||||||
})
|
txMeta.status === 'confirmed' ||
|
||||||
if (txIndex < 0) stripping = false
|
txMeta.status === 'dropped')
|
||||||
else reverseTxList.splice(txIndex, 1)
|
})
|
||||||
|
if (txIndex < 0) stripping = false
|
||||||
|
else reverseTxList.splice(txIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
newState.TransactionController.transactions = reverseTxList.reverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
newState.TransactionController.transactions = reverseTxList.reverse()
|
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
@ -36,15 +36,28 @@ log.setLevel('debug')
|
|||||||
//
|
//
|
||||||
|
|
||||||
const qs = require('qs')
|
const qs = require('qs')
|
||||||
let queryString = qs.parse(window.location.href.split('#')[1])
|
const routerPath = window.location.href.split('#')[1]
|
||||||
let selectedView = queryString.view || 'first time'
|
let queryString = {}
|
||||||
|
let selectedView
|
||||||
|
|
||||||
|
if (routerPath) {
|
||||||
|
queryString = qs.parse(routerPath.split('?')[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedView = queryString.view || 'first time'
|
||||||
const firstState = states[selectedView]
|
const firstState = states[selectedView]
|
||||||
updateQueryParams(selectedView)
|
updateQueryParams(selectedView)
|
||||||
|
|
||||||
function updateQueryParams(newView) {
|
function updateQueryParams (newView) {
|
||||||
queryString.view = newView
|
queryString.view = newView
|
||||||
const params = qs.stringify(queryString)
|
const params = qs.stringify(queryString)
|
||||||
window.location.href = window.location.href.split('#')[0] + `#${params}`
|
const locationPaths = window.location.href.split('#')
|
||||||
|
const routerPath = locationPaths[1] || ''
|
||||||
|
const newPath = locationPaths[0] + '#' + routerPath.split('?')[0] + `?${params}`
|
||||||
|
|
||||||
|
if (window.location.href !== newPath) {
|
||||||
|
window.location.href = newPath
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
48
docs/QA_Guide.md
Normal file
48
docs/QA_Guide.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# QA Guide
|
||||||
|
|
||||||
|
Steps to mark a full pass of QA complete.
|
||||||
|
* Browsers: Opera, Chrome, Firefox, Edge.
|
||||||
|
* OS: Ubuntu, Mac OSX, Windows
|
||||||
|
* Load older version of MetaMask and attempt to simulate updating the extension.
|
||||||
|
* Open Developer Console in background and popup, inspect errors.
|
||||||
|
* Watch the state logs
|
||||||
|
* Transactions (unapproved txs -> rejected/submitted -> confirmed)
|
||||||
|
* Nonces/LocalNonces
|
||||||
|
* Vault integrity
|
||||||
|
* create vault
|
||||||
|
* Log out
|
||||||
|
* Log in again
|
||||||
|
* Log out
|
||||||
|
* Restore from seed
|
||||||
|
* Create a second account
|
||||||
|
* Import a loose account (not related to HD Wallet)
|
||||||
|
* Import old existing vault seed phrase (pref with test Ether)
|
||||||
|
* Download State Logs, Priv key file, seed phrase file.
|
||||||
|
* Send Ether
|
||||||
|
* by address
|
||||||
|
* by ens name
|
||||||
|
* Web3 API Stability
|
||||||
|
* Create a contract from a Ðapp (remix)
|
||||||
|
* Load a Ðapp that reads using events/logs (ENS)
|
||||||
|
* Connect to MEW/MyCypto
|
||||||
|
* Send a transaction from any Ðapp
|
||||||
|
- MEW
|
||||||
|
- EtherDelta
|
||||||
|
- Leeroy
|
||||||
|
- Aragon
|
||||||
|
- (https://tmashuang.github.io/demo-dapp)
|
||||||
|
* Check account balances
|
||||||
|
* Token Management
|
||||||
|
* create a token with tokenfactory (http://tokenfactory.surge.sh/#/factory)
|
||||||
|
* Add that token to the token view
|
||||||
|
* Send that token to another metamask address.
|
||||||
|
* confirm the token arrived.
|
||||||
|
* Send a transaction and sign a message (https://danfinlay.github.io/js-eth-personal-sign-examples/) for each keyring type
|
||||||
|
* hd keyring
|
||||||
|
* imported keyring
|
||||||
|
* Change network from mainnet → ropsten → rinkeby → localhost (ganache)
|
||||||
|
* Ganache set blocktime to simulate retryTx in MetaMask
|
||||||
|
* Copy public key to clipboard
|
||||||
|
* Export private key
|
||||||
|
|
||||||
|
* Explore changes in master, target features that have been changed and break.
|
151
mascara/src/app/first-time/confirm-seed-screen.js
Normal file
151
mascara/src/app/first-time/confirm-seed-screen.js
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { withRouter } from 'react-router-dom'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import shuffle from 'lodash.shuffle'
|
||||||
|
import { compose } from 'recompose'
|
||||||
|
import Identicon from '../../../../ui/app/components/identicon'
|
||||||
|
import { confirmSeedWords, showModal } from '../../../../ui/app/actions'
|
||||||
|
import Breadcrumbs from './breadcrumbs'
|
||||||
|
import LoadingScreen from './loading-screen'
|
||||||
|
import { DEFAULT_ROUTE } from '../../../../ui/app/routes'
|
||||||
|
|
||||||
|
class ConfirmSeedScreen extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
isLoading: PropTypes.bool,
|
||||||
|
address: PropTypes.string,
|
||||||
|
seedWords: PropTypes.string,
|
||||||
|
confirmSeedWords: PropTypes.func,
|
||||||
|
history: PropTypes.object,
|
||||||
|
openBuyEtherModal: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
seedWords: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
const { seedWords } = props
|
||||||
|
this.state = {
|
||||||
|
selectedSeeds: [],
|
||||||
|
shuffledSeeds: seedWords && shuffle(seedWords.split(' ')) || [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { seedWords, history } = this.props
|
||||||
|
|
||||||
|
if (!seedWords) {
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick () {
|
||||||
|
const { confirmSeedWords, history, openBuyEtherModal } = this.props
|
||||||
|
|
||||||
|
confirmSeedWords()
|
||||||
|
.then(() => {
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
|
openBuyEtherModal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { seedWords } = this.props
|
||||||
|
const { selectedSeeds, shuffledSeeds } = this.state
|
||||||
|
const isValid = seedWords === selectedSeeds.map(([_, seed]) => seed).join(' ')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="first-time-flow">
|
||||||
|
{
|
||||||
|
this.props.isLoading
|
||||||
|
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||||
|
: (
|
||||||
|
<div className="first-view-main-wrapper">
|
||||||
|
<div className="first-view-main">
|
||||||
|
<div className="backup-phrase">
|
||||||
|
<Identicon address={this.props.address} diameter={70} />
|
||||||
|
<div className="backup-phrase__content-wrapper">
|
||||||
|
<div>
|
||||||
|
<div className="backup-phrase__title">
|
||||||
|
Confirm your Secret Backup Phrase
|
||||||
|
</div>
|
||||||
|
<div className="backup-phrase__body-text">
|
||||||
|
Please select each phrase in order to make sure it is correct.
|
||||||
|
</div>
|
||||||
|
<div className="backup-phrase__confirm-secret">
|
||||||
|
{selectedSeeds.map(([_, word], i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
className="backup-phrase__confirm-seed-option"
|
||||||
|
>
|
||||||
|
{word}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="backup-phrase__confirm-seed-options">
|
||||||
|
{shuffledSeeds.map((word, i) => {
|
||||||
|
const isSelected = selectedSeeds
|
||||||
|
.filter(([index, seed]) => seed === word && index === i)
|
||||||
|
.length
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
className={classnames('backup-phrase__confirm-seed-option', {
|
||||||
|
'backup-phrase__confirm-seed-option--selected': isSelected,
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
if (!isSelected) {
|
||||||
|
this.setState({
|
||||||
|
selectedSeeds: [...selectedSeeds, [i, word]],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
selectedSeeds: selectedSeeds
|
||||||
|
.filter(([index, seed]) => !(seed === word && index === i)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{word}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className="first-time-flow__button"
|
||||||
|
onClick={() => isValid && this.handleClick()}
|
||||||
|
disabled={!isValid}
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Breadcrumbs total={3} currentIndex={1} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withRouter,
|
||||||
|
connect(
|
||||||
|
({ metamask: { selectedAddress, seedWords }, appState: { isLoading } }) => ({
|
||||||
|
seedWords,
|
||||||
|
isLoading,
|
||||||
|
address: selectedAddress,
|
||||||
|
}),
|
||||||
|
dispatch => ({
|
||||||
|
confirmSeedWords: () => dispatch(confirmSeedWords()),
|
||||||
|
openBuyEtherModal: () => dispatch(showModal({ name: 'DEPOSIT_ETHER'})),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)(ConfirmSeedScreen)
|
@ -1,20 +1,26 @@
|
|||||||
import EventEmitter from 'events'
|
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import classnames from 'classnames'
|
import { withRouter } from 'react-router-dom'
|
||||||
import {createNewVaultAndKeychain} from '../../../../ui/app/actions'
|
import { compose } from 'recompose'
|
||||||
import LoadingScreen from './loading-screen'
|
import { createNewVaultAndKeychain } from '../../../../ui/app/actions'
|
||||||
import Breadcrumbs from './breadcrumbs'
|
import Breadcrumbs from './breadcrumbs'
|
||||||
|
import EventEmitter from 'events'
|
||||||
import Mascot from '../../../../ui/app/components/mascot'
|
import Mascot from '../../../../ui/app/components/mascot'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import {
|
||||||
|
INITIALIZE_UNIQUE_IMAGE_ROUTE,
|
||||||
|
INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE,
|
||||||
|
INITIALIZE_NOTICE_ROUTE,
|
||||||
|
} from '../../../../ui/app/routes'
|
||||||
|
|
||||||
class CreatePasswordScreen extends Component {
|
class CreatePasswordScreen extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
isLoading: PropTypes.bool.isRequired,
|
isLoading: PropTypes.bool.isRequired,
|
||||||
createAccount: PropTypes.func.isRequired,
|
createAccount: PropTypes.func.isRequired,
|
||||||
goToImportWithSeedPhrase: PropTypes.func.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
goToImportAccount: PropTypes.func.isRequired,
|
isInitialized: PropTypes.bool,
|
||||||
next: PropTypes.func.isRequired,
|
isUnlocked: PropTypes.bool,
|
||||||
isMascara: PropTypes.bool.isRequired,
|
isMascara: PropTypes.bool.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,13 +29,21 @@ class CreatePasswordScreen extends Component {
|
|||||||
confirmPassword: '',
|
confirmPassword: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor () {
|
constructor (props) {
|
||||||
super()
|
super(props)
|
||||||
this.animationEventEmitter = new EventEmitter()
|
this.animationEventEmitter = new EventEmitter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { isInitialized, history } = this.props
|
||||||
|
|
||||||
|
if (isInitialized) {
|
||||||
|
history.push(INITIALIZE_NOTICE_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isValid () {
|
isValid () {
|
||||||
const {password, confirmPassword} = this.state
|
const { password, confirmPassword } = this.state
|
||||||
|
|
||||||
if (!password || !confirmPassword) {
|
if (!password || !confirmPassword) {
|
||||||
return false
|
return false
|
||||||
@ -47,93 +61,182 @@ class CreatePasswordScreen extends Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const {password} = this.state
|
const { password } = this.state
|
||||||
const {createAccount, next} = this.props
|
const { createAccount, history } = this.props
|
||||||
|
|
||||||
|
this.setState({ isLoading: true })
|
||||||
createAccount(password)
|
createAccount(password)
|
||||||
.then(next)
|
.then(() => history.push(INITIALIZE_UNIQUE_IMAGE_ROUTE))
|
||||||
|
}
|
||||||
|
|
||||||
|
renderFields () {
|
||||||
|
const { isMascara, history } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
|
||||||
|
<div className={classnames({
|
||||||
|
'first-view-main': !isMascara,
|
||||||
|
'first-view-main__mascara': isMascara,
|
||||||
|
})}>
|
||||||
|
{isMascara && <div className="mascara-info first-view-phone-invisible">
|
||||||
|
<Mascot
|
||||||
|
animationEventEmitter={this.animationEventEmitter}
|
||||||
|
width="225"
|
||||||
|
height="225"
|
||||||
|
/>
|
||||||
|
<div className="info">
|
||||||
|
MetaMask is a secure identity vault for Ethereum.
|
||||||
|
</div>
|
||||||
|
<div className="info">
|
||||||
|
It allows you to hold ether & tokens, and interact with decentralized applications.
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
|
<div className="create-password">
|
||||||
|
<div className="create-password__title">
|
||||||
|
Create Password
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
className="first-time-flow__input"
|
||||||
|
type="password"
|
||||||
|
placeholder="New Password (min 8 characters)"
|
||||||
|
onChange={e => this.setState({password: e.target.value})}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
className="first-time-flow__input create-password__confirm-input"
|
||||||
|
type="password"
|
||||||
|
placeholder="Confirm Password"
|
||||||
|
onChange={e => this.setState({confirmPassword: e.target.value})}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className="first-time-flow__button"
|
||||||
|
disabled={!this.isValid()}
|
||||||
|
onClick={this.createAccount}
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
<a
|
||||||
|
href=""
|
||||||
|
className="first-time-flow__link create-password__import-link"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Import with seed phrase
|
||||||
|
</a>
|
||||||
|
{ /* }
|
||||||
|
<a
|
||||||
|
href=""
|
||||||
|
className="first-time-flow__link create-password__import-link"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
history.push(INITIALIZE_IMPORT_ACCOUNT_ROUTE)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Import an account
|
||||||
|
</a>
|
||||||
|
{ */ }
|
||||||
|
<Breadcrumbs total={3} currentIndex={0} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { isLoading, goToImportWithSeedPhrase, isMascara } = this.props
|
const { history, isMascara } = this.props
|
||||||
|
|
||||||
return isLoading
|
return (
|
||||||
? <LoadingScreen loadingMessage="Creating your new account" />
|
<div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
|
||||||
: (
|
<div className={classnames({
|
||||||
<div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
|
'first-view-main': !isMascara,
|
||||||
<div className={classnames({
|
'first-view-main__mascara': isMascara,
|
||||||
'first-view-main': !isMascara,
|
})}>
|
||||||
'first-view-main__mascara': isMascara,
|
{isMascara && <div className="mascara-info first-view-phone-invisible">
|
||||||
})}>
|
<Mascot
|
||||||
{isMascara && <div className="mascara-info first-view-phone-invisible">
|
animationEventEmitter={this.animationEventEmitter}
|
||||||
<Mascot
|
width="225"
|
||||||
animationEventEmitter={this.animationEventEmitter}
|
height="225"
|
||||||
width="225"
|
/>
|
||||||
height="225"
|
<div className="info">
|
||||||
/>
|
MetaMask is a secure identity vault for Ethereum.
|
||||||
<div className="info">
|
|
||||||
MetaMask is a secure identity vault for Ethereum.
|
|
||||||
</div>
|
|
||||||
<div className="info">
|
|
||||||
It allows you to hold ether & tokens, and interact with decentralized applications.
|
|
||||||
</div>
|
|
||||||
</div>}
|
|
||||||
<div className="create-password">
|
|
||||||
<div className="create-password__title">
|
|
||||||
Create Password
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
className="first-time-flow__input"
|
|
||||||
type="password"
|
|
||||||
placeholder="New Password (min 8 characters)"
|
|
||||||
onChange={e => this.setState({password: e.target.value})}
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
className="first-time-flow__input create-password__confirm-input"
|
|
||||||
type="password"
|
|
||||||
placeholder="Confirm Password"
|
|
||||||
onChange={e => this.setState({confirmPassword: e.target.value})}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
className="first-time-flow__button"
|
|
||||||
disabled={!this.isValid()}
|
|
||||||
onClick={this.createAccount}
|
|
||||||
>
|
|
||||||
Create
|
|
||||||
</button>
|
|
||||||
<a
|
|
||||||
href=""
|
|
||||||
className="first-time-flow__link create-password__import-link"
|
|
||||||
onClick={e => {
|
|
||||||
e.preventDefault()
|
|
||||||
goToImportWithSeedPhrase()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Import with seed phrase
|
|
||||||
</a>
|
|
||||||
{ /* }
|
|
||||||
<a
|
|
||||||
href=""
|
|
||||||
className="first-time-flow__link create-password__import-link"
|
|
||||||
onClick={e => {
|
|
||||||
e.preventDefault()
|
|
||||||
goToImportAccount()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Import an account
|
|
||||||
</a>
|
|
||||||
{ */ }
|
|
||||||
<Breadcrumbs total={3} currentIndex={0} />
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="info">
|
||||||
|
It allows you to hold ether & tokens, and interact with decentralized applications.
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
|
<div className="create-password">
|
||||||
|
<div className="create-password__title">
|
||||||
|
Create Password
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
className="first-time-flow__input"
|
||||||
|
type="password"
|
||||||
|
placeholder="New Password (min 8 characters)"
|
||||||
|
onChange={e => this.setState({password: e.target.value})}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
className="first-time-flow__input create-password__confirm-input"
|
||||||
|
type="password"
|
||||||
|
placeholder="Confirm Password"
|
||||||
|
onChange={e => this.setState({confirmPassword: e.target.value})}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className="first-time-flow__button"
|
||||||
|
disabled={!this.isValid()}
|
||||||
|
onClick={this.createAccount}
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
<a
|
||||||
|
href=""
|
||||||
|
className="first-time-flow__link create-password__import-link"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Import with seed phrase
|
||||||
|
</a>
|
||||||
|
{ /* }
|
||||||
|
<a
|
||||||
|
href=""
|
||||||
|
className="first-time-flow__link create-password__import-link"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
history.push(INITIALIZE_IMPORT_ACCOUNT_ROUTE)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Import an account
|
||||||
|
</a>
|
||||||
|
{ */ }
|
||||||
|
<Breadcrumbs total={3} currentIndex={0} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
const mapStateToProps = ({ metamask, appState }) => {
|
||||||
({ appState: { isLoading }, metamask: { isMascara } }) => ({ isLoading, isMascara }),
|
const { isInitialized, isUnlocked, isMascara, noActiveNotices } = metamask
|
||||||
dispatch => ({
|
const { isLoading } = appState
|
||||||
createAccount: password => dispatch(createNewVaultAndKeychain(password)),
|
|
||||||
})
|
return {
|
||||||
|
isLoading,
|
||||||
|
isInitialized,
|
||||||
|
isUnlocked,
|
||||||
|
isMascara,
|
||||||
|
noActiveNotices,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withRouter,
|
||||||
|
connect(
|
||||||
|
mapStateToProps,
|
||||||
|
dispatch => ({
|
||||||
|
createAccount: password => dispatch(createNewVaultAndKeychain(password)),
|
||||||
|
})
|
||||||
|
)
|
||||||
)(CreatePasswordScreen)
|
)(CreatePasswordScreen)
|
||||||
|
@ -8,16 +8,16 @@ import {
|
|||||||
displayWarning,
|
displayWarning,
|
||||||
unMarkPasswordForgotten,
|
unMarkPasswordForgotten,
|
||||||
} from '../../../../ui/app/actions'
|
} from '../../../../ui/app/actions'
|
||||||
|
import { DEFAULT_ROUTE, INITIALIZE_NOTICE_ROUTE } from '../../../../ui/app/routes'
|
||||||
|
|
||||||
class ImportSeedPhraseScreen extends Component {
|
class ImportSeedPhraseScreen extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
warning: PropTypes.string,
|
warning: PropTypes.string,
|
||||||
back: PropTypes.func.isRequired,
|
|
||||||
next: PropTypes.func.isRequired,
|
|
||||||
createNewVaultAndRestore: PropTypes.func.isRequired,
|
createNewVaultAndRestore: PropTypes.func.isRequired,
|
||||||
hideWarning: PropTypes.func.isRequired,
|
hideWarning: PropTypes.func.isRequired,
|
||||||
displayWarning: PropTypes.func,
|
displayWarning: PropTypes.func,
|
||||||
leaveImportSeedScreenState: PropTypes.func,
|
leaveImportSeedScreenState: PropTypes.func,
|
||||||
|
history: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -64,20 +64,21 @@ class ImportSeedPhraseScreen extends Component {
|
|||||||
const { password, seedPhrase } = this.state
|
const { password, seedPhrase } = this.state
|
||||||
const {
|
const {
|
||||||
createNewVaultAndRestore,
|
createNewVaultAndRestore,
|
||||||
next,
|
|
||||||
displayWarning,
|
displayWarning,
|
||||||
leaveImportSeedScreenState,
|
leaveImportSeedScreenState,
|
||||||
|
history,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
leaveImportSeedScreenState()
|
leaveImportSeedScreenState()
|
||||||
createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase))
|
createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase))
|
||||||
.then(next)
|
.then(() => history.push(INITIALIZE_NOTICE_ROUTE))
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { seedPhrase, password, confirmPassword } = this.state
|
const { seedPhrase, password, confirmPassword } = this.state
|
||||||
const { warning } = this.props
|
const { warning, isLoading } = this.props
|
||||||
const importDisabled = warning || !seedPhrase || !password || !confirmPassword
|
const importDisabled = warning || !seedPhrase || !password || !confirmPassword || isLoading
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="first-view-main-wrapper">
|
<div className="first-view-main-wrapper">
|
||||||
<div className="first-view-main">
|
<div className="first-view-main">
|
||||||
@ -86,7 +87,7 @@ class ImportSeedPhraseScreen extends Component {
|
|||||||
className="import-account__back-button"
|
className="import-account__back-button"
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.props.back()
|
this.props.history.goBack()
|
||||||
}}
|
}}
|
||||||
href="#"
|
href="#"
|
||||||
>
|
>
|
||||||
@ -152,7 +153,7 @@ class ImportSeedPhraseScreen extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
({ appState: { warning } }) => ({ warning }),
|
({ appState: { warning, isLoading } }) => ({ warning, isLoading }),
|
||||||
dispatch => ({
|
dispatch => ({
|
||||||
leaveImportSeedScreenState: () => {
|
leaveImportSeedScreenState: () => {
|
||||||
dispatch(unMarkPasswordForgotten())
|
dispatch(unMarkPasswordForgotten())
|
||||||
|
@ -1,17 +1,26 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
|
import { withRouter, Switch, Route } from 'react-router-dom'
|
||||||
|
import { compose } from 'recompose'
|
||||||
import CreatePasswordScreen from './create-password-screen'
|
import CreatePasswordScreen from './create-password-screen'
|
||||||
import UniqueImageScreen from './unique-image-screen'
|
import UniqueImageScreen from './unique-image-screen'
|
||||||
import NoticeScreen from './notice-screen'
|
import NoticeScreen from './notice-screen'
|
||||||
import BackupPhraseScreen from './backup-phrase-screen'
|
import BackupPhraseScreen from './seed-screen'
|
||||||
import ImportAccountScreen from './import-account-screen'
|
import ImportAccountScreen from './import-account-screen'
|
||||||
import ImportSeedPhraseScreen from './import-seed-phrase-screen'
|
import ImportSeedPhraseScreen from './import-seed-phrase-screen'
|
||||||
|
import ConfirmSeed from './confirm-seed-screen'
|
||||||
import {
|
import {
|
||||||
onboardingBuyEthView,
|
INITIALIZE_ROUTE,
|
||||||
unMarkPasswordForgotten,
|
INITIALIZE_IMPORT_ACCOUNT_ROUTE,
|
||||||
showModal,
|
INITIALIZE_UNIQUE_IMAGE_ROUTE,
|
||||||
} from '../../../../ui/app/actions'
|
INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE,
|
||||||
|
INITIALIZE_NOTICE_ROUTE,
|
||||||
|
INITIALIZE_BACKUP_PHRASE_ROUTE,
|
||||||
|
INITIALIZE_CONFIRM_SEED_ROUTE,
|
||||||
|
INITIALIZE_CREATE_PASSWORD_ROUTE,
|
||||||
|
} from '../../../../ui/app/routes'
|
||||||
|
import WelcomeScreen from '../../../../ui/app/welcome-screen'
|
||||||
|
|
||||||
class FirstTimeFlow extends Component {
|
class FirstTimeFlow extends Component {
|
||||||
|
|
||||||
@ -20,6 +29,10 @@ class FirstTimeFlow extends Component {
|
|||||||
seedWords: PropTypes.string,
|
seedWords: PropTypes.string,
|
||||||
address: PropTypes.string,
|
address: PropTypes.string,
|
||||||
noActiveNotices: PropTypes.bool,
|
noActiveNotices: PropTypes.bool,
|
||||||
|
goToBuyEtherView: PropTypes.func,
|
||||||
|
isUnlocked: PropTypes.bool,
|
||||||
|
history: PropTypes.object,
|
||||||
|
welcomeScreenSeen: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@ -28,145 +41,53 @@ class FirstTimeFlow extends Component {
|
|||||||
noActiveNotices: false,
|
noActiveNotices: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static SCREEN_TYPE = {
|
|
||||||
CREATE_PASSWORD: 'create_password',
|
|
||||||
IMPORT_ACCOUNT: 'import_account',
|
|
||||||
IMPORT_SEED_PHRASE: 'import_seed_phrase',
|
|
||||||
UNIQUE_IMAGE: 'unique_image',
|
|
||||||
NOTICE: 'notice',
|
|
||||||
BACK_UP_PHRASE: 'back_up_phrase',
|
|
||||||
CONFIRM_BACK_UP_PHRASE: 'confirm_back_up_phrase',
|
|
||||||
LOADING: 'loading',
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
this.state = {
|
|
||||||
screenType: this.getScreenType(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setScreenType (screenType) {
|
|
||||||
this.setState({ screenType })
|
|
||||||
}
|
|
||||||
|
|
||||||
getScreenType () {
|
|
||||||
const {
|
|
||||||
isInitialized,
|
|
||||||
seedWords,
|
|
||||||
noActiveNotices,
|
|
||||||
forgottenPassword,
|
|
||||||
} = this.props
|
|
||||||
const {SCREEN_TYPE} = FirstTimeFlow
|
|
||||||
|
|
||||||
// return SCREEN_TYPE.NOTICE
|
|
||||||
|
|
||||||
if (forgottenPassword) {
|
|
||||||
return SCREEN_TYPE.IMPORT_SEED_PHRASE
|
|
||||||
}
|
|
||||||
if (!isInitialized) {
|
|
||||||
return SCREEN_TYPE.CREATE_PASSWORD
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!noActiveNotices) {
|
|
||||||
return SCREEN_TYPE.NOTICE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seedWords) {
|
|
||||||
return SCREEN_TYPE.BACK_UP_PHRASE
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderScreen () {
|
|
||||||
const {SCREEN_TYPE} = FirstTimeFlow
|
|
||||||
const {
|
|
||||||
openBuyEtherModal,
|
|
||||||
address,
|
|
||||||
restoreCreatePasswordScreen,
|
|
||||||
forgottenPassword,
|
|
||||||
leaveImportSeedScreenState,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
switch (this.state.screenType) {
|
|
||||||
case SCREEN_TYPE.CREATE_PASSWORD:
|
|
||||||
return (
|
|
||||||
<CreatePasswordScreen
|
|
||||||
next={() => this.setScreenType(SCREEN_TYPE.UNIQUE_IMAGE)}
|
|
||||||
goToImportAccount={() => this.setScreenType(SCREEN_TYPE.IMPORT_ACCOUNT)}
|
|
||||||
goToImportWithSeedPhrase={() => this.setScreenType(SCREEN_TYPE.IMPORT_SEED_PHRASE)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case SCREEN_TYPE.IMPORT_ACCOUNT:
|
|
||||||
return (
|
|
||||||
<ImportAccountScreen
|
|
||||||
back={() => this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD)}
|
|
||||||
next={() => this.setScreenType(SCREEN_TYPE.NOTICE)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case SCREEN_TYPE.IMPORT_SEED_PHRASE:
|
|
||||||
return (
|
|
||||||
<ImportSeedPhraseScreen
|
|
||||||
back={() => {
|
|
||||||
leaveImportSeedScreenState()
|
|
||||||
this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD)
|
|
||||||
}}
|
|
||||||
next={() => {
|
|
||||||
const newScreenType = forgottenPassword ? null : SCREEN_TYPE.NOTICE
|
|
||||||
this.setScreenType(newScreenType)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case SCREEN_TYPE.UNIQUE_IMAGE:
|
|
||||||
return (
|
|
||||||
<UniqueImageScreen
|
|
||||||
next={() => this.setScreenType(SCREEN_TYPE.NOTICE)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case SCREEN_TYPE.NOTICE:
|
|
||||||
return (
|
|
||||||
<NoticeScreen
|
|
||||||
next={() => this.setScreenType(SCREEN_TYPE.BACK_UP_PHRASE)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case SCREEN_TYPE.BACK_UP_PHRASE:
|
|
||||||
return (
|
|
||||||
<BackupPhraseScreen
|
|
||||||
next={() => openBuyEtherModal()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
return <noscript />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className="first-time-flow">
|
<div className="first-time-flow">
|
||||||
{this.renderScreen()}
|
<Switch>
|
||||||
|
<Route exact path={INITIALIZE_IMPORT_ACCOUNT_ROUTE} component={ImportAccountScreen} />
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE}
|
||||||
|
component={ImportSeedPhraseScreen}
|
||||||
|
/>
|
||||||
|
<Route exact path={INITIALIZE_UNIQUE_IMAGE_ROUTE} component={UniqueImageScreen} />
|
||||||
|
<Route exact path={INITIALIZE_NOTICE_ROUTE} component={NoticeScreen} />
|
||||||
|
<Route exact path={INITIALIZE_BACKUP_PHRASE_ROUTE} component={BackupPhraseScreen} />
|
||||||
|
<Route exact path={INITIALIZE_CONFIRM_SEED_ROUTE} component={ConfirmSeed} />
|
||||||
|
<Route exact path={INITIALIZE_CREATE_PASSWORD_ROUTE} component={CreatePasswordScreen} />
|
||||||
|
<Route exact path={INITIALIZE_ROUTE} component={WelcomeScreen} />
|
||||||
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
const mapStateToProps = ({ metamask }) => {
|
||||||
({
|
const {
|
||||||
metamask: {
|
isInitialized,
|
||||||
isInitialized,
|
seedWords,
|
||||||
seedWords,
|
noActiveNotices,
|
||||||
noActiveNotices,
|
selectedAddress,
|
||||||
selectedAddress,
|
forgottenPassword,
|
||||||
forgottenPassword,
|
isMascara,
|
||||||
}
|
isUnlocked,
|
||||||
}) => ({
|
welcomeScreenSeen,
|
||||||
|
} = metamask
|
||||||
|
|
||||||
|
return {
|
||||||
|
isMascara,
|
||||||
isInitialized,
|
isInitialized,
|
||||||
seedWords,
|
seedWords,
|
||||||
noActiveNotices,
|
noActiveNotices,
|
||||||
address: selectedAddress,
|
address: selectedAddress,
|
||||||
forgottenPassword,
|
forgottenPassword,
|
||||||
}),
|
isUnlocked,
|
||||||
dispatch => ({
|
welcomeScreenSeen,
|
||||||
leaveImportSeedScreenState: () => dispatch(unMarkPasswordForgotten()),
|
}
|
||||||
openBuyEtherModal: () => dispatch(showModal({ name: 'DEPOSIT_ETHER'})),
|
}
|
||||||
})
|
|
||||||
|
export default compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps)
|
||||||
)(FirstTimeFlow)
|
)(FirstTimeFlow)
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import Markdown from 'react-markdown'
|
import Markdown from 'react-markdown'
|
||||||
import {connect} from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
import { withRouter } from 'react-router-dom'
|
||||||
|
import { compose } from 'recompose'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
import {markNoticeRead} from '../../../../ui/app/actions'
|
import { markNoticeRead } from '../../../../ui/app/actions'
|
||||||
import Identicon from '../../../../ui/app/components/identicon'
|
import Identicon from '../../../../ui/app/components/identicon'
|
||||||
import Breadcrumbs from './breadcrumbs'
|
import Breadcrumbs from './breadcrumbs'
|
||||||
|
import { INITIALIZE_BACKUP_PHRASE_ROUTE } from '../../../../ui/app/routes'
|
||||||
import LoadingScreen from './loading-screen'
|
import LoadingScreen from './loading-screen'
|
||||||
|
|
||||||
class NoticeScreen extends Component {
|
class NoticeScreen extends Component {
|
||||||
@ -16,8 +19,15 @@ class NoticeScreen extends Component {
|
|||||||
date: PropTypes.string,
|
date: PropTypes.string,
|
||||||
body: PropTypes.string,
|
body: PropTypes.string,
|
||||||
}),
|
}),
|
||||||
next: PropTypes.func.isRequired,
|
location: PropTypes.shape({
|
||||||
|
state: PropTypes.shape({
|
||||||
|
next: PropTypes.func.isRequired,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
markNoticeRead: PropTypes.func,
|
markNoticeRead: PropTypes.func,
|
||||||
|
history: PropTypes.object,
|
||||||
|
isLoading: PropTypes.bool,
|
||||||
|
noActiveNotices: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@ -29,17 +39,24 @@ class NoticeScreen extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
if (this.props.noActiveNotices) {
|
||||||
|
this.props.history.push(INITIALIZE_BACKUP_PHRASE_ROUTE)
|
||||||
|
}
|
||||||
|
|
||||||
this.onScroll()
|
this.onScroll()
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptTerms = () => {
|
acceptTerms = () => {
|
||||||
const { markNoticeRead, lastUnreadNotice, next } = this.props
|
const { markNoticeRead, lastUnreadNotice, history } = this.props
|
||||||
const defer = markNoticeRead(lastUnreadNotice)
|
markNoticeRead(lastUnreadNotice)
|
||||||
.then(() => this.setState({ atBottom: false }))
|
.then(hasActiveNotices => {
|
||||||
|
if (!hasActiveNotices) {
|
||||||
if ((/terms/gi).test(lastUnreadNotice.title)) {
|
history.push(INITIALIZE_BACKUP_PHRASE_ROUTE)
|
||||||
defer.then(next)
|
} else {
|
||||||
}
|
this.setState({ atBottom: false })
|
||||||
|
this.onScroll()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onScroll = debounce(() => {
|
onScroll = debounce(() => {
|
||||||
@ -64,27 +81,29 @@ class NoticeScreen extends Component {
|
|||||||
isLoading
|
isLoading
|
||||||
? <LoadingScreen />
|
? <LoadingScreen />
|
||||||
: (
|
: (
|
||||||
<div className="first-view-main-wrapper">
|
<div className="first-time-flow">
|
||||||
<div className="first-view-main">
|
<div className="first-view-main-wrapper">
|
||||||
<div
|
<div className="first-view-main">
|
||||||
className="tou"
|
<div
|
||||||
onScroll={this.onScroll}
|
className="tou"
|
||||||
>
|
onScroll={this.onScroll}
|
||||||
<Identicon address={address} diameter={70} />
|
|
||||||
<div className="tou__title">{title}</div>
|
|
||||||
<Markdown
|
|
||||||
className="tou__body markdown"
|
|
||||||
source={body}
|
|
||||||
skipHtml
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
className="first-time-flow__button"
|
|
||||||
onClick={atBottom && this.acceptTerms}
|
|
||||||
disabled={!atBottom}
|
|
||||||
>
|
>
|
||||||
Accept
|
<Identicon address={address} diameter={70} />
|
||||||
</button>
|
<div className="tou__title">{title}</div>
|
||||||
<Breadcrumbs total={3} currentIndex={2} />
|
<Markdown
|
||||||
|
className="tou__body markdown"
|
||||||
|
source={body}
|
||||||
|
skipHtml
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className="first-time-flow__button"
|
||||||
|
onClick={atBottom && this.acceptTerms}
|
||||||
|
disabled={!atBottom}
|
||||||
|
>
|
||||||
|
Accept
|
||||||
|
</button>
|
||||||
|
<Breadcrumbs total={3} currentIndex={2} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -93,12 +112,24 @@ class NoticeScreen extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
const mapStateToProps = ({ metamask, appState }) => {
|
||||||
({ metamask: { selectedAddress, lastUnreadNotice }, appState: { isLoading } }) => ({
|
const { selectedAddress, lastUnreadNotice, noActiveNotices } = metamask
|
||||||
lastUnreadNotice,
|
const { isLoading } = appState
|
||||||
|
|
||||||
|
return {
|
||||||
address: selectedAddress,
|
address: selectedAddress,
|
||||||
}),
|
lastUnreadNotice,
|
||||||
dispatch => ({
|
noActiveNotices,
|
||||||
markNoticeRead: notice => dispatch(markNoticeRead(notice)),
|
isLoading,
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withRouter,
|
||||||
|
connect(
|
||||||
|
mapStateToProps,
|
||||||
|
dispatch => ({
|
||||||
|
markNoticeRead: notice => dispatch(markNoticeRead(notice)),
|
||||||
|
})
|
||||||
|
)
|
||||||
)(NoticeScreen)
|
)(NoticeScreen)
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import {connect} from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import shuffle from 'lodash.shuffle'
|
import { withRouter } from 'react-router-dom'
|
||||||
import {compose, onlyUpdateForPropTypes} from 'recompose'
|
import { compose } from 'recompose'
|
||||||
import Identicon from '../../../../ui/app/components/identicon'
|
import Identicon from '../../../../ui/app/components/identicon'
|
||||||
import {confirmSeedWords} from '../../../../ui/app/actions'
|
|
||||||
import Breadcrumbs from './breadcrumbs'
|
import Breadcrumbs from './breadcrumbs'
|
||||||
import LoadingScreen from './loading-screen'
|
import LoadingScreen from './loading-screen'
|
||||||
|
import { DEFAULT_ROUTE, INITIALIZE_CONFIRM_SEED_ROUTE } from '../../../../ui/app/routes'
|
||||||
|
|
||||||
const LockIcon = props => (
|
const LockIcon = props => (
|
||||||
<svg
|
<svg
|
||||||
@ -36,34 +36,32 @@ const LockIcon = props => (
|
|||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
)
|
||||||
|
|
||||||
class BackupPhraseScreen extends Component {
|
class BackupPhraseScreen extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
isLoading: PropTypes.bool.isRequired,
|
isLoading: PropTypes.bool.isRequired,
|
||||||
address: PropTypes.string.isRequired,
|
address: PropTypes.string.isRequired,
|
||||||
seedWords: PropTypes.string.isRequired,
|
seedWords: PropTypes.string,
|
||||||
next: PropTypes.func.isRequired,
|
history: PropTypes.object,
|
||||||
confirmSeedWords: PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
seedWords: ''
|
seedWords: '',
|
||||||
};
|
}
|
||||||
|
|
||||||
static PAGE = {
|
constructor (props) {
|
||||||
SECRET: 'secret',
|
|
||||||
CONFIRM: 'confirm'
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
const {seedWords} = props
|
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
isShowingSecret: false,
|
isShowingSecret: false,
|
||||||
page: BackupPhraseScreen.PAGE.SECRET,
|
}
|
||||||
selectedSeeds: [],
|
}
|
||||||
shuffledSeeds: seedWords && shuffle(seedWords.split(' ')),
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { seedWords, history } = this.props
|
||||||
|
|
||||||
|
if (!seedWords) {
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +71,7 @@ class BackupPhraseScreen extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className="backup-phrase__secret">
|
<div className="backup-phrase__secret">
|
||||||
<div className={classnames('backup-phrase__secret-words', {
|
<div className={classnames('backup-phrase__secret-words', {
|
||||||
'backup-phrase__secret-words--hidden': !isShowingSecret
|
'backup-phrase__secret-words--hidden': !isShowingSecret,
|
||||||
})}>
|
})}>
|
||||||
{this.props.seedWords}
|
{this.props.seedWords}
|
||||||
</div>
|
</div>
|
||||||
@ -96,6 +94,7 @@ class BackupPhraseScreen extends Component {
|
|||||||
|
|
||||||
renderSecretScreen () {
|
renderSecretScreen () {
|
||||||
const { isShowingSecret } = this.state
|
const { isShowingSecret } = this.state
|
||||||
|
const { history } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="backup-phrase__content-wrapper">
|
<div className="backup-phrase__content-wrapper">
|
||||||
@ -124,10 +123,7 @@ class BackupPhraseScreen extends Component {
|
|||||||
<div className="backup-phrase__next-button">
|
<div className="backup-phrase__next-button">
|
||||||
<button
|
<button
|
||||||
className="first-time-flow__button"
|
className="first-time-flow__button"
|
||||||
onClick={() => isShowingSecret && this.setState({
|
onClick={() => isShowingSecret && history.push(INITIALIZE_CONFIRM_SEED_ROUTE)}
|
||||||
isShowingSecret: false,
|
|
||||||
page: BackupPhraseScreen.PAGE.CONFIRM,
|
|
||||||
})}
|
|
||||||
disabled={!isShowingSecret}
|
disabled={!isShowingSecret}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
@ -138,99 +134,6 @@ class BackupPhraseScreen extends Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderConfirmationScreen() {
|
|
||||||
const { seedWords, confirmSeedWords, next } = this.props;
|
|
||||||
const { selectedSeeds, shuffledSeeds } = this.state;
|
|
||||||
const isValid = seedWords === selectedSeeds.map(([_, seed]) => seed).join(' ')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="backup-phrase__content-wrapper">
|
|
||||||
<div>
|
|
||||||
<div className="backup-phrase__title">Confirm your Secret Backup Phrase</div>
|
|
||||||
<div className="backup-phrase__body-text">
|
|
||||||
Please select each phrase in order to make sure it is correct.
|
|
||||||
</div>
|
|
||||||
<div className="backup-phrase__confirm-secret">
|
|
||||||
{selectedSeeds.map(([_, word], i) => (
|
|
||||||
<button
|
|
||||||
key={i}
|
|
||||||
className="backup-phrase__confirm-seed-option"
|
|
||||||
>
|
|
||||||
{word}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className="backup-phrase__confirm-seed-options">
|
|
||||||
{shuffledSeeds.map((word, i) => {
|
|
||||||
const isSelected = selectedSeeds
|
|
||||||
.filter(([index, seed]) => seed === word && index === i)
|
|
||||||
.length
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={i}
|
|
||||||
className={classnames('backup-phrase__confirm-seed-option', {
|
|
||||||
'backup-phrase__confirm-seed-option--selected': isSelected
|
|
||||||
})}
|
|
||||||
onClick={() => {
|
|
||||||
if (!isSelected) {
|
|
||||||
this.setState({
|
|
||||||
selectedSeeds: [...selectedSeeds, [i, word]]
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
selectedSeeds: selectedSeeds
|
|
||||||
.filter(([index, seed]) => !(seed === word && index === i))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{word}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className="first-time-flow__button"
|
|
||||||
onClick={() => isValid && confirmSeedWords().then(next)}
|
|
||||||
disabled={!isValid}
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderBack () {
|
|
||||||
return this.state.page === BackupPhraseScreen.PAGE.CONFIRM
|
|
||||||
? (
|
|
||||||
<a
|
|
||||||
className="backup-phrase__back-button"
|
|
||||||
onClick={e => {
|
|
||||||
e.preventDefault()
|
|
||||||
this.setState({
|
|
||||||
page: BackupPhraseScreen.PAGE.SECRET
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
href="#"
|
|
||||||
>
|
|
||||||
{`< Back`}
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
|
|
||||||
renderContent () {
|
|
||||||
switch (this.state.page) {
|
|
||||||
case BackupPhraseScreen.PAGE.CONFIRM:
|
|
||||||
return this.renderConfirmationScreen()
|
|
||||||
case BackupPhraseScreen.PAGE.SECRET:
|
|
||||||
default:
|
|
||||||
return this.renderSecretScreen()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return this.props.isLoading
|
return this.props.isLoading
|
||||||
? <LoadingScreen loadingMessage="Creating your new account" />
|
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||||
@ -238,9 +141,8 @@ class BackupPhraseScreen extends Component {
|
|||||||
<div className="first-view-main-wrapper">
|
<div className="first-view-main-wrapper">
|
||||||
<div className="first-view-main">
|
<div className="first-view-main">
|
||||||
<div className="backup-phrase">
|
<div className="backup-phrase">
|
||||||
{this.renderBack()}
|
|
||||||
<Identicon address={this.props.address} diameter={70} />
|
<Identicon address={this.props.address} diameter={70} />
|
||||||
{this.renderContent()}
|
{this.renderSecretScreen()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -249,15 +151,12 @@ class BackupPhraseScreen extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
onlyUpdateForPropTypes,
|
withRouter,
|
||||||
connect(
|
connect(
|
||||||
({ metamask: { selectedAddress, seedWords }, appState: { isLoading } }) => ({
|
({ metamask: { selectedAddress, seedWords }, appState: { isLoading } }) => ({
|
||||||
seedWords,
|
seedWords,
|
||||||
isLoading,
|
isLoading,
|
||||||
address: selectedAddress,
|
address: selectedAddress,
|
||||||
}),
|
|
||||||
dispatch => ({
|
|
||||||
confirmSeedWords: () => dispatch(confirmSeedWords()),
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)(BackupPhraseScreen)
|
)(BackupPhraseScreen)
|
@ -1,13 +1,16 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { withRouter } from 'react-router-dom'
|
||||||
|
import { compose } from 'recompose'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import Identicon from '../../../../ui/app/components/identicon'
|
import Identicon from '../../../../ui/app/components/identicon'
|
||||||
import Breadcrumbs from './breadcrumbs'
|
import Breadcrumbs from './breadcrumbs'
|
||||||
|
import { INITIALIZE_NOTICE_ROUTE } from '../../../../ui/app/routes'
|
||||||
|
|
||||||
class UniqueImageScreen extends Component {
|
class UniqueImageScreen extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
address: PropTypes.string,
|
address: PropTypes.string,
|
||||||
next: PropTypes.func.isRequired,
|
history: PropTypes.object,
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@ -25,7 +28,7 @@ class UniqueImageScreen extends Component {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="first-time-flow__button"
|
className="first-time-flow__button"
|
||||||
onClick={this.props.next}
|
onClick={() => this.props.history.push(INITIALIZE_NOTICE_ROUTE)}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</button>
|
</button>
|
||||||
@ -37,8 +40,11 @@ class UniqueImageScreen extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default compose(
|
||||||
({ metamask: { selectedAddress } }) => ({
|
withRouter,
|
||||||
address: selectedAddress,
|
connect(
|
||||||
})
|
({ metamask: { selectedAddress } }) => ({
|
||||||
|
address: selectedAddress,
|
||||||
|
})
|
||||||
|
)
|
||||||
)(UniqueImageScreen)
|
)(UniqueImageScreen)
|
||||||
|
98
package-lock.json
generated
98
package-lock.json
generated
@ -5112,7 +5112,7 @@
|
|||||||
"lodash": "4.17.4",
|
"lodash": "4.17.4",
|
||||||
"object.assign": "4.1.0",
|
"object.assign": "4.1.0",
|
||||||
"object.values": "1.0.4",
|
"object.values": "1.0.4",
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"enzyme-adapter-utils": {
|
"enzyme-adapter-utils": {
|
||||||
@ -5123,7 +5123,7 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"lodash": "4.17.4",
|
"lodash": "4.17.4",
|
||||||
"object.assign": "4.1.0",
|
"object.assign": "4.1.0",
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"errno": {
|
"errno": {
|
||||||
@ -5454,7 +5454,7 @@
|
|||||||
"doctrine": "2.0.2",
|
"doctrine": "2.0.2",
|
||||||
"has": "1.0.1",
|
"has": "1.0.1",
|
||||||
"jsx-ast-utils": "2.0.1",
|
"jsx-ast-utils": "2.0.1",
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eslint-scope": {
|
"eslint-scope": {
|
||||||
@ -10394,6 +10394,18 @@
|
|||||||
"request": "2.83.0"
|
"request": "2.83.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"history": {
|
||||||
|
"version": "4.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz",
|
||||||
|
"integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==",
|
||||||
|
"requires": {
|
||||||
|
"invariant": "2.2.2",
|
||||||
|
"loose-envify": "1.3.1",
|
||||||
|
"resolve-pathname": "2.2.0",
|
||||||
|
"value-equal": "0.4.0",
|
||||||
|
"warning": "3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hmac-drbg": {
|
"hmac-drbg": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||||
@ -18886,9 +18898,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prop-types": {
|
"prop-types": {
|
||||||
"version": "15.6.0",
|
"version": "15.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz",
|
||||||
"integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=",
|
"integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"fbjs": "0.8.16",
|
"fbjs": "0.8.16",
|
||||||
"loose-envify": "1.3.1",
|
"loose-envify": "1.3.1",
|
||||||
@ -19316,7 +19328,7 @@
|
|||||||
"fbjs": "0.8.16",
|
"fbjs": "0.8.16",
|
||||||
"loose-envify": "1.3.1",
|
"loose-envify": "1.3.1",
|
||||||
"object-assign": "4.1.1",
|
"object-assign": "4.1.1",
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-addons-css-transition-group": {
|
"react-addons-css-transition-group": {
|
||||||
@ -19335,7 +19347,7 @@
|
|||||||
"chain-function": "1.0.0",
|
"chain-function": "1.0.0",
|
||||||
"dom-helpers": "3.3.1",
|
"dom-helpers": "3.3.1",
|
||||||
"loose-envify": "1.3.1",
|
"loose-envify": "1.3.1",
|
||||||
"prop-types": "15.6.0",
|
"prop-types": "15.6.1",
|
||||||
"warning": "3.0.0"
|
"warning": "3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19355,7 +19367,7 @@
|
|||||||
"fbjs": "0.8.16",
|
"fbjs": "0.8.16",
|
||||||
"loose-envify": "1.3.1",
|
"loose-envify": "1.3.1",
|
||||||
"object-assign": "4.1.1",
|
"object-assign": "4.1.1",
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-hyperscript": {
|
"react-hyperscript": {
|
||||||
@ -19368,7 +19380,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.1.2.tgz",
|
||||||
"integrity": "sha512-uAfIE4XEfBNXqjqQvd31Eoo20UkVk0xHJpfgP8HRT8gLczaN4LEmB1e2d8CJ5ziEt4clWnsk/1+QhTN27iO/EA==",
|
"integrity": "sha512-uAfIE4XEfBNXqjqQvd31Eoo20UkVk0xHJpfgP8HRT8gLczaN4LEmB1e2d8CJ5ziEt4clWnsk/1+QhTN27iO/EA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-markdown": {
|
"react-markdown": {
|
||||||
@ -19376,7 +19388,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-3.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-3.1.4.tgz",
|
||||||
"integrity": "sha512-i8WueytRXbYzyJ2GemIOTMRx/NigPo8r4m3R/KvWD7r+PxPyc9ke66cI3DR7MBRSS+nVG82VWEgRDE1VaZUCqA==",
|
"integrity": "sha512-i8WueytRXbYzyJ2GemIOTMRx/NigPo8r4m3R/KvWD7r+PxPyc9ke66cI3DR7MBRSS+nVG82VWEgRDE1VaZUCqA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"prop-types": "15.6.0",
|
"prop-types": "15.6.1",
|
||||||
"remark-parse": "4.0.0",
|
"remark-parse": "4.0.0",
|
||||||
"unified": "6.1.6",
|
"unified": "6.1.6",
|
||||||
"unist-util-visit": "1.3.0",
|
"unist-util-visit": "1.3.0",
|
||||||
@ -19389,7 +19401,7 @@
|
|||||||
"integrity": "sha512-9q3YAvHoUiWlP3cK0v+w1N5Z23HXMj4IF4YuvjvWegWqNPfLXsOBE/V7UvQGpXxHFKRQQcNcVQE31g9SB/6qgQ==",
|
"integrity": "sha512-9q3YAvHoUiWlP3cK0v+w1N5Z23HXMj4IF4YuvjvWegWqNPfLXsOBE/V7UvQGpXxHFKRQQcNcVQE31g9SB/6qgQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"performance-now": "0.2.0",
|
"performance-now": "0.2.0",
|
||||||
"prop-types": "15.6.0",
|
"prop-types": "15.6.1",
|
||||||
"raf": "3.4.0"
|
"raf": "3.4.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -19410,7 +19422,49 @@
|
|||||||
"lodash": "4.17.4",
|
"lodash": "4.17.4",
|
||||||
"lodash-es": "4.17.4",
|
"lodash-es": "4.17.4",
|
||||||
"loose-envify": "1.3.1",
|
"loose-envify": "1.3.1",
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-router": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-DY6pjwRhdARE4TDw7XjxjZsbx9lKmIcyZoZ+SDO7SBJ1KUeWNxT22Kara2AC7u6/c2SYEHlEDLnzBCcNhLE8Vg==",
|
||||||
|
"requires": {
|
||||||
|
"history": "4.7.2",
|
||||||
|
"hoist-non-react-statics": "2.3.1",
|
||||||
|
"invariant": "2.2.2",
|
||||||
|
"loose-envify": "1.3.1",
|
||||||
|
"path-to-regexp": "1.7.0",
|
||||||
|
"prop-types": "15.6.1",
|
||||||
|
"warning": "3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
|
},
|
||||||
|
"path-to-regexp": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
|
||||||
|
"integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
|
||||||
|
"requires": {
|
||||||
|
"isarray": "0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-router-dom": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-cHMFC1ZoLDfEaMFoKTjN7fry/oczMgRt5BKfMAkTu5zEuJvUiPp1J8d0eXSVTnBh6pxlbdqDhozunOOLtmKfPA==",
|
||||||
|
"requires": {
|
||||||
|
"history": "4.7.2",
|
||||||
|
"invariant": "2.2.2",
|
||||||
|
"loose-envify": "1.3.1",
|
||||||
|
"prop-types": "15.6.1",
|
||||||
|
"react-router": "4.2.0",
|
||||||
|
"warning": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-select": {
|
"react-select": {
|
||||||
@ -19419,7 +19473,7 @@
|
|||||||
"integrity": "sha512-c4CdxweEHN9ra85HGWjSjIMBlJ5c0fsIXOymLFZS5UbZEQCiJGHnZTVLTt6/wDh8RKQnxl85gHUwzhG5XZLcyw==",
|
"integrity": "sha512-c4CdxweEHN9ra85HGWjSjIMBlJ5c0fsIXOymLFZS5UbZEQCiJGHnZTVLTt6/wDh8RKQnxl85gHUwzhG5XZLcyw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"classnames": "2.2.5",
|
"classnames": "2.2.5",
|
||||||
"prop-types": "15.6.0",
|
"prop-types": "15.6.1",
|
||||||
"react-input-autosize": "2.1.2"
|
"react-input-autosize": "2.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -19428,7 +19482,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-simple-file-input/-/react-simple-file-input-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-simple-file-input/-/react-simple-file-input-2.0.1.tgz",
|
||||||
"integrity": "sha1-Fa1P/Hj+sbiCZJrWsBwDPvJ1ceY=",
|
"integrity": "sha1-Fa1P/Hj+sbiCZJrWsBwDPvJ1ceY=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-test-renderer": {
|
"react-test-renderer": {
|
||||||
@ -19472,7 +19526,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-toggle-button/-/react-toggle-button-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-toggle-button/-/react-toggle-button-2.2.0.tgz",
|
||||||
"integrity": "sha1-obkhQ6oN9BRkL8sUHwh59UW8Wok=",
|
"integrity": "sha1-obkhQ6oN9BRkL8sUHwh59UW8Wok=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"prop-types": "15.6.0",
|
"prop-types": "15.6.1",
|
||||||
"react-motion": "0.5.2"
|
"react-motion": "0.5.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -19499,7 +19553,7 @@
|
|||||||
"classnames": "2.2.5",
|
"classnames": "2.2.5",
|
||||||
"dom-helpers": "3.3.1",
|
"dom-helpers": "3.3.1",
|
||||||
"loose-envify": "1.3.1",
|
"loose-envify": "1.3.1",
|
||||||
"prop-types": "15.6.0",
|
"prop-types": "15.6.1",
|
||||||
"warning": "3.0.0"
|
"warning": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -20058,6 +20112,11 @@
|
|||||||
"value-or-function": "3.0.0"
|
"value-or-function": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"resolve-pathname": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
|
||||||
|
},
|
||||||
"resolve-url": {
|
"resolve-url": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||||
@ -23736,6 +23795,11 @@
|
|||||||
"spdx-expression-parse": "1.0.4"
|
"spdx-expression-parse": "1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"value-equal": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw=="
|
||||||
|
},
|
||||||
"value-or-function": {
|
"value-or-function": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
|
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
|
||||||
"ethereumjs-wallet": "^0.6.0",
|
"ethereumjs-wallet": "^0.6.0",
|
||||||
"etherscan-link": "^1.0.2",
|
"etherscan-link": "^1.0.2",
|
||||||
"ethjs": "^0.2.8",
|
"ethjs": "^0.3.4",
|
||||||
"ethjs-contract": "^0.1.9",
|
"ethjs-contract": "^0.1.9",
|
||||||
"ethjs-ens": "^2.0.0",
|
"ethjs-ens": "^2.0.0",
|
||||||
"ethjs-query": "^0.3.4",
|
"ethjs-query": "^0.3.4",
|
||||||
@ -114,7 +114,7 @@
|
|||||||
"gulp-autoprefixer": "^5.0.0",
|
"gulp-autoprefixer": "^5.0.0",
|
||||||
"gulp-debug": "^3.2.0",
|
"gulp-debug": "^3.2.0",
|
||||||
"gulp-eslint": "^4.0.0",
|
"gulp-eslint": "^4.0.0",
|
||||||
"gulp-sass": "^3.1.0",
|
"gulp-sass": "^4.0.0",
|
||||||
"hat": "0.0.3",
|
"hat": "0.0.3",
|
||||||
"human-standard-token-abi": "^1.0.2",
|
"human-standard-token-abi": "^1.0.2",
|
||||||
"idb-global": "^2.1.0",
|
"idb-global": "^2.1.0",
|
||||||
@ -131,7 +131,7 @@
|
|||||||
"lodash.uniqby": "^4.7.0",
|
"lodash.uniqby": "^4.7.0",
|
||||||
"loglevel": "^1.4.1",
|
"loglevel": "^1.4.1",
|
||||||
"metamascara": "^2.0.0",
|
"metamascara": "^2.0.0",
|
||||||
"metamask-logo": "^2.1.2",
|
"metamask-logo": "^2.1.4",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"multiplex": "^6.7.0",
|
"multiplex": "^6.7.0",
|
||||||
"number-to-bn": "^1.7.0",
|
"number-to-bn": "^1.7.0",
|
||||||
@ -145,6 +145,7 @@
|
|||||||
"post-message-stream": "^3.0.0",
|
"post-message-stream": "^3.0.0",
|
||||||
"promise-filter": "^1.1.0",
|
"promise-filter": "^1.1.0",
|
||||||
"promise-to-callback": "^1.0.0",
|
"promise-to-callback": "^1.0.0",
|
||||||
|
"prop-types": "^15.6.1",
|
||||||
"pump": "^3.0.0",
|
"pump": "^3.0.0",
|
||||||
"pumpify": "^1.3.4",
|
"pumpify": "^1.3.4",
|
||||||
"qrcode-npm": "0.0.3",
|
"qrcode-npm": "0.0.3",
|
||||||
@ -156,6 +157,7 @@
|
|||||||
"react-hyperscript": "^3.0.0",
|
"react-hyperscript": "^3.0.0",
|
||||||
"react-markdown": "^3.0.0",
|
"react-markdown": "^3.0.0",
|
||||||
"react-redux": "^5.0.5",
|
"react-redux": "^5.0.5",
|
||||||
|
"react-router-dom": "^4.2.2",
|
||||||
"react-select": "^1.0.0",
|
"react-select": "^1.0.0",
|
||||||
"react-simple-file-input": "^2.0.0",
|
"react-simple-file-input": "^2.0.0",
|
||||||
"react-tippy": "^1.2.2",
|
"react-tippy": "^1.2.2",
|
||||||
|
@ -21,11 +21,22 @@ async function runConfirmSigRequestsTest(assert, done) {
|
|||||||
selectState.val('confirm sig requests')
|
selectState.val('confirm sig requests')
|
||||||
reactTriggerChange(selectState[0])
|
reactTriggerChange(selectState[0])
|
||||||
|
|
||||||
|
// await timeout(1000000)
|
||||||
|
|
||||||
|
const pendingRequestItem = $.find('.tx-list-item.tx-list-pending-item-container.tx-list-clickable')
|
||||||
|
|
||||||
|
if (pendingRequestItem[0]) {
|
||||||
|
pendingRequestItem[0].click()
|
||||||
|
}
|
||||||
|
|
||||||
let confirmSigHeadline = await queryAsync($, '.request-signature__headline')
|
let confirmSigHeadline = await queryAsync($, '.request-signature__headline')
|
||||||
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
||||||
|
|
||||||
|
let confirmSigMessage = await queryAsync($, '.request-signature__notice')
|
||||||
|
assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/))
|
||||||
|
|
||||||
let confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
|
let confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
|
||||||
assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/))
|
assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0')
|
||||||
|
|
||||||
let confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg')
|
let confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg')
|
||||||
confirmSigSignButton[0].click()
|
confirmSigSignButton[0].click()
|
||||||
@ -33,11 +44,8 @@ async function runConfirmSigRequestsTest(assert, done) {
|
|||||||
confirmSigHeadline = await queryAsync($, '.request-signature__headline')
|
confirmSigHeadline = await queryAsync($, '.request-signature__headline')
|
||||||
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
||||||
|
|
||||||
let confirmSigMessage = await queryAsync($, '.request-signature__notice')
|
|
||||||
assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/))
|
|
||||||
|
|
||||||
confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
|
confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
|
||||||
assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0')
|
assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/))
|
||||||
|
|
||||||
confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg')
|
confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg')
|
||||||
confirmSigSignButton[0].click()
|
confirmSigSignButton[0].click()
|
||||||
|
@ -13,6 +13,9 @@ async function runFirstTimeUsageTest (assert, done) {
|
|||||||
|
|
||||||
await skipNotices(app)
|
await skipNotices(app)
|
||||||
|
|
||||||
|
const welcomeButton = (await findAsync(app, '.welcome-screen__button'))[0]
|
||||||
|
welcomeButton.click()
|
||||||
|
|
||||||
// Scroll through terms
|
// Scroll through terms
|
||||||
const title = (await findAsync(app, '.create-password__title')).text()
|
const title = (await findAsync(app, '.create-password__title')).text()
|
||||||
assert.equal(title, 'Create Password', 'create password screen')
|
assert.equal(title, 'Create Password', 'create password screen')
|
||||||
|
@ -53,7 +53,7 @@ async function runSendFlowTest(assert, done) {
|
|||||||
assert.equal(sendFromDropdownList.children().length, 4, 'send from dropdown shows all accounts')
|
assert.equal(sendFromDropdownList.children().length, 4, 'send from dropdown shows all accounts')
|
||||||
sendFromDropdownList.children()[1].click()
|
sendFromDropdownList.children()[1].click()
|
||||||
|
|
||||||
sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
|
sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
|
||||||
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name')
|
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name')
|
||||||
|
|
||||||
let sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input')
|
let sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input')
|
||||||
@ -164,17 +164,27 @@ async function runSendFlowTest(assert, done) {
|
|||||||
|
|
||||||
const sendButtonInEdit = await queryAsync($, '.btn-primary--lg.page-container__footer-button')
|
const sendButtonInEdit = await queryAsync($, '.btn-primary--lg.page-container__footer-button')
|
||||||
assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered')
|
assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered')
|
||||||
sendButtonInEdit[0].click()
|
|
||||||
|
|
||||||
// TODO: Need a way to mock background so that we can test correct transition from editing to confirm
|
selectState.val('send new ui')
|
||||||
selectState.val('confirm new ui')
|
|
||||||
reactTriggerChange(selectState[0])
|
reactTriggerChange(selectState[0])
|
||||||
const confirmScreenConfirmButton = await queryAsync($, '.btn-confirm.page-container__footer-button')
|
|
||||||
console.log(`+++++++++++++++++++++++++++++++= confirmScreenConfirmButton[0]`, confirmScreenConfirmButton[0]);
|
|
||||||
confirmScreenConfirmButton[0].click()
|
|
||||||
|
|
||||||
const txView = await queryAsync($, '.tx-view')
|
const cancelButtonInEdit = await queryAsync($, '.btn-secondary--lg.page-container__footer-button')
|
||||||
console.log(`++++++++++++++++++++++++++++++++ txView[0]`, txView[0]);
|
cancelButtonInEdit[0].click()
|
||||||
|
// sendButtonInEdit[0].click()
|
||||||
|
|
||||||
assert.ok(txView[0], 'Should return to the account details screen after confirming')
|
// // TODO: Need a way to mock background so that we can test correct transition from editing to confirm
|
||||||
|
// selectState.val('confirm new ui')
|
||||||
|
// reactTriggerChange(selectState[0])
|
||||||
|
|
||||||
|
|
||||||
|
// const confirmScreenConfirmButton = await queryAsync($, '.btn-confirm.page-container__footer-button')
|
||||||
|
// console.log(`+++++++++++++++++++++++++++++++= confirmScreenConfirmButton[0]`, confirmScreenConfirmButton[0]);
|
||||||
|
// confirmScreenConfirmButton[0].click()
|
||||||
|
|
||||||
|
// await timeout(10000000)
|
||||||
|
|
||||||
|
// const txView = await queryAsync($, '.tx-view')
|
||||||
|
// console.log(`++++++++++++++++++++++++++++++++ txView[0]`, txView[0]);
|
||||||
|
|
||||||
|
// assert.ok(txView[0], 'Should return to the account details screen after confirming')
|
||||||
}
|
}
|
||||||
|
@ -50,11 +50,19 @@ describe('Migrator', () => {
|
|||||||
const migrator = new Migrator({ migrations: liveMigrations })
|
const migrator = new Migrator({ migrations: liveMigrations })
|
||||||
migrator.migrateData(firstTimeState)
|
migrator.migrateData(firstTimeState)
|
||||||
.then((migratedData) => {
|
.then((migratedData) => {
|
||||||
console.log(migratedData)
|
|
||||||
const last = liveMigrations.length - 1
|
const last = liveMigrations.length - 1
|
||||||
assert.equal(migratedData.meta.version, liveMigrations[last].version)
|
assert.equal(migratedData.meta.version, liveMigrations[last].version)
|
||||||
done()
|
done()
|
||||||
}).catch(done)
|
}).catch(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should emit an error', function (done) {
|
||||||
|
this.timeout(15000)
|
||||||
|
const migrator = new Migrator({ migrations: [{ version: 1, migrate: async () => { throw new Error('test') } } ] })
|
||||||
|
migrator.on('error', () => done())
|
||||||
|
migrator.migrateData({ meta: {version: 0} })
|
||||||
|
.then((migratedData) => {
|
||||||
|
}).catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -349,7 +349,7 @@ function transitionBackward () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function confirmSeedWords () {
|
function confirmSeedWords () {
|
||||||
return (dispatch) => {
|
return dispatch => {
|
||||||
dispatch(actions.showLoadingIndication())
|
dispatch(actions.showLoadingIndication())
|
||||||
log.debug(`background.clearSeedWordCache`)
|
log.debug(`background.clearSeedWordCache`)
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -357,7 +357,7 @@ function confirmSeedWords () {
|
|||||||
dispatch(actions.hideLoadingIndication())
|
dispatch(actions.hideLoadingIndication())
|
||||||
if (err) {
|
if (err) {
|
||||||
dispatch(actions.displayWarning(err.message))
|
dispatch(actions.displayWarning(err.message))
|
||||||
reject(err)
|
return reject(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info('Seed word cache cleared. ' + account)
|
log.info('Seed word cache cleared. ' + account)
|
||||||
@ -573,35 +573,47 @@ function signMsg (msgData) {
|
|||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(actions.showLoadingIndication())
|
dispatch(actions.showLoadingIndication())
|
||||||
|
|
||||||
log.debug(`actions calling background.signMessage`)
|
return new Promise((resolve, reject) => {
|
||||||
background.signMessage(msgData, (err, newState) => {
|
log.debug(`actions calling background.signMessage`)
|
||||||
log.debug('signMessage called back')
|
background.signMessage(msgData, (err, newState) => {
|
||||||
dispatch(actions.updateMetamaskState(newState))
|
log.debug('signMessage called back')
|
||||||
dispatch(actions.hideLoadingIndication())
|
dispatch(actions.updateMetamaskState(newState))
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
|
||||||
if (err) log.error(err)
|
if (err) {
|
||||||
if (err) return dispatch(actions.displayWarning(err.message))
|
log.error(err)
|
||||||
|
dispatch(actions.displayWarning(err.message))
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(actions.completedTx(msgData.metamaskId))
|
dispatch(actions.completedTx(msgData.metamaskId))
|
||||||
|
return resolve(msgData)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function signPersonalMsg (msgData) {
|
function signPersonalMsg (msgData) {
|
||||||
log.debug('action - signPersonalMsg')
|
log.debug('action - signPersonalMsg')
|
||||||
return (dispatch) => {
|
return dispatch => {
|
||||||
dispatch(actions.showLoadingIndication())
|
dispatch(actions.showLoadingIndication())
|
||||||
|
|
||||||
log.debug(`actions calling background.signPersonalMessage`)
|
return new Promise((resolve, reject) => {
|
||||||
background.signPersonalMessage(msgData, (err, newState) => {
|
log.debug(`actions calling background.signPersonalMessage`)
|
||||||
log.debug('signPersonalMessage called back')
|
background.signPersonalMessage(msgData, (err, newState) => {
|
||||||
dispatch(actions.updateMetamaskState(newState))
|
log.debug('signPersonalMessage called back')
|
||||||
dispatch(actions.hideLoadingIndication())
|
dispatch(actions.updateMetamaskState(newState))
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
|
||||||
if (err) log.error(err)
|
if (err) {
|
||||||
if (err) return dispatch(actions.displayWarning(err.message))
|
log.error(err)
|
||||||
|
dispatch(actions.displayWarning(err.message))
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(actions.completedTx(msgData.metamaskId))
|
dispatch(actions.completedTx(msgData.metamaskId))
|
||||||
|
return resolve(msgData)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,16 +623,22 @@ function signTypedMsg (msgData) {
|
|||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(actions.showLoadingIndication())
|
dispatch(actions.showLoadingIndication())
|
||||||
|
|
||||||
log.debug(`actions calling background.signTypedMessage`)
|
return new Promise((resolve, reject) => {
|
||||||
background.signTypedMessage(msgData, (err, newState) => {
|
log.debug(`actions calling background.signTypedMessage`)
|
||||||
log.debug('signTypedMessage called back')
|
background.signTypedMessage(msgData, (err, newState) => {
|
||||||
dispatch(actions.updateMetamaskState(newState))
|
log.debug('signTypedMessage called back')
|
||||||
dispatch(actions.hideLoadingIndication())
|
dispatch(actions.updateMetamaskState(newState))
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
|
||||||
if (err) log.error(err)
|
if (err) {
|
||||||
if (err) return dispatch(actions.displayWarning(err.message))
|
log.error(err)
|
||||||
|
dispatch(actions.displayWarning(err.message))
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(actions.completedTx(msgData.metamaskId))
|
dispatch(actions.completedTx(msgData.metamaskId))
|
||||||
|
return resolve(msgData)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -800,17 +818,24 @@ function updateTransaction (txData) {
|
|||||||
function updateAndApproveTx (txData) {
|
function updateAndApproveTx (txData) {
|
||||||
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
|
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
log.debug(`actions calling background.updateAndApproveTx.`)
|
log.debug(`actions calling background.updateAndApproveTx`)
|
||||||
background.updateAndApproveTransaction(txData, (err) => {
|
|
||||||
dispatch(actions.hideLoadingIndication())
|
return new Promise((resolve, reject) => {
|
||||||
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
|
background.updateAndApproveTransaction(txData, err => {
|
||||||
dispatch(actions.clearSend())
|
dispatch(actions.hideLoadingIndication())
|
||||||
if (err) {
|
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
|
||||||
dispatch(actions.txError(err))
|
dispatch(actions.clearSend())
|
||||||
dispatch(actions.goHome())
|
|
||||||
return log.error(err.message)
|
if (err) {
|
||||||
}
|
dispatch(actions.txError(err))
|
||||||
dispatch(actions.completedTx(txData.id))
|
dispatch(actions.goHome())
|
||||||
|
log.error(err.message)
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(actions.completedTx(txData.id))
|
||||||
|
resolve(txData)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -838,29 +863,77 @@ function txError (err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cancelMsg (msgData) {
|
function cancelMsg (msgData) {
|
||||||
log.debug(`background.cancelMessage`)
|
return dispatch => {
|
||||||
background.cancelMessage(msgData.id)
|
dispatch(actions.showLoadingIndication())
|
||||||
return actions.completedTx(msgData.id)
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
log.debug(`background.cancelMessage`)
|
||||||
|
background.cancelMessage(msgData.id, (err, newState) => {
|
||||||
|
dispatch(actions.updateMetamaskState(newState))
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(actions.completedTx(msgData.id))
|
||||||
|
return resolve(msgData)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelPersonalMsg (msgData) {
|
function cancelPersonalMsg (msgData) {
|
||||||
const id = msgData.id
|
return dispatch => {
|
||||||
background.cancelPersonalMessage(id)
|
dispatch(actions.showLoadingIndication())
|
||||||
return actions.completedTx(id)
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const id = msgData.id
|
||||||
|
background.cancelPersonalMessage(id, (err, newState) => {
|
||||||
|
dispatch(actions.updateMetamaskState(newState))
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(actions.completedTx(id))
|
||||||
|
return resolve(msgData)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelTypedMsg (msgData) {
|
function cancelTypedMsg (msgData) {
|
||||||
const id = msgData.id
|
return dispatch => {
|
||||||
background.cancelTypedMessage(id)
|
dispatch(actions.showLoadingIndication())
|
||||||
return actions.completedTx(id)
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const id = msgData.id
|
||||||
|
background.cancelTypedMessage(id, (err, newState) => {
|
||||||
|
dispatch(actions.updateMetamaskState(newState))
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(actions.completedTx(id))
|
||||||
|
return resolve(msgData)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelTx (txData) {
|
function cancelTx (txData) {
|
||||||
return (dispatch) => {
|
return dispatch => {
|
||||||
log.debug(`background.cancelTransaction`)
|
log.debug(`background.cancelTransaction`)
|
||||||
background.cancelTransaction(txData.id, () => {
|
return new Promise((resolve, reject) => {
|
||||||
dispatch(actions.clearSend())
|
background.cancelTransaction(txData.id, () => {
|
||||||
dispatch(actions.completedTx(txData.id))
|
dispatch(actions.clearSend())
|
||||||
|
dispatch(actions.completedTx(txData.id))
|
||||||
|
resolve(txData)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1251,12 +1324,13 @@ function markNoticeRead (notice) {
|
|||||||
dispatch(actions.displayWarning(err))
|
dispatch(actions.displayWarning(err))
|
||||||
return reject(err)
|
return reject(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notice) {
|
if (notice) {
|
||||||
dispatch(actions.showNotice(notice))
|
dispatch(actions.showNotice(notice))
|
||||||
resolve()
|
resolve(true)
|
||||||
} else {
|
} else {
|
||||||
dispatch(actions.clearNotices())
|
dispatch(actions.clearNotices())
|
||||||
resolve()
|
resolve(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -1775,7 +1849,7 @@ function forceUpdateMetamaskState (dispatch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispatch(actions.updateMetamaskState(newState))
|
dispatch(actions.updateMetamaskState(newState))
|
||||||
resolve()
|
resolve(newState)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
934
ui/app/app.js
934
ui/app/app.js
@ -1,62 +1,421 @@
|
|||||||
const inherits = require('util').inherits
|
const { Component } = require('react')
|
||||||
const Component = require('react').Component
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
|
const connect = require('react-redux').connect
|
||||||
|
const { Route, Switch, withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
const actions = require('./actions')
|
const actions = require('./actions')
|
||||||
const classnames = require('classnames')
|
const classnames = require('classnames')
|
||||||
|
|
||||||
// mascara
|
|
||||||
const MascaraFirstTime = require('../../mascara/src/app/first-time').default
|
|
||||||
const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default
|
|
||||||
// init
|
// init
|
||||||
const OldUIInitializeMenuScreen = require('./first-time/init-menu')
|
const InitializeScreen = require('../../mascara/src/app/first-time').default
|
||||||
const InitializeMenuScreen = MascaraFirstTime
|
|
||||||
const NewKeyChainScreen = require('./new-keychain')
|
|
||||||
const WelcomeScreen = require('./welcome-screen').default
|
|
||||||
|
|
||||||
// accounts
|
// accounts
|
||||||
const MainContainer = require('./main-container')
|
|
||||||
const SendTransactionScreen2 = require('./components/send/send-v2-container')
|
const SendTransactionScreen2 = require('./components/send/send-v2-container')
|
||||||
const ConfirmTxScreen = require('./conf-tx')
|
const ConfirmTxScreen = require('./conf-tx')
|
||||||
// notice
|
|
||||||
const NoticeScreen = require('./components/notice')
|
|
||||||
const generateLostAccountsNotice = require('../lib/lost-accounts-notice')
|
|
||||||
|
|
||||||
// slideout menu
|
// slideout menu
|
||||||
const WalletView = require('./components/wallet-view')
|
const WalletView = require('./components/wallet-view')
|
||||||
|
|
||||||
// other views
|
// other views
|
||||||
const Settings = require('./settings')
|
const Home = require('./components/pages/home')
|
||||||
const AddTokenScreen = require('./add-token')
|
const Authenticated = require('./components/pages/authenticated')
|
||||||
const Import = require('./accounts/import')
|
const Initialized = require('./components/pages/initialized')
|
||||||
const NewAccount = require('./accounts/new-account')
|
const Settings = require('./components/pages/settings')
|
||||||
|
const UnlockPage = require('./components/pages/unlock')
|
||||||
|
const RestoreVaultPage = require('./components/pages/keychains/restore-vault')
|
||||||
|
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
|
||||||
|
const AddTokenPage = require('./components/pages/add-token')
|
||||||
|
const CreateAccountPage = require('./components/pages/create-account')
|
||||||
|
const NoticeScreen = require('./components/pages/notice')
|
||||||
|
|
||||||
const Loading = require('./components/loading')
|
const Loading = require('./components/loading')
|
||||||
const NetworkIndicator = require('./components/network')
|
const NetworkIndicator = require('./components/network')
|
||||||
const Identicon = require('./components/identicon')
|
const Identicon = require('./components/identicon')
|
||||||
const BuyView = require('./components/buy-button-subview')
|
|
||||||
const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete')
|
|
||||||
const HDRestoreVaultScreen = require('./keychains/hd/restore-vault')
|
|
||||||
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
|
|
||||||
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
|
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
|
||||||
const NetworkDropdown = require('./components/dropdowns/network-dropdown')
|
const NetworkDropdown = require('./components/dropdowns/network-dropdown')
|
||||||
const AccountMenu = require('./components/account-menu')
|
const AccountMenu = require('./components/account-menu')
|
||||||
const QrView = require('./components/qr-code')
|
|
||||||
|
|
||||||
// Global Modals
|
// Global Modals
|
||||||
const Modal = require('./components/modals/index').Modal
|
const Modal = require('./components/modals/index').Modal
|
||||||
|
|
||||||
App.contextTypes = {
|
// Routes
|
||||||
|
const {
|
||||||
|
DEFAULT_ROUTE,
|
||||||
|
UNLOCK_ROUTE,
|
||||||
|
SETTINGS_ROUTE,
|
||||||
|
REVEAL_SEED_ROUTE,
|
||||||
|
RESTORE_VAULT_ROUTE,
|
||||||
|
ADD_TOKEN_ROUTE,
|
||||||
|
NEW_ACCOUNT_ROUTE,
|
||||||
|
SEND_ROUTE,
|
||||||
|
CONFIRM_TRANSACTION_ROUTE,
|
||||||
|
INITIALIZE_ROUTE,
|
||||||
|
NOTICE_ROUTE,
|
||||||
|
} = require('./routes')
|
||||||
|
|
||||||
|
class App extends Component {
|
||||||
|
componentWillMount () {
|
||||||
|
const { currentCurrency, setCurrentCurrencyToUSD } = this.props
|
||||||
|
|
||||||
|
if (!currentCurrency) {
|
||||||
|
setCurrentCurrencyToUSD()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRoutes () {
|
||||||
|
const exact = true
|
||||||
|
|
||||||
|
return (
|
||||||
|
h(Switch, [
|
||||||
|
h(Route, { path: INITIALIZE_ROUTE, component: InitializeScreen }),
|
||||||
|
h(Initialized, { path: REVEAL_SEED_ROUTE, exact, component: RevealSeedConfirmation }),
|
||||||
|
h(Initialized, { path: UNLOCK_ROUTE, exact, component: UnlockPage }),
|
||||||
|
h(Initialized, { path: SETTINGS_ROUTE, component: Settings }),
|
||||||
|
h(Initialized, { path: RESTORE_VAULT_ROUTE, exact, component: RestoreVaultPage }),
|
||||||
|
h(Initialized, { path: NOTICE_ROUTE, exact, component: NoticeScreen }),
|
||||||
|
h(Authenticated, { path: CONFIRM_TRANSACTION_ROUTE, component: ConfirmTxScreen }),
|
||||||
|
h(Authenticated, { path: SEND_ROUTE, exact, component: SendTransactionScreen2 }),
|
||||||
|
h(Authenticated, { path: ADD_TOKEN_ROUTE, exact, component: AddTokenPage }),
|
||||||
|
h(Authenticated, { path: NEW_ACCOUNT_ROUTE, component: CreateAccountPage }),
|
||||||
|
h(Authenticated, { path: DEFAULT_ROUTE, exact, component: Home }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
isLoading,
|
||||||
|
loadingMessage,
|
||||||
|
network,
|
||||||
|
isMouseUser,
|
||||||
|
provider,
|
||||||
|
frequentRpcList,
|
||||||
|
currentView,
|
||||||
|
setMouseUserState,
|
||||||
|
} = this.props
|
||||||
|
const isLoadingNetwork = network === 'loading' && currentView.name !== 'config'
|
||||||
|
const loadMessage = loadingMessage || isLoadingNetwork ?
|
||||||
|
this.getConnectingLabel() : null
|
||||||
|
log.debug('Main ui render function')
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('.flex-column.full-height', {
|
||||||
|
className: classnames({ 'mouse-user-styles': isMouseUser }),
|
||||||
|
style: {
|
||||||
|
overflowX: 'hidden',
|
||||||
|
position: 'relative',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
tabIndex: '0',
|
||||||
|
onClick: () => setMouseUserState(true),
|
||||||
|
onKeyDown: (e) => {
|
||||||
|
if (e.keyCode === 9) {
|
||||||
|
setMouseUserState(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
|
||||||
|
// global modal
|
||||||
|
h(Modal, {}, []),
|
||||||
|
|
||||||
|
// app bar
|
||||||
|
this.renderAppBar(),
|
||||||
|
|
||||||
|
// sidebar
|
||||||
|
this.renderSidebar(),
|
||||||
|
|
||||||
|
// network dropdown
|
||||||
|
h(NetworkDropdown, {
|
||||||
|
provider,
|
||||||
|
frequentRpcList,
|
||||||
|
}, []),
|
||||||
|
|
||||||
|
h(AccountMenu),
|
||||||
|
|
||||||
|
(isLoading || isLoadingNetwork) && h(Loading, {
|
||||||
|
loadingMessage: loadMessage,
|
||||||
|
}),
|
||||||
|
|
||||||
|
// this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }),
|
||||||
|
|
||||||
|
// content
|
||||||
|
this.renderRoutes(),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderGlobalModal () {
|
||||||
|
return h(Modal, {
|
||||||
|
ref: 'modalRef',
|
||||||
|
}, [
|
||||||
|
// h(BuyOptions, {}, []),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSidebar () {
|
||||||
|
return h('div', [
|
||||||
|
h('style', `
|
||||||
|
.sidebar-enter {
|
||||||
|
transition: transform 300ms ease-in-out;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
.sidebar-enter.sidebar-enter-active {
|
||||||
|
transition: transform 300ms ease-in-out;
|
||||||
|
transform: translateX(0%);
|
||||||
|
}
|
||||||
|
.sidebar-leave {
|
||||||
|
transition: transform 200ms ease-out;
|
||||||
|
transform: translateX(0%);
|
||||||
|
}
|
||||||
|
.sidebar-leave.sidebar-leave-active {
|
||||||
|
transition: transform 200ms ease-out;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
|
||||||
|
h(ReactCSSTransitionGroup, {
|
||||||
|
transitionName: 'sidebar',
|
||||||
|
transitionEnterTimeout: 300,
|
||||||
|
transitionLeaveTimeout: 200,
|
||||||
|
}, [
|
||||||
|
// A second instance of Walletview is used for non-mobile viewports
|
||||||
|
this.props.sidebarOpen ? h(WalletView, {
|
||||||
|
responsiveDisplayClassname: '.sidebar',
|
||||||
|
style: {},
|
||||||
|
}) : undefined,
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
|
// overlay
|
||||||
|
// TODO: add onClick for overlay to close sidebar
|
||||||
|
this.props.sidebarOpen ? h('div.sidebar-overlay', {
|
||||||
|
style: {},
|
||||||
|
onClick: () => {
|
||||||
|
this.props.hideSidebar()
|
||||||
|
},
|
||||||
|
}, []) : undefined,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAppBar () {
|
||||||
|
const {
|
||||||
|
isUnlocked,
|
||||||
|
network,
|
||||||
|
provider,
|
||||||
|
networkDropdownOpen,
|
||||||
|
showNetworkDropdown,
|
||||||
|
hideNetworkDropdown,
|
||||||
|
isInitialized,
|
||||||
|
welcomeScreenSeen,
|
||||||
|
isPopup,
|
||||||
|
betaUI,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
if (window.METAMASK_UI_TYPE === 'notification') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = this.props
|
||||||
|
const {isMascara, isOnboarding} = props
|
||||||
|
|
||||||
|
// Do not render header if user is in mascara onboarding
|
||||||
|
if (isMascara && isOnboarding) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not render header if user is in mascara buy ether
|
||||||
|
if (isMascara && props.currentView.name === 'buyEth') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
h('.full-width', {
|
||||||
|
style: {},
|
||||||
|
}, [
|
||||||
|
|
||||||
|
(isInitialized || welcomeScreenSeen || isPopup || !betaUI) && h('.app-header.flex-row.flex-space-between', {
|
||||||
|
className: classnames({
|
||||||
|
'app-header--initialized': !isOnboarding,
|
||||||
|
}),
|
||||||
|
}, [
|
||||||
|
h('div.app-header-contents', {}, [
|
||||||
|
h('div.left-menu-wrapper', {
|
||||||
|
onClick: () => props.history.push(DEFAULT_ROUTE),
|
||||||
|
}, [
|
||||||
|
// mini logo
|
||||||
|
h('img.metafox-icon', {
|
||||||
|
height: 42,
|
||||||
|
width: 42,
|
||||||
|
src: '/images/metamask-fox.svg',
|
||||||
|
}),
|
||||||
|
|
||||||
|
// metamask name
|
||||||
|
h('.flex-row', [
|
||||||
|
h('h1', this.context.t('appName')),
|
||||||
|
h('div.beta-label', this.context.t('beta')),
|
||||||
|
]),
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
|
betaUI && isInitialized && h('div.header__right-actions', [
|
||||||
|
h('div.network-component-wrapper', {
|
||||||
|
style: {},
|
||||||
|
}, [
|
||||||
|
// Network Indicator
|
||||||
|
h(NetworkIndicator, {
|
||||||
|
network,
|
||||||
|
provider,
|
||||||
|
disabled: this.props.location.pathname === CONFIRM_TRANSACTION_ROUTE,
|
||||||
|
onClick: (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
return networkDropdownOpen === false
|
||||||
|
? showNetworkDropdown()
|
||||||
|
: hideNetworkDropdown()
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
|
isUnlocked && h('div.account-menu__icon', { onClick: this.props.toggleAccountMenu }, [
|
||||||
|
h(Identicon, {
|
||||||
|
address: this.props.selectedAddress,
|
||||||
|
diameter: 32,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
|
||||||
|
!isInitialized && !isPopup && betaUI && h('.alpha-warning__container', {}, [
|
||||||
|
h('h2', {
|
||||||
|
className: classnames({
|
||||||
|
'alpha-warning': welcomeScreenSeen,
|
||||||
|
'alpha-warning-welcome-screen': !welcomeScreenSeen,
|
||||||
|
}),
|
||||||
|
}, 'Please be aware that this version is still under development'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLoadingIndicator ({ isLoading, isLoadingNetwork, loadMessage }) {
|
||||||
|
const { isMascara } = this.props
|
||||||
|
|
||||||
|
return isMascara
|
||||||
|
? null
|
||||||
|
: h(Loading, {
|
||||||
|
isLoading: isLoading || isLoadingNetwork,
|
||||||
|
loadingMessage: loadMessage,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleMetamaskActive () {
|
||||||
|
if (!this.props.isUnlocked) {
|
||||||
|
// currently inactive: redirect to password box
|
||||||
|
var passwordBox = document.querySelector('input[type=password]')
|
||||||
|
if (!passwordBox) return
|
||||||
|
passwordBox.focus()
|
||||||
|
} else {
|
||||||
|
// currently active: deactivate
|
||||||
|
this.props.dispatch(actions.lockMetamask(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getConnectingLabel = function () {
|
||||||
|
const { provider } = this.props
|
||||||
|
const providerName = provider.type
|
||||||
|
|
||||||
|
let name
|
||||||
|
|
||||||
|
if (providerName === 'mainnet') {
|
||||||
|
name = this.context.t('connectingToMainnet')
|
||||||
|
} else if (providerName === 'ropsten') {
|
||||||
|
name = this.context.t('connectingToRopsten')
|
||||||
|
} else if (providerName === 'kovan') {
|
||||||
|
name = this.context.t('connectingToRopsten')
|
||||||
|
} else if (providerName === 'rinkeby') {
|
||||||
|
name = this.context.t('connectingToRinkeby')
|
||||||
|
} else {
|
||||||
|
name = this.context.t('connectingToUnknown')
|
||||||
|
}
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkName () {
|
||||||
|
const { provider } = this.props
|
||||||
|
const providerName = provider.type
|
||||||
|
|
||||||
|
let name
|
||||||
|
|
||||||
|
if (providerName === 'mainnet') {
|
||||||
|
name = this.context.t('mainnet')
|
||||||
|
} else if (providerName === 'ropsten') {
|
||||||
|
name = this.context.t('ropsten')
|
||||||
|
} else if (providerName === 'kovan') {
|
||||||
|
name = this.context.t('kovan')
|
||||||
|
} else if (providerName === 'rinkeby') {
|
||||||
|
name = this.context.t('rinkeby')
|
||||||
|
} else {
|
||||||
|
name = this.context.t('unknownNetwork')
|
||||||
|
}
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
App.propTypes = {
|
||||||
|
currentCurrency: PropTypes.string,
|
||||||
|
setCurrentCurrencyToUSD: PropTypes.func,
|
||||||
|
isLoading: PropTypes.bool,
|
||||||
|
loadingMessage: PropTypes.string,
|
||||||
|
network: PropTypes.string,
|
||||||
|
provider: PropTypes.object,
|
||||||
|
frequentRpcList: PropTypes.array,
|
||||||
|
currentView: PropTypes.object,
|
||||||
|
sidebarOpen: PropTypes.bool,
|
||||||
|
hideSidebar: PropTypes.func,
|
||||||
|
isMascara: PropTypes.bool,
|
||||||
|
isOnboarding: PropTypes.bool,
|
||||||
|
isUnlocked: PropTypes.bool,
|
||||||
|
networkDropdownOpen: PropTypes.bool,
|
||||||
|
showNetworkDropdown: PropTypes.func,
|
||||||
|
hideNetworkDropdown: PropTypes.func,
|
||||||
|
history: PropTypes.object,
|
||||||
|
location: PropTypes.object,
|
||||||
|
dispatch: PropTypes.func,
|
||||||
|
toggleAccountMenu: PropTypes.func,
|
||||||
|
selectedAddress: PropTypes.string,
|
||||||
|
noActiveNotices: PropTypes.bool,
|
||||||
|
lostAccounts: PropTypes.array,
|
||||||
|
isInitialized: PropTypes.bool,
|
||||||
|
forgottenPassword: PropTypes.bool,
|
||||||
|
activeAddress: PropTypes.string,
|
||||||
|
unapprovedTxs: PropTypes.object,
|
||||||
|
seedWords: PropTypes.string,
|
||||||
|
unapprovedMsgCount: PropTypes.number,
|
||||||
|
unapprovedPersonalMsgCount: PropTypes.number,
|
||||||
|
unapprovedTypedMessagesCount: PropTypes.number,
|
||||||
|
welcomeScreenSeen: PropTypes.bool,
|
||||||
|
isPopup: PropTypes.bool,
|
||||||
|
betaUI: PropTypes.bool,
|
||||||
|
isMouseUser: PropTypes.bool,
|
||||||
|
setMouseUserState: PropTypes.func,
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(App)
|
|
||||||
|
|
||||||
|
|
||||||
inherits(App, Component)
|
|
||||||
function App () { Component.call(this) }
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
|
const { appState, metamask } = state
|
||||||
|
const {
|
||||||
|
networkDropdownOpen,
|
||||||
|
sidebarOpen,
|
||||||
|
isLoading,
|
||||||
|
loadingMessage,
|
||||||
|
} = appState
|
||||||
|
|
||||||
const {
|
const {
|
||||||
identities,
|
identities,
|
||||||
accounts,
|
accounts,
|
||||||
@ -65,17 +424,23 @@ function mapStateToProps (state) {
|
|||||||
isInitialized,
|
isInitialized,
|
||||||
noActiveNotices,
|
noActiveNotices,
|
||||||
seedWords,
|
seedWords,
|
||||||
} = state.metamask
|
unapprovedTxs,
|
||||||
|
lastUnreadNotice,
|
||||||
|
lostAccounts,
|
||||||
|
unapprovedMsgCount,
|
||||||
|
unapprovedPersonalMsgCount,
|
||||||
|
unapprovedTypedMessagesCount,
|
||||||
|
} = metamask
|
||||||
const selected = address || Object.keys(accounts)[0]
|
const selected = address || Object.keys(accounts)[0]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// state from plugin
|
// state from plugin
|
||||||
networkDropdownOpen: state.appState.networkDropdownOpen,
|
networkDropdownOpen,
|
||||||
sidebarOpen: state.appState.sidebarOpen,
|
sidebarOpen,
|
||||||
isLoading: state.appState.isLoading,
|
isLoading,
|
||||||
loadingMessage: state.appState.loadingMessage,
|
loadingMessage,
|
||||||
noActiveNotices: state.metamask.noActiveNotices,
|
noActiveNotices,
|
||||||
isInitialized: state.metamask.isInitialized,
|
isInitialized,
|
||||||
isUnlocked: state.metamask.isUnlocked,
|
isUnlocked: state.metamask.isUnlocked,
|
||||||
selectedAddress: state.metamask.selectedAddress,
|
selectedAddress: state.metamask.selectedAddress,
|
||||||
currentView: state.appState.currentView,
|
currentView: state.appState.currentView,
|
||||||
@ -85,14 +450,17 @@ function mapStateToProps (state) {
|
|||||||
isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized),
|
isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized),
|
||||||
isPopup: state.metamask.isPopup,
|
isPopup: state.metamask.isPopup,
|
||||||
seedWords: state.metamask.seedWords,
|
seedWords: state.metamask.seedWords,
|
||||||
unapprovedTxs: state.metamask.unapprovedTxs,
|
unapprovedTxs,
|
||||||
unapprovedMsgs: state.metamask.unapprovedMsgs,
|
unapprovedMsgs: state.metamask.unapprovedMsgs,
|
||||||
|
unapprovedMsgCount,
|
||||||
|
unapprovedPersonalMsgCount,
|
||||||
|
unapprovedTypedMessagesCount,
|
||||||
menuOpen: state.appState.menuOpen,
|
menuOpen: state.appState.menuOpen,
|
||||||
network: state.metamask.network,
|
network: state.metamask.network,
|
||||||
provider: state.metamask.provider,
|
provider: state.metamask.provider,
|
||||||
forgottenPassword: state.metamask.forgottenPassword,
|
forgottenPassword: state.appState.forgottenPassword,
|
||||||
lastUnreadNotice: state.metamask.lastUnreadNotice,
|
lastUnreadNotice,
|
||||||
lostAccounts: state.metamask.lostAccounts,
|
lostAccounts,
|
||||||
frequentRpcList: state.metamask.frequentRpcList || [],
|
frequentRpcList: state.metamask.frequentRpcList || [],
|
||||||
currentCurrency: state.metamask.currentCurrency,
|
currentCurrency: state.metamask.currentCurrency,
|
||||||
isMouseUser: state.appState.isMouseUser,
|
isMouseUser: state.appState.isMouseUser,
|
||||||
@ -120,479 +488,11 @@ function mapDispatchToProps (dispatch, ownProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
App.prototype.componentWillMount = function () {
|
App.contextTypes = {
|
||||||
if (!this.props.currentCurrency) {
|
t: PropTypes.func,
|
||||||
this.props.setCurrentCurrencyToUSD()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
App.prototype.render = function () {
|
module.exports = compose(
|
||||||
var props = this.props
|
withRouter,
|
||||||
const {
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
isLoading,
|
)(App)
|
||||||
loadingMessage,
|
|
||||||
network,
|
|
||||||
isMouseUser,
|
|
||||||
setMouseUserState,
|
|
||||||
} = props
|
|
||||||
const isLoadingNetwork = network === 'loading' && props.currentView.name !== 'config'
|
|
||||||
const loadMessage = loadingMessage || isLoadingNetwork ?
|
|
||||||
this.getConnectingLabel() : null
|
|
||||||
log.debug('Main ui render function')
|
|
||||||
|
|
||||||
return (
|
|
||||||
h('.flex-column.full-height', {
|
|
||||||
className: classnames({ 'mouse-user-styles': isMouseUser }),
|
|
||||||
style: {
|
|
||||||
overflowX: 'hidden',
|
|
||||||
position: 'relative',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
tabIndex: '0',
|
|
||||||
onClick: () => setMouseUserState(true),
|
|
||||||
onKeyDown: (e) => {
|
|
||||||
if (e.keyCode === 9) {
|
|
||||||
setMouseUserState(false)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
|
|
||||||
// global modal
|
|
||||||
h(Modal, {}, []),
|
|
||||||
|
|
||||||
// app bar
|
|
||||||
this.renderAppBar(),
|
|
||||||
|
|
||||||
// sidebar
|
|
||||||
this.renderSidebar(),
|
|
||||||
|
|
||||||
// network dropdown
|
|
||||||
h(NetworkDropdown, {
|
|
||||||
provider: this.props.provider,
|
|
||||||
frequentRpcList: this.props.frequentRpcList,
|
|
||||||
}, []),
|
|
||||||
|
|
||||||
h(AccountMenu),
|
|
||||||
|
|
||||||
(isLoading || isLoadingNetwork) && h(Loading, {
|
|
||||||
loadingMessage: loadMessage,
|
|
||||||
}),
|
|
||||||
|
|
||||||
// this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }),
|
|
||||||
|
|
||||||
// content
|
|
||||||
this.renderPrimary(),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.renderGlobalModal = function () {
|
|
||||||
return h(Modal, {
|
|
||||||
ref: 'modalRef',
|
|
||||||
}, [
|
|
||||||
// h(BuyOptions, {}, []),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.renderSidebar = function () {
|
|
||||||
|
|
||||||
return h('div', {
|
|
||||||
}, [
|
|
||||||
h('style', `
|
|
||||||
.sidebar-enter {
|
|
||||||
transition: transform 300ms ease-in-out;
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
.sidebar-enter.sidebar-enter-active {
|
|
||||||
transition: transform 300ms ease-in-out;
|
|
||||||
transform: translateX(0%);
|
|
||||||
}
|
|
||||||
.sidebar-leave {
|
|
||||||
transition: transform 200ms ease-out;
|
|
||||||
transform: translateX(0%);
|
|
||||||
}
|
|
||||||
.sidebar-leave.sidebar-leave-active {
|
|
||||||
transition: transform 200ms ease-out;
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
`),
|
|
||||||
|
|
||||||
h(ReactCSSTransitionGroup, {
|
|
||||||
transitionName: 'sidebar',
|
|
||||||
transitionEnterTimeout: 300,
|
|
||||||
transitionLeaveTimeout: 200,
|
|
||||||
}, [
|
|
||||||
// A second instance of Walletview is used for non-mobile viewports
|
|
||||||
this.props.sidebarOpen ? h(WalletView, {
|
|
||||||
responsiveDisplayClassname: '.sidebar',
|
|
||||||
style: {},
|
|
||||||
}) : undefined,
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
// overlay
|
|
||||||
// TODO: add onClick for overlay to close sidebar
|
|
||||||
this.props.sidebarOpen ? h('div.sidebar-overlay', {
|
|
||||||
style: {},
|
|
||||||
onClick: () => {
|
|
||||||
this.props.hideSidebar()
|
|
||||||
},
|
|
||||||
}, []) : undefined,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.renderAppBar = function () {
|
|
||||||
const {
|
|
||||||
isUnlocked,
|
|
||||||
network,
|
|
||||||
provider,
|
|
||||||
networkDropdownOpen,
|
|
||||||
showNetworkDropdown,
|
|
||||||
hideNetworkDropdown,
|
|
||||||
currentView,
|
|
||||||
isInitialized,
|
|
||||||
betaUI,
|
|
||||||
isPopup,
|
|
||||||
welcomeScreenSeen,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
if (window.METAMASK_UI_TYPE === 'notification') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = this.props
|
|
||||||
const {isMascara, isOnboarding} = props
|
|
||||||
|
|
||||||
// Do not render header if user is in mascara onboarding
|
|
||||||
if (isMascara && isOnboarding) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not render header if user is in mascara buy ether
|
|
||||||
if (isMascara && props.currentView.name === 'buyEth') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
h('.full-width', {
|
|
||||||
style: {},
|
|
||||||
}, [
|
|
||||||
|
|
||||||
(isInitialized || welcomeScreenSeen || isPopup || !betaUI) && h('.app-header.flex-row.flex-space-between', {
|
|
||||||
className: classnames({
|
|
||||||
'app-header--initialized': !isOnboarding,
|
|
||||||
}),
|
|
||||||
}, [
|
|
||||||
h('div.app-header-contents', {}, [
|
|
||||||
h('div.left-menu-wrapper', {
|
|
||||||
onClick: () => {
|
|
||||||
props.dispatch(actions.backToAccountDetail(props.activeAddress))
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
// mini logo
|
|
||||||
h('img.metafox-icon', {
|
|
||||||
height: 42,
|
|
||||||
width: 42,
|
|
||||||
src: './images/metamask-fox.svg',
|
|
||||||
}),
|
|
||||||
|
|
||||||
// metamask name
|
|
||||||
h('.flex-row', [
|
|
||||||
h('h1', this.context.t('appName')),
|
|
||||||
h('div.beta-label', this.context.t('beta')),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
|
|
||||||
betaUI && isInitialized && h('div.header__right-actions', [
|
|
||||||
h('div.network-component-wrapper', {
|
|
||||||
style: {},
|
|
||||||
}, [
|
|
||||||
// Network Indicator
|
|
||||||
h(NetworkIndicator, {
|
|
||||||
network,
|
|
||||||
provider,
|
|
||||||
disabled: currentView.name === 'confTx',
|
|
||||||
onClick: (event) => {
|
|
||||||
event.preventDefault()
|
|
||||||
event.stopPropagation()
|
|
||||||
return networkDropdownOpen === false
|
|
||||||
? showNetworkDropdown()
|
|
||||||
: hideNetworkDropdown()
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
isUnlocked && h('div.account-menu__icon', { onClick: this.props.toggleAccountMenu }, [
|
|
||||||
h(Identicon, {
|
|
||||||
address: this.props.selectedAddress,
|
|
||||||
diameter: 32,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
|
|
||||||
!isInitialized && !isPopup && betaUI && h('.alpha-warning__container', {}, [
|
|
||||||
h('h2', {
|
|
||||||
className: classnames({
|
|
||||||
'alpha-warning': welcomeScreenSeen,
|
|
||||||
'alpha-warning-welcome-screen': !welcomeScreenSeen,
|
|
||||||
}),
|
|
||||||
}, 'Please be aware that this version is still under development'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.renderLoadingIndicator = function ({ isLoading, isLoadingNetwork, loadMessage }) {
|
|
||||||
const { isMascara } = this.props
|
|
||||||
|
|
||||||
return isMascara
|
|
||||||
? null
|
|
||||||
: h(Loading, {
|
|
||||||
isLoading: isLoading || isLoadingNetwork,
|
|
||||||
loadingMessage: loadMessage,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.renderBackButton = function (style, justArrow = false) {
|
|
||||||
var props = this.props
|
|
||||||
return (
|
|
||||||
h('.flex-row', {
|
|
||||||
key: 'leftArrow',
|
|
||||||
style: style,
|
|
||||||
onClick: () => props.dispatch(actions.goBackToInitView()),
|
|
||||||
}, [
|
|
||||||
h('i.fa.fa-arrow-left.cursor-pointer'),
|
|
||||||
justArrow ? null : h('div.cursor-pointer', {
|
|
||||||
style: {
|
|
||||||
marginLeft: '3px',
|
|
||||||
},
|
|
||||||
onClick: () => props.dispatch(actions.goBackToInitView()),
|
|
||||||
}, 'BACK'),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.renderPrimary = function () {
|
|
||||||
log.debug('rendering primary')
|
|
||||||
var props = this.props
|
|
||||||
const {
|
|
||||||
isMascara,
|
|
||||||
isOnboarding,
|
|
||||||
betaUI,
|
|
||||||
isRevealingSeedWords,
|
|
||||||
welcomeScreenSeen,
|
|
||||||
Qr,
|
|
||||||
isInitialized,
|
|
||||||
isUnlocked,
|
|
||||||
} = props
|
|
||||||
const isMascaraOnboarding = isMascara && isOnboarding
|
|
||||||
const isBetaUIOnboarding = betaUI && isOnboarding
|
|
||||||
|
|
||||||
if (!welcomeScreenSeen && betaUI && !isInitialized && !isUnlocked) {
|
|
||||||
return h(WelcomeScreen)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMascaraOnboarding || isBetaUIOnboarding) {
|
|
||||||
return h(MascaraFirstTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
// notices
|
|
||||||
if (!props.noActiveNotices && !betaUI) {
|
|
||||||
log.debug('rendering notice screen for unread notices.')
|
|
||||||
return h(NoticeScreen, {
|
|
||||||
notice: props.lastUnreadNotice,
|
|
||||||
key: 'NoticeScreen',
|
|
||||||
onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)),
|
|
||||||
})
|
|
||||||
} else if (props.lostAccounts && props.lostAccounts.length > 0) {
|
|
||||||
log.debug('rendering notice screen for lost accounts view.')
|
|
||||||
return h(NoticeScreen, {
|
|
||||||
notice: generateLostAccountsNotice(props.lostAccounts),
|
|
||||||
key: 'LostAccountsNotice',
|
|
||||||
onConfirm: () => props.dispatch(actions.markAccountsFound()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.isInitialized && props.forgottenPassword) {
|
|
||||||
log.debug('rendering restore vault screen')
|
|
||||||
return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
|
|
||||||
} else if (!props.isInitialized && !props.isUnlocked && !isRevealingSeedWords) {
|
|
||||||
log.debug('rendering menu screen')
|
|
||||||
return !betaUI
|
|
||||||
? h(OldUIInitializeMenuScreen, {key: 'menuScreenInit'})
|
|
||||||
: h(InitializeMenuScreen, {key: 'menuScreenInit'})
|
|
||||||
}
|
|
||||||
|
|
||||||
// show unlock screen
|
|
||||||
if (!props.isUnlocked) {
|
|
||||||
return h(MainContainer, {
|
|
||||||
currentViewName: props.currentView.name,
|
|
||||||
isUnlocked: props.isUnlocked,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// show seed words screen
|
|
||||||
if (props.seedWords) {
|
|
||||||
log.debug('rendering seed words')
|
|
||||||
return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'})
|
|
||||||
}
|
|
||||||
|
|
||||||
// show current view
|
|
||||||
switch (props.currentView.name) {
|
|
||||||
|
|
||||||
case 'accountDetail':
|
|
||||||
log.debug('rendering main container')
|
|
||||||
return h(MainContainer, {key: 'account-detail'})
|
|
||||||
|
|
||||||
case 'sendTransaction':
|
|
||||||
log.debug('rendering send tx screen')
|
|
||||||
|
|
||||||
// Going to leave this here until we are ready to delete SendTransactionScreen v1
|
|
||||||
// const SendComponentToRender = checkFeatureToggle('send-v2')
|
|
||||||
// ? SendTransactionScreen2
|
|
||||||
// : SendTransactionScreen
|
|
||||||
|
|
||||||
return h(SendTransactionScreen2, {key: 'send-transaction'})
|
|
||||||
|
|
||||||
case 'sendToken':
|
|
||||||
log.debug('rendering send token screen')
|
|
||||||
|
|
||||||
// Going to leave this here until we are ready to delete SendTransactionScreen v1
|
|
||||||
// const SendTokenComponentToRender = checkFeatureToggle('send-v2')
|
|
||||||
// ? SendTransactionScreen2
|
|
||||||
// : SendTokenScreen
|
|
||||||
|
|
||||||
return h(SendTransactionScreen2, {key: 'sendToken'})
|
|
||||||
|
|
||||||
case 'newKeychain':
|
|
||||||
log.debug('rendering new keychain screen')
|
|
||||||
return h(NewKeyChainScreen, {key: 'new-keychain'})
|
|
||||||
|
|
||||||
case 'confTx':
|
|
||||||
log.debug('rendering confirm tx screen')
|
|
||||||
return h(ConfirmTxScreen, {key: 'confirm-tx'})
|
|
||||||
|
|
||||||
case 'add-token':
|
|
||||||
log.debug('rendering add-token screen from unlock screen.')
|
|
||||||
return h(AddTokenScreen, {key: 'add-token'})
|
|
||||||
|
|
||||||
case 'config':
|
|
||||||
log.debug('rendering config screen')
|
|
||||||
return h(Settings, {key: 'config'})
|
|
||||||
|
|
||||||
case 'import-menu':
|
|
||||||
log.debug('rendering import screen')
|
|
||||||
return h(Import, {key: 'import-menu'})
|
|
||||||
|
|
||||||
case 'new-account-page':
|
|
||||||
log.debug('rendering new account screen')
|
|
||||||
return h(NewAccount, {key: 'new-account'})
|
|
||||||
|
|
||||||
case 'reveal-seed-conf':
|
|
||||||
log.debug('rendering reveal seed confirmation screen')
|
|
||||||
return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'})
|
|
||||||
|
|
||||||
case 'info':
|
|
||||||
log.debug('rendering info screen')
|
|
||||||
return h(Settings, {key: 'info', tab: 'info'})
|
|
||||||
|
|
||||||
case 'buyEth':
|
|
||||||
log.debug('rendering buy ether screen')
|
|
||||||
return h(BuyView, {key: 'buyEthView'})
|
|
||||||
|
|
||||||
case 'onboardingBuyEth':
|
|
||||||
log.debug('rendering onboarding buy ether screen')
|
|
||||||
return h(MascaraBuyEtherScreen, {key: 'buyEthView'})
|
|
||||||
|
|
||||||
case 'qr':
|
|
||||||
log.debug('rendering show qr screen')
|
|
||||||
return h('div', {
|
|
||||||
style: {
|
|
||||||
position: 'absolute',
|
|
||||||
height: '100%',
|
|
||||||
top: '0px',
|
|
||||||
left: '0px',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
|
|
||||||
onClick: () => props.dispatch(actions.backToAccountDetail(props.activeAddress)),
|
|
||||||
style: {
|
|
||||||
marginLeft: '10px',
|
|
||||||
marginTop: '50px',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
h('div', {
|
|
||||||
style: {
|
|
||||||
position: 'absolute',
|
|
||||||
left: '44px',
|
|
||||||
width: '285px',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
h(QrView, {key: 'qr', Qr}),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
|
|
||||||
default:
|
|
||||||
log.debug('rendering default, account detail screen')
|
|
||||||
return h(MainContainer, {key: 'account-detail'})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.toggleMetamaskActive = function () {
|
|
||||||
if (!this.props.isUnlocked) {
|
|
||||||
// currently inactive: redirect to password box
|
|
||||||
var passwordBox = document.querySelector('input[type=password]')
|
|
||||||
if (!passwordBox) return
|
|
||||||
passwordBox.focus()
|
|
||||||
} else {
|
|
||||||
// currently active: deactivate
|
|
||||||
this.props.dispatch(actions.lockMetamask(false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.getConnectingLabel = function () {
|
|
||||||
const { provider } = this.props
|
|
||||||
const providerName = provider.type
|
|
||||||
|
|
||||||
let name
|
|
||||||
|
|
||||||
if (providerName === 'mainnet') {
|
|
||||||
name = this.context.t('connectingToMainnet')
|
|
||||||
} else if (providerName === 'ropsten') {
|
|
||||||
name = this.context.t('connectingToRopsten')
|
|
||||||
} else if (providerName === 'kovan') {
|
|
||||||
name = this.context.t('connectingToRopsten')
|
|
||||||
} else if (providerName === 'rinkeby') {
|
|
||||||
name = this.context.t('connectingToRinkeby')
|
|
||||||
} else {
|
|
||||||
name = this.context.t('connectingToUnknown')
|
|
||||||
}
|
|
||||||
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
App.prototype.getNetworkName = function () {
|
|
||||||
const { provider } = this.props
|
|
||||||
const providerName = provider.type
|
|
||||||
|
|
||||||
let name
|
|
||||||
|
|
||||||
if (providerName === 'mainnet') {
|
|
||||||
name = this.context.t('mainnet')
|
|
||||||
} else if (providerName === 'ropsten') {
|
|
||||||
name = this.context.t('ropsten')
|
|
||||||
} else if (providerName === 'kovan') {
|
|
||||||
name = this.context.t('kovan')
|
|
||||||
} else if (providerName === 'rinkeby') {
|
|
||||||
name = this.context.t('rinkeby')
|
|
||||||
} else {
|
|
||||||
name = this.context.t('unknownNetwork')
|
|
||||||
}
|
|
||||||
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
@ -1,20 +1,31 @@
|
|||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const actions = require('../../actions')
|
const actions = require('../../actions')
|
||||||
const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu')
|
const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu')
|
||||||
const Identicon = require('../identicon')
|
const Identicon = require('../identicon')
|
||||||
const { formatBalance } = require('../../util')
|
const { formatBalance } = require('../../util')
|
||||||
|
const {
|
||||||
|
SETTINGS_ROUTE,
|
||||||
|
INFO_ROUTE,
|
||||||
|
NEW_ACCOUNT_ROUTE,
|
||||||
|
IMPORT_ACCOUNT_ROUTE,
|
||||||
|
DEFAULT_ROUTE,
|
||||||
|
} = require('../../routes')
|
||||||
|
|
||||||
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(AccountMenu)
|
||||||
|
|
||||||
AccountMenu.contextTypes = {
|
AccountMenu.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu)
|
|
||||||
|
|
||||||
|
|
||||||
inherits(AccountMenu, Component)
|
inherits(AccountMenu, Component)
|
||||||
function AccountMenu () { Component.call(this) }
|
function AccountMenu () { Component.call(this) }
|
||||||
|
|
||||||
@ -25,7 +36,6 @@ function mapStateToProps (state) {
|
|||||||
keyrings: state.metamask.keyrings,
|
keyrings: state.metamask.keyrings,
|
||||||
identities: state.metamask.identities,
|
identities: state.metamask.identities,
|
||||||
accounts: state.metamask.accounts,
|
accounts: state.metamask.accounts,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,11 +58,6 @@ function mapDispatchToProps (dispatch) {
|
|||||||
dispatch(actions.hideSidebar())
|
dispatch(actions.hideSidebar())
|
||||||
dispatch(actions.toggleAccountMenu())
|
dispatch(actions.toggleAccountMenu())
|
||||||
},
|
},
|
||||||
showNewAccountPage: (formToSelect) => {
|
|
||||||
dispatch(actions.showNewAccountPage(formToSelect))
|
|
||||||
dispatch(actions.hideSidebar())
|
|
||||||
dispatch(actions.toggleAccountMenu())
|
|
||||||
},
|
|
||||||
showInfoPage: () => {
|
showInfoPage: () => {
|
||||||
dispatch(actions.showInfoPage())
|
dispatch(actions.showInfoPage())
|
||||||
dispatch(actions.hideSidebar())
|
dispatch(actions.hideSidebar())
|
||||||
@ -65,10 +70,8 @@ AccountMenu.prototype.render = function () {
|
|||||||
const {
|
const {
|
||||||
isAccountMenuOpen,
|
isAccountMenuOpen,
|
||||||
toggleAccountMenu,
|
toggleAccountMenu,
|
||||||
showNewAccountPage,
|
|
||||||
lockMetamask,
|
lockMetamask,
|
||||||
showConfigPage,
|
history,
|
||||||
showInfoPage,
|
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
return h(Menu, { className: 'account-menu', isShowing: isAccountMenuOpen }, [
|
return h(Menu, { className: 'account-menu', isShowing: isAccountMenuOpen }, [
|
||||||
@ -78,30 +81,45 @@ AccountMenu.prototype.render = function () {
|
|||||||
}, [
|
}, [
|
||||||
this.context.t('myAccounts'),
|
this.context.t('myAccounts'),
|
||||||
h('button.account-menu__logout-button', {
|
h('button.account-menu__logout-button', {
|
||||||
onClick: lockMetamask,
|
onClick: () => {
|
||||||
|
lockMetamask()
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
|
},
|
||||||
}, this.context.t('logout')),
|
}, this.context.t('logout')),
|
||||||
]),
|
]),
|
||||||
h(Divider),
|
h(Divider),
|
||||||
h('div.account-menu__accounts', this.renderAccounts()),
|
h('div.account-menu__accounts', this.renderAccounts()),
|
||||||
h(Divider),
|
h(Divider),
|
||||||
h(Item, {
|
h(Item, {
|
||||||
onClick: () => showNewAccountPage('CREATE'),
|
onClick: () => {
|
||||||
|
toggleAccountMenu()
|
||||||
|
history.push(NEW_ACCOUNT_ROUTE)
|
||||||
|
},
|
||||||
icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }),
|
icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }),
|
||||||
text: this.context.t('createAccount'),
|
text: this.context.t('createAccount'),
|
||||||
}),
|
}),
|
||||||
h(Item, {
|
h(Item, {
|
||||||
onClick: () => showNewAccountPage('IMPORT'),
|
onClick: () => {
|
||||||
|
toggleAccountMenu()
|
||||||
|
history.push(IMPORT_ACCOUNT_ROUTE)
|
||||||
|
},
|
||||||
icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }),
|
icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }),
|
||||||
text: this.context.t('importAccount'),
|
text: this.context.t('importAccount'),
|
||||||
}),
|
}),
|
||||||
h(Divider),
|
h(Divider),
|
||||||
h(Item, {
|
h(Item, {
|
||||||
onClick: showInfoPage,
|
onClick: () => {
|
||||||
|
toggleAccountMenu()
|
||||||
|
history.push(INFO_ROUTE)
|
||||||
|
},
|
||||||
icon: h('img', { src: 'images/mm-info-icon.svg' }),
|
icon: h('img', { src: 'images/mm-info-icon.svg' }),
|
||||||
text: this.context.t('infoHelp'),
|
text: this.context.t('infoHelp'),
|
||||||
}),
|
}),
|
||||||
h(Item, {
|
h(Item, {
|
||||||
onClick: showConfigPage,
|
onClick: () => {
|
||||||
|
toggleAccountMenu()
|
||||||
|
history.push(SETTINGS_ROUTE)
|
||||||
|
},
|
||||||
icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }),
|
icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }),
|
||||||
text: this.context.t('settings'),
|
text: this.context.t('settings'),
|
||||||
}),
|
}),
|
||||||
|
@ -7,8 +7,8 @@ const connect = require('react-redux').connect
|
|||||||
const R = require('ramda')
|
const R = require('ramda')
|
||||||
const Fuse = require('fuse.js')
|
const Fuse = require('fuse.js')
|
||||||
const contractMap = require('eth-contract-metadata')
|
const contractMap = require('eth-contract-metadata')
|
||||||
const TokenBalance = require('./components/token-balance')
|
const TokenBalance = require('../../components/token-balance')
|
||||||
const Identicon = require('./components/identicon')
|
const Identicon = require('../../components/identicon')
|
||||||
const contractList = Object.entries(contractMap)
|
const contractList = Object.entries(contractMap)
|
||||||
.map(([ _, tokenData]) => tokenData)
|
.map(([ _, tokenData]) => tokenData)
|
||||||
.filter(tokenData => Boolean(tokenData.erc20))
|
.filter(tokenData => Boolean(tokenData.erc20))
|
||||||
@ -24,9 +24,10 @@ const fuse = new Fuse(contractList, {
|
|||||||
{ name: 'symbol', weight: 0.5 },
|
{ name: 'symbol', weight: 0.5 },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
const actions = require('./actions')
|
const actions = require('../../actions')
|
||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
const { tokenInfoGetter } = require('./token-util')
|
const { tokenInfoGetter } = require('../../token-util')
|
||||||
|
const { DEFAULT_ROUTE } = require('../../routes')
|
||||||
|
|
||||||
const emptyAddr = '0x0000000000000000000000000000000000000000'
|
const emptyAddr = '0x0000000000000000000000000000000000000000'
|
||||||
|
|
||||||
@ -47,7 +48,6 @@ function mapStateToProps (state) {
|
|||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
function mapDispatchToProps (dispatch) {
|
||||||
return {
|
return {
|
||||||
goHome: () => dispatch(actions.goHome()),
|
|
||||||
addTokens: tokens => dispatch(actions.addTokens(tokens)),
|
addTokens: tokens => dispatch(actions.addTokens(tokens)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,7 +296,7 @@ AddTokenScreen.prototype.renderConfirmation = function () {
|
|||||||
selectedTokens,
|
selectedTokens,
|
||||||
} = this.state
|
} = this.state
|
||||||
|
|
||||||
const { addTokens, goHome } = this.props
|
const { addTokens, history } = this.props
|
||||||
|
|
||||||
const customToken = {
|
const customToken = {
|
||||||
address,
|
address,
|
||||||
@ -333,7 +333,7 @@ AddTokenScreen.prototype.renderConfirmation = function () {
|
|||||||
onClick: () => this.setState({ isShowingConfirmation: false }),
|
onClick: () => this.setState({ isShowingConfirmation: false }),
|
||||||
}, this.context.t('back')),
|
}, this.context.t('back')),
|
||||||
h('button.btn-primary--lg', {
|
h('button.btn-primary--lg', {
|
||||||
onClick: () => addTokens(tokens).then(goHome),
|
onClick: () => addTokens(tokens).then(() => history.push(DEFAULT_ROUTE)),
|
||||||
}, this.context.t('addTokens')),
|
}, this.context.t('addTokens')),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
@ -382,12 +382,12 @@ AddTokenScreen.prototype.render = function () {
|
|||||||
isShowingConfirmation,
|
isShowingConfirmation,
|
||||||
displayedTab,
|
displayedTab,
|
||||||
} = this.state
|
} = this.state
|
||||||
const { goHome } = this.props
|
const { history } = this.props
|
||||||
|
|
||||||
return h('div.add-token', [
|
return h('div.add-token', [
|
||||||
h('div.add-token__header', [
|
h('div.add-token__header', [
|
||||||
h('div.add-token__header__cancel', {
|
h('div.add-token__header__cancel', {
|
||||||
onClick: () => goHome(),
|
onClick: () => history.push(DEFAULT_ROUTE),
|
||||||
}, [
|
}, [
|
||||||
h('i.fa.fa-angle-left.fa-lg'),
|
h('i.fa.fa-angle-left.fa-lg'),
|
||||||
h('span', this.context.t('cancel')),
|
h('span', this.context.t('cancel')),
|
||||||
@ -414,14 +414,14 @@ AddTokenScreen.prototype.render = function () {
|
|||||||
|
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
//
|
|
||||||
isShowingConfirmation
|
isShowingConfirmation
|
||||||
? this.renderConfirmation()
|
? this.renderConfirmation()
|
||||||
: this.renderTabs(),
|
: this.renderTabs(),
|
||||||
|
|
||||||
!isShowingConfirmation && h('div.add-token__buttons', [
|
!isShowingConfirmation && h('div.add-token__buttons', [
|
||||||
h('button.btn-secondary--lg.add-token__cancel-button', {
|
h('button.btn-secondary--lg.add-token__cancel-button', {
|
||||||
onClick: goHome,
|
onClick: () => history.push(DEFAULT_ROUTE),
|
||||||
}, this.context.t('cancel')),
|
}, this.context.t('cancel')),
|
||||||
h('button.btn-primary--lg.add-token__confirm-button', {
|
h('button.btn-primary--lg.add-token__confirm-button', {
|
||||||
onClick: this.onNext,
|
onClick: this.onNext,
|
34
ui/app/components/pages/authenticated.js
Normal file
34
ui/app/components/pages/authenticated.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const { connect } = require('react-redux')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const { Redirect } = require('react-router-dom')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const MetamaskRoute = require('./metamask-route')
|
||||||
|
const { UNLOCK_ROUTE, INITIALIZE_ROUTE } = require('../../routes')
|
||||||
|
|
||||||
|
const Authenticated = props => {
|
||||||
|
const { isUnlocked, isInitialized } = props
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case isUnlocked && isInitialized:
|
||||||
|
return h(MetamaskRoute, { ...props })
|
||||||
|
case !isInitialized:
|
||||||
|
return h(Redirect, { to: { pathname: INITIALIZE_ROUTE } })
|
||||||
|
default:
|
||||||
|
return h(Redirect, { to: { pathname: UNLOCK_ROUTE } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Authenticated.propTypes = {
|
||||||
|
isUnlocked: PropTypes.bool,
|
||||||
|
isInitialized: PropTypes.bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const { metamask: { isUnlocked, isInitialized } } = state
|
||||||
|
return {
|
||||||
|
isUnlocked,
|
||||||
|
isInitialized,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps)(Authenticated)
|
@ -1,11 +1,12 @@
|
|||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const actions = require('../../actions')
|
const actions = require('../../../../actions')
|
||||||
const FileInput = require('react-simple-file-input').default
|
const FileInput = require('react-simple-file-input').default
|
||||||
|
const { DEFAULT_ROUTE } = require('../../../../routes')
|
||||||
|
|
||||||
const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts'
|
const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts'
|
||||||
|
|
||||||
class JsonImportSubview extends Component {
|
class JsonImportSubview extends Component {
|
||||||
@ -51,7 +52,7 @@ class JsonImportSubview extends Component {
|
|||||||
h('div.new-account-create-form__buttons', {}, [
|
h('div.new-account-create-form__buttons', {}, [
|
||||||
|
|
||||||
h('button.btn-secondary.new-account-create-form__button', {
|
h('button.btn-secondary.new-account-create-form__button', {
|
||||||
onClick: () => this.props.goHome(),
|
onClick: () => this.props.history.push(DEFAULT_ROUTE),
|
||||||
}, [
|
}, [
|
||||||
this.context.t('cancel'),
|
this.context.t('cancel'),
|
||||||
]),
|
]),
|
||||||
@ -112,6 +113,7 @@ JsonImportSubview.propTypes = {
|
|||||||
goHome: PropTypes.func,
|
goHome: PropTypes.func,
|
||||||
displayWarning: PropTypes.func,
|
displayWarning: PropTypes.func,
|
||||||
importNewJsonAccount: PropTypes.func,
|
importNewJsonAccount: PropTypes.func,
|
||||||
|
history: PropTypes.object,
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,5 +135,7 @@ JsonImportSubview.contextTypes = {
|
|||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(JsonImportSubview)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(JsonImportSubview)
|
@ -1,15 +1,21 @@
|
|||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const actions = require('../../actions')
|
const actions = require('../../../../actions')
|
||||||
|
const { DEFAULT_ROUTE } = require('../../../../routes')
|
||||||
|
|
||||||
PrivateKeyImportView.contextTypes = {
|
PrivateKeyImportView.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(PrivateKeyImportView)
|
||||||
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
@ -20,9 +26,8 @@ function mapStateToProps (state) {
|
|||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
function mapDispatchToProps (dispatch) {
|
||||||
return {
|
return {
|
||||||
goHome: () => dispatch(actions.goHome()),
|
|
||||||
importNewAccount: (strategy, [ privateKey ]) => {
|
importNewAccount: (strategy, [ privateKey ]) => {
|
||||||
dispatch(actions.importNewAccount(strategy, [ privateKey ]))
|
return dispatch(actions.importNewAccount(strategy, [ privateKey ]))
|
||||||
},
|
},
|
||||||
displayWarning: () => dispatch(actions.displayWarning(null)),
|
displayWarning: () => dispatch(actions.displayWarning(null)),
|
||||||
}
|
}
|
||||||
@ -35,7 +40,7 @@ function PrivateKeyImportView () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PrivateKeyImportView.prototype.render = function () {
|
PrivateKeyImportView.prototype.render = function () {
|
||||||
const { error, goHome } = this.props
|
const { error } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
h('div.new-account-import-form__private-key', [
|
h('div.new-account-import-form__private-key', [
|
||||||
@ -55,7 +60,7 @@ PrivateKeyImportView.prototype.render = function () {
|
|||||||
h('div.new-account-import-form__buttons', {}, [
|
h('div.new-account-import-form__buttons', {}, [
|
||||||
|
|
||||||
h('button.btn-secondary--lg.new-account-create-form__button', {
|
h('button.btn-secondary--lg.new-account-create-form__button', {
|
||||||
onClick: () => goHome(),
|
onClick: () => this.props.history.push(DEFAULT_ROUTE),
|
||||||
}, [
|
}, [
|
||||||
this.context.t('cancel'),
|
this.context.t('cancel'),
|
||||||
]),
|
]),
|
||||||
@ -83,6 +88,8 @@ PrivateKeyImportView.prototype.createKeyringOnEnter = function (event) {
|
|||||||
PrivateKeyImportView.prototype.createNewKeychain = function () {
|
PrivateKeyImportView.prototype.createNewKeychain = function () {
|
||||||
const input = document.getElementById('private-key-box')
|
const input = document.getElementById('private-key-box')
|
||||||
const privateKey = input.value
|
const privateKey = input.value
|
||||||
|
const { importNewAccount, history } = this.props
|
||||||
|
|
||||||
this.props.importNewAccount('Private Key', [ privateKey ])
|
importNewAccount('Private Key', [ privateKey ])
|
||||||
|
.then(() => history.push(DEFAULT_ROUTE))
|
||||||
}
|
}
|
81
ui/app/components/pages/create-account/index.js
Normal file
81
ui/app/components/pages/create-account/index.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
const Component = require('react').Component
|
||||||
|
const { Switch, Route, matchPath } = require('react-router-dom')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const connect = require('react-redux').connect
|
||||||
|
const actions = require('../../../actions')
|
||||||
|
const { getCurrentViewContext } = require('../../../selectors')
|
||||||
|
const classnames = require('classnames')
|
||||||
|
const NewAccountCreateForm = require('./new-account')
|
||||||
|
const NewAccountImportForm = require('./import-account')
|
||||||
|
const { NEW_ACCOUNT_ROUTE, IMPORT_ACCOUNT_ROUTE } = require('../../../routes')
|
||||||
|
|
||||||
|
class CreateAccountPage extends Component {
|
||||||
|
renderTabs () {
|
||||||
|
const { history, location } = this.props
|
||||||
|
|
||||||
|
return h('div.new-account__tabs', [
|
||||||
|
h('div.new-account__tabs__tab', {
|
||||||
|
className: classnames('new-account__tabs__tab', {
|
||||||
|
'new-account__tabs__selected': matchPath(location.pathname, {
|
||||||
|
path: NEW_ACCOUNT_ROUTE, exact: true,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
onClick: () => history.push(NEW_ACCOUNT_ROUTE),
|
||||||
|
}, 'Create'),
|
||||||
|
|
||||||
|
h('div.new-account__tabs__tab', {
|
||||||
|
className: classnames('new-account__tabs__tab', {
|
||||||
|
'new-account__tabs__selected': matchPath(location.pathname, {
|
||||||
|
path: IMPORT_ACCOUNT_ROUTE, exact: true,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
onClick: () => history.push(IMPORT_ACCOUNT_ROUTE),
|
||||||
|
}, 'Import'),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return h('div.new-account', {}, [
|
||||||
|
h('div.new-account__header', [
|
||||||
|
h('div.new-account__title', 'New Account'),
|
||||||
|
this.renderTabs(),
|
||||||
|
]),
|
||||||
|
h('div.new-account__form', [
|
||||||
|
h(Switch, [
|
||||||
|
h(Route, {
|
||||||
|
exact: true,
|
||||||
|
path: NEW_ACCOUNT_ROUTE,
|
||||||
|
component: NewAccountCreateForm,
|
||||||
|
}),
|
||||||
|
h(Route, {
|
||||||
|
exact: true,
|
||||||
|
path: IMPORT_ACCOUNT_ROUTE,
|
||||||
|
component: NewAccountImportForm,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateAccountPage.propTypes = {
|
||||||
|
location: PropTypes.object,
|
||||||
|
history: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
displayedForm: getCurrentViewContext(state),
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
displayForm: form => dispatch(actions.setNewAccountForm(form)),
|
||||||
|
showQrView: (selected, identity) => dispatch(actions.showQrView(selected, identity)),
|
||||||
|
showExportPrivateKeyModal: () => {
|
||||||
|
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
|
||||||
|
},
|
||||||
|
hideModal: () => dispatch(actions.hideModal()),
|
||||||
|
saveAccountLabel: (address, label) => dispatch(actions.saveAccountLabel(address, label)),
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps, mapDispatchToProps)(CreateAccountPage)
|
@ -2,7 +2,8 @@ const { Component } = require('react')
|
|||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const actions = require('../../actions')
|
const actions = require('../../../actions')
|
||||||
|
const { DEFAULT_ROUTE } = require('../../../routes')
|
||||||
|
|
||||||
class NewAccountCreateForm extends Component {
|
class NewAccountCreateForm extends Component {
|
||||||
constructor (props, context) {
|
constructor (props, context) {
|
||||||
@ -19,7 +20,7 @@ class NewAccountCreateForm extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { newAccountName, defaultAccountName } = this.state
|
const { newAccountName, defaultAccountName } = this.state
|
||||||
|
const { history, createAccount } = this.props
|
||||||
|
|
||||||
return h('div.new-account-create-form', [
|
return h('div.new-account-create-form', [
|
||||||
|
|
||||||
@ -38,13 +39,16 @@ class NewAccountCreateForm extends Component {
|
|||||||
h('div.new-account-create-form__buttons', {}, [
|
h('div.new-account-create-form__buttons', {}, [
|
||||||
|
|
||||||
h('button.btn-secondary--lg.new-account-create-form__button', {
|
h('button.btn-secondary--lg.new-account-create-form__button', {
|
||||||
onClick: () => this.props.goHome(),
|
onClick: () => history.push(DEFAULT_ROUTE),
|
||||||
}, [
|
}, [
|
||||||
this.context.t('cancel'),
|
this.context.t('cancel'),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
h('button.btn-primary--lg.new-account-create-form__button', {
|
h('button.btn-primary--lg.new-account-create-form__button', {
|
||||||
onClick: () => this.props.createAccount(newAccountName || defaultAccountName),
|
onClick: () => {
|
||||||
|
createAccount(newAccountName || defaultAccountName)
|
||||||
|
.then(() => history.push(DEFAULT_ROUTE))
|
||||||
|
},
|
||||||
}, [
|
}, [
|
||||||
this.context.t('create'),
|
this.context.t('create'),
|
||||||
]),
|
]),
|
||||||
@ -59,8 +63,8 @@ NewAccountCreateForm.propTypes = {
|
|||||||
hideModal: PropTypes.func,
|
hideModal: PropTypes.func,
|
||||||
showImportPage: PropTypes.func,
|
showImportPage: PropTypes.func,
|
||||||
createAccount: PropTypes.func,
|
createAccount: PropTypes.func,
|
||||||
goHome: PropTypes.func,
|
|
||||||
numberOfExistingAccounts: PropTypes.number,
|
numberOfExistingAccounts: PropTypes.number,
|
||||||
|
history: PropTypes.object,
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,23 +81,17 @@ const mapStateToProps = state => {
|
|||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
toCoinbase: (address) => {
|
toCoinbase: address => dispatch(actions.buyEth({ network: '1', address, amount: 0 })),
|
||||||
dispatch(actions.buyEth({ network: '1', address, amount: 0 }))
|
hideModal: () => dispatch(actions.hideModal()),
|
||||||
},
|
createAccount: newAccountName => {
|
||||||
hideModal: () => {
|
return dispatch(actions.addNewAccount())
|
||||||
dispatch(actions.hideModal())
|
.then(newAccountAddress => {
|
||||||
},
|
|
||||||
createAccount: (newAccountName) => {
|
|
||||||
dispatch(actions.addNewAccount())
|
|
||||||
.then((newAccountAddress) => {
|
|
||||||
if (newAccountName) {
|
if (newAccountName) {
|
||||||
dispatch(actions.saveAccountLabel(newAccountAddress, newAccountName))
|
dispatch(actions.saveAccountLabel(newAccountAddress, newAccountName))
|
||||||
}
|
}
|
||||||
dispatch(actions.goHome())
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
showImportPage: () => dispatch(actions.showImportPage()),
|
showImportPage: () => dispatch(actions.showImportPage()),
|
||||||
goHome: () => dispatch(actions.goHome()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
332
ui/app/components/pages/home.js
Normal file
332
ui/app/components/pages/home.js
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
const { Component } = require('react')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const connect = require('../../metamask-connect')
|
||||||
|
const { Redirect, withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const actions = require('../../actions')
|
||||||
|
|
||||||
|
// init
|
||||||
|
const NewKeyChainScreen = require('../../new-keychain')
|
||||||
|
// mascara
|
||||||
|
const MascaraBuyEtherScreen = require('../../../../mascara/src/app/first-time/buy-ether-screen').default
|
||||||
|
|
||||||
|
// accounts
|
||||||
|
const MainContainer = require('../../main-container')
|
||||||
|
|
||||||
|
// other views
|
||||||
|
const BuyView = require('../../components/buy-button-subview')
|
||||||
|
const QrView = require('../../components/qr-code')
|
||||||
|
|
||||||
|
// Routes
|
||||||
|
const {
|
||||||
|
REVEAL_SEED_ROUTE,
|
||||||
|
RESTORE_VAULT_ROUTE,
|
||||||
|
CONFIRM_TRANSACTION_ROUTE,
|
||||||
|
NOTICE_ROUTE,
|
||||||
|
} = require('../../routes')
|
||||||
|
|
||||||
|
class Home extends Component {
|
||||||
|
componentDidMount () {
|
||||||
|
const {
|
||||||
|
history,
|
||||||
|
unapprovedTxs = {},
|
||||||
|
unapprovedMsgCount = 0,
|
||||||
|
unapprovedPersonalMsgCount = 0,
|
||||||
|
unapprovedTypedMessagesCount = 0,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
// unapprovedTxs and unapproved messages
|
||||||
|
if (Object.keys(unapprovedTxs).length ||
|
||||||
|
unapprovedTypedMessagesCount + unapprovedMsgCount + unapprovedPersonalMsgCount > 0) {
|
||||||
|
history.push(CONFIRM_TRANSACTION_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
log.debug('rendering primary')
|
||||||
|
const {
|
||||||
|
noActiveNotices,
|
||||||
|
lostAccounts,
|
||||||
|
forgottenPassword,
|
||||||
|
currentView,
|
||||||
|
activeAddress,
|
||||||
|
seedWords,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
// notices
|
||||||
|
if (!noActiveNotices || (lostAccounts && lostAccounts.length > 0)) {
|
||||||
|
return h(Redirect, {
|
||||||
|
to: {
|
||||||
|
pathname: NOTICE_ROUTE,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// seed words
|
||||||
|
if (seedWords) {
|
||||||
|
log.debug('rendering seed words')
|
||||||
|
return h(Redirect, {
|
||||||
|
to: {
|
||||||
|
pathname: REVEAL_SEED_ROUTE,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forgottenPassword) {
|
||||||
|
log.debug('rendering restore vault screen')
|
||||||
|
return h(Redirect, {
|
||||||
|
to: {
|
||||||
|
pathname: RESTORE_VAULT_ROUTE,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!props.noActiveNotices) {
|
||||||
|
// log.debug('rendering notice screen for unread notices.')
|
||||||
|
// return h(NoticeScreen, {
|
||||||
|
// notice: props.lastUnreadNotice,
|
||||||
|
// key: 'NoticeScreen',
|
||||||
|
// onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)),
|
||||||
|
// })
|
||||||
|
// } else if (props.lostAccounts && props.lostAccounts.length > 0) {
|
||||||
|
// log.debug('rendering notice screen for lost accounts view.')
|
||||||
|
// return h(NoticeScreen, {
|
||||||
|
// notice: generateLostAccountsNotice(props.lostAccounts),
|
||||||
|
// key: 'LostAccountsNotice',
|
||||||
|
// onConfirm: () => props.dispatch(actions.markAccountsFound()),
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (props.seedWords) {
|
||||||
|
// log.debug('rendering seed words')
|
||||||
|
// return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'})
|
||||||
|
// }
|
||||||
|
|
||||||
|
// show initialize screen
|
||||||
|
// if (!isInitialized || forgottenPassword) {
|
||||||
|
// // show current view
|
||||||
|
// log.debug('rendering an initialize screen')
|
||||||
|
// // switch (props.currentView.name) {
|
||||||
|
|
||||||
|
// // case 'restoreVault':
|
||||||
|
// // log.debug('rendering restore vault screen')
|
||||||
|
// // return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
|
||||||
|
|
||||||
|
// // default:
|
||||||
|
// // log.debug('rendering menu screen')
|
||||||
|
// // return h(InitializeScreen, {key: 'menuScreenInit'})
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // show unlock screen
|
||||||
|
// if (!props.isUnlocked) {
|
||||||
|
// return h(MainContainer, {
|
||||||
|
// currentViewName: props.currentView.name,
|
||||||
|
// isUnlocked: props.isUnlocked,
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// show current view
|
||||||
|
switch (currentView.name) {
|
||||||
|
|
||||||
|
case 'accountDetail':
|
||||||
|
log.debug('rendering main container')
|
||||||
|
return h(MainContainer, {key: 'account-detail'})
|
||||||
|
|
||||||
|
// case 'sendTransaction':
|
||||||
|
// log.debug('rendering send tx screen')
|
||||||
|
|
||||||
|
// // Going to leave this here until we are ready to delete SendTransactionScreen v1
|
||||||
|
// // const SendComponentToRender = checkFeatureToggle('send-v2')
|
||||||
|
// // ? SendTransactionScreen2
|
||||||
|
// // : SendTransactionScreen
|
||||||
|
|
||||||
|
// return h(SendTransactionScreen2, {key: 'send-transaction'})
|
||||||
|
|
||||||
|
// case 'sendToken':
|
||||||
|
// log.debug('rendering send token screen')
|
||||||
|
|
||||||
|
// // Going to leave this here until we are ready to delete SendTransactionScreen v1
|
||||||
|
// // const SendTokenComponentToRender = checkFeatureToggle('send-v2')
|
||||||
|
// // ? SendTransactionScreen2
|
||||||
|
// // : SendTokenScreen
|
||||||
|
|
||||||
|
// return h(SendTransactionScreen2, {key: 'sendToken'})
|
||||||
|
|
||||||
|
case 'newKeychain':
|
||||||
|
log.debug('rendering new keychain screen')
|
||||||
|
return h(NewKeyChainScreen, {key: 'new-keychain'})
|
||||||
|
|
||||||
|
// case 'confTx':
|
||||||
|
// log.debug('rendering confirm tx screen')
|
||||||
|
// return h(Redirect, {
|
||||||
|
// to: {
|
||||||
|
// pathname: CONFIRM_TRANSACTION_ROUTE,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// return h(ConfirmTxScreen, {key: 'confirm-tx'})
|
||||||
|
|
||||||
|
// case 'add-token':
|
||||||
|
// log.debug('rendering add-token screen from unlock screen.')
|
||||||
|
// return h(AddTokenScreen, {key: 'add-token'})
|
||||||
|
|
||||||
|
// case 'config':
|
||||||
|
// log.debug('rendering config screen')
|
||||||
|
// return h(Settings, {key: 'config'})
|
||||||
|
|
||||||
|
// case 'import-menu':
|
||||||
|
// log.debug('rendering import screen')
|
||||||
|
// return h(Import, {key: 'import-menu'})
|
||||||
|
|
||||||
|
// case 'reveal-seed-conf':
|
||||||
|
// log.debug('rendering reveal seed confirmation screen')
|
||||||
|
// return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'})
|
||||||
|
|
||||||
|
// case 'info':
|
||||||
|
// log.debug('rendering info screen')
|
||||||
|
// return h(Settings, {key: 'info', tab: 'info'})
|
||||||
|
|
||||||
|
case 'buyEth':
|
||||||
|
log.debug('rendering buy ether screen')
|
||||||
|
return h(BuyView, {key: 'buyEthView'})
|
||||||
|
|
||||||
|
case 'onboardingBuyEth':
|
||||||
|
log.debug('rendering onboarding buy ether screen')
|
||||||
|
return h(MascaraBuyEtherScreen, {key: 'buyEthView'})
|
||||||
|
|
||||||
|
case 'qr':
|
||||||
|
log.debug('rendering show qr screen')
|
||||||
|
return h('div', {
|
||||||
|
style: {
|
||||||
|
position: 'absolute',
|
||||||
|
height: '100%',
|
||||||
|
top: '0px',
|
||||||
|
left: '0px',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
|
||||||
|
onClick: () => this.props.dispatch(actions.backToAccountDetail(activeAddress)),
|
||||||
|
style: {
|
||||||
|
marginLeft: '10px',
|
||||||
|
marginTop: '50px',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h('div', {
|
||||||
|
style: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: '44px',
|
||||||
|
width: '285px',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
h(QrView, {key: 'qr'}),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.debug('rendering default, account detail screen')
|
||||||
|
return h(MainContainer, {key: 'account-detail'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Home.propTypes = {
|
||||||
|
currentCurrency: PropTypes.string,
|
||||||
|
isLoading: PropTypes.bool,
|
||||||
|
loadingMessage: PropTypes.string,
|
||||||
|
network: PropTypes.string,
|
||||||
|
provider: PropTypes.object,
|
||||||
|
frequentRpcList: PropTypes.array,
|
||||||
|
currentView: PropTypes.object,
|
||||||
|
sidebarOpen: PropTypes.bool,
|
||||||
|
isMascara: PropTypes.bool,
|
||||||
|
isOnboarding: PropTypes.bool,
|
||||||
|
isUnlocked: PropTypes.bool,
|
||||||
|
networkDropdownOpen: PropTypes.bool,
|
||||||
|
history: PropTypes.object,
|
||||||
|
dispatch: PropTypes.func,
|
||||||
|
selectedAddress: PropTypes.string,
|
||||||
|
noActiveNotices: PropTypes.bool,
|
||||||
|
lostAccounts: PropTypes.array,
|
||||||
|
isInitialized: PropTypes.bool,
|
||||||
|
forgottenPassword: PropTypes.bool,
|
||||||
|
activeAddress: PropTypes.string,
|
||||||
|
unapprovedTxs: PropTypes.object,
|
||||||
|
seedWords: PropTypes.string,
|
||||||
|
unapprovedMsgCount: PropTypes.number,
|
||||||
|
unapprovedPersonalMsgCount: PropTypes.number,
|
||||||
|
unapprovedTypedMessagesCount: PropTypes.number,
|
||||||
|
welcomeScreenSeen: PropTypes.bool,
|
||||||
|
isPopup: PropTypes.bool,
|
||||||
|
isMouseUser: PropTypes.bool,
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
const { appState, metamask } = state
|
||||||
|
const {
|
||||||
|
networkDropdownOpen,
|
||||||
|
sidebarOpen,
|
||||||
|
isLoading,
|
||||||
|
loadingMessage,
|
||||||
|
} = appState
|
||||||
|
|
||||||
|
const {
|
||||||
|
accounts,
|
||||||
|
address,
|
||||||
|
isInitialized,
|
||||||
|
noActiveNotices,
|
||||||
|
seedWords,
|
||||||
|
unapprovedTxs,
|
||||||
|
lastUnreadNotice,
|
||||||
|
lostAccounts,
|
||||||
|
unapprovedMsgCount,
|
||||||
|
unapprovedPersonalMsgCount,
|
||||||
|
unapprovedTypedMessagesCount,
|
||||||
|
} = metamask
|
||||||
|
const selected = address || Object.keys(accounts)[0]
|
||||||
|
|
||||||
|
return {
|
||||||
|
// state from plugin
|
||||||
|
networkDropdownOpen,
|
||||||
|
sidebarOpen,
|
||||||
|
isLoading,
|
||||||
|
loadingMessage,
|
||||||
|
noActiveNotices,
|
||||||
|
isInitialized,
|
||||||
|
isUnlocked: state.metamask.isUnlocked,
|
||||||
|
selectedAddress: state.metamask.selectedAddress,
|
||||||
|
currentView: state.appState.currentView,
|
||||||
|
activeAddress: state.appState.activeAddress,
|
||||||
|
transForward: state.appState.transForward,
|
||||||
|
isMascara: state.metamask.isMascara,
|
||||||
|
isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized),
|
||||||
|
isPopup: state.metamask.isPopup,
|
||||||
|
seedWords: state.metamask.seedWords,
|
||||||
|
unapprovedTxs,
|
||||||
|
unapprovedMsgs: state.metamask.unapprovedMsgs,
|
||||||
|
unapprovedMsgCount,
|
||||||
|
unapprovedPersonalMsgCount,
|
||||||
|
unapprovedTypedMessagesCount,
|
||||||
|
menuOpen: state.appState.menuOpen,
|
||||||
|
network: state.metamask.network,
|
||||||
|
provider: state.metamask.provider,
|
||||||
|
forgottenPassword: state.appState.forgottenPassword,
|
||||||
|
lastUnreadNotice,
|
||||||
|
lostAccounts,
|
||||||
|
frequentRpcList: state.metamask.frequentRpcList || [],
|
||||||
|
currentCurrency: state.metamask.currentCurrency,
|
||||||
|
isMouseUser: state.appState.isMouseUser,
|
||||||
|
isRevealingSeedWords: state.metamask.isRevealingSeedWords,
|
||||||
|
Qr: state.appState.Qr,
|
||||||
|
welcomeScreenSeen: state.metamask.welcomeScreenSeen,
|
||||||
|
|
||||||
|
// state needed to get account dropdown temporarily rendering from app bar
|
||||||
|
selected,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps)
|
||||||
|
)(Home)
|
25
ui/app/components/pages/initialized.js
Normal file
25
ui/app/components/pages/initialized.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const { connect } = require('react-redux')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const { Redirect } = require('react-router-dom')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const { INITIALIZE_ROUTE } = require('../../routes')
|
||||||
|
const MetamaskRoute = require('./metamask-route')
|
||||||
|
|
||||||
|
const Initialized = props => {
|
||||||
|
return props.isInitialized
|
||||||
|
? h(MetamaskRoute, { ...props })
|
||||||
|
: h(Redirect, { to: { pathname: INITIALIZE_ROUTE } })
|
||||||
|
}
|
||||||
|
|
||||||
|
Initialized.propTypes = {
|
||||||
|
isInitialized: PropTypes.bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const { metamask: { isInitialized } } = state
|
||||||
|
return {
|
||||||
|
isInitialized,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps)(Initialized)
|
177
ui/app/components/pages/keychains/restore-vault.js
Normal file
177
ui/app/components/pages/keychains/restore-vault.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
const PersistentForm = require('../../../../lib/persistent-form')
|
||||||
|
const connect = require('../../../metamask-connect')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const { createNewVaultAndRestore, unMarkPasswordForgotten } = require('../../../actions')
|
||||||
|
const { DEFAULT_ROUTE } = require('../../../routes')
|
||||||
|
|
||||||
|
class RestoreVaultPage extends PersistentForm {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
error: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createOnEnter (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
this.createNewVaultAndRestore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel () {
|
||||||
|
this.props.unMarkPasswordForgotten()
|
||||||
|
.then(this.props.history.push(DEFAULT_ROUTE))
|
||||||
|
}
|
||||||
|
|
||||||
|
createNewVaultAndRestore () {
|
||||||
|
this.setState({ error: null })
|
||||||
|
|
||||||
|
// check password
|
||||||
|
var passwordBox = document.getElementById('password-box')
|
||||||
|
var password = passwordBox.value
|
||||||
|
var passwordConfirmBox = document.getElementById('password-box-confirm')
|
||||||
|
var passwordConfirm = passwordConfirmBox.value
|
||||||
|
|
||||||
|
if (password.length < 8) {
|
||||||
|
this.setState({ error: 'Password not long enough' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password !== passwordConfirm) {
|
||||||
|
this.setState({ error: 'Passwords don\'t match' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check seed
|
||||||
|
var seedBox = document.querySelector('textarea.twelve-word-phrase')
|
||||||
|
var seed = seedBox.value.trim()
|
||||||
|
if (seed.split(' ').length !== 12) {
|
||||||
|
this.setState({ error: 'Seed phrases are 12 words long' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// submit
|
||||||
|
this.props.createNewVaultAndRestore(password, seed)
|
||||||
|
.then(() => this.props.history.push(DEFAULT_ROUTE))
|
||||||
|
.catch(({ message }) => {
|
||||||
|
this.setState({ error: message })
|
||||||
|
log.error(message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { error } = this.state
|
||||||
|
this.persistentFormParentId = 'restore-vault-form'
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('.initialize-screen.flex-column.flex-center.flex-grow', [
|
||||||
|
|
||||||
|
h('h3.flex-center.text-transform-uppercase', {
|
||||||
|
style: {
|
||||||
|
background: '#EBEBEB',
|
||||||
|
color: '#AEAEAE',
|
||||||
|
marginBottom: 24,
|
||||||
|
width: '100%',
|
||||||
|
fontSize: '20px',
|
||||||
|
padding: 6,
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
this.props.t('restoreVault'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
// wallet seed entry
|
||||||
|
h('h3', 'Wallet Seed'),
|
||||||
|
h('textarea.twelve-word-phrase.letter-spacey', {
|
||||||
|
dataset: {
|
||||||
|
persistentFormId: 'wallet-seed',
|
||||||
|
},
|
||||||
|
placeholder: this.props.t('secretPhrase'),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// password
|
||||||
|
h('input.large-input.letter-spacey', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box',
|
||||||
|
placeholder: this.props.t('newPassword8Chars'),
|
||||||
|
dataset: {
|
||||||
|
persistentFormId: 'password',
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
// confirm password
|
||||||
|
h('input.large-input.letter-spacey', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box-confirm',
|
||||||
|
placeholder: this.props.t('confirmPassword'),
|
||||||
|
onKeyPress: this.createOnEnter.bind(this),
|
||||||
|
dataset: {
|
||||||
|
persistentFormId: 'password-confirmation',
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
marginTop: 16,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
error && (
|
||||||
|
h('span.error.in-progress-notification', error)
|
||||||
|
),
|
||||||
|
|
||||||
|
// submit
|
||||||
|
h('.flex-row.flex-space-between', {
|
||||||
|
style: {
|
||||||
|
marginTop: 30,
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
|
||||||
|
// cancel
|
||||||
|
h('button.primary', {
|
||||||
|
onClick: () => this.cancel(),
|
||||||
|
}, this.props.t('cancel')),
|
||||||
|
|
||||||
|
// submit
|
||||||
|
h('button.primary', {
|
||||||
|
onClick: this.createNewVaultAndRestore.bind(this),
|
||||||
|
}, this.props.t('ok')),
|
||||||
|
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RestoreVaultPage.propTypes = {
|
||||||
|
history: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const { appState: { warning, forgottenPassword } } = state
|
||||||
|
|
||||||
|
return {
|
||||||
|
warning,
|
||||||
|
forgottenPassword,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
createNewVaultAndRestore: (password, seed) => {
|
||||||
|
return dispatch(createNewVaultAndRestore(password, seed))
|
||||||
|
},
|
||||||
|
unMarkPasswordForgotten: () => dispatch(unMarkPasswordForgotten()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(RestoreVaultPage)
|
195
ui/app/components/pages/keychains/reveal-seed.js
Normal file
195
ui/app/components/pages/keychains/reveal-seed.js
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
const { Component } = require('react')
|
||||||
|
const { connect } = require('react-redux')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const { exportAsFile } = require('../../../util')
|
||||||
|
const { requestRevealSeed, confirmSeedWords } = require('../../../actions')
|
||||||
|
const { DEFAULT_ROUTE } = require('../../../routes')
|
||||||
|
|
||||||
|
class RevealSeedPage extends Component {
|
||||||
|
componentDidMount () {
|
||||||
|
const passwordBox = document.getElementById('password-box')
|
||||||
|
if (passwordBox) {
|
||||||
|
passwordBox.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkConfirmation (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
event.preventDefault()
|
||||||
|
this.revealSeedWords()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
revealSeedWords () {
|
||||||
|
const password = document.getElementById('password-box').value
|
||||||
|
this.props.requestRevealSeed(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSeed () {
|
||||||
|
const { seedWords, confirmSeedWords, history } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('.initialize-screen.flex-column.flex-center.flex-grow', [
|
||||||
|
|
||||||
|
h('h3.flex-center.text-transform-uppercase', {
|
||||||
|
style: {
|
||||||
|
background: '#EBEBEB',
|
||||||
|
color: '#AEAEAE',
|
||||||
|
marginTop: 36,
|
||||||
|
marginBottom: 8,
|
||||||
|
width: '100%',
|
||||||
|
fontSize: '20px',
|
||||||
|
padding: 6,
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
'Vault Created',
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('div', {
|
||||||
|
style: {
|
||||||
|
fontSize: '1em',
|
||||||
|
marginTop: '10px',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
h('span.error', 'These 12 words are the only way to restore your MetaMask accounts.\nSave them somewhere safe and secret.'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('textarea.twelve-word-phrase', {
|
||||||
|
readOnly: true,
|
||||||
|
value: seedWords,
|
||||||
|
}),
|
||||||
|
|
||||||
|
h('button.primary', {
|
||||||
|
onClick: () => confirmSeedWords().then(() => history.push(DEFAULT_ROUTE)),
|
||||||
|
style: {
|
||||||
|
margin: '24px',
|
||||||
|
fontSize: '0.9em',
|
||||||
|
marginBottom: '10px',
|
||||||
|
},
|
||||||
|
}, 'I\'ve copied it somewhere safe'),
|
||||||
|
|
||||||
|
h('button.primary', {
|
||||||
|
onClick: () => exportAsFile(`MetaMask Seed Words`, seedWords),
|
||||||
|
style: {
|
||||||
|
margin: '10px',
|
||||||
|
fontSize: '0.9em',
|
||||||
|
},
|
||||||
|
}, 'Save Seed Words As File'),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderConfirmation () {
|
||||||
|
const { history, warning, inProgress } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('.initialize-screen.flex-column.flex-center.flex-grow', {
|
||||||
|
style: { maxWidth: '420px' },
|
||||||
|
}, [
|
||||||
|
|
||||||
|
h('h3.flex-center.text-transform-uppercase', {
|
||||||
|
style: {
|
||||||
|
background: '#EBEBEB',
|
||||||
|
color: '#AEAEAE',
|
||||||
|
marginBottom: 24,
|
||||||
|
width: '100%',
|
||||||
|
fontSize: '20px',
|
||||||
|
padding: 6,
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
'Reveal Seed Words',
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('.div', {
|
||||||
|
style: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: '20px',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
|
||||||
|
h('h4', 'Do not recover your seed words in a public place! These words can be used to steal all your accounts.'),
|
||||||
|
|
||||||
|
// confirmation
|
||||||
|
h('input.large-input.letter-spacey', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box',
|
||||||
|
placeholder: 'Enter your password to confirm',
|
||||||
|
onKeyPress: this.checkConfirmation.bind(this),
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
marginTop: '12px',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
h('.flex-row.flex-start', {
|
||||||
|
style: {
|
||||||
|
marginTop: 30,
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
// cancel
|
||||||
|
h('button.primary', {
|
||||||
|
onClick: () => history.push(DEFAULT_ROUTE),
|
||||||
|
}, 'CANCEL'),
|
||||||
|
|
||||||
|
// submit
|
||||||
|
h('button.primary', {
|
||||||
|
style: { marginLeft: '10px' },
|
||||||
|
onClick: this.revealSeedWords.bind(this),
|
||||||
|
}, 'OK'),
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
|
warning && (
|
||||||
|
h('span.error', {
|
||||||
|
style: {
|
||||||
|
margin: '20px',
|
||||||
|
},
|
||||||
|
}, warning.split('-'))
|
||||||
|
),
|
||||||
|
|
||||||
|
inProgress && (
|
||||||
|
h('span.in-progress-notification', 'Generating Seed...')
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return this.props.seedWords
|
||||||
|
? this.renderSeed()
|
||||||
|
: this.renderConfirmation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RevealSeedPage.propTypes = {
|
||||||
|
requestRevealSeed: PropTypes.func,
|
||||||
|
confirmSeedWords: PropTypes.func,
|
||||||
|
seedWords: PropTypes.string,
|
||||||
|
inProgress: PropTypes.bool,
|
||||||
|
history: PropTypes.object,
|
||||||
|
warning: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const { appState: { warning }, metamask: { seedWords } } = state
|
||||||
|
|
||||||
|
return {
|
||||||
|
warning,
|
||||||
|
seedWords,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
requestRevealSeed: password => dispatch(requestRevealSeed(password)),
|
||||||
|
confirmSeedWords: () => dispatch(confirmSeedWords()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps, mapDispatchToProps)(RevealSeedPage)
|
28
ui/app/components/pages/metamask-route.js
Normal file
28
ui/app/components/pages/metamask-route.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const { connect } = require('react-redux')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const { Route } = require('react-router-dom')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
|
||||||
|
const MetamaskRoute = ({ component, mascaraComponent, isMascara, ...props }) => {
|
||||||
|
return (
|
||||||
|
h(Route, {
|
||||||
|
...props,
|
||||||
|
component: isMascara && mascaraComponent ? mascaraComponent : component,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
MetamaskRoute.propTypes = {
|
||||||
|
component: PropTypes.func,
|
||||||
|
mascaraComponent: PropTypes.func,
|
||||||
|
isMascara: PropTypes.bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const { metamask: { isMascara } } = state
|
||||||
|
return {
|
||||||
|
isMascara,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps)(MetamaskRoute)
|
203
ui/app/components/pages/notice.js
Normal file
203
ui/app/components/pages/notice.js
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
const { Component } = require('react')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const { connect } = require('react-redux')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const ReactMarkdown = require('react-markdown')
|
||||||
|
const linker = require('extension-link-enabler')
|
||||||
|
const generateLostAccountsNotice = require('../../../lib/lost-accounts-notice')
|
||||||
|
const findDOMNode = require('react-dom').findDOMNode
|
||||||
|
const actions = require('../../actions')
|
||||||
|
const { DEFAULT_ROUTE } = require('../../routes')
|
||||||
|
|
||||||
|
class Notice extends Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
disclaimerDisabled: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
if (!this.props.notice) {
|
||||||
|
this.props.history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
// eslint-disable-next-line react/no-find-dom-node
|
||||||
|
var node = findDOMNode(this)
|
||||||
|
linker.setupListener(node)
|
||||||
|
if (document.getElementsByClassName('notice-box')[0].clientHeight < 310) {
|
||||||
|
this.setState({ disclaimerDisabled: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
if (!nextProps.notice) {
|
||||||
|
this.props.history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
// eslint-disable-next-line react/no-find-dom-node
|
||||||
|
var node = findDOMNode(this)
|
||||||
|
linker.teardownListener(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAccept () {
|
||||||
|
this.setState({ disclaimerDisabled: true })
|
||||||
|
this.props.onConfirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { notice = {} } = this.props
|
||||||
|
const { title, date, body } = notice
|
||||||
|
const { disclaimerDisabled } = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('.flex-column.flex-center.flex-grow', {
|
||||||
|
style: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
h('h3.flex-center.text-transform-uppercase.terms-header', {
|
||||||
|
style: {
|
||||||
|
background: '#EBEBEB',
|
||||||
|
color: '#AEAEAE',
|
||||||
|
width: '100%',
|
||||||
|
fontSize: '20px',
|
||||||
|
textAlign: 'center',
|
||||||
|
padding: 6,
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
title,
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('h5.flex-center.text-transform-uppercase.terms-header', {
|
||||||
|
style: {
|
||||||
|
background: '#EBEBEB',
|
||||||
|
color: '#AEAEAE',
|
||||||
|
marginBottom: 24,
|
||||||
|
width: '100%',
|
||||||
|
fontSize: '20px',
|
||||||
|
textAlign: 'center',
|
||||||
|
padding: 6,
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
date,
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('style', `
|
||||||
|
|
||||||
|
.markdown {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1, .markdown h2, .markdown h3 {
|
||||||
|
margin: 10px 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.markdown em {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown p {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown a {
|
||||||
|
color: #df6b0e;
|
||||||
|
}
|
||||||
|
|
||||||
|
`),
|
||||||
|
|
||||||
|
h('div.markdown', {
|
||||||
|
onScroll: (e) => {
|
||||||
|
var object = e.currentTarget
|
||||||
|
if (object.offsetHeight + object.scrollTop + 100 >= object.scrollHeight) {
|
||||||
|
this.setState({ disclaimerDisabled: false })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
background: 'rgb(235, 235, 235)',
|
||||||
|
height: '310px',
|
||||||
|
padding: '6px',
|
||||||
|
width: '90%',
|
||||||
|
overflowY: 'scroll',
|
||||||
|
scroll: 'auto',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
h(ReactMarkdown, {
|
||||||
|
className: 'notice-box',
|
||||||
|
source: body,
|
||||||
|
skipHtml: true,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('button.primary', {
|
||||||
|
disabled: disclaimerDisabled,
|
||||||
|
onClick: () => this.handleAccept(),
|
||||||
|
style: {
|
||||||
|
marginTop: '18px',
|
||||||
|
},
|
||||||
|
}, 'Accept'),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const { metamask } = state
|
||||||
|
const { noActiveNotices, lastUnreadNotice, lostAccounts } = metamask
|
||||||
|
|
||||||
|
return {
|
||||||
|
noActiveNotices,
|
||||||
|
lastUnreadNotice,
|
||||||
|
lostAccounts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Notice.propTypes = {
|
||||||
|
notice: PropTypes.object,
|
||||||
|
onConfirm: PropTypes.func,
|
||||||
|
history: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
markNoticeRead: lastUnreadNotice => dispatch(actions.markNoticeRead(lastUnreadNotice)),
|
||||||
|
markAccountsFound: () => dispatch(actions.markAccountsFound()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||||
|
const { noActiveNotices, lastUnreadNotice, lostAccounts } = stateProps
|
||||||
|
const { markNoticeRead, markAccountsFound } = dispatchProps
|
||||||
|
|
||||||
|
let notice
|
||||||
|
let onConfirm
|
||||||
|
|
||||||
|
if (!noActiveNotices) {
|
||||||
|
notice = lastUnreadNotice
|
||||||
|
onConfirm = () => markNoticeRead(lastUnreadNotice)
|
||||||
|
} else if (lostAccounts && lostAccounts.length > 0) {
|
||||||
|
notice = generateLostAccountsNotice(lostAccounts)
|
||||||
|
onConfirm = () => markAccountsFound()
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...stateProps,
|
||||||
|
...dispatchProps,
|
||||||
|
...ownProps,
|
||||||
|
notice,
|
||||||
|
onConfirm,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Notice)
|
59
ui/app/components/pages/settings/index.js
Normal file
59
ui/app/components/pages/settings/index.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const { Component } = require('react')
|
||||||
|
const { Switch, Route, matchPath } = require('react-router-dom')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const TabBar = require('../../tab-bar')
|
||||||
|
const Settings = require('./settings')
|
||||||
|
const Info = require('./info')
|
||||||
|
const { DEFAULT_ROUTE, SETTINGS_ROUTE, INFO_ROUTE } = require('../../../routes')
|
||||||
|
|
||||||
|
class Config extends Component {
|
||||||
|
renderTabs () {
|
||||||
|
const { history, location } = this.props
|
||||||
|
|
||||||
|
return h('div.settings__tabs', [
|
||||||
|
h(TabBar, {
|
||||||
|
tabs: [
|
||||||
|
{ content: 'Settings', key: SETTINGS_ROUTE },
|
||||||
|
{ content: 'Info', key: INFO_ROUTE },
|
||||||
|
],
|
||||||
|
isActive: key => matchPath(location.pathname, { path: key, exact: true }),
|
||||||
|
onSelect: key => history.push(key),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { history } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('.main-container.settings', {}, [
|
||||||
|
h('.settings__header', [
|
||||||
|
h('div.settings__close-button', {
|
||||||
|
onClick: () => history.push(DEFAULT_ROUTE),
|
||||||
|
}),
|
||||||
|
this.renderTabs(),
|
||||||
|
]),
|
||||||
|
h(Switch, [
|
||||||
|
h(Route, {
|
||||||
|
exact: true,
|
||||||
|
path: INFO_ROUTE,
|
||||||
|
component: Info,
|
||||||
|
}),
|
||||||
|
h(Route, {
|
||||||
|
exact: true,
|
||||||
|
path: SETTINGS_ROUTE,
|
||||||
|
component: Settings,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.propTypes = {
|
||||||
|
location: PropTypes.object,
|
||||||
|
history: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Config
|
112
ui/app/components/pages/settings/info.js
Normal file
112
ui/app/components/pages/settings/info.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
const { Component } = require('react')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
|
||||||
|
class Info extends Component {
|
||||||
|
renderLogo () {
|
||||||
|
return (
|
||||||
|
h('div.settings__info-logo-wrapper', [
|
||||||
|
h('img.settings__info-logo', { src: 'images/info-logo.png' }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderInfoLinks () {
|
||||||
|
return (
|
||||||
|
h('div.settings__content-item.settings__content-item--without-height', [
|
||||||
|
h('div.settings__info-link-header', this.context.t('links')),
|
||||||
|
h('div.settings__info-link-item', [
|
||||||
|
h('a', {
|
||||||
|
href: 'https://metamask.io/privacy.html',
|
||||||
|
target: '_blank',
|
||||||
|
}, [
|
||||||
|
h('span.settings__info-link', this.context.t('privacyMsg')),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
h('div.settings__info-link-item', [
|
||||||
|
h('a', {
|
||||||
|
href: 'https://metamask.io/terms.html',
|
||||||
|
target: '_blank',
|
||||||
|
}, [
|
||||||
|
h('span.settings__info-link', this.context.t('terms')),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
h('div.settings__info-link-item', [
|
||||||
|
h('a', {
|
||||||
|
href: 'https://metamask.io/attributions.html',
|
||||||
|
target: '_blank',
|
||||||
|
}, [
|
||||||
|
h('span.settings__info-link', this.context.t('attributions')),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
h('hr.settings__info-separator'),
|
||||||
|
h('div.settings__info-link-item', [
|
||||||
|
h('a', {
|
||||||
|
href: 'https://support.metamask.io',
|
||||||
|
target: '_blank',
|
||||||
|
}, [
|
||||||
|
h('span.settings__info-link', this.context.t('supportCenter')),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
h('div.settings__info-link-item', [
|
||||||
|
h('a', {
|
||||||
|
href: 'https://metamask.io/',
|
||||||
|
target: '_blank',
|
||||||
|
}, [
|
||||||
|
h('span.settings__info-link', this.context.t('visitWebSite')),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
h('div.settings__info-link-item', [
|
||||||
|
h('a', {
|
||||||
|
target: '_blank',
|
||||||
|
href: 'mailto:help@metamask.io?subject=Feedback',
|
||||||
|
}, [
|
||||||
|
h('span.settings__info-link', this.context.t('emailUs')),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
h('div.settings__content', [
|
||||||
|
h('div.settings__content-row', [
|
||||||
|
h('div.settings__content-item.settings__content-item--without-height', [
|
||||||
|
this.renderLogo(),
|
||||||
|
h('div.settings__info-item', [
|
||||||
|
h('div.settings__info-version-header', 'MetaMask Version'),
|
||||||
|
h('div.settings__info-version-number', '4.0.0'),
|
||||||
|
]),
|
||||||
|
h('div.settings__info-item', [
|
||||||
|
h(
|
||||||
|
'div.settings__info-about',
|
||||||
|
this.context.t('builtInCalifornia')
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
this.renderInfoLinks(),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Info.propTypes = {
|
||||||
|
tab: PropTypes.string,
|
||||||
|
metamask: PropTypes.object,
|
||||||
|
setCurrentCurrency: PropTypes.func,
|
||||||
|
setRpcTarget: PropTypes.func,
|
||||||
|
displayWarning: PropTypes.func,
|
||||||
|
revealSeedConfirmation: PropTypes.func,
|
||||||
|
warning: PropTypes.string,
|
||||||
|
location: PropTypes.object,
|
||||||
|
history: PropTypes.object,
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
Info.contextTypes = {
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Info
|
@ -1,16 +1,18 @@
|
|||||||
const { Component } = require('react')
|
const { Component } = require('react')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const actions = require('./actions')
|
const actions = require('../../../actions')
|
||||||
const infuraCurrencies = require('./infura-conversion.json')
|
const infuraCurrencies = require('../../../infura-conversion.json')
|
||||||
const validUrl = require('valid-url')
|
const validUrl = require('valid-url')
|
||||||
const { exportAsFile } = require('./util')
|
const { exportAsFile } = require('../../../util')
|
||||||
const TabBar = require('./components/tab-bar')
|
const SimpleDropdown = require('../../dropdowns/simple-dropdown')
|
||||||
const SimpleDropdown = require('./components/dropdowns/simple-dropdown')
|
|
||||||
const ToggleButton = require('react-toggle-button')
|
const ToggleButton = require('react-toggle-button')
|
||||||
const locales = require('../../app/_locales/index.json')
|
const { REVEAL_SEED_ROUTE } = require('../../../routes')
|
||||||
const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
|
const locales = require('../../../../../app/_locales/index.json')
|
||||||
|
const { OLD_UI_NETWORK_TYPE } = require('../../../../../app/scripts/config').enums
|
||||||
|
|
||||||
const getInfuraCurrencyOptions = () => {
|
const getInfuraCurrencyOptions = () => {
|
||||||
const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => {
|
const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => {
|
||||||
@ -40,30 +42,11 @@ class Settings extends Component {
|
|||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
const { tab } = props
|
|
||||||
const activeTab = tab === 'info' ? 'info' : 'settings'
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
activeTab,
|
|
||||||
newRpc: '',
|
newRpc: '',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTabs () {
|
|
||||||
const { activeTab } = this.state
|
|
||||||
|
|
||||||
return h('div.settings__tabs', [
|
|
||||||
h(TabBar, {
|
|
||||||
tabs: [
|
|
||||||
{ content: this.context.t('settings'), key: 'settings' },
|
|
||||||
{ content: this.context.t('info'), key: 'info' },
|
|
||||||
],
|
|
||||||
defaultTab: activeTab,
|
|
||||||
tabSelected: key => this.setState({ activeTab: key }),
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
renderBlockieOptIn () {
|
renderBlockieOptIn () {
|
||||||
const { metamask: { useBlockie }, setUseBlockie } = this.props
|
const { metamask: { useBlockie }, setUseBlockie } = this.props
|
||||||
|
|
||||||
@ -253,7 +236,7 @@ class Settings extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderSeedWords () {
|
renderSeedWords () {
|
||||||
const { revealSeedConfirmation } = this.props
|
const { history } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
h('div.settings__content-row', [
|
h('div.settings__content-row', [
|
||||||
@ -261,9 +244,9 @@ class Settings extends Component {
|
|||||||
h('div.settings__content-item', [
|
h('div.settings__content-item', [
|
||||||
h('div.settings__content-item-col', [
|
h('div.settings__content-item-col', [
|
||||||
h('button.btn-primary--lg.settings__button--red', {
|
h('button.btn-primary--lg.settings__button--red', {
|
||||||
onClick (event) {
|
onClick: event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
revealSeedConfirmation()
|
history.push(REVEAL_SEED_ROUTE)
|
||||||
},
|
},
|
||||||
}, this.context.t('revealSeedWords')),
|
}, this.context.t('revealSeedWords')),
|
||||||
]),
|
]),
|
||||||
@ -310,7 +293,7 @@ class Settings extends Component {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSettingsContent () {
|
render () {
|
||||||
const { warning, isMascara } = this.props
|
const { warning, isMascara } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -328,120 +311,9 @@ class Settings extends Component {
|
|||||||
])
|
])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLogo () {
|
|
||||||
return (
|
|
||||||
h('div.settings__info-logo-wrapper', [
|
|
||||||
h('img.settings__info-logo', { src: 'images/info-logo.png' }),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderInfoLinks () {
|
|
||||||
return (
|
|
||||||
h('div.settings__content-item.settings__content-item--without-height', [
|
|
||||||
h('div.settings__info-link-header', this.context.t('links')),
|
|
||||||
h('div.settings__info-link-item', [
|
|
||||||
h('a', {
|
|
||||||
href: 'https://metamask.io/privacy.html',
|
|
||||||
target: '_blank',
|
|
||||||
}, [
|
|
||||||
h('span.settings__info-link', this.context.t('privacyMsg')),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
h('div.settings__info-link-item', [
|
|
||||||
h('a', {
|
|
||||||
href: 'https://metamask.io/terms.html',
|
|
||||||
target: '_blank',
|
|
||||||
}, [
|
|
||||||
h('span.settings__info-link', this.context.t('terms')),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
h('div.settings__info-link-item', [
|
|
||||||
h('a', {
|
|
||||||
href: 'https://metamask.io/attributions.html',
|
|
||||||
target: '_blank',
|
|
||||||
}, [
|
|
||||||
h('span.settings__info-link', this.context.t('attributions')),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
h('hr.settings__info-separator'),
|
|
||||||
h('div.settings__info-link-item', [
|
|
||||||
h('a', {
|
|
||||||
href: 'https://support.metamask.io',
|
|
||||||
target: '_blank',
|
|
||||||
}, [
|
|
||||||
h('span.settings__info-link', this.context.t('supportCenter')),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
h('div.settings__info-link-item', [
|
|
||||||
h('a', {
|
|
||||||
href: 'https://metamask.io/',
|
|
||||||
target: '_blank',
|
|
||||||
}, [
|
|
||||||
h('span.settings__info-link', this.context.t('visitWebSite')),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
h('div.settings__info-link-item', [
|
|
||||||
h('a', {
|
|
||||||
target: '_blank',
|
|
||||||
href: 'mailto:help@metamask.io?subject=Feedback',
|
|
||||||
}, [
|
|
||||||
h('span.settings__info-link', this.context.t('emailUs')),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderInfoContent () {
|
|
||||||
const version = global.platform.getVersion()
|
|
||||||
|
|
||||||
return (
|
|
||||||
h('div.settings__content', [
|
|
||||||
h('div.settings__content-row', [
|
|
||||||
h('div.settings__content-item.settings__content-item--without-height', [
|
|
||||||
this.renderLogo(),
|
|
||||||
h('div.settings__info-item', [
|
|
||||||
h('div.settings__info-version-header', 'MetaMask Version'),
|
|
||||||
h('div.settings__info-version-number', `${version}`),
|
|
||||||
]),
|
|
||||||
h('div.settings__info-item', [
|
|
||||||
h(
|
|
||||||
'div.settings__info-about',
|
|
||||||
this.context.t('builtInCalifornia')
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
this.renderInfoLinks(),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { goHome } = this.props
|
|
||||||
const { activeTab } = this.state
|
|
||||||
|
|
||||||
return (
|
|
||||||
h('.main-container.settings', {}, [
|
|
||||||
h('.settings__header', [
|
|
||||||
h('div.settings__close-button', {
|
|
||||||
onClick: goHome,
|
|
||||||
}),
|
|
||||||
this.renderTabs(),
|
|
||||||
]),
|
|
||||||
|
|
||||||
activeTab === 'settings'
|
|
||||||
? this.renderSettingsContent()
|
|
||||||
: this.renderInfoContent(),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings.propTypes = {
|
Settings.propTypes = {
|
||||||
tab: PropTypes.string,
|
|
||||||
metamask: PropTypes.object,
|
metamask: PropTypes.object,
|
||||||
setUseBlockie: PropTypes.func,
|
setUseBlockie: PropTypes.func,
|
||||||
setCurrentCurrency: PropTypes.func,
|
setCurrentCurrency: PropTypes.func,
|
||||||
@ -451,7 +323,7 @@ Settings.propTypes = {
|
|||||||
setFeatureFlagToBeta: PropTypes.func,
|
setFeatureFlagToBeta: PropTypes.func,
|
||||||
showResetAccountConfirmationModal: PropTypes.func,
|
showResetAccountConfirmationModal: PropTypes.func,
|
||||||
warning: PropTypes.string,
|
warning: PropTypes.string,
|
||||||
goHome: PropTypes.func,
|
history: PropTypes.object,
|
||||||
isMascara: PropTypes.bool,
|
isMascara: PropTypes.bool,
|
||||||
updateCurrentLocale: PropTypes.func,
|
updateCurrentLocale: PropTypes.func,
|
||||||
currentLocale: PropTypes.string,
|
currentLocale: PropTypes.string,
|
||||||
@ -469,7 +341,6 @@ const mapStateToProps = state => {
|
|||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
goHome: () => dispatch(actions.goHome()),
|
|
||||||
setCurrentCurrency: currency => dispatch(actions.setCurrentCurrency(currency)),
|
setCurrentCurrency: currency => dispatch(actions.setCurrentCurrency(currency)),
|
||||||
setRpcTarget: newRpc => dispatch(actions.setRpcTarget(newRpc)),
|
setRpcTarget: newRpc => dispatch(actions.setRpcTarget(newRpc)),
|
||||||
displayWarning: warning => dispatch(actions.displayWarning(warning)),
|
displayWarning: warning => dispatch(actions.displayWarning(warning)),
|
||||||
@ -490,5 +361,7 @@ Settings.contextTypes = {
|
|||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(Settings)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(Settings)
|
193
ui/app/components/pages/unlock.js
Normal file
193
ui/app/components/pages/unlock.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
const { Component } = require('react')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const connect = require('../../metamask-connect')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
const {
|
||||||
|
tryUnlockMetamask,
|
||||||
|
forgotPassword,
|
||||||
|
markPasswordForgotten,
|
||||||
|
setNetworkEndpoints,
|
||||||
|
setFeatureFlag,
|
||||||
|
} = require('../../actions')
|
||||||
|
const environmentType = require('../../../../app/scripts/lib/environment-type')
|
||||||
|
const getCaretCoordinates = require('textarea-caret')
|
||||||
|
const EventEmitter = require('events').EventEmitter
|
||||||
|
const Mascot = require('../mascot')
|
||||||
|
const { OLD_UI_NETWORK_TYPE } = require('../../../../app/scripts/config').enums
|
||||||
|
const { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } = require('../../routes')
|
||||||
|
|
||||||
|
class UnlockScreen extends Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
error: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.animationEventEmitter = new EventEmitter()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { isUnlocked, history } = this.props
|
||||||
|
|
||||||
|
if (isUnlocked) {
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
const passwordBox = document.getElementById('password-box')
|
||||||
|
|
||||||
|
if (passwordBox) {
|
||||||
|
passwordBox.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tryUnlockMetamask (password) {
|
||||||
|
const { tryUnlockMetamask, history } = this.props
|
||||||
|
tryUnlockMetamask(password)
|
||||||
|
.then(() => history.push(DEFAULT_ROUTE))
|
||||||
|
.catch(({ message }) => this.setState({ error: message }))
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit (event) {
|
||||||
|
const input = document.getElementById('password-box')
|
||||||
|
const password = input.value
|
||||||
|
this.tryUnlockMetamask(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyPress (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
this.submitPassword(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
submitPassword (event) {
|
||||||
|
var element = event.target
|
||||||
|
var password = element.value
|
||||||
|
// reset input
|
||||||
|
element.value = ''
|
||||||
|
this.tryUnlockMetamask(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputChanged (event) {
|
||||||
|
// tell mascot to look at page action
|
||||||
|
var element = event.target
|
||||||
|
var boundingRect = element.getBoundingClientRect()
|
||||||
|
var coordinates = getCaretCoordinates(element, element.selectionEnd)
|
||||||
|
this.animationEventEmitter.emit('point', {
|
||||||
|
x: boundingRect.left + coordinates.left - element.scrollLeft,
|
||||||
|
y: boundingRect.top + coordinates.top - element.scrollTop,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { error } = this.state
|
||||||
|
return (
|
||||||
|
h('.unlock-screen', [
|
||||||
|
|
||||||
|
h(Mascot, {
|
||||||
|
animationEventEmitter: this.animationEventEmitter,
|
||||||
|
}),
|
||||||
|
|
||||||
|
h('h1', {
|
||||||
|
style: {
|
||||||
|
fontSize: '1.4em',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
color: '#7F8082',
|
||||||
|
},
|
||||||
|
}, this.props.t('appName')),
|
||||||
|
|
||||||
|
h('input.large-input', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box',
|
||||||
|
placeholder: 'enter password',
|
||||||
|
style: {
|
||||||
|
background: 'white',
|
||||||
|
},
|
||||||
|
onKeyPress: this.onKeyPress.bind(this),
|
||||||
|
onInput: this.inputChanged.bind(this),
|
||||||
|
}),
|
||||||
|
|
||||||
|
h('.error', {
|
||||||
|
style: {
|
||||||
|
display: error ? 'block' : 'none',
|
||||||
|
padding: '0 20px',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
}, error),
|
||||||
|
|
||||||
|
h('button.primary.cursor-pointer', {
|
||||||
|
onClick: this.onSubmit.bind(this),
|
||||||
|
style: {
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
}, this.props.t('login')),
|
||||||
|
|
||||||
|
h('p.pointer', {
|
||||||
|
onClick: () => {
|
||||||
|
this.props.markPasswordForgotten()
|
||||||
|
this.props.history.push(RESTORE_VAULT_ROUTE)
|
||||||
|
|
||||||
|
if (environmentType() === 'popup') {
|
||||||
|
global.platform.openExtensionInBrowser()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
fontSize: '0.8em',
|
||||||
|
color: 'rgb(247, 134, 28)',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}, this.props.t('restoreFromSeed')),
|
||||||
|
|
||||||
|
h('p.pointer', {
|
||||||
|
onClick: () => {
|
||||||
|
this.props.useOldInterface()
|
||||||
|
.then(() => this.props.setNetworkEndpoints(OLD_UI_NETWORK_TYPE))
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
fontSize: '0.8em',
|
||||||
|
color: '#aeaeae',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
marginTop: '32px',
|
||||||
|
},
|
||||||
|
}, this.props.t('classicInterface')),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockScreen.propTypes = {
|
||||||
|
forgotPassword: PropTypes.func,
|
||||||
|
tryUnlockMetamask: PropTypes.func,
|
||||||
|
markPasswordForgotten: PropTypes.func,
|
||||||
|
history: PropTypes.object,
|
||||||
|
isUnlocked: PropTypes.bool,
|
||||||
|
t: PropTypes.func,
|
||||||
|
useOldInterface: PropTypes.func,
|
||||||
|
setNetworkEndpoints: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const { metamask: { isUnlocked } } = state
|
||||||
|
return {
|
||||||
|
isUnlocked,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
forgotPassword: () => dispatch(forgotPassword()),
|
||||||
|
tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)),
|
||||||
|
markPasswordForgotten: () => dispatch(markPasswordForgotten()),
|
||||||
|
useOldInterface: () => dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')),
|
||||||
|
setNetworkEndpoints: type => dispatch(setNetworkEndpoints(type)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(UnlockScreen)
|
@ -1,4 +1,6 @@
|
|||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
@ -23,12 +25,16 @@ const SenderToRecipient = require('../sender-to-recipient')
|
|||||||
const NetworkDisplay = require('../network-display')
|
const NetworkDisplay = require('../network-display')
|
||||||
|
|
||||||
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
|
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
|
||||||
|
const { SEND_ROUTE, DEFAULT_ROUTE } = require('../../routes')
|
||||||
|
|
||||||
ConfirmSendEther.contextTypes = {
|
ConfirmSendEther.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmSendEther)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(ConfirmSendEther)
|
||||||
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
@ -72,7 +78,6 @@ function mapDispatchToProps (dispatch) {
|
|||||||
errors: { to: null, amount: null },
|
errors: { to: null, amount: null },
|
||||||
editingTransactionId: id,
|
editingTransactionId: id,
|
||||||
}))
|
}))
|
||||||
dispatch(actions.showSendPage())
|
|
||||||
},
|
},
|
||||||
cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
|
cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
|
||||||
showCustomizeGasModal: (txMeta, sendGasLimit, sendGasPrice, sendGasTotal) => {
|
showCustomizeGasModal: (txMeta, sendGasLimit, sendGasPrice, sendGasTotal) => {
|
||||||
@ -270,9 +275,14 @@ ConfirmSendEther.prototype.getData = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmSendEther.prototype.editTransaction = function (txMeta) {
|
||||||
|
const { editTransaction, history } = this.props
|
||||||
|
editTransaction(txMeta)
|
||||||
|
history.push(SEND_ROUTE)
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmSendEther.prototype.render = function () {
|
ConfirmSendEther.prototype.render = function () {
|
||||||
const {
|
const {
|
||||||
editTransaction,
|
|
||||||
currentCurrency,
|
currentCurrency,
|
||||||
clearSend,
|
clearSend,
|
||||||
conversionRate,
|
conversionRate,
|
||||||
@ -328,7 +338,7 @@ ConfirmSendEther.prototype.render = function () {
|
|||||||
h('.page-container__header', [
|
h('.page-container__header', [
|
||||||
h('.page-container__header-row', [
|
h('.page-container__header-row', [
|
||||||
h('span.page-container__back-button', {
|
h('span.page-container__back-button', {
|
||||||
onClick: () => editTransaction(txMeta),
|
onClick: () => this.editTransaction(txMeta),
|
||||||
style: {
|
style: {
|
||||||
visibility: !txMeta.lastGasPrice ? 'initial' : 'hidden',
|
visibility: !txMeta.lastGasPrice ? 'initial' : 'hidden',
|
||||||
},
|
},
|
||||||
@ -506,7 +516,9 @@ ConfirmSendEther.prototype.render = function () {
|
|||||||
}, this.context.t('cancel')),
|
}, this.context.t('cancel')),
|
||||||
|
|
||||||
// Accept Button
|
// Accept Button
|
||||||
h('button.btn-confirm.page-container__footer-button.allcaps', [this.context.t('confirm')]),
|
h('button.btn-confirm.page-container__footer-button.allcaps', {
|
||||||
|
onClick: event => this.onSubmit(event),
|
||||||
|
}, this.context.t('confirm')),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
@ -544,6 +556,7 @@ ConfirmSendEther.prototype.cancel = function (event, txMeta) {
|
|||||||
const { cancelTransaction } = this.props
|
const { cancelTransaction } = this.props
|
||||||
|
|
||||||
cancelTransaction(txMeta)
|
cancelTransaction(txMeta)
|
||||||
|
.then(() => this.props.history.push(DEFAULT_ROUTE))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmSendEther.prototype.isBalanceSufficient = function (txMeta) {
|
ConfirmSendEther.prototype.isBalanceSufficient = function (txMeta) {
|
||||||
@ -631,4 +644,4 @@ ConfirmSendEther.prototype.bnMultiplyByFraction = function (targetBN, numerator,
|
|||||||
const numBN = new BN(numerator)
|
const numBN = new BN(numerator)
|
||||||
const denomBN = new BN(denominator)
|
const denomBN = new BN(denominator)
|
||||||
return targetBN.mul(numBN).div(denomBN)
|
return targetBN.mul(numBN).div(denomBN)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
@ -33,12 +35,16 @@ const {
|
|||||||
getSelectedAddress,
|
getSelectedAddress,
|
||||||
getSelectedTokenContract,
|
getSelectedTokenContract,
|
||||||
} = require('../../selectors')
|
} = require('../../selectors')
|
||||||
|
const { SEND_ROUTE, DEFAULT_ROUTE } = require('../../routes')
|
||||||
|
|
||||||
ConfirmSendToken.contextTypes = {
|
ConfirmSendToken.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmSendToken)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(ConfirmSendToken)
|
||||||
|
|
||||||
|
|
||||||
function mapStateToProps (state, ownProps) {
|
function mapStateToProps (state, ownProps) {
|
||||||
@ -147,6 +153,12 @@ function ConfirmSendToken () {
|
|||||||
this.onSubmit = this.onSubmit.bind(this)
|
this.onSubmit = this.onSubmit.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmSendToken.prototype.editTransaction = function (txMeta) {
|
||||||
|
const { editTransaction, history } = this.props
|
||||||
|
editTransaction(txMeta)
|
||||||
|
history.push(SEND_ROUTE)
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmSendToken.prototype.updateComponentSendErrors = function (prevProps) {
|
ConfirmSendToken.prototype.updateComponentSendErrors = function (prevProps) {
|
||||||
const {
|
const {
|
||||||
balance: oldBalance,
|
balance: oldBalance,
|
||||||
@ -406,7 +418,6 @@ ConfirmSendToken.prototype.renderErrorMessage = function (message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfirmSendToken.prototype.render = function () {
|
ConfirmSendToken.prototype.render = function () {
|
||||||
const { editTransaction } = this.props
|
|
||||||
const txMeta = this.gatherTxMeta()
|
const txMeta = this.gatherTxMeta()
|
||||||
const {
|
const {
|
||||||
from: {
|
from: {
|
||||||
@ -433,7 +444,7 @@ ConfirmSendToken.prototype.render = function () {
|
|||||||
h('div.page-container', [
|
h('div.page-container', [
|
||||||
h('div.page-container__header', [
|
h('div.page-container__header', [
|
||||||
!txMeta.lastGasPrice && h('button.confirm-screen-back-button', {
|
!txMeta.lastGasPrice && h('button.confirm-screen-back-button', {
|
||||||
onClick: () => editTransaction(txMeta),
|
onClick: () => this.editTransaction(txMeta),
|
||||||
}, this.context.t('edit')),
|
}, this.context.t('edit')),
|
||||||
h('div.page-container__title', title),
|
h('div.page-container__title', title),
|
||||||
h('div.page-container__subtitle', subtitle),
|
h('div.page-container__subtitle', subtitle),
|
||||||
@ -513,7 +524,9 @@ ConfirmSendToken.prototype.render = function () {
|
|||||||
}, this.context.t('cancel')),
|
}, this.context.t('cancel')),
|
||||||
|
|
||||||
// Accept Button
|
// Accept Button
|
||||||
h('button.btn-confirm.page-container__footer-button.allcaps', [this.context.t('confirm')]),
|
h('button.btn-confirm.page-container__footer-button.allcaps', {
|
||||||
|
onClick: event => this.onSubmit(event),
|
||||||
|
}, [this.context.t('confirm')]),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
@ -566,6 +579,7 @@ ConfirmSendToken.prototype.cancel = function (event, txMeta) {
|
|||||||
const { cancelTransaction } = this.props
|
const { cancelTransaction } = this.props
|
||||||
|
|
||||||
cancelTransaction(txMeta)
|
cancelTransaction(txMeta)
|
||||||
|
.then(() => this.props.history.push(DEFAULT_ROUTE))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmSendToken.prototype.checkValidity = function () {
|
ConfirmSendToken.prototype.checkValidity = function () {
|
||||||
|
@ -2,6 +2,8 @@ const connect = require('react-redux').connect
|
|||||||
const actions = require('../../actions')
|
const actions = require('../../actions')
|
||||||
const abi = require('ethereumjs-abi')
|
const abi = require('ethereumjs-abi')
|
||||||
const SendEther = require('../../send-v2')
|
const SendEther = require('../../send-v2')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
accountsWithSendEtherInfoSelector,
|
accountsWithSendEtherInfoSelector,
|
||||||
@ -16,7 +18,10 @@ const {
|
|||||||
getSelectedTokenContract,
|
getSelectedTokenContract,
|
||||||
} = require('../../selectors')
|
} = require('../../selectors')
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(SendEther)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(SendEther)
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const fromAccounts = accountsWithSendEtherInfoSelector(state)
|
const fromAccounts = accountsWithSendEtherInfoSelector(state)
|
||||||
@ -79,7 +84,6 @@ function mapDispatchToProps (dispatch) {
|
|||||||
updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)),
|
updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)),
|
||||||
updateSendMemo: newMemo => dispatch(actions.updateSendMemo(newMemo)),
|
updateSendMemo: newMemo => dispatch(actions.updateSendMemo(newMemo)),
|
||||||
updateSendErrors: newError => dispatch(actions.updateSendErrors(newError)),
|
updateSendErrors: newError => dispatch(actions.updateSendErrors(newError)),
|
||||||
goHome: () => dispatch(actions.goHome()),
|
|
||||||
clearSend: () => dispatch(actions.clearSend()),
|
clearSend: () => dispatch(actions.clearSend()),
|
||||||
setMaxModeTo: bool => dispatch(actions.setMaxModeTo(bool)),
|
setMaxModeTo: bool => dispatch(actions.setMaxModeTo(bool)),
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ const Identicon = require('./identicon')
|
|||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
const classnames = require('classnames')
|
const classnames = require('classnames')
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
|
||||||
const AccountDropdownMini = require('./dropdowns/account-dropdown-mini')
|
const AccountDropdownMini = require('./dropdowns/account-dropdown-mini')
|
||||||
|
|
||||||
@ -20,6 +22,8 @@ const {
|
|||||||
conversionRateSelector,
|
conversionRateSelector,
|
||||||
} = require('../selectors.js')
|
} = require('../selectors.js')
|
||||||
|
|
||||||
|
const { DEFAULT_ROUTE } = require('../routes')
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
return {
|
return {
|
||||||
balance: getSelectedAccount(state).balance,
|
balance: getSelectedAccount(state).balance,
|
||||||
@ -42,7 +46,10 @@ SignatureRequest.contextTypes = {
|
|||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(SignatureRequest)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(SignatureRequest)
|
||||||
|
|
||||||
|
|
||||||
inherits(SignatureRequest, Component)
|
inherits(SignatureRequest, Component)
|
||||||
@ -229,10 +236,14 @@ SignatureRequest.prototype.renderFooter = function () {
|
|||||||
|
|
||||||
return h('div.request-signature__footer', [
|
return h('div.request-signature__footer', [
|
||||||
h('button.btn-secondary--lg.request-signature__footer__cancel-button', {
|
h('button.btn-secondary--lg.request-signature__footer__cancel-button', {
|
||||||
onClick: cancel,
|
onClick: event => {
|
||||||
|
cancel(event).then(() => this.props.history.push(DEFAULT_ROUTE))
|
||||||
|
},
|
||||||
}, this.context.t('cancel')),
|
}, this.context.t('cancel')),
|
||||||
h('button.btn-primary--lg', {
|
h('button.btn-primary--lg', {
|
||||||
onClick: sign,
|
onClick: event => {
|
||||||
|
sign(event).then(() => this.props.history.push(DEFAULT_ROUTE))
|
||||||
|
},
|
||||||
}, this.context.t('sign')),
|
}, this.context.t('sign')),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -4,31 +4,17 @@ const PropTypes = require('prop-types')
|
|||||||
const classnames = require('classnames')
|
const classnames = require('classnames')
|
||||||
|
|
||||||
class TabBar extends Component {
|
class TabBar extends Component {
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
const { defaultTab, tabs } = props
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
subview: defaultTab || tabs[0].key,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { tabs = [], tabSelected } = this.props
|
const { tabs = [], onSelect, isActive } = this.props
|
||||||
const { subview } = this.state
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
h('.tab-bar', {}, [
|
h('.tab-bar', {}, [
|
||||||
tabs.map((tab) => {
|
tabs.map(({ key, content }) => {
|
||||||
const { key, content } = tab
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
className: classnames('tab-bar__tab pointer', {
|
className: classnames('tab-bar__tab pointer', {
|
||||||
'tab-bar__tab--active': subview === key,
|
'tab-bar__tab--active': isActive(key, content),
|
||||||
}),
|
}),
|
||||||
onClick: () => {
|
onClick: () => onSelect(key),
|
||||||
this.setState({ subview: key })
|
|
||||||
tabSelected(key)
|
|
||||||
},
|
|
||||||
key,
|
key,
|
||||||
}, content)
|
}, content)
|
||||||
}),
|
}),
|
||||||
@ -39,9 +25,9 @@ class TabBar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TabBar.propTypes = {
|
TabBar.propTypes = {
|
||||||
defaultTab: PropTypes.string,
|
isActive: PropTypes.func.isRequired,
|
||||||
tabs: PropTypes.array,
|
tabs: PropTypes.array,
|
||||||
tabSelected: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TabBar
|
module.exports = TabBar
|
||||||
|
@ -11,14 +11,19 @@ const { formatDate } = require('../util')
|
|||||||
const { showConfTxPage } = require('../actions')
|
const { showConfTxPage } = require('../actions')
|
||||||
const classnames = require('classnames')
|
const classnames = require('classnames')
|
||||||
const { tokenInfoGetter } = require('../token-util')
|
const { tokenInfoGetter } = require('../token-util')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
const { CONFIRM_TRANSACTION_ROUTE } = require('../routes')
|
||||||
|
|
||||||
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(TxList)
|
||||||
|
|
||||||
TxList.contextTypes = {
|
TxList.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(TxList)
|
|
||||||
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
return {
|
return {
|
||||||
txsToRender: selectors.transactionsSelector(state),
|
txsToRender: selectors.transactionsSelector(state),
|
||||||
@ -96,7 +101,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa
|
|||||||
transactionNetworkId,
|
transactionNetworkId,
|
||||||
transactionSubmittedTime,
|
transactionSubmittedTime,
|
||||||
} = props
|
} = props
|
||||||
const { showConfTxPage } = this.props
|
const { history } = this.props
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
key: transactionId || transactionHash,
|
key: transactionId || transactionHash,
|
||||||
@ -116,7 +121,10 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa
|
|||||||
const isUnapproved = transactionStatus === 'unapproved'
|
const isUnapproved = transactionStatus === 'unapproved'
|
||||||
|
|
||||||
if (isUnapproved) {
|
if (isUnapproved) {
|
||||||
opts.onClick = () => showConfTxPage({ id: transactionId })
|
opts.onClick = () => {
|
||||||
|
this.props.showConfTxPage({ id: transactionId })
|
||||||
|
history.push(CONFIRM_TRANSACTION_ROUTE)
|
||||||
|
}
|
||||||
opts.transactionStatus = this.context.t('notStarted')
|
opts.transactionStatus = this.context.t('notStarted')
|
||||||
} else if (transactionHash) {
|
} else if (transactionHash) {
|
||||||
opts.onClick = () => this.view(transactionHash, transactionNetworkId)
|
opts.onClick = () => this.view(transactionHash, transactionNetworkId)
|
||||||
|
@ -4,20 +4,25 @@ const connect = require('react-redux').connect
|
|||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const actions = require('../actions')
|
const actions = require('../actions')
|
||||||
const selectors = require('../selectors')
|
const selectors = require('../selectors')
|
||||||
|
const { SEND_ROUTE } = require('../routes')
|
||||||
|
|
||||||
const BalanceComponent = require('./balance-component')
|
const BalanceComponent = require('./balance-component')
|
||||||
const TxList = require('./tx-list')
|
const TxList = require('./tx-list')
|
||||||
const Identicon = require('./identicon')
|
const Identicon = require('./identicon')
|
||||||
|
|
||||||
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(TxView)
|
||||||
|
|
||||||
TxView.contextTypes = {
|
TxView.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(TxView)
|
|
||||||
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const sidebarOpen = state.appState.sidebarOpen
|
const sidebarOpen = state.appState.sidebarOpen
|
||||||
const isMascara = state.appState.isMascara
|
const isMascara = state.appState.isMascara
|
||||||
@ -69,7 +74,7 @@ TxView.prototype.renderHeroBalance = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TxView.prototype.renderButtons = function () {
|
TxView.prototype.renderButtons = function () {
|
||||||
const {selectedToken, showModal, showSendPage, showSendTokenPage } = this.props
|
const {selectedToken, showModal, history } = this.props
|
||||||
|
|
||||||
return !selectedToken
|
return !selectedToken
|
||||||
? (
|
? (
|
||||||
@ -84,14 +89,14 @@ TxView.prototype.renderButtons = function () {
|
|||||||
style: {
|
style: {
|
||||||
marginLeft: '0.8em',
|
marginLeft: '0.8em',
|
||||||
},
|
},
|
||||||
onClick: showSendPage,
|
onClick: () => history.push(SEND_ROUTE),
|
||||||
}, this.context.t('send')),
|
}, this.context.t('send')),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
h('div.flex-row.flex-center.hero-balance-buttons', [
|
h('div.flex-row.flex-center.hero-balance-buttons', [
|
||||||
h('button.btn-primary.hero-balance-button', {
|
h('button.btn-primary.hero-balance-button', {
|
||||||
onClick: showSendTokenPage,
|
onClick: () => history.push(SEND_ROUTE),
|
||||||
}, this.context.t('send')),
|
}, this.context.t('send')),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,8 @@ const Component = require('react').Component
|
|||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const classnames = require('classnames')
|
const classnames = require('classnames')
|
||||||
const Identicon = require('./identicon')
|
const Identicon = require('./identicon')
|
||||||
@ -12,14 +14,17 @@ const actions = require('../actions')
|
|||||||
const BalanceComponent = require('./balance-component')
|
const BalanceComponent = require('./balance-component')
|
||||||
const TokenList = require('./token-list')
|
const TokenList = require('./token-list')
|
||||||
const selectors = require('../selectors')
|
const selectors = require('../selectors')
|
||||||
|
const { ADD_TOKEN_ROUTE } = require('../routes')
|
||||||
|
|
||||||
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(WalletView)
|
||||||
|
|
||||||
WalletView.contextTypes = {
|
WalletView.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView)
|
|
||||||
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -97,7 +102,7 @@ WalletView.prototype.render = function () {
|
|||||||
keyrings,
|
keyrings,
|
||||||
showAccountDetailModal,
|
showAccountDetailModal,
|
||||||
hideSidebar,
|
hideSidebar,
|
||||||
showAddTokenPage,
|
history,
|
||||||
} = this.props
|
} = this.props
|
||||||
// temporary logs + fake extra wallets
|
// temporary logs + fake extra wallets
|
||||||
// console.log('walletview, selectedAccount:', selectedAccount)
|
// console.log('walletview, selectedAccount:', selectedAccount)
|
||||||
@ -174,10 +179,7 @@ WalletView.prototype.render = function () {
|
|||||||
h(TokenList),
|
h(TokenList),
|
||||||
|
|
||||||
h('button.btn-primary.wallet-view__add-token-button', {
|
h('button.btn-primary.wallet-view__add-token-button', {
|
||||||
onClick: () => {
|
onClick: () => history.push(ADD_TOKEN_ROUTE),
|
||||||
showAddTokenPage()
|
|
||||||
hideSidebar()
|
|
||||||
},
|
|
||||||
}, this.context.t('addToken')),
|
}, this.context.t('addToken')),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ const inherits = require('util').inherits
|
|||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const actions = require('./actions')
|
const actions = require('./actions')
|
||||||
const txHelper = require('../lib/tx-helper')
|
const txHelper = require('../lib/tx-helper')
|
||||||
|
|
||||||
@ -11,19 +13,21 @@ const SignatureRequest = require('./components/signature-request')
|
|||||||
// const PendingPersonalMsg = require('./components/pending-personal-msg')
|
// const PendingPersonalMsg = require('./components/pending-personal-msg')
|
||||||
// const PendingTypedMsg = require('./components/pending-typed-msg')
|
// const PendingTypedMsg = require('./components/pending-typed-msg')
|
||||||
const Loading = require('./components/loading')
|
const Loading = require('./components/loading')
|
||||||
|
const { DEFAULT_ROUTE } = require('./routes')
|
||||||
|
|
||||||
// const contentDivider = h('div', {
|
module.exports = compose(
|
||||||
// style: {
|
withRouter,
|
||||||
// marginLeft: '16px',
|
connect(mapStateToProps)
|
||||||
// marginRight: '16px',
|
)(ConfirmTxScreen)
|
||||||
// height:'1px',
|
|
||||||
// background:'#E7E7E7',
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(ConfirmTxScreen)
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
|
const { metamask } = state
|
||||||
|
const {
|
||||||
|
unapprovedMsgCount,
|
||||||
|
unapprovedPersonalMsgCount,
|
||||||
|
unapprovedTypedMessagesCount,
|
||||||
|
} = metamask
|
||||||
|
|
||||||
return {
|
return {
|
||||||
identities: state.metamask.identities,
|
identities: state.metamask.identities,
|
||||||
accounts: state.metamask.accounts,
|
accounts: state.metamask.accounts,
|
||||||
@ -40,6 +44,10 @@ function mapStateToProps (state) {
|
|||||||
currentCurrency: state.metamask.currentCurrency,
|
currentCurrency: state.metamask.currentCurrency,
|
||||||
blockGasLimit: state.metamask.currentBlockGasLimit,
|
blockGasLimit: state.metamask.currentBlockGasLimit,
|
||||||
computedBalances: state.metamask.computedBalances,
|
computedBalances: state.metamask.computedBalances,
|
||||||
|
unapprovedMsgCount,
|
||||||
|
unapprovedPersonalMsgCount,
|
||||||
|
unapprovedTypedMessagesCount,
|
||||||
|
send: state.metamask.send,
|
||||||
selectedAddressTxList: state.metamask.selectedAddressTxList,
|
selectedAddressTxList: state.metamask.selectedAddressTxList,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,11 +57,35 @@ function ConfirmTxScreen () {
|
|||||||
Component.call(this)
|
Component.call(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmTxScreen.prototype.getUnapprovedMessagesTotal = function () {
|
||||||
|
const {
|
||||||
|
unapprovedMsgCount = 0,
|
||||||
|
unapprovedPersonalMsgCount = 0,
|
||||||
|
unapprovedTypedMessagesCount = 0,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return unapprovedTypedMessagesCount + unapprovedMsgCount + unapprovedPersonalMsgCount
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfirmTxScreen.prototype.componentDidMount = function () {
|
||||||
|
const {
|
||||||
|
unapprovedTxs = {},
|
||||||
|
network,
|
||||||
|
send,
|
||||||
|
} = this.props
|
||||||
|
const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network)
|
||||||
|
|
||||||
|
if (unconfTxList.length === 0 && !send.to && this.getUnapprovedMessagesTotal() === 0) {
|
||||||
|
this.props.history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) {
|
ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) {
|
||||||
const {
|
const {
|
||||||
unapprovedTxs,
|
unapprovedTxs = {},
|
||||||
network,
|
network,
|
||||||
selectedAddressTxList,
|
selectedAddressTxList,
|
||||||
|
send,
|
||||||
} = this.props
|
} = this.props
|
||||||
const { index: prevIndex, unapprovedTxs: prevUnapprovedTxs } = prevProps
|
const { index: prevIndex, unapprovedTxs: prevUnapprovedTxs } = prevProps
|
||||||
const prevUnconfTxList = txHelper(prevUnapprovedTxs, {}, {}, {}, network)
|
const prevUnconfTxList = txHelper(prevUnapprovedTxs, {}, {}, {}, network)
|
||||||
@ -61,8 +93,9 @@ ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) {
|
|||||||
const prevTx = selectedAddressTxList.find(({ id }) => id === prevTxData.id) || {}
|
const prevTx = selectedAddressTxList.find(({ id }) => id === prevTxData.id) || {}
|
||||||
const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network)
|
const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network)
|
||||||
|
|
||||||
if (prevTx.status === 'dropped' && unconfTxList.length === 0) {
|
if (unconfTxList.length === 0 &&
|
||||||
this.goHome({})
|
(prevTx.status === 'dropped' || !send.to && this.getUnapprovedMessagesTotal() === 0)) {
|
||||||
|
this.props.history.push(DEFAULT_ROUTE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +136,6 @@ ConfirmTxScreen.prototype.render = function () {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
|
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
|
||||||
if (unconfTxList.length === 0) return h(Loading)
|
|
||||||
|
|
||||||
return currentTxView({
|
return currentTxView({
|
||||||
// Properties
|
// Properties
|
||||||
@ -152,6 +184,7 @@ function currentTxView (opts) {
|
|||||||
// return h(PendingTypedMsg, opts)
|
// return h(PendingTypedMsg, opts)
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return h(Loading)
|
return h(Loading)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +196,7 @@ ConfirmTxScreen.prototype.buyEth = function (address, event) {
|
|||||||
ConfirmTxScreen.prototype.sendTransaction = function (txData, event) {
|
ConfirmTxScreen.prototype.sendTransaction = function (txData, event) {
|
||||||
this.stopPropagation(event)
|
this.stopPropagation(event)
|
||||||
this.props.dispatch(actions.updateAndApproveTx(txData))
|
this.props.dispatch(actions.updateAndApproveTx(txData))
|
||||||
|
.then(() => this.props.history.push(DEFAULT_ROUTE))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelTransaction = function (txData, event) {
|
ConfirmTxScreen.prototype.cancelTransaction = function (txData, event) {
|
||||||
@ -182,7 +216,7 @@ ConfirmTxScreen.prototype.signMessage = function (msgData, event) {
|
|||||||
var params = msgData.msgParams
|
var params = msgData.msgParams
|
||||||
params.metamaskId = msgData.id
|
params.metamaskId = msgData.id
|
||||||
this.stopPropagation(event)
|
this.stopPropagation(event)
|
||||||
this.props.dispatch(actions.signMsg(params))
|
return this.props.dispatch(actions.signMsg(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.stopPropagation = function (event) {
|
ConfirmTxScreen.prototype.stopPropagation = function (event) {
|
||||||
@ -196,7 +230,7 @@ ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) {
|
|||||||
var params = msgData.msgParams
|
var params = msgData.msgParams
|
||||||
params.metamaskId = msgData.id
|
params.metamaskId = msgData.id
|
||||||
this.stopPropagation(event)
|
this.stopPropagation(event)
|
||||||
this.props.dispatch(actions.signPersonalMsg(params))
|
return this.props.dispatch(actions.signPersonalMsg(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) {
|
ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) {
|
||||||
@ -204,25 +238,25 @@ ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) {
|
|||||||
var params = msgData.msgParams
|
var params = msgData.msgParams
|
||||||
params.metamaskId = msgData.id
|
params.metamaskId = msgData.id
|
||||||
this.stopPropagation(event)
|
this.stopPropagation(event)
|
||||||
this.props.dispatch(actions.signTypedMsg(params))
|
return this.props.dispatch(actions.signTypedMsg(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) {
|
ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) {
|
||||||
log.info('canceling message')
|
log.info('canceling message')
|
||||||
this.stopPropagation(event)
|
this.stopPropagation(event)
|
||||||
this.props.dispatch(actions.cancelMsg(msgData))
|
return this.props.dispatch(actions.cancelMsg(msgData))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) {
|
ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) {
|
||||||
log.info('canceling personal message')
|
log.info('canceling personal message')
|
||||||
this.stopPropagation(event)
|
this.stopPropagation(event)
|
||||||
this.props.dispatch(actions.cancelPersonalMsg(msgData))
|
return this.props.dispatch(actions.cancelPersonalMsg(msgData))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) {
|
ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) {
|
||||||
log.info('canceling typed message')
|
log.info('canceling typed message')
|
||||||
this.stopPropagation(event)
|
this.stopPropagation(event)
|
||||||
this.props.dispatch(actions.cancelTypedMsg(msgData))
|
return this.props.dispatch(actions.cancelTypedMsg(msgData))
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.goHome = function (event) {
|
ConfirmTxScreen.prototype.goHome = function (event) {
|
||||||
|
@ -6,9 +6,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import './itcss/settings/index.scss';
|
@import './itcss/settings/index.scss';
|
||||||
|
|
||||||
@import './itcss/tools/index.scss';
|
@import './itcss/tools/index.scss';
|
||||||
|
|
||||||
@import './itcss/generic/index.scss';
|
@import './itcss/generic/index.scss';
|
||||||
|
|
||||||
@import './itcss/base/index.scss';
|
@import './itcss/base/index.scss';
|
||||||
|
|
||||||
@import './itcss/objects/index.scss';
|
@import './itcss/objects/index.scss';
|
||||||
|
|
||||||
@import './itcss/components/index.scss';
|
@import './itcss/components/index.scss';
|
||||||
|
|
||||||
@import './itcss/trumps/index.scss';
|
@import './itcss/trumps/index.scss';
|
||||||
|
@ -52,6 +52,8 @@
|
|||||||
|
|
||||||
@import './editable-label.scss';
|
@import './editable-label.scss';
|
||||||
|
|
||||||
|
@import './pages/index.scss';
|
||||||
|
|
||||||
@import './new-account.scss';
|
@import './new-account.scss';
|
||||||
|
|
||||||
@import './tooltip.scss';
|
@import './tooltip.scss';
|
||||||
|
@ -35,13 +35,14 @@
|
|||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__tab:first-of-type {
|
&__tab:first-of-type {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__unselected:hover {
|
&__tab:hover {
|
||||||
color: $black;
|
color: $black;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
@ -49,9 +50,9 @@
|
|||||||
&__selected {
|
&__selected {
|
||||||
color: $curious-blue;
|
color: $curious-blue;
|
||||||
border-bottom: 3px solid $curious-blue;
|
border-bottom: 3px solid $curious-blue;
|
||||||
|
cursor: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-account-import-disclaimer {
|
.new-account-import-disclaimer {
|
||||||
|
1
ui/app/css/itcss/components/pages/index.scss
Normal file
1
ui/app/css/itcss/components/pages/index.scss
Normal file
@ -0,0 +1 @@
|
|||||||
|
@import './unlock.scss';
|
9
ui/app/css/itcss/components/pages/unlock.scss
Normal file
9
ui/app/css/itcss/components/pages/unlock.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.unlock-page {
|
||||||
|
box-shadow: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgb(247, 247, 247);
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -17,6 +17,12 @@ textarea.twelve-word-phrase {
|
|||||||
resize: none;
|
resize: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.initialize-screen {
|
||||||
|
width: 100%;
|
||||||
|
z-index: $main-container-z-index;
|
||||||
|
background: #f7f7f7;
|
||||||
|
}
|
||||||
|
|
||||||
.initialize-screen hr {
|
.initialize-screen hr {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
margin: 12px;
|
margin: 12px;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
const inherits = require('util').inherits
|
const { EventEmitter } = require('events')
|
||||||
const EventEmitter = require('events').EventEmitter
|
const { Component } = require('react')
|
||||||
const Component = require('react').Component
|
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
@ -8,205 +7,219 @@ const Mascot = require('../components/mascot')
|
|||||||
const actions = require('../actions')
|
const actions = require('../actions')
|
||||||
const Tooltip = require('../components/tooltip')
|
const Tooltip = require('../components/tooltip')
|
||||||
const getCaretCoordinates = require('textarea-caret')
|
const getCaretCoordinates = require('textarea-caret')
|
||||||
|
const { RESTORE_VAULT_ROUTE, DEFAULT_ROUTE } = require('../routes')
|
||||||
const environmentType = require('../../../app/scripts/lib/environment-type')
|
const environmentType = require('../../../app/scripts/lib/environment-type')
|
||||||
const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums
|
const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums
|
||||||
|
|
||||||
let isSubmitting = false
|
class InitializeMenuScreen extends Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.animationEventEmitter = new EventEmitter()
|
||||||
|
this.state = {
|
||||||
|
warning: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { isInitialized, isUnlocked, history } = this.props
|
||||||
|
if (isInitialized || isUnlocked) {
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
document.getElementById('password-box').focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { warning } = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('.initialize-screen.flex-column.flex-center', [
|
||||||
|
|
||||||
|
h(Mascot, {
|
||||||
|
animationEventEmitter: this.animationEventEmitter,
|
||||||
|
}),
|
||||||
|
|
||||||
|
h('h1', {
|
||||||
|
style: {
|
||||||
|
fontSize: '1.3em',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
color: '#7F8082',
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
}, this.context.t('appName')),
|
||||||
|
|
||||||
|
h('div', [
|
||||||
|
h('h3', {
|
||||||
|
style: {
|
||||||
|
fontSize: '0.8em',
|
||||||
|
color: '#7F8082',
|
||||||
|
display: 'inline',
|
||||||
|
},
|
||||||
|
}, this.context.t('encryptNewDen')),
|
||||||
|
|
||||||
|
h(Tooltip, {
|
||||||
|
title: this.context.t('denExplainer'),
|
||||||
|
}, [
|
||||||
|
h('i.fa.fa-question-circle.pointer', {
|
||||||
|
style: {
|
||||||
|
fontSize: '18px',
|
||||||
|
position: 'relative',
|
||||||
|
color: 'rgb(247, 134, 28)',
|
||||||
|
top: '2px',
|
||||||
|
marginLeft: '4px',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('span.error.in-progress-notification', warning),
|
||||||
|
|
||||||
|
// password
|
||||||
|
h('input.large-input.letter-spacey', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box',
|
||||||
|
placeholder: this.context.t('newPassword'),
|
||||||
|
onInput: this.inputChanged.bind(this),
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
// confirm password
|
||||||
|
h('input.large-input.letter-spacey', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box-confirm',
|
||||||
|
placeholder: this.context.t('confirmPassword'),
|
||||||
|
onKeyPress: this.createVaultOnEnter.bind(this),
|
||||||
|
onInput: this.inputChanged.bind(this),
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
marginTop: 16,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
|
h('button.primary', {
|
||||||
|
onClick: this.createNewVaultAndKeychain.bind(this),
|
||||||
|
style: {
|
||||||
|
margin: 12,
|
||||||
|
},
|
||||||
|
}, this.context.t('createDen')),
|
||||||
|
|
||||||
|
h('.flex-row.flex-center.flex-grow', [
|
||||||
|
h('p.pointer', {
|
||||||
|
onClick: () => this.showRestoreVault(),
|
||||||
|
style: {
|
||||||
|
fontSize: '0.8em',
|
||||||
|
color: 'rgb(247, 134, 28)',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}, this.context.t('importDen')),
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('.flex-row.flex-center.flex-grow', [
|
||||||
|
h('p.pointer', {
|
||||||
|
onClick: this.showOldUI.bind(this),
|
||||||
|
style: {
|
||||||
|
fontSize: '0.8em',
|
||||||
|
color: '#aeaeae',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
marginTop: '32px',
|
||||||
|
},
|
||||||
|
}, 'Use classic interface'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
createVaultOnEnter (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
event.preventDefault()
|
||||||
|
this.createNewVaultAndKeychain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createNewVaultAndKeychain () {
|
||||||
|
const { history } = this.props
|
||||||
|
var passwordBox = document.getElementById('password-box')
|
||||||
|
var password = passwordBox.value
|
||||||
|
var passwordConfirmBox = document.getElementById('password-box-confirm')
|
||||||
|
var passwordConfirm = passwordConfirmBox.value
|
||||||
|
|
||||||
|
this.setState({ warning: null })
|
||||||
|
|
||||||
|
if (password.length < 8) {
|
||||||
|
this.setState({ warning: this.context.t('passwordShort') })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password !== passwordConfirm) {
|
||||||
|
this.setState({ warning: this.context.t('passwordMismatch') })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.createNewVaultAndKeychain(password)
|
||||||
|
.then(() => history.push(DEFAULT_ROUTE))
|
||||||
|
}
|
||||||
|
|
||||||
|
inputChanged (event) {
|
||||||
|
// tell mascot to look at page action
|
||||||
|
var element = event.target
|
||||||
|
var boundingRect = element.getBoundingClientRect()
|
||||||
|
var coordinates = getCaretCoordinates(element, element.selectionEnd)
|
||||||
|
this.animationEventEmitter.emit('point', {
|
||||||
|
x: boundingRect.left + coordinates.left - element.scrollLeft,
|
||||||
|
y: boundingRect.top + coordinates.top - element.scrollTop,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
showRestoreVault () {
|
||||||
|
this.props.markPasswordForgotten()
|
||||||
|
if (environmentType() === 'popup') {
|
||||||
|
global.platform.openExtensionInBrowser()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.history.push(RESTORE_VAULT_ROUTE)
|
||||||
|
}
|
||||||
|
|
||||||
|
showOldUI () {
|
||||||
|
this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
|
||||||
|
.then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeMenuScreen.propTypes = {
|
||||||
|
history: PropTypes.object,
|
||||||
|
isInitialized: PropTypes.bool,
|
||||||
|
isUnlocked: PropTypes.bool,
|
||||||
|
createNewVaultAndKeychain: PropTypes.func,
|
||||||
|
markPasswordForgotten: PropTypes.func,
|
||||||
|
dispatch: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
InitializeMenuScreen.contextTypes = {
|
InitializeMenuScreen.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(InitializeMenuScreen)
|
const mapStateToProps = state => {
|
||||||
|
const { metamask: { isInitialized, isUnlocked } } = state
|
||||||
|
|
||||||
|
|
||||||
inherits(InitializeMenuScreen, Component)
|
|
||||||
function InitializeMenuScreen () {
|
|
||||||
Component.call(this)
|
|
||||||
this.animationEventEmitter = new EventEmitter()
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
return {
|
return {
|
||||||
// state from plugin
|
isInitialized,
|
||||||
currentView: state.appState.currentView,
|
isUnlocked,
|
||||||
warning: state.appState.warning,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.render = function () {
|
const mapDispatchToProps = dispatch => {
|
||||||
var state = this.props
|
return {
|
||||||
|
createNewVaultAndKeychain: password => dispatch(actions.createNewVaultAndKeychain(password)),
|
||||||
switch (state.currentView.name) {
|
markPasswordForgotten: () => dispatch(actions.markPasswordForgotten()),
|
||||||
|
|
||||||
default:
|
|
||||||
return this.renderMenu(state)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeMenuScreen.prototype.componentDidMount = function(){
|
module.exports = connect(mapStateToProps, mapDispatchToProps)(InitializeMenuScreen)
|
||||||
// document.getElementById('password-box').focus()
|
|
||||||
// }
|
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.renderMenu = function (state) {
|
|
||||||
return (
|
|
||||||
|
|
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', [
|
|
||||||
|
|
||||||
h(Mascot, {
|
|
||||||
animationEventEmitter: this.animationEventEmitter,
|
|
||||||
}),
|
|
||||||
|
|
||||||
h('h1', {
|
|
||||||
style: {
|
|
||||||
fontSize: '1.3em',
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
color: '#7F8082',
|
|
||||||
marginBottom: 10,
|
|
||||||
},
|
|
||||||
}, this.context.t('appName')),
|
|
||||||
|
|
||||||
|
|
||||||
h('div', [
|
|
||||||
h('h3', {
|
|
||||||
style: {
|
|
||||||
fontSize: '0.8em',
|
|
||||||
color: '#7F8082',
|
|
||||||
display: 'inline',
|
|
||||||
},
|
|
||||||
}, this.context.t('encryptNewDen')),
|
|
||||||
|
|
||||||
h(Tooltip, {
|
|
||||||
title: this.context.t('denExplainer'),
|
|
||||||
}, [
|
|
||||||
h('i.fa.fa-question-circle.pointer', {
|
|
||||||
style: {
|
|
||||||
fontSize: '18px',
|
|
||||||
position: 'relative',
|
|
||||||
color: 'rgb(247, 134, 28)',
|
|
||||||
top: '2px',
|
|
||||||
marginLeft: '4px',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('span.in-progress-notification', state.warning),
|
|
||||||
|
|
||||||
// password
|
|
||||||
h('input.large-input.letter-spacey', {
|
|
||||||
type: 'password',
|
|
||||||
id: 'password-box',
|
|
||||||
placeholder: this.context.t('newPassword'),
|
|
||||||
onInput: this.inputChanged.bind(this),
|
|
||||||
style: {
|
|
||||||
width: 260,
|
|
||||||
marginTop: 12,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
// confirm password
|
|
||||||
h('input.large-input.letter-spacey', {
|
|
||||||
type: 'password',
|
|
||||||
id: 'password-box-confirm',
|
|
||||||
placeholder: this.context.t('confirmPassword'),
|
|
||||||
onKeyPress: this.createVaultOnEnter.bind(this),
|
|
||||||
onInput: this.inputChanged.bind(this),
|
|
||||||
style: {
|
|
||||||
width: 260,
|
|
||||||
marginTop: 16,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
|
|
||||||
h('button.primary', {
|
|
||||||
onClick: this.createNewVaultAndKeychain.bind(this),
|
|
||||||
style: {
|
|
||||||
margin: 12,
|
|
||||||
},
|
|
||||||
}, this.context.t('createDen')),
|
|
||||||
|
|
||||||
h('.flex-row.flex-center.flex-grow', [
|
|
||||||
h('p.pointer', {
|
|
||||||
onClick: this.showRestoreVault.bind(this),
|
|
||||||
style: {
|
|
||||||
fontSize: '0.8em',
|
|
||||||
color: 'rgb(247, 134, 28)',
|
|
||||||
textDecoration: 'underline',
|
|
||||||
},
|
|
||||||
}, this.context.t('importDen')),
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('.flex-row.flex-center.flex-grow', [
|
|
||||||
h('p.pointer', {
|
|
||||||
onClick: this.showOldUI.bind(this),
|
|
||||||
style: {
|
|
||||||
fontSize: '0.8em',
|
|
||||||
color: '#aeaeae',
|
|
||||||
textDecoration: 'underline',
|
|
||||||
marginTop: '32px',
|
|
||||||
},
|
|
||||||
}, 'Use classic interface'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.createVaultOnEnter = function (event) {
|
|
||||||
if (event.key === 'Enter') {
|
|
||||||
event.preventDefault()
|
|
||||||
this.createNewVaultAndKeychain()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.componentDidMount = function () {
|
|
||||||
document.getElementById('password-box').focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.showRestoreVault = function () {
|
|
||||||
this.props.dispatch(actions.markPasswordForgotten())
|
|
||||||
if (environmentType() === 'popup') {
|
|
||||||
global.platform.openExtensionInBrowser()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.showOldUI = function () {
|
|
||||||
this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
|
|
||||||
.then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () {
|
|
||||||
var passwordBox = document.getElementById('password-box')
|
|
||||||
var password = passwordBox.value
|
|
||||||
var passwordConfirmBox = document.getElementById('password-box-confirm')
|
|
||||||
var passwordConfirm = passwordConfirmBox.value
|
|
||||||
|
|
||||||
if (password.length < 8) {
|
|
||||||
this.warning = this.context.t('passwordShort')
|
|
||||||
this.props.dispatch(actions.displayWarning(this.warning))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (password !== passwordConfirm) {
|
|
||||||
this.warning = this.context.t('passwordMismatch')
|
|
||||||
this.props.dispatch(actions.displayWarning(this.warning))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSubmitting) {
|
|
||||||
isSubmitting = true
|
|
||||||
this.props.dispatch(actions.createNewVaultAndKeychain(password))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.inputChanged = function (event) {
|
|
||||||
// tell mascot to look at page action
|
|
||||||
var element = event.target
|
|
||||||
var boundingRect = element.getBoundingClientRect()
|
|
||||||
var coordinates = getCaretCoordinates(element, element.selectionEnd)
|
|
||||||
this.animationEventEmitter.emit('point', {
|
|
||||||
x: boundingRect.left + coordinates.left - element.scrollLeft,
|
|
||||||
y: boundingRect.top + coordinates.top - element.scrollTop,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
const { Component } = require('react')
|
const { Component } = require('react')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
const t = require('../i18n-helper').getMessage
|
const t = require('../i18n-helper').getMessage
|
||||||
|
|
||||||
class I18nProvider extends Component {
|
class I18nProvider extends Component {
|
||||||
@ -32,5 +34,8 @@ const mapStateToProps = state => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(I18nProvider)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps)
|
||||||
|
)(I18nProvider)
|
||||||
|
|
||||||
|
@ -4,12 +4,21 @@ const PropTypes = require('prop-types')
|
|||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const actions = require('../../../actions')
|
const actions = require('../../../actions')
|
||||||
|
const { withRouter } = require('react-router-dom')
|
||||||
|
const { compose } = require('recompose')
|
||||||
|
const {
|
||||||
|
DEFAULT_ROUTE,
|
||||||
|
INITIALIZE_BACKUP_PHRASE_ROUTE,
|
||||||
|
} = require('../../../routes')
|
||||||
|
|
||||||
RevealSeedConfirmation.contextTypes = {
|
RevealSeedConfirmation.contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(RevealSeedConfirmation)
|
module.exports = compose(
|
||||||
|
withRouter,
|
||||||
|
connect(mapStateToProps)
|
||||||
|
)(RevealSeedConfirmation)
|
||||||
|
|
||||||
|
|
||||||
inherits(RevealSeedConfirmation, Component)
|
inherits(RevealSeedConfirmation, Component)
|
||||||
@ -109,6 +118,8 @@ RevealSeedConfirmation.prototype.componentDidMount = function () {
|
|||||||
|
|
||||||
RevealSeedConfirmation.prototype.goHome = function () {
|
RevealSeedConfirmation.prototype.goHome = function () {
|
||||||
this.props.dispatch(actions.showConfigPage(false))
|
this.props.dispatch(actions.showConfigPage(false))
|
||||||
|
this.props.dispatch(actions.confirmSeedWords())
|
||||||
|
.then(() => this.props.history.push(DEFAULT_ROUTE))
|
||||||
}
|
}
|
||||||
|
|
||||||
// create vault
|
// create vault
|
||||||
@ -123,4 +134,5 @@ RevealSeedConfirmation.prototype.checkConfirmation = function (event) {
|
|||||||
RevealSeedConfirmation.prototype.revealSeedWords = function () {
|
RevealSeedConfirmation.prototype.revealSeedWords = function () {
|
||||||
var password = document.getElementById('password-box').value
|
var password = document.getElementById('password-box').value
|
||||||
this.props.dispatch(actions.requestRevealSeed(password))
|
this.props.dispatch(actions.requestRevealSeed(password))
|
||||||
|
.then(() => this.props.history.push(INITIALIZE_BACKUP_PHRASE_ROUTE))
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ const Component = require('react').Component
|
|||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const AccountAndTransactionDetails = require('./account-and-transaction-details')
|
const AccountAndTransactionDetails = require('./account-and-transaction-details')
|
||||||
const Settings = require('./settings')
|
const Settings = require('./components/pages/settings')
|
||||||
const UnlockScreen = require('./unlock')
|
const UnlockScreen = require('./components/pages/unlock')
|
||||||
|
|
||||||
module.exports = MainContainer
|
module.exports = MainContainer
|
||||||
|
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
const inherits = require('util').inherits
|
const { Component } = require('react')
|
||||||
const Component = require('react').Component
|
const PropTypes = require('prop-types')
|
||||||
const Provider = require('react-redux').Provider
|
const { Provider } = require('react-redux')
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const SelectedApp = require('./select-app')
|
const SelectedApp = require('./select-app')
|
||||||
|
|
||||||
module.exports = Root
|
class Root extends Component {
|
||||||
|
render () {
|
||||||
|
const { store } = this.props
|
||||||
|
|
||||||
inherits(Root, Component)
|
return (
|
||||||
function Root () { Component.call(this) }
|
h(Provider, { store }, [
|
||||||
|
h(SelectedApp),
|
||||||
Root.prototype.render = function () {
|
])
|
||||||
return (
|
)
|
||||||
|
}
|
||||||
h(Provider, {
|
|
||||||
store: this.props.store,
|
|
||||||
}, [
|
|
||||||
h(SelectedApp),
|
|
||||||
])
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Root.propTypes = {
|
||||||
|
store: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Root
|
||||||
|
49
ui/app/routes.js
Normal file
49
ui/app/routes.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
const DEFAULT_ROUTE = '/'
|
||||||
|
const UNLOCK_ROUTE = '/unlock'
|
||||||
|
const SETTINGS_ROUTE = '/settings'
|
||||||
|
const INFO_ROUTE = '/settings/info'
|
||||||
|
const REVEAL_SEED_ROUTE = '/seed'
|
||||||
|
const CONFIRM_SEED_ROUTE = '/confirm-seed'
|
||||||
|
const RESTORE_VAULT_ROUTE = '/restore-vault'
|
||||||
|
const ADD_TOKEN_ROUTE = '/add-token'
|
||||||
|
const NEW_ACCOUNT_ROUTE = '/new-account'
|
||||||
|
const IMPORT_ACCOUNT_ROUTE = '/new-account/import'
|
||||||
|
const SEND_ROUTE = '/send'
|
||||||
|
const CONFIRM_TRANSACTION_ROUTE = '/confirm-transaction'
|
||||||
|
const SIGNATURE_REQUEST_ROUTE = '/confirm-transaction/signature-request'
|
||||||
|
const NOTICE_ROUTE = '/notice'
|
||||||
|
const WELCOME_ROUTE = '/welcome'
|
||||||
|
const INITIALIZE_ROUTE = '/initialize'
|
||||||
|
const INITIALIZE_CREATE_PASSWORD_ROUTE = '/initialize/create-password'
|
||||||
|
const INITIALIZE_IMPORT_ACCOUNT_ROUTE = '/initialize/import-account'
|
||||||
|
const INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE = '/initialize/import-with-seed-phrase'
|
||||||
|
const INITIALIZE_UNIQUE_IMAGE_ROUTE = '/initialize/unique-image'
|
||||||
|
const INITIALIZE_NOTICE_ROUTE = '/initialize/notice'
|
||||||
|
const INITIALIZE_BACKUP_PHRASE_ROUTE = '/initialize/backup-phrase'
|
||||||
|
const INITIALIZE_CONFIRM_SEED_ROUTE = '/initialize/confirm-phrase'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
DEFAULT_ROUTE,
|
||||||
|
UNLOCK_ROUTE,
|
||||||
|
SETTINGS_ROUTE,
|
||||||
|
INFO_ROUTE,
|
||||||
|
REVEAL_SEED_ROUTE,
|
||||||
|
CONFIRM_SEED_ROUTE,
|
||||||
|
RESTORE_VAULT_ROUTE,
|
||||||
|
ADD_TOKEN_ROUTE,
|
||||||
|
NEW_ACCOUNT_ROUTE,
|
||||||
|
IMPORT_ACCOUNT_ROUTE,
|
||||||
|
SEND_ROUTE,
|
||||||
|
CONFIRM_TRANSACTION_ROUTE,
|
||||||
|
NOTICE_ROUTE,
|
||||||
|
SIGNATURE_REQUEST_ROUTE,
|
||||||
|
WELCOME_ROUTE,
|
||||||
|
INITIALIZE_ROUTE,
|
||||||
|
INITIALIZE_CREATE_PASSWORD_ROUTE,
|
||||||
|
INITIALIZE_IMPORT_ACCOUNT_ROUTE,
|
||||||
|
INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE,
|
||||||
|
INITIALIZE_UNIQUE_IMAGE_ROUTE,
|
||||||
|
INITIALIZE_NOTICE_ROUTE,
|
||||||
|
INITIALIZE_BACKUP_PHRASE_ROUTE,
|
||||||
|
INITIALIZE_CONFIRM_SEED_ROUTE,
|
||||||
|
}
|
@ -2,6 +2,7 @@ const inherits = require('util').inherits
|
|||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
|
const { HashRouter } = require('react-router-dom')
|
||||||
const App = require('./app')
|
const App = require('./app')
|
||||||
const OldApp = require('../../old-ui/app/app')
|
const OldApp = require('../../old-ui/app/app')
|
||||||
const { autoAddToBetaUI } = require('./selectors')
|
const { autoAddToBetaUI } = require('./selectors')
|
||||||
@ -63,7 +64,12 @@ SelectedApp.prototype.render = function () {
|
|||||||
// const Selected = betaUI || isMascara || firstTime ? App : OldApp
|
// const Selected = betaUI || isMascara || firstTime ? App : OldApp
|
||||||
|
|
||||||
const { betaUI, isMascara } = this.props
|
const { betaUI, isMascara } = this.props
|
||||||
const Selected = betaUI || isMascara ? h(I18nProvider, [ h(App) ]) : h(OldApp)
|
|
||||||
|
|
||||||
return Selected
|
return betaUI || isMascara
|
||||||
|
? h(HashRouter, {
|
||||||
|
hashType: 'noslash',
|
||||||
|
}, [
|
||||||
|
h(I18nProvider, [ h(App) ]),
|
||||||
|
])
|
||||||
|
: h(OldApp)
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ const {
|
|||||||
getGasTotal,
|
getGasTotal,
|
||||||
} = require('./components/send/send-utils')
|
} = require('./components/send/send-utils')
|
||||||
const { isValidAddress } = require('./util')
|
const { isValidAddress } = require('./util')
|
||||||
|
const { CONFIRM_TRANSACTION_ROUTE, DEFAULT_ROUTE } = require('./routes')
|
||||||
|
|
||||||
import PageContainer from './components/page-container/page-container.component'
|
import PageContainer from './components/page-container/page-container.component'
|
||||||
import SendHeader from './components/send_/send-header/send-header.container'
|
import SendHeader from './components/send_/send-header/send-header.container'
|
||||||
@ -186,6 +187,25 @@ SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SendTransactionScreen.prototype.renderHeader = function () {
|
||||||
|
const { selectedToken, clearSend, history } = this.props
|
||||||
|
|
||||||
|
return h('div.page-container__header', [
|
||||||
|
|
||||||
|
h('div.page-container__title', selectedToken ? this.context.t('sendTokens') : this.context.t('sendETH')),
|
||||||
|
|
||||||
|
h('div.page-container__subtitle', this.context.t('onlySendToEtherAddress')),
|
||||||
|
|
||||||
|
h('div.page-container__header-close', {
|
||||||
|
onClick: () => {
|
||||||
|
clearSend()
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
SendTransactionScreen.prototype.renderErrorMessage = function (errorType) {
|
SendTransactionScreen.prototype.renderErrorMessage = function (errorType) {
|
||||||
const { errors } = this.props
|
const { errors } = this.props
|
||||||
const errorMessage = errors[errorType]
|
const errorMessage = errors[errorType]
|
||||||
@ -478,12 +498,12 @@ SendTransactionScreen.prototype.renderForm = function () {
|
|||||||
|
|
||||||
SendTransactionScreen.prototype.renderFooter = function () {
|
SendTransactionScreen.prototype.renderFooter = function () {
|
||||||
const {
|
const {
|
||||||
goHome,
|
|
||||||
clearSend,
|
clearSend,
|
||||||
gasTotal,
|
gasTotal,
|
||||||
tokenBalance,
|
tokenBalance,
|
||||||
selectedToken,
|
selectedToken,
|
||||||
errors: { amount: amountError, to: toError },
|
errors: { amount: amountError, to: toError },
|
||||||
|
history,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
const missingTokenBalance = selectedToken && !tokenBalance
|
const missingTokenBalance = selectedToken && !tokenBalance
|
||||||
@ -492,7 +512,7 @@ SendTransactionScreen.prototype.renderFooter = function () {
|
|||||||
return h(PageContainerFooter, {
|
return h(PageContainerFooter, {
|
||||||
onCancel: () => {
|
onCancel: () => {
|
||||||
clearSend()
|
clearSend()
|
||||||
goHome()
|
history.push(DEFAULT_ROUTE)
|
||||||
},
|
},
|
||||||
onSubmit: e => this.onSubmit(e),
|
onSubmit: e => this.onSubmit(e),
|
||||||
disabled: !noErrors || !gasTotal || missingTokenBalance,
|
disabled: !noErrors || !gasTotal || missingTokenBalance,
|
||||||
@ -600,7 +620,6 @@ SendTransactionScreen.prototype.onSubmit = function (event) {
|
|||||||
|
|
||||||
if (editingTransactionId) {
|
if (editingTransactionId) {
|
||||||
const editedTx = this.getEditedTx()
|
const editedTx = this.getEditedTx()
|
||||||
|
|
||||||
updateTx(editedTx)
|
updateTx(editedTx)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -624,4 +643,6 @@ SendTransactionScreen.prototype.onSubmit = function (event) {
|
|||||||
? signTokenTx(selectedToken.address, to, amount, txParams)
|
? signTokenTx(selectedToken.address, to, amount, txParams)
|
||||||
: signTx(txParams)
|
: signTx(txParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.props.history.push(CONFIRM_TRANSACTION_ROUTE)
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,35 @@ import h from 'react-hyperscript'
|
|||||||
import { Component } from 'react'
|
import { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
|
import { withRouter } from 'react-router-dom'
|
||||||
|
import { compose } from 'recompose'
|
||||||
import {closeWelcomeScreen} from './actions'
|
import {closeWelcomeScreen} from './actions'
|
||||||
import Mascot from './components/mascot'
|
import Mascot from './components/mascot'
|
||||||
|
import { INITIALIZE_CREATE_PASSWORD_ROUTE } from './routes'
|
||||||
|
|
||||||
class WelcomeScreen extends Component {
|
class WelcomeScreen extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
closeWelcomeScreen: PropTypes.func.isRequired,
|
closeWelcomeScreen: PropTypes.func.isRequired,
|
||||||
|
welcomeScreenSeen: PropTypes.bool,
|
||||||
|
history: PropTypes.object,
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.animationEventEmitter = new EventEmitter()
|
this.animationEventEmitter = new EventEmitter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { history, welcomeScreenSeen } = this.props
|
||||||
|
|
||||||
|
if (welcomeScreenSeen) {
|
||||||
|
history.push(INITIALIZE_CREATE_PASSWORD_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initiateAccountCreation = () => {
|
initiateAccountCreation = () => {
|
||||||
this.props.closeWelcomeScreen()
|
this.props.closeWelcomeScreen()
|
||||||
|
this.props.history.push(INITIALIZE_CREATE_PASSWORD_ROUTE)
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@ -48,9 +62,18 @@ class WelcomeScreen extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
const mapStateToProps = ({ metamask: { welcomeScreenSeen } }) => {
|
||||||
null,
|
return {
|
||||||
dispatch => ({
|
welcomeScreenSeen,
|
||||||
closeWelcomeScreen: () => dispatch(closeWelcomeScreen()),
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withRouter,
|
||||||
|
connect(
|
||||||
|
mapStateToProps,
|
||||||
|
dispatch => ({
|
||||||
|
closeWelcomeScreen: () => dispatch(closeWelcomeScreen()),
|
||||||
|
})
|
||||||
|
)
|
||||||
)(WelcomeScreen)
|
)(WelcomeScreen)
|
||||||
|
Loading…
Reference in New Issue
Block a user