[BUG #1990] Improved amount validation in wallet/send screen

This commit is contained in:
Julien Eluard 2017-10-04 16:05:57 +02:00 committed by Roman Volosovskyi
parent 10752aeb5e
commit 23eeadf95a
16 changed files with 182 additions and 183 deletions

1
.env
View File

@ -1,5 +1,4 @@
TESTFAIRY_ENABLED=0 TESTFAIRY_ENABLED=0
WALLET_WIP_ENABLED=1
NOTIFICATIONS_WIP_ENABLED=1 NOTIFICATIONS_WIP_ENABLED=1
DEBUG_LOGS_ENABLED=1 DEBUG_LOGS_ENABLED=1
STUB_STATUS_GO=0 STUB_STATUS_GO=0

View File

@ -1,5 +1,4 @@
TESTFAIRY_ENABLED=1 TESTFAIRY_ENABLED=1
WALLET_WIP_ENABLED=1
NOTIFICATIONS_WIP_ENABLED=1 NOTIFICATIONS_WIP_ENABLED=1
DEBUG_LOGS_ENABLED=1 DEBUG_LOGS_ENABLED=1
STUB_STATUS_GO=0 STUB_STATUS_GO=0

View File

@ -1,4 +1,3 @@
TESTFAIRY_ENABLED=0 TESTFAIRY_ENABLED=0
WALLET_WIP_ENABLED=0
NOTIFICATIONS_WIP_ENABLED=0 NOTIFICATIONS_WIP_ENABLED=0
DEBUG_LOGS_ENABLED=0 DEBUG_LOGS_ENABLED=0

View File

@ -3,46 +3,34 @@
[status-im.components.react :as react] [status-im.components.react :as react]
[status-im.utils.platform :as platform])) [status-im.utils.platform :as platform]))
(defn- button [{:keys [on-press style text text-style disabled? fit-to-text?]}] (defn button-text [{:keys [disabled? text-style]} label]
[react/text {:style (merge (button.styles/button-text disabled?)
text-style)
:font (if platform/android? :medium :default)
:uppercase? (get-in platform/platform-specific [:uppercase?])}
label])
(defn button [{:keys [on-press style disabled? fit-to-text?] :as props} label]
[react/touchable-highlight (merge {:underlay-color button.styles/border-color-high} [react/touchable-highlight (merge {:underlay-color button.styles/border-color-high}
(when-not fit-to-text? (when-not fit-to-text?
{:style button.styles/button-container}) {:style button.styles/button-container})
(when (and on-press (when (and on-press (not disabled?))
(not disabled?))
{:on-press on-press})) {:on-press on-press}))
[react/view {:style (merge (button.styles/button disabled?) [react/view {:style (merge (button.styles/button disabled?)
style)} style)}
[react/text {:style (merge (button.styles/button-text disabled?) [button-text props
text-style) label]]])
:font :medium
:uppercase? platform/android?}
text]]])
(defn primary-button [{:keys [style text-style] :as m}] (defn primary-button [{:keys [style text-style] :as m} label]
(button (assoc m [button (assoc m
:fit-to-text? true :fit-to-text? true
:style (merge button.styles/primary-button style) :style (merge button.styles/primary-button style)
:text-style (merge button.styles/primary-button-text text-style)))) :text-style (merge button.styles/primary-button-text text-style))
label])
(defn secondary-button [{:keys [style text-style] :as m}] (defn secondary-button [{:keys [style text-style] :as m} label]
(button (assoc m [button (assoc m
:fit-to-text? true :fit-to-text? true
:style (merge button.styles/secondary-button style) :style (merge button.styles/secondary-button style)
:text-style (merge button.styles/secondary-button-text text-style)))) :text-style (merge button.styles/secondary-button-text text-style))
label])
(defn- position [i v]
(cond
(zero? i) :first
(= i (dec (count v))) :last
:else :other))
(defn buttons
([v] (buttons nil v))
([{:keys [style button-text-style]} v]
[react/view {:style (merge button.styles/buttons-container style)}
(doall
(map-indexed
(fn [i m] ^{:key i} [button (merge m
{:style (button.styles/button-bar (position i v))
:text-style button-text-style})])
v))]))

View File

@ -362,6 +362,7 @@
:wallet-total-value "Total value" :wallet-total-value "Total value"
:wallet-settings "Wallet Settings" :wallet-settings "Wallet Settings"
:signing-phrase-description "Sign the transaction by entering your password. Make sure that the words above match your secret signing phrase" :signing-phrase-description "Sign the transaction by entering your password. Make sure that the words above match your secret signing phrase"
:wallet-insufficient-funds "Insufficient funds"
:request-transaction "Request Transaction" :request-transaction "Request Transaction"
:send-request "Send request" :send-request "Send request"
:share "Share" :share "Share"
@ -385,7 +386,7 @@
:view-transaction-details "View Transaction Details" :view-transaction-details "View Transaction Details"
:transaction-description "If you want to be sure you transaction will not be compromised wait until it gets at least 10 block confirmations" :transaction-description "If you want to be sure you transaction will not be compromised wait until it gets at least 10 block confirmations"
:transaction-sent "Transaction Sent" :transaction-sent "Transaction Sent"
:transaction-moved-text "The transaction has ben successfully moved to “Unsigned”" :transaction-moved-text "The transaction has been successfully moved to “Unsigned”"
:transaction-moved-title "Transaction Moved" :transaction-moved-title "Transaction Moved"
:sign-later-title "Sign Transaction Later?" :sign-later-title "Sign Transaction Later?"
:sign-later-text "You will be able to sign in in the transaction history" :sign-later-text "You will be able to sign in in the transaction history"
@ -398,7 +399,8 @@
:wallet-choose-from-contacts "Choose From Contacts" :wallet-choose-from-contacts "Choose From Contacts"
:wallet-address-from-clipboard "Use Address From Clipboard" :wallet-address-from-clipboard "Use Address From Clipboard"
:wallet-browse-photos "Browse Photos" :wallet-browse-photos "Browse Photos"
:validation-amount-invalid-number "Amount is not valid number" :validation-amount-invalid "Amount is not valid"
:validation-amount-invalid-number "Amount is not a valid number"
:validation-amount-is-too-precise "Amount is too precise. The smallest unit you can send is 1 Wei (1x10^-18 ETH)" :validation-amount-is-too-precise "Amount is too precise. The smallest unit you can send is 1 Wei (1x10^-18 ETH)"

View File

@ -7,6 +7,7 @@
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.components.icons.vector-icons :as vector-icons] [status-im.components.icons.vector-icons :as vector-icons]
[status-im.components.animation :as animation] [status-im.components.animation :as animation]
[status-im.utils.money :as money]
[status-im.utils.platform :as platform] [status-im.utils.platform :as platform]
[status-im.ui.screens.wallet.components.animations :as animations])) [status-im.ui.screens.wallet.components.animations :as animations]))
@ -73,16 +74,18 @@
;;TODO (andrey) this should be choose component with the list of wallets ;;TODO (andrey) this should be choose component with the list of wallets
(views/defview choose-wallet [& [style]] (views/defview choose-wallet [& [style]]
(views/letsubs [eth-balance [:eth-balance]] (views/letsubs [balance [:balance]]
[react/view [react/view
[react/text {:style styles/label} (i18n/label :t/wallet)] [react/text {:style styles/label} (i18n/label :t/wallet)]
[react/view (merge styles/wallet-container [react/view (merge styles/wallet-container
style) style)
[react/text {:style styles/wallet-name} "Main wallet"] [react/text {:style styles/wallet-name} (i18n/label :t/main-wallet)]
[react/text {:style styles/wallet-value [react/text {:style styles/wallet-value
:number-of-lines 1 :number-of-lines 1
:ellipsizeMode :middle} :ellipsizeMode :middle}
(str eth-balance " ETH")]]])) (if balance
(money/wei->str :eth balance)
"...")]]]))
(defn network-label (defn network-label
([n] (network-label [{} n])) ([n] (network-label [{} n]))

View File

@ -24,9 +24,12 @@
(let [amount' (string/replace amount #"," ".") (let [amount' (string/replace amount #"," ".")
amount-splited (string/split amount' #"[.]")] amount-splited (string/split amount' #"[.]")]
(cond (cond
(or (nil? amount) (= amount "") (= amount "0") (re-matches #"0[,.]0*$" amount)) (or (nil? amount) (= amount "") (re-matches #"0[,.]0*$" amount))
nil nil
(= amount "0")
(i18n/label :t/validation-amount-invalid)
(or (js/isNaN (js/parseFloat amount')) (or (js/isNaN (js/parseFloat amount'))
(try (when (<= (.toWei web3 amount' "ether") 0) true) (try (when (<= (.toWei web3 amount' "ether") 0) true)
(catch :default err true))) (catch :default err true)))

View File

@ -12,11 +12,13 @@
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.react-native.resources :as resources] [status-im.react-native.resources :as resources]
[status-im.utils.config :as config] [status-im.utils.config :as config]
[status-im.utils.utils :as utils] [status-im.utils.money :as money]
[status-im.utils.platform :as platform] [status-im.utils.platform :as platform]
[status-im.utils.utils :as utils]
[status-im.ui.screens.wallet.main.styles :as styles] [status-im.ui.screens.wallet.main.styles :as styles]
[status-im.ui.screens.wallet.styles :as wallet.styles] [status-im.ui.screens.wallet.styles :as wallet.styles]
[status-im.components.styles :as components.styles] [status-im.components.styles :as components.styles]
[status-im.components.button.styles :as button.styles]
[status-im.ui.screens.wallet.views :as wallet.views])) [status-im.ui.screens.wallet.views :as wallet.views]))
(defn- show-not-implemented! [] (defn- show-not-implemented! []
@ -59,6 +61,11 @@
(str (when pos-change? "+") change "%") (str (when pos-change? "+") change "%")
"-%")]])) "-%")]]))
(defn- wallet-send []
(rf/dispatch [:navigate-to :wallet-send-transaction])
(when platform/android?
(rf/dispatch [:request-permissions [:camera]])))
(defn main-section [usd-value change error-message] (defn main-section [usd-value change error-message]
[react/view {:style styles/main-section} [react/view {:style styles/main-section}
(when error-message (when error-message
@ -71,17 +78,13 @@
[react/text {:style styles/value-variation-title} [react/text {:style styles/value-variation-title}
(i18n/label :t/wallet-total-value)] (i18n/label :t/wallet-total-value)]
[change-display change]] [change-display change]]
[btn/buttons {:style styles/buttons :button-text-style styles/main-button-text} [react/view {:style (merge button.styles/buttons-container styles/buttons) :button-text-style styles/main-button-text}
[{:text (i18n/label :t/wallet-send) [btn/button {:on-press wallet-send :style (button.styles/button-bar :first)}
:on-press #(do (rf/dispatch [:navigate-to :wallet-send-transaction]) (i18n/label :t/wallet-send)]
(when platform/android? [btn/button {:on-press #(rf/dispatch [:navigate-to :wallet-request-transaction]) :style (button.styles/button-bar :other)}
(rf/dispatch [:request-permissions [:camera]]))) (i18n/label :t/wallet-request)]
:disabled? (not config/wallet-wip-enabled?)} [btn/button {:disabled? true :style (button.styles/button-bar :last)}
{:text (i18n/label :t/wallet-request) (i18n/label :t/wallet-exchange)]]]])
:on-press #(rf/dispatch [:navigate-to :wallet-request-transaction])
:disabled? (not config/wallet-wip-enabled?)}
{:text (i18n/label :t/wallet-exchange)
:disabled? true}]]]])
(defn- token->image [id] (defn- token->image [id]
(case id (case id
@ -115,14 +118,14 @@
(let [{:keys [source style]} (token->image id)] (let [{:keys [source style]} (token->image id)]
[list/item-image source style]) [list/item-image source style])
[react/view {:style styles/asset-item-value-container} [react/view {:style styles/asset-item-value-container}
[react/text {:style styles/asset-item-value} (str amount)] [react/text {:style styles/asset-item-value} (str (money/wei->ether amount))]
[react/text {:style styles/asset-item-currency [react/text {:style styles/asset-item-currency
:uppercase? true} :uppercase? true}
id]]]] id]]]]
[add-asset])) [add-asset]))
(defn asset-section [eth prices-loading? balance-loading?] (defn asset-section [balance prices-loading? balance-loading?]
(let [assets [{:id "eth" :currency :eth :amount eth}]] (let [assets [{:id "eth" :currency :eth :amount balance}]]
[react/view {:style styles/asset-section} [react/view {:style styles/asset-section}
[react/text {:style styles/asset-section-title} (i18n/label :t/wallet-assets)] [react/text {:style styles/asset-section-title} (i18n/label :t/wallet-assets)]
[list/flat-list [list/flat-list
@ -132,7 +135,7 @@
:refreshing (boolean (or prices-loading? balance-loading?))}]])) :refreshing (boolean (or prices-loading? balance-loading?))}]]))
(defview wallet [] (defview wallet []
(letsubs [eth-balance [:eth-balance] (letsubs [balance [:balance]
portfolio-value [:portfolio-value] portfolio-value [:portfolio-value]
portfolio-change [:portfolio-change] portfolio-change [:portfolio-change]
prices-loading? [:prices-loading?] prices-loading? [:prices-loading?]
@ -142,4 +145,4 @@
[toolbar-view] [toolbar-view]
[react/view components.styles/flex [react/view components.styles/flex
[main-section portfolio-value portfolio-change error-message] [main-section portfolio-value portfolio-change error-message]
[asset-section eth-balance prices-loading? balance-loading?]]])) [asset-section balance prices-loading? balance-loading?]]]))

View File

@ -99,7 +99,7 @@
:wallet/keys [send-transaction] :wallet/keys [send-transaction]
:accounts/keys [accounts current-account-id] :as db} :db} [_ later?]] :accounts/keys [accounts current-account-id] :as db} :db} [_ later?]]
(let [{:keys [amount transaction-id password]} send-transaction (let [{:keys [amount transaction-id password]} send-transaction
amount' (money/to-wei (string/replace amount #"," "."))] amount-in-wei (money/to-wei (string/replace amount #"," "."))]
(if transaction-id (if transaction-id
{::accept-transaction {:id transaction-id {::accept-transaction {:id transaction-id
:password password :password password
@ -110,7 +110,7 @@
::send-transaction {:web3 web3 ::send-transaction {:web3 web3
:from (get-in accounts [current-account-id :address]) :from (get-in accounts [current-account-id :address])
:to (:to-address send-transaction) :to (:to-address send-transaction)
:value amount'}})))) :value amount-in-wei}}))))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/discard-transaction :wallet/discard-transaction

View File

@ -1,27 +1,24 @@
(ns status-im.ui.screens.wallet.send.views (ns status-im.ui.screens.wallet.send.views
(:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [clojure.string :as str] (:require [clojure.string :as string]
[status-im.components.react :as react]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[status-im.components.button.view :as button] [status-im.components.animation :as animation]
[status-im.components.icons.vector-icons :as vector-icons]
[status-im.components.react :as react]
[status-im.components.status-bar :as status-bar] [status-im.components.status-bar :as status-bar]
[status-im.components.styles :as components.styles]
[status-im.components.toolbar-new.actions :as act] [status-im.components.toolbar-new.actions :as act]
[status-im.components.toolbar-new.view :as toolbar] [status-im.components.toolbar-new.view :as toolbar]
[status-im.components.camera :as camera] [status-im.components.camera :as camera]
[status-im.utils.utils :as utils] [status-im.utils.utils :as utils]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.screens.wallet.send.styles :as send.styles] [status-im.utils.money :as money]
[status-im.components.icons.vector-icons :as vector-icons]
[reagent.core :as r]
[status-im.utils.platform :as platform] [status-im.utils.platform :as platform]
[status-im.ui.screens.wallet.request.styles :as request.styles] [status-im.ui.screens.wallet.request.styles :as request.styles]
[status-im.ui.screens.wallet.send.styles :as styles]
[status-im.ui.screens.wallet.components.views :as components] [status-im.ui.screens.wallet.components.views :as components]
[status-im.components.styles :as components.styles]
[status-im.components.icons.vector-icons :as vi]
[status-im.components.animation :as animation]
[status-im.ui.screens.wallet.styles :as wallet.styles] [status-im.ui.screens.wallet.styles :as wallet.styles]
[status-im.ui.screens.wallet.send.animations :as send.animations])) [status-im.ui.screens.wallet.send.animations :as send.animations]
[status-im.ui.screens.wallet.send.styles :as send.styles]))
(defn toolbar-view [signing?] (defn toolbar-view [signing?]
[toolbar/toolbar2 {:style wallet.styles/toolbar} [toolbar/toolbar2 {:style wallet.styles/toolbar}
@ -45,24 +42,22 @@
bottom-value (animation/create-value -250) bottom-value (animation/create-value -250)
opacity-value (animation/create-value 0)] opacity-value (animation/create-value 0)]
{:component-did-mount #(send.animations/animate-sign-panel opacity-value bottom-value)} {:component-did-mount #(send.animations/animate-sign-panel opacity-value bottom-value)}
[react/animated-view {:style (styles/animated-sign-panel bottom-value)} [react/animated-view {:style (send.styles/animated-sign-panel bottom-value)}
[react/animated-view {:style (styles/sign-panel opacity-value)} [react/animated-view {:style (send.styles/sign-panel opacity-value)}
[react/view styles/signing-phrase-container [react/view send.styles/signing-phrase-container
[react/text {:style styles/signing-phrase} signing-phrase]] [react/text {:style send.styles/signing-phrase} signing-phrase]]
[react/text {:style styles/signing-phrase-description} (i18n/label :t/signing-phrase-description)] [react/text {:style send.styles/signing-phrase-description} (i18n/label :t/signing-phrase-description)]
[react/view styles/password-container [react/view send.styles/password-container
[react/text-input [react/text-input
{:auto-focus true {:auto-focus true
:secure-text-entry true :secure-text-entry true
:placeholder (i18n/label :t/enter-password) :placeholder (i18n/label :t/enter-password)
:placeholder-text-color "#939ba1" :placeholder-text-color "#939ba1"
:on-change-text #(do :on-change-text #(re-frame/dispatch [:set-in [:wallet/send-transaction :password] %])
(re-frame/dispatch [:set-in [:wallet/send-transaction :password] %])) :style send.styles/password}]]]
:style styles/password}]]]
(when wrong-password? (when wrong-password?
[components/tooltip (i18n/label :t/wrong-password)])])) [components/tooltip (i18n/label :t/wrong-password)])]))
(defview signing-buttons [] (defview signing-buttons []
(letsubs [sign-enabled? [:wallet.send/sign-password-enabled?]] (letsubs [sign-enabled? [:wallet.send/sign-password-enabled?]]
[react/view wallet.styles/buttons-container [react/view wallet.styles/buttons-container
@ -73,52 +68,64 @@
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet/sign-transaction])} [react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet/sign-transaction])}
[react/view (wallet.styles/button-container sign-enabled?) [react/view (wallet.styles/button-container sign-enabled?)
[components/button-text (i18n/label :t/transactions-sign-transaction)] [components/button-text (i18n/label :t/transactions-sign-transaction)]
[vi/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]])) [vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
(defview sign-buttons [] (defn sign-enabled? [amount-error to-address amount]
(letsubs [sign-enabled? [:wallet.send/sign-enabled?]] (and
(nil? amount-error)
(not (nil? to-address)) (not= to-address "")
(not (nil? amount)) (not= amount "")))
(defn- sign-buttons [amount-error to-address amount sufficient-funds?]
(let [sign-enabled? (sign-enabled? amount-error to-address amount)
immediate-sign-enabled? (and sign-enabled? sufficient-funds?)]
[react/view wallet.styles/buttons-container [react/view wallet.styles/buttons-container
(when sign-enabled? (when sign-enabled?
[react/touchable-highlight {:on-press sign-later} [react/touchable-highlight {:on-press sign-later}
[react/view (wallet.styles/button-container sign-enabled?) [react/view (wallet.styles/button-container sign-enabled?)
[components/button-text (i18n/label :t/transactions-sign-later)]]]) [components/button-text (i18n/label :t/transactions-sign-later)]]])
[react/view components.styles/flex] [react/view components.styles/flex]
[react/touchable-highlight {:on-press (when sign-enabled? #(re-frame/dispatch [:set-in [:wallet/send-transaction :signing?] true]))} [react/touchable-highlight {:on-press (when immediate-sign-enabled? #(re-frame/dispatch [:set-in [:wallet/send-transaction :signing?] true]))}
[react/view (wallet.styles/button-container sign-enabled?) [react/view (wallet.styles/button-container immediate-sign-enabled?)
[components/button-text (i18n/label :t/transactions-sign-transaction)] [components/button-text (i18n/label :t/transactions-sign-transaction)]
[vi/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]])) [vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
(defn- sufficient-funds? [amount balance]
(<= amount (money/wei->ether balance)))
(defview send-transaction [] (defview send-transaction []
(letsubs [amount [:get-in [:wallet/send-transaction :amount]] (letsubs [balance [:balance]
amount [:get-in [:wallet/send-transaction :amount]]
amount-error [:get-in [:wallet/send-transaction :amount-error]] amount-error [:get-in [:wallet/send-transaction :amount-error]]
signing? [:get-in [:wallet/send-transaction :signing?]] signing? [:get-in [:wallet/send-transaction :signing?]]
to-address [:get-in [:wallet/send-transaction :to-address]] to-address [:get-in [:wallet/send-transaction :to-address]]
to-name [:get-in [:wallet/send-transaction :to-name]]] to-name [:get-in [:wallet/send-transaction :to-name]]]
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container (let [sufficient-funds? (sufficient-funds? amount balance)]
[react/view components.styles/flex [react/keyboard-avoiding-view wallet.styles/wallet-modal-container
[status-bar/status-bar {:type :wallet}]
[toolbar-view signing?]
[react/scroll-view {:keyboardShouldPersistTaps :always}
[react/view components.styles/flex [react/view components.styles/flex
[react/view wallet.styles/choose-participant-container [status-bar/status-bar {:type :wallet}]
[components/choose-recipient {:address to-address [toolbar-view signing?]
:name to-name [react/scroll-view {:keyboardShouldPersistTaps :always}
:on-press #(re-frame/dispatch [:navigate-to :choose-recipient])}]] [react/view components.styles/flex
[react/view wallet.styles/choose-wallet-container [react/view wallet.styles/choose-participant-container
[components/choose-wallet]] [components/choose-recipient {:address to-address
[react/view wallet.styles/amount-container :name to-name
[components/amount-input :on-press #(re-frame/dispatch [:navigate-to :choose-recipient])}]]
{:error amount-error [react/view wallet.styles/choose-wallet-container
:input-options {:auto-focus true [components/choose-wallet]]
:default-value amount [react/view wallet.styles/amount-container
:on-change-text #(do [components/amount-input
(re-frame/dispatch [:set-in [:wallet/send-transaction :amount] %]) {:error (or amount-error (when-not sufficient-funds? (i18n/label :t/wallet-insufficient-funds)))
(re-frame/dispatch [:wallet-validate-amount]))}}] :input-options {:auto-focus true
[react/view wallet.styles/choose-currency-container :default-value amount
[components/choose-currency wallet.styles/choose-currency]]]]] :on-change-text #(let [value (string/trim %)]
[components/separator] (re-frame/dispatch [:set-in [:wallet/send-transaction :amount] value])
(if signing? (re-frame/dispatch [:wallet-validate-amount]))}}]
[signing-buttons] [react/view wallet.styles/choose-currency-container
[sign-buttons]) [components/choose-currency wallet.styles/choose-currency]]]]]
(when signing? [components/separator]
[sign-panel])]])) (if signing?
[signing-buttons]
[sign-buttons amount-error to-address amount sufficient-funds?])
(when signing?
[sign-panel])]])))

View File

@ -25,13 +25,6 @@
(or (get-in wallet [:errors :balance-update]) (or (get-in wallet [:errors :balance-update])
(get-in wallet [:errors :prices-update])))) (get-in wallet [:errors :prices-update]))))
(reg-sub :eth-balance
:<- [:balance]
(fn [balance]
(if balance
(money/wei->ether balance)
"...")))
(reg-sub :portfolio-value (reg-sub :portfolio-value
:<- [:balance] :<- [:balance]
:<- [:price] :<- [:price]

View File

@ -92,50 +92,50 @@
;; transaction details ;; transaction details
(def transaction-details-row (def details-row
{:flex-direction :row {:flex-direction :row
:margin-vertical 5}) :margin-vertical 5})
(def transaction-details-item-label (def details-item-label
{:flex 1 {:flex 1
:margin-right 10 :margin-right 10
:color styles/color-gray4 :color styles/color-gray4
:font-size 14}) :font-size 14})
(def transaction-details-item-value-wrapper (def details-item-value-wrapper
{:flex 5}) {:flex 5})
(def transaction-details-item-value (def details-item-value
{:font-size 14 {:font-size 14
:color styles/color-black}) :color styles/color-black})
(def transaction-details-item-extra-value (def details-item-extra-value
{:font-size 14 {:font-size 14
:color styles/color-gray4}) :color styles/color-gray4})
(def transaction-details-header (def details-header
{:margin-horizontal 16 {:margin-horizontal 16
:margin-top 10 :margin-top 10
:flex-direction :row}) :flex-direction :row})
(def transaction-details-header-icon (def details-header-icon
{:margin-vertical 7}) {:margin-vertical 7})
(def transaction-details-header-infos (def details-header-infos
{:flex 1 {:flex 1
:flex-direction :column :flex-direction :column
:margin-left 12 :margin-left 12
:margin-vertical 7}) :margin-vertical 7})
(def transaction-details-header-value (def details-header-value
{:font-size 16 {:font-size 16
:color styles/color-black}) :color styles/color-black})
(def transaction-details-header-date (def details-header-date
{:font-size 14 {:font-size 14
:color styles/color-gray4}) :color styles/color-gray4})
(def transaction-details-block (def details-block
{:margin-horizontal 16}) {:margin-horizontal 16})
(def progress-bar (def progress-bar
@ -152,17 +152,17 @@
:background-color styles/color-blue2 :background-color styles/color-blue2
:opacity 0.30}) :opacity 0.30})
(def transaction-details-confirmations-count (def details-confirmations-count
{:color styles/color-black {:color styles/color-black
:font-size 15 :font-size 15
:margin-vertical 2}) :margin-vertical 2})
(def transaction-details-confirmations-helper-text (def details-confirmations-helper-text
{:color styles/color-gray4 {:color styles/color-gray4
:font-size 14 :font-size 14
:margin-vertical 2}) :margin-vertical 2})
(def transaction-details-separator (def details-separator
{:background-color styles/color-light-gray3 {:background-color styles/color-light-gray3
:height 1 :height 1
:margin-vertical 10}) :margin-vertical 10})

View File

@ -26,12 +26,11 @@
(group-by :type (vals transactions)))) (group-by :type (vals transactions))))
(defn format-unsigned-transaction [{:keys [message-id gas-price] :as transaction}] (defn format-unsigned-transaction [{:keys [message-id gas-price] :as transaction}]
(-> transaction (assoc transaction
(update :value money/wei->ether) :type :unsigned
(assoc :type :unsigned :confirmations 0
:confirmations 0 :symbol "ETH"
:symbol "ETH" :hash message-id))
:hash message-id)))
(reg-sub :wallet.transactions/unsigned-transactions (reg-sub :wallet.transactions/unsigned-transactions
:<- [:transactions] :<- [:transactions]

View File

@ -13,6 +13,7 @@
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.screens.wallet.transactions.styles :as transactions.styles] [status-im.ui.screens.wallet.transactions.styles :as transactions.styles]
[status-im.ui.screens.wallet.views :as wallet.views] [status-im.ui.screens.wallet.views :as wallet.views]
[status-im.utils.money :as money]
[status-im.utils.utils :as utils]) [status-im.utils.utils :as utils])
(:require-macros [status-im.utils.views :refer [defview letsubs]])) (:require-macros [status-im.utils.views :refer [defview letsubs]]))
@ -98,7 +99,7 @@
[list/item [list/item
[list/item-icon (transaction-type->icon (keyword type))] [list/item-icon (transaction-type->icon (keyword type))]
[list/item-content [list/item-content
(str value " " symbol) (money/wei->str :eth value)
(if (inbound? type) (if (inbound? type)
(str (i18n/label :t/from) " " from) (str (i18n/label :t/from) " " from)
(str (i18n/label :t/to) " " to)) (str (i18n/label :t/to) " " to))
@ -205,66 +206,70 @@
[toolbar-view view-id unsigned-transactions-count] [toolbar-view view-id unsigned-transactions-count]
[main-section view-id tabs]]))) [main-section view-id tabs]])))
(defn transaction-details-header [{:keys [value date type]}] (defn- pretty-print-asset [symbol amount]
[react/view {:style transactions.styles/transaction-details-header} (case symbol
[react/view {:style transactions.styles/transaction-details-header-icon} "ETH" (if amount (money/wei->str :eth amount) "...")))
(defn details-header [{:keys [value date type symbol]}]
[react/view {:style transactions.styles/details-header}
[react/view {:style transactions.styles/details-header-icon}
[list/item-icon (transaction-type->icon type)]] [list/item-icon (transaction-type->icon type)]]
[react/view {:style transactions.styles/transaction-details-header-infos} [react/view {:style transactions.styles/details-header-infos}
[react/text {:style transactions.styles/transaction-details-header-value} (str value " ETH")] [react/text {:style transactions.styles/details-header-value} (pretty-print-asset symbol value)]
[react/text {:style transactions.styles/transaction-details-header-date} date]]]) [react/text {:style transactions.styles/details-header-date} date]]])
(defn progress-bar [progress] (defn progress-bar [progress]
[react/view {:style transactions.styles/progress-bar} [react/view {:style transactions.styles/progress-bar}
[react/view {:style (transactions.styles/progress-bar-done progress)}] [react/view {:style (transactions.styles/progress-bar-done progress)}]
[react/view {:style (transactions.styles/progress-bar-todo (- 100 progress))}]]) [react/view {:style (transactions.styles/progress-bar-todo (- 100 progress))}]])
(defn transaction-details-confirmations [confirmations confirmations-progress] (defn details-confirmations [confirmations confirmations-progress]
[react/view {:style transactions.styles/transaction-details-block} [react/view {:style transactions.styles/details-block}
[progress-bar confirmations-progress] [progress-bar confirmations-progress]
[react/text {:style transactions.styles/transaction-details-confirmations-count} [react/text {:style transactions.styles/details-confirmations-count}
(str confirmations " " (i18n/label :t/confirmations))] (str confirmations " " (i18n/label :t/confirmations))]
[react/text {:style transactions.styles/transaction-details-confirmations-helper-text} [react/text {:style transactions.styles/details-confirmations-helper-text}
(i18n/label :t/confirmations-helper-text)]]) (i18n/label :t/confirmations-helper-text)]])
(defn transaction-details-list-row (defn details-list-row
([label value] ([label value]
(transaction-details-list-row label value nil)) (details-list-row label value nil))
([label value extra-value] ([label value extra-value]
[react/view {:style transactions.styles/transaction-details-row} [react/view {:style transactions.styles/details-row}
[react/text {:style transactions.styles/transaction-details-item-label} (i18n/label label)] [react/text {:style transactions.styles/details-item-label} (i18n/label label)]
[react/view {:style transactions.styles/transaction-details-item-value-wrapper} [react/view {:style transactions.styles/details-item-value-wrapper}
[react/text {:style transactions.styles/transaction-details-item-value} (str value)] [react/text {:style transactions.styles/details-item-value} (str value)]
[react/text {:style transactions.styles/transaction-details-item-extra-value} (str extra-value)]]])) [react/text {:style transactions.styles/details-item-extra-value} (str extra-value)]]]))
(defn transaction-details-list [{:keys [block hash from from-wallet to to-wallet gas-limit gas-price-gwei gas-price-eth gas-used cost nonce data]}] (defn details-list [{:keys [block hash from from-wallet to to-wallet gas-limit gas-price-gwei gas-price-eth gas-used cost nonce data]}]
[react/view {:style transactions.styles/transaction-details-block} [react/view {:style transactions.styles/details-block}
[transaction-details-list-row :t/block block] [details-list-row :t/block block]
[transaction-details-list-row :t/hash hash] [details-list-row :t/hash hash]
[transaction-details-list-row :t/from (or from-wallet from) (when from-wallet from)] [details-list-row :t/from (or from-wallet from) (when from-wallet from)]
[transaction-details-list-row :t/to (or to-wallet to) (when to-wallet to)] [details-list-row :t/to (or to-wallet to) (when to-wallet to)]
[transaction-details-list-row :t/gas-limit gas-limit] [details-list-row :t/gas-limit gas-limit]
[transaction-details-list-row :t/gas-price gas-price-gwei gas-price-eth] [details-list-row :t/gas-price gas-price-gwei gas-price-eth]
[transaction-details-list-row :t/gas-used gas-used] [details-list-row :t/gas-used gas-used]
[transaction-details-list-row :t/cost-fee cost] [details-list-row :t/cost-fee cost]
[transaction-details-list-row :t/nonce nonce] [details-list-row :t/nonce nonce]
[transaction-details-list-row :t/data data]]) [details-list-row :t/data data]])
(defn details-action [hash url] (defn details-action [hash url]
[(actions/opts [{:text (i18n/label :t/copy-transaction-hash) :value #(react/copy-to-clipboard hash)} [(actions/opts [{:text (i18n/label :t/copy-transaction-hash) :value #(react/copy-to-clipboard hash)}
{:text (i18n/label :t/open-on-etherscan) :value #(.openURL react/linking url)}])]) {:text (i18n/label :t/open-on-etherscan) :value #(.openURL react/linking url)}])])
(defview transaction-details [] (defview transaction-details []
(letsubs [{:keys [hash url type] :as transaction-details} [:wallet.transactions/transaction-details] (letsubs [{:keys [hash url type] :as transactions} [:wallet.transactions/details]
confirmations [:wallet.transactions.details/confirmations] confirmations [:wallet.transactions.details/confirmations]
confirmations-progress [:wallet.transactions.details/confirmations-progress]] confirmations-progress [:wallet.transactions.details/confirmations-progress]]
[react/view {:style styles/flex} [react/view {:style styles/flex}
[status-bar/status-bar] [status-bar/status-bar]
[toolbar/toolbar2 {} [toolbar/toolbar2 {}
toolbar/default-nav-back toolbar/default-nav-back
[toolbar/content-title (i18n/label :t/transaction-details)] [toolbar/content-title (i18n/label :t/details)]
[toolbar/actions (details-action hash url)]] [toolbar/actions (details-action hash url)]]
[react/scroll-view {:style transactions.styles/main-section} [react/scroll-view {:style transactions.styles/main-section}
[transaction-details-header transaction-details] [details-header transactions]
[transaction-details-confirmations confirmations confirmations-progress] [details-confirmations confirmations confirmations-progress]
[react/view {:style transactions.styles/transaction-details-separator}] [react/view {:style transactions.styles/details-separator}]
[transaction-details-list transaction-details]]])) [details-list transactions]]]))

View File

@ -10,7 +10,6 @@
(defn enabled? [v] (= "1" v)) (defn enabled? [v] (= "1" v))
(def testfairy-enabled? (enabled? (get-config :TESTFAIRY_ENABLED))) (def testfairy-enabled? (enabled? (get-config :TESTFAIRY_ENABLED)))
(def wallet-wip-enabled? (enabled? (get-config :WALLET_WIP_ENABLED 0)))
(def notifications-wip-enabled? (enabled? (get-config :NOTIFICATIONS_WIP_ENABLED 0))) (def notifications-wip-enabled? (enabled? (get-config :NOTIFICATIONS_WIP_ENABLED 0)))
(def stub-status-go? (enabled? (get-config :STUB_STATUS_GO 0))) (def stub-status-go? (enabled? (get-config :STUB_STATUS_GO 0)))
(def network-switching-enabled? (enabled? (get-config :NETWORK_SWITCHING 0))) (def network-switching-enabled? (enabled? (get-config :NETWORK_SWITCHING 0)))

View File

@ -18,9 +18,9 @@
(str "https://" network-subdomain ".etherscan.io/api?module=account&action=txlist&address=0x" (str "https://" network-subdomain ".etherscan.io/api?module=account&action=txlist&address=0x"
account "&startblock=0&endblock=99999999&sort=desc&apikey=YourApiKeyToken?q=json"))) account "&startblock=0&endblock=99999999&sort=desc&apikey=YourApiKeyToken?q=json")))
(defn format-transaction [account {:keys [value timeStamp blockNumber hash from to gas gasPrice gasUsed nonce confirmations input]}] (defn- format-transaction [account {:keys [value timeStamp blockNumber hash from to gas gasPrice gasUsed nonce confirmations input]}]
(let [inbound? (= (str "0x" account) to)] (let [inbound? (= (str "0x" account) to)]
{:value (money/wei->ether value) {:value value
;; timestamp is in seconds, we convert it in ms ;; timestamp is in seconds, we convert it in ms
:timestamp (str timeStamp "000") :timestamp (str timeStamp "000")
:symbol "ETH" :symbol "ETH"
@ -36,7 +36,7 @@
:confirmations confirmations :confirmations confirmations
:data input})) :data input}))
(defn format-transactions-response [response account] (defn- format-transactions-response [response account]
(->> response (->> response
types/json->clj types/json->clj
:result :result