fix: no routes are found in case of valid amount in fiat is entered (#20000)

Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
Brian Sztamfater 2024-05-20 10:08:31 -03:00 committed by GitHub
parent 3de86b09bd
commit d4e7e4cd52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 300 additions and 245 deletions

View File

@ -6,14 +6,16 @@
(h/describe "Wallet: Token Input" (h/describe "Wallet: Token Input"
(h/test "Token label renders" (h/test "Token label renders"
(h/render-with-theme-provider [token-input/view (h/render-with-theme-provider [token-input/view
{:token :snt {:token :snt
:currency :eur :currency :eur
:conversion 1}]) :currency-symbol "€"
:conversion 1}])
(h/is-truthy (h/get-by-text "SNT"))) (h/is-truthy (h/get-by-text "SNT")))
(h/test "Amount renders" (h/test "Amount renders"
(h/render-with-theme-provider [token-input/view (h/render-with-theme-provider [token-input/view
{:token :snt {:token :snt
:currency :eur :currency :eur
:conversion 1}]) :currency-symbol "€"
:conversion 1}])
(h/is-truthy (h/get-by-text "€0.00")))) (h/is-truthy (h/get-by-text "€0.00"))))

View File

@ -12,30 +12,22 @@
{:padding-horizontal 20 {:padding-horizontal 20
:padding-bottom 4 :padding-bottom 4
:height 36 :height 36
:flex-direction :row :flex-direction :row})
:justify-content :space-between})
(defn token-name (defn token-name
[theme] [theme]
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme) {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:margin-right 8 :padding-bottom 3})
:padding-bottom 2})
(def token-label-container
{:position :absolute
:left 40 ; token image size + margin
:right 0
:bottom 0
:top 0
:flex-direction :row
:align-items :flex-end})
(def text-input-container (def text-input-container
{:position :absolute {:flex-direction :row
:top 0 :align-items :flex-end})
:bottom 0
:left 40 ; token image size + margin (defn input-container
:right 0}) [window-width]
{:width (- window-width 120)
:margin-left 8
:margin-right 8})
(def text-input-dimensions (def text-input-dimensions
(-> typography/heading-1 (-> typography/heading-1
@ -54,7 +46,8 @@
:color :color
(if error? (if error?
(colors/resolve-color :danger theme) (colors/resolve-color :danger theme)
(colors/theme-colors colors/neutral-100 colors/white theme)))) (colors/theme-colors colors/neutral-100 colors/white theme))
:flex-shrink 1))
(defn placeholder-text (defn placeholder-text
[theme] [theme]

View File

@ -9,32 +9,34 @@
[quo.components.utilities.token.view :as token] [quo.components.utilities.token.view :as token]
[quo.components.wallet.token-input.schema :as component-schema] [quo.components.wallet.token-input.schema :as component-schema]
[quo.components.wallet.token-input.style :as style] [quo.components.wallet.token-input.style :as style]
[quo.foundations.common :as common]
[quo.theme :as quo.theme] [quo.theme :as quo.theme]
[react-native.core :as rn] [react-native.core :as rn]
[schema.core :as schema])) [schema.core :as schema]
[utils.number :as number]))
(defn fiat-format (defn fiat-format
[currency num-value conversion] [currency-symbol num-value conversion]
(str (get common/currency-label currency) (.toFixed (* num-value conversion) 2))) (str currency-symbol (.toFixed (* num-value conversion) 2)))
(defn crypto-format (defn crypto-format
[num-value conversion crypto-decimals token] [num-value conversion crypto-decimals token]
(str (.toFixed (/ num-value conversion) (or crypto-decimals 2)) (str (number/remove-trailing-zeroes
(.toFixed (/ num-value conversion) (or crypto-decimals 2)))
" " " "
(string/upper-case (or (clj->js token) "")))) (string/upper-case (or (clj->js token) ""))))
(defn calc-value (defn calc-value
[{:keys [crypto? currency token value conversion crypto-decimals]}] [{:keys [crypto? currency-symbol token value conversion crypto-decimals]}]
(let [num-value (if (string? value) (let [num-value (if (string? value)
(or (parse-double value) 0) (or (parse-double value) 0)
value)] value)]
(if crypto? (if crypto?
(fiat-format currency num-value conversion) (fiat-format currency-symbol num-value conversion)
(crypto-format num-value conversion crypto-decimals token)))) (crypto-format num-value conversion crypto-decimals token))))
(defn- data-info (defn- data-info
[{:keys [theme token crypto-decimals conversion networks title crypto? currency amount error?]}] [{:keys [theme token crypto-decimals conversion networks title crypto? currency-symbol amount
error?]}]
[rn/view {:style style/data-container} [rn/view {:style style/data-container}
[network-tag/view [network-tag/view
{:networks networks {:networks networks
@ -45,7 +47,7 @@
:weight :medium :weight :medium
:style (style/fiat-amount theme)} :style (style/fiat-amount theme)}
(calc-value {:crypto? crypto? (calc-value {:crypto? crypto?
:currency currency :currency-symbol currency-symbol
:token token :token token
:value amount :value amount
:conversion conversion :conversion conversion
@ -59,20 +61,6 @@
:weight :semi-bold} :weight :semi-bold}
(string/upper-case (or (clj->js text) ""))]) (string/upper-case (or (clj->js text) ""))])
(defn- token-label
[{:keys [theme value text]}]
[rn/view
{:style style/token-label-container
:pointer-events :none}
[rn/text-input
{:max-length 12
:style style/text-input-dimensions
:editable false
:placeholder "0"
:opacity 0
:value value}]
[token-name-text theme text]])
(defn input-section (defn input-section
[{:keys [on-change-text value value-internal set-value-internal on-selection-change [{:keys [on-change-text value value-internal set-value-internal on-selection-change
on-token-press]}] on-token-press]}]
@ -92,36 +80,45 @@
(oops/oget "nativeEvent.selection") (oops/oget "nativeEvent.selection")
(js->clj :keywordize-keys true) (js->clj :keywordize-keys true)
(on-selection-change))))] (on-selection-change))))]
(fn [{:keys [token customization-color show-keyboard? crypto? currency value error? selection] (fn [{:keys [token customization-color show-keyboard? crypto? currency value error? selection
handle-on-swap]
:or {show-keyboard? true}}] :or {show-keyboard? true}}]
(let [theme (quo.theme/use-theme)] (let [theme (quo.theme/use-theme)
[rn/view {:style {:flex 1}} window-width (:width (rn/get-window))]
[rn/pressable {:on-press on-token-press} [rn/pressable
[token/view {:style {:width "100%"
{:token token :flex-direction :row}
:size :size-32}]] :on-press on-token-press}
[rn/pressable [token/view
{:style style/text-input-container {:token token
:on-press focus-input} :size :size-32}]
[rn/text-input [rn/view {:style (style/input-container window-width)}
(cond-> {:style (style/text-input theme error?) [rn/pressable
:placeholder-text-color (style/placeholder-text theme) {:style style/text-input-container
:auto-focus true :on-press focus-input}
:ref set-ref [rn/text-input
:placeholder "0" (cond-> {:style (style/text-input theme error?)
:keyboard-type :numeric :placeholder-text-color (style/placeholder-text theme)
:max-length 12 :auto-focus true
:on-change-text handle-on-change-text :ref set-ref
:selection-color customization-color :placeholder "0"
:show-soft-input-on-focus show-keyboard? :keyboard-type :numeric
:on-selection-change handle-selection-change :on-change-text handle-on-change-text
:selection (clj->js selection)} :selection-color customization-color
controlled-input? (assoc :value value) :show-soft-input-on-focus show-keyboard?
(not controlled-input?) (assoc :default-value value-internal))]] :on-selection-change handle-selection-change
[token-label :selection (clj->js selection)}
{:theme theme controlled-input? (assoc :value value)
:text (if crypto? token currency) (not controlled-input?) (assoc :default-value value-internal))]
:value (if controlled-input? value value-internal)}]])))) [token-name-text theme (if crypto? token currency)]]]
[button/button
{:icon true
:icon-only? true
:size 32
:on-press handle-on-swap
:type :outline
:accessibility-label :reorder}
:i/reorder]]))))
(defn- view-internal (defn- view-internal
[{:keys [container-style value on-swap] :as props}] [{:keys [container-style value on-swap] :as props}]
@ -141,15 +138,8 @@
:value-internal value-internal :value-internal value-internal
:theme theme :theme theme
:set-value-internal set-value-internal :set-value-internal set-value-internal
:crypto? crypto?)] :handle-on-swap handle-on-swap
[button/button :crypto? crypto?)]]
{:icon true
:icon-only? true
:size 32
:on-press handle-on-swap
:type :outline
:accessibility-label :reorder}
:i/reorder]]
[divider-line/view {:container-style (style/divider theme)}] [divider-line/view {:container-style (style/divider theme)}]
[data-info [data-info
(assoc props (assoc props

View File

@ -1,5 +0,0 @@
(ns quo.foundations.common)
(def currency-label
{:eur "€"
:usd "$"})

View File

@ -37,7 +37,7 @@
[state] [state]
(set-input-error state (upper-limit-exceeded? state))) (set-input-error state (upper-limit-exceeded? state)))
(defn- set-input-value (defn set-input-value
[state value] [state value]
(-> state (-> state
(assoc :value value) (assoc :value value)

View File

@ -4,7 +4,7 @@
[status-im.common.qr-codes.view :as qr-codes] [status-im.common.qr-codes.view :as qr-codes]
[status-im.constants :as constants] [status-im.constants :as constants]
[utils.money :as money] [utils.money :as money]
[utils.number])) [utils.number :as number]))
(defn get-first-name (defn get-first-name
[full-name] [full-name]
@ -56,16 +56,6 @@
(inc max-decimals) (inc max-decimals)
max-decimals))) max-decimals)))
(defn remove-trailing-zeroes
[num]
(let [parts (clojure.string/split (str num) #"\.")]
(str (first parts)
(if-let [decimals (second parts)]
(if (seq (clojure.string/replace decimals #"0+$" ""))
(str "." (clojure.string/replace decimals #"0+$" ""))
"")
""))))
(defn get-crypto-decimals-count (defn get-crypto-decimals-count
[{:keys [market-values-per-currency]}] [{:keys [market-values-per-currency]}]
(let [price (get-in market-values-per-currency [:usd :price]) (let [price (get-in market-values-per-currency [:usd :price])
@ -83,8 +73,8 @@
one-cent-value (if (pos? price) (/ 0.01 price) 0) one-cent-value (if (pos? price) (/ 0.01 price) 0)
decimals-count (calc-max-crypto-decimals one-cent-value)] decimals-count (calc-max-crypto-decimals one-cent-value)]
(if (< token-units one-cent-value) (if (< token-units one-cent-value)
(str "<" (remove-trailing-zeroes (.toFixed one-cent-value decimals-count))) (str "<" (number/remove-trailing-zeroes (.toFixed one-cent-value decimals-count)))
(remove-trailing-zeroes (.toFixed token-units decimals-count)))))) (number/remove-trailing-zeroes (.toFixed token-units decimals-count))))))
(defn get-market-value (defn get-market-value
[currency {:keys [market-values-per-currency]}] [currency {:keys [market-values-per-currency]}]

View File

@ -117,6 +117,7 @@
dissoc dissoc
:suggested-routes :suggested-routes
:route :route
:amount
:from-values-by-chain :from-values-by-chain
:to-values-by-chain :to-values-by-chain
:sender-network-values :sender-network-values

View File

@ -69,6 +69,7 @@
:view-id :screen/wallet.send-input-amount :view-id :screen/wallet.send-input-amount
:wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064" :wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064"
:profile/currency-symbol "$" :profile/currency-symbol "$"
:profile/currency :usd
:wallet/token-by-symbol {:symbol :eth :wallet/token-by-symbol {:symbol :eth
:total-balance 100 :total-balance 100
:market-values-per-currency {:usd {:price 10}}} :market-values-per-currency {:usd {:price 10}}}
@ -86,7 +87,8 @@
:chain-id 1 :chain-id 1
:related-chain-id 1 :related-chain-id 1
:layer 1}] :layer 1}]
:wallet/wallet-send-enabled-from-chain-ids [1]}) :wallet/wallet-send-enabled-from-chain-ids [1]
:wallet/wallet-send-amount nil})
(h/describe "Send > input amount screen" (h/describe "Send > input amount screen"
(h/setup-restorable-re-frame) (h/setup-restorable-re-frame)
@ -173,6 +175,6 @@
(h/is-truthy (h/get-by-label-text :container-error)) (h/is-truthy (h/get-by-label-text :container-error))
(h/fire-event :press (h/query-by-label-text :reorder)) (h/fire-event :press (h/query-by-label-text :reorder))
(-> (h/wait-for #(h/get-by-text "Max: 1000.00 USD")) (-> (h/wait-for #(h/get-by-text "Max: $1000.00"))
(.then (fn [] (.then (fn []
(h/wait-for #(h/is-truthy (h/get-by-label-text :container)))))))) (h/wait-for #(h/is-truthy (h/get-by-label-text :container))))))))

View File

@ -16,11 +16,13 @@
[status-im.contexts.wallet.send.utils :as send-utils] [status-im.contexts.wallet.send.utils :as send-utils]
[status-im.contexts.wallet.sheets.unpreferred-networks-alert.view :as unpreferred-networks-alert] [status-im.contexts.wallet.sheets.unpreferred-networks-alert.view :as unpreferred-networks-alert]
[utils.address :as address] [utils.address :as address]
[utils.debounce :as debounce]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.money :as money] [utils.money :as money]
[utils.number :as number]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn- make-limit-label (defn- make-limit-label-crypto
[amount currency] [amount currency]
(str amount (str amount
" " " "
@ -28,6 +30,10 @@
name name
string/upper-case))) string/upper-case)))
(defn- make-limit-label-fiat
[amount currency-symbol]
(str currency-symbol amount))
(defn- estimated-fees (defn- estimated-fees
[{:keys [loading-routes? fees amount receiver]}] [{:keys [loading-routes? fees amount receiver]}]
[rn/view {:style style/estimated-fees-container} [rn/view {:style style/estimated-fees-container}
@ -61,6 +67,7 @@
(every? (fn [{:keys [total-amount]}] (every? (fn [{:keys [total-amount]}]
(and (and
total-amount total-amount
(money/bignumber? total-amount)
(money/equal-to total-amount (money/equal-to total-amount
(money/bignumber "0")))) (money/bignumber "0"))))
sender-network-values)) sender-network-values))
@ -127,129 +134,138 @@
crypto-currency? (reagent/atom initial-crypto-currency?) crypto-currency? (reagent/atom initial-crypto-currency?)
on-navigate-back on-navigate-back] on-navigate-back on-navigate-back]
(fn [] (fn []
(let [[input-state set-input-state] (rn/use-state controlled-input/init-state) (let [[input-state set-input-state] (rn/use-state controlled-input/init-state)
clear-input! #(set-input-state controlled-input/delete-all) [just-toggled-mode? set-just-toggled-mode?] (rn/use-state false)
handle-on-confirm (fn [] clear-input! #(set-input-state controlled-input/delete-all)
(rf/dispatch [:wallet/set-token-amount-to-send handle-on-confirm (fn []
{:amount (rf/dispatch [:wallet/set-token-amount-to-send
(controlled-input/input-value {:amount
input-state) (controlled-input/input-value
:stack-id current-screen-id}])) input-state)
{fiat-currency :currency} (rf/sub [:profile/profile]) :stack-id current-screen-id}]))
{fiat-currency :currency} (rf/sub [:profile/profile])
{token-symbol :symbol {token-symbol :symbol
token-networks :networks} (rf/sub [:wallet/wallet-send-token]) token-networks :networks
send-enabled-networks (rf/sub [:wallet/wallet-send-enabled-networks]) token-decimals :decimals} (rf/sub [:wallet/wallet-send-token])
enabled-from-chain-ids (rf/sub send-enabled-networks (rf/sub [:wallet/wallet-send-enabled-networks])
[:wallet/wallet-send-enabled-from-chain-ids]) enabled-from-chain-ids (rf/sub
[:wallet/wallet-send-enabled-from-chain-ids])
{token-balance :total-balance {token-balance :total-balance
available-balance :available-balance available-balance :available-balance
:as :as
token} (rf/sub token} (rf/sub
[:wallet/current-viewing-account-tokens-filtered [:wallet/current-viewing-account-tokens-filtered
(str token-symbol) enabled-from-chain-ids]) (str token-symbol) enabled-from-chain-ids])
conversion-rate (-> token :market-values-per-currency :usd :price) currency-symbol (rf/sub [:profile/currency-symbol])
loading-routes? (rf/sub currency (rf/sub [:profile/currency])
[:wallet/wallet-send-loading-suggested-routes?]) conversion-rate (-> token :market-values-per-currency currency :price)
loading-routes? (rf/sub
route (rf/sub [:wallet/wallet-send-route]) [:wallet/wallet-send-loading-suggested-routes?])
to-address (rf/sub [:wallet/wallet-send-to-address]) route (rf/sub [:wallet/wallet-send-route])
to-address (rf/sub [:wallet/wallet-send-to-address])
on-confirm (or default-on-confirm handle-on-confirm) on-confirm (or default-on-confirm handle-on-confirm)
crypto-decimals (or default-crypto-decimals crypto-decimals (or token-decimals default-crypto-decimals)
(utils/get-crypto-decimals-count token)) current-crypto-limit (or default-limit-crypto
current-crypto-limit (or default-limit-crypto (utils/get-standard-crypto-format
(utils/get-standard-crypto-format token
token token-balance))
token-balance)) available-crypto-limit (or default-limit-crypto
available-crypto-limit (or default-limit-crypto (utils/get-standard-crypto-format
(utils/get-standard-crypto-format token
token available-balance))
available-balance)) current-fiat-limit (.toFixed (* token-balance conversion-rate) 2)
current-fiat-limit (.toFixed (* token-balance conversion-rate) 2) available-fiat-limit (.toFixed (* available-balance conversion-rate) 2)
available-fiat-limit (.toFixed (* available-balance conversion-rate) 2) current-limit (if @crypto-currency?
current-limit (if @crypto-currency? current-crypto-limit
current-crypto-limit current-fiat-limit)
current-fiat-limit) available-limit (if @crypto-currency?
available-limit (if @crypto-currency? available-crypto-limit
available-crypto-limit available-fiat-limit)
available-fiat-limit) valid-input? (not (or (string/blank?
valid-input? (not (or (string/blank? (controlled-input/input-value
(controlled-input/input-value input-state))
input-state)) (<= (controlled-input/numeric-value
(<= (controlled-input/numeric-value input-state)
input-state) 0)
0) (> (controlled-input/numeric-value
(> (controlled-input/numeric-value input-state)
input-state) available-limit)))
available-limit))) input-num-value (controlled-input/numeric-value input-state)
current-currency (if @crypto-currency? token-symbol fiat-currency) input-amount (controlled-input/input-value input-state)
input-num-value (controlled-input/numeric-value input-state) confirm-disabled? (or (nil? route)
confirm-disabled? (or (nil? route) (empty? route)
(empty? route) (string/blank? (controlled-input/input-value
(string/blank? (controlled-input/input-value input-state))
input-state)) (<= input-num-value 0)
(<= input-num-value 0) (> input-num-value current-limit))
(> input-num-value current-limit)) amount (if @crypto-currency?
amount-text (str (controlled-input/input-value input-state) input-amount
" " (number/remove-trailing-zeroes
token-symbol) (.toFixed (/ input-amount conversion-rate)
first-route (first route) crypto-decimals)))
native-currency-symbol (when-not confirm-disabled? send-amount (rf/sub [:wallet/wallet-send-amount])
(get-in first-route amount-text (str (number/remove-trailing-zeroes
[:from :native-currency-symbol])) (.toFixed (js/parseFloat send-amount)
native-token (when native-currency-symbol (min token-decimals 6)))
(rf/sub [:wallet/token-by-symbol " "
native-currency-symbol])) token-symbol)
fee-in-native-token (when-not confirm-disabled? first-route (first route)
(send-utils/calculate-full-route-gas-fee route)) native-currency-symbol (when-not confirm-disabled?
fee-in-crypto-formatted (when fee-in-native-token (get-in first-route
(utils/get-standard-crypto-format [:from :native-currency-symbol]))
native-token native-token (when native-currency-symbol
fee-in-native-token)) (rf/sub [:wallet/token-by-symbol
fee-in-fiat (when-not confirm-disabled? native-currency-symbol]))
(utils/calculate-token-fiat-value fee-in-native-token (when-not confirm-disabled?
{:currency fiat-currency (send-utils/calculate-full-route-gas-fee route))
:balance fee-in-native-token fee-in-crypto-formatted (when fee-in-native-token
:token native-token})) (utils/get-standard-crypto-format
currency-symbol (rf/sub [:profile/currency-symbol]) native-token
fee-formatted (when fee-in-fiat fee-in-native-token))
(utils/get-standard-fiat-format fee-in-fiat (when-not confirm-disabled?
fee-in-crypto-formatted (utils/calculate-token-fiat-value
currency-symbol {:currency fiat-currency
fee-in-fiat)) :balance fee-in-native-token
show-select-asset-sheet #(rf/dispatch :token native-token}))
[:show-bottom-sheet fee-formatted (when fee-in-fiat
{:content (fn [] (utils/get-standard-fiat-format
[select-asset-bottom-sheet fee-in-crypto-formatted
clear-input!])}]) currency-symbol
sender-network-values (rf/sub fee-in-fiat))
[:wallet/wallet-send-sender-network-values]) show-select-asset-sheet #(rf/dispatch
receiver-network-values (rf/sub [:show-bottom-sheet
[:wallet/wallet-send-receiver-network-values]) {:content (fn []
[select-asset-bottom-sheet
clear-input!])}])
sender-network-values (rf/sub
[:wallet/wallet-send-sender-network-values])
receiver-network-values (rf/sub
[:wallet/wallet-send-receiver-network-values])
token-not-supported-in-receiver-networks? (every? #(= (:type %) :not-available) token-not-supported-in-receiver-networks? (every? #(= (:type %) :not-available)
(filter #(not= (:type %) :add) (filter #(not= (:type %) :add)
receiver-network-values)) receiver-network-values))
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes]) suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
routes (when suggested-routes routes (when suggested-routes
(or (:best suggested-routes) [])) (or (:best suggested-routes) []))
no-routes-found? (and no-routes-found? (and
(every-network-value-is-zero? (every-network-value-is-zero?
sender-network-values) sender-network-values)
(not (nil? routes)) (not (nil? routes))
(not loading-routes?) (not loading-routes?)
(not token-not-supported-in-receiver-networks?)) (not token-not-supported-in-receiver-networks?))
receiver-networks (rf/sub [:wallet/wallet-send-receiver-networks]) receiver-networks (rf/sub [:wallet/wallet-send-receiver-networks])
receiver-preferred-networks (rf/sub receiver-preferred-networks (rf/sub
[:wallet/wallet-send-receiver-preferred-networks]) [:wallet/wallet-send-receiver-preferred-networks])
receiver-preferred-networks-set (set receiver-preferred-networks) receiver-preferred-networks-set (set receiver-preferred-networks)
sending-to-unpreferred-networks? (not (every? (fn [receiver-selected-network] sending-to-unpreferred-networks? (not (every? (fn [receiver-selected-network]
(contains? (contains?
receiver-preferred-networks-set receiver-preferred-networks-set
receiver-selected-network)) receiver-selected-network))
receiver-networks)) receiver-networks))
limit-insufficient? (> (controlled-input/numeric-value input-state) input-error (controlled-input/input-error input-state)
current-limit) limit-insufficient? (> (controlled-input/numeric-value input-state)
should-try-again? (and (not limit-insufficient?) no-routes-found?)] current-limit)
should-try-again? (and (not limit-insufficient?) no-routes-found?)]
(rn/use-mount (rn/use-mount
(fn [] (fn []
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!)) (let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
@ -259,6 +275,9 @@
(fn [] (fn []
(set-input-state #(controlled-input/set-upper-limit % current-limit))) (set-input-state #(controlled-input/set-upper-limit % current-limit)))
[current-limit]) [current-limit])
(rn/use-effect
#(when input-error (debounce/clear-all))
[input-error])
[rn/view [rn/view
{:style style/screen {:style style/screen
:accessibility-label (str "container" :accessibility-label (str "container"
@ -270,22 +289,40 @@
[quo/token-input [quo/token-input
{:container-style style/input-container {:container-style style/input-container
:token token-symbol :token token-symbol
:currency current-currency :currency fiat-currency
:crypto-decimals crypto-decimals :currency-symbol currency-symbol
:crypto-decimals (min token-decimals 6)
:error? (controlled-input/input-error input-state) :error? (controlled-input/input-error input-state)
:networks (seq send-enabled-networks) :networks (seq send-enabled-networks)
:title (i18n/label :t/send-limit :title (i18n/label
{:limit (make-limit-label current-limit current-currency)}) :t/send-limit
{:limit (if @crypto-currency?
(make-limit-label-crypto current-limit token-symbol)
(make-limit-label-fiat current-limit currency-symbol))})
:conversion conversion-rate :conversion conversion-rate
:show-keyboard? false :show-keyboard? false
:value (controlled-input/input-value input-state) :value input-amount
:on-swap #(reset! crypto-currency? %) :on-swap (fn [swap-to-crypto-currency?]
(set-just-toggled-mode? true)
(reset! crypto-currency? swap-to-crypto-currency?)
(set-input-state
(fn [input-state]
(controlled-input/set-input-value
input-state
(let [value (controlled-input/input-value input-state)
new-value (if swap-to-crypto-currency?
(.toFixed (/ value conversion-rate)
crypto-decimals)
(.toFixed (* value conversion-rate) 12))]
(number/remove-trailing-zeroes new-value))))))
:on-token-press show-select-asset-sheet}] :on-token-press show-select-asset-sheet}]
[routes/view [routes/view
{:token token {:token token
:input-value (controlled-input/input-value input-state) :input-value input-amount
:value amount
:valid-input? valid-input? :valid-input? valid-input?
:token-not-supported-in-receiver-networks? token-not-supported-in-receiver-networks? :token-not-supported-in-receiver-networks? token-not-supported-in-receiver-networks?
:lock-fetch-routes? just-toggled-mode?
:current-screen-id current-screen-id}] :current-screen-id current-screen-id}]
(when (and (not loading-routes?) (when (and (not loading-routes?)
sender-network-values sender-network-values
@ -314,9 +351,15 @@
{:disabled? (and (not should-try-again?) confirm-disabled?) {:disabled? (and (not should-try-again?) confirm-disabled?)
:on-press (cond :on-press (cond
should-try-again? should-try-again?
#(rf/dispatch [:wallet/get-suggested-routes #(let [input-amount (controlled-input/input-value
{:amount (controlled-input/input-value input-state)
input-state)}]) amount (if @crypto-currency?
input-amount
(.toFixed (* token-balance
conversion-rate)
2))]
(rf/dispatch [:wallet/get-suggested-routes
{:amount amount}]))
sending-to-unpreferred-networks? sending-to-unpreferred-networks?
#(show-unpreferred-networks-alert on-confirm) #(show-unpreferred-networks-alert on-confirm)
:else :else
@ -328,11 +371,22 @@
:left-action :dot :left-action :dot
:delete-key? true :delete-key? true
:on-press (fn [c] :on-press (fn [c]
(when-not loading-routes? (let [new-text (str input-amount c)
(set-input-state #(controlled-input/add-character % c)))) max-decimals (if @crypto-currency? crypto-decimals 2)
regex-pattern (str "^\\d*\\.?\\d{0," max-decimals "}$")
regex (re-pattern regex-pattern)]
(when (and (not loading-routes?)
(re-matches regex new-text))
(debounce/clear-all)
(set-just-toggled-mode? false)
(set-input-state #(controlled-input/add-character % c)))))
:on-delete (fn [] :on-delete (fn []
(when-not loading-routes? (when-not loading-routes?
(debounce/clear-all)
(set-just-toggled-mode? false)
(set-input-state controlled-input/delete-last))) (set-input-state controlled-input/delete-last)))
:on-long-press-delete (fn [] :on-long-press-delete (fn []
(when-not loading-routes? (when-not loading-routes?
(debounce/clear-all)
(set-just-toggled-mode? false)
(set-input-state controlled-input/delete-all)))}]])))) (set-input-state controlled-input/delete-all)))}]]))))

View File

@ -16,8 +16,8 @@
(def network-link-1x-height 56) (def network-link-1x-height 56)
(def network-link-2x-height 111) (def network-link-2x-height 111)
(defn fetch-routes (defn- fetch-routes
[amount valid-input? bounce-duration-ms] [{:keys [amount bounce-duration-ms valid-input?]}]
(if valid-input? (if valid-input?
(debounce/debounce-and-dispatch (debounce/debounce-and-dispatch
[:wallet/get-suggested-routes {:amount amount}] [:wallet/get-suggested-routes {:amount amount}]
@ -174,8 +174,8 @@
:text (i18n/label :t/at-least-one-network-must-be-activated)}])))) :text (i18n/label :t/at-least-one-network-must-be-activated)}]))))
(defn view (defn view
[{:keys [token theme input-value valid-input? [{:keys [token theme input-value value valid-input?
on-press-to-network current-screen-id lock-fetch-routes? on-press-to-network current-screen-id
token-not-supported-in-receiver-networks?]}] token-not-supported-in-receiver-networks?]}]
(let [token-symbol (:symbol token) (let [token-symbol (:symbol token)
nav-current-screen-id (rf/sub [:view-id]) nav-current-screen-id (rf/sub [:view-id])
@ -198,12 +198,21 @@
:disabled-chain-ids disabled-from-chain-ids}) :disabled-chain-ids disabled-from-chain-ids})
show-routes? (not-empty sender-network-values)] show-routes? (not-empty sender-network-values)]
(rn/use-effect (rn/use-effect
#(when (and active-screen? (> (count token-available-networks-for-suggested-routes) 0)) (fn []
(fetch-routes input-value valid-input? 2000)) (when (and active-screen?
(> (count token-available-networks-for-suggested-routes) 0)
(not lock-fetch-routes?))
(fetch-routes
{:amount value
:valid-input? valid-input?
:bounce-duration-ms 2000})))
[input-value valid-input?]) [input-value valid-input?])
(rn/use-effect (rn/use-effect
#(when (and active-screen? (> (count token-available-networks-for-suggested-routes) 0)) #(when (and active-screen? (> (count token-available-networks-for-suggested-routes) 0))
(fetch-routes input-value valid-input? 0)) (fetch-routes
{:amount value
:valid-input? valid-input?
:bounce-duration-ms 0}))
[disabled-from-chain-ids]) [disabled-from-chain-ids])
[rn/scroll-view {:content-container-style style/routes-container} [rn/scroll-view {:content-container-style style/routes-container}
(when show-routes? (when show-routes?
@ -238,5 +247,8 @@
:loading-routes? loading-routes? :loading-routes? loading-routes?
:theme theme :theme theme
:token-not-supported-in-receiver-networks? token-not-supported-in-receiver-networks? :token-not-supported-in-receiver-networks? token-not-supported-in-receiver-networks?
:on-save #(fetch-routes input-value valid-input? 0)}]]])) :on-save #(fetch-routes
{:amount input-value
:valid-input? valid-input?
:bounce-duration-ms 0})}]]]))

View File

@ -24,6 +24,11 @@
:<- [:wallet/wallet-send] :<- [:wallet/wallet-send]
:-> :transaction-ids) :-> :transaction-ids)
(rf/reg-sub
:wallet/wallet-send-amount
:<- [:wallet/wallet-send]
:-> :amount)
(rf/reg-sub (rf/reg-sub
:wallet/send-transaction-progress :wallet/send-transaction-progress
:<- [:wallet/send-transaction-ids] :<- [:wallet/send-transaction-ids]

View File

@ -1,4 +1,5 @@
(ns utils.number) (ns utils.number
(:require [clojure.string :as string]))
(defn naive-round (defn naive-round
"Quickly and naively round number `n` up to `decimal-places`. "Quickly and naively round number `n` up to `decimal-places`.
@ -29,3 +30,13 @@
if `num` exceeds a given bound, then returns the bound exceeded." if `num` exceeds a given bound, then returns the bound exceeded."
[number lower-bound upper-bound] [number lower-bound upper-bound]
(max lower-bound (min number upper-bound))) (max lower-bound (min number upper-bound)))
(defn remove-trailing-zeroes
[num]
(let [parts (string/split (str num) #"\.")]
(str (first parts)
(if-let [decimals (second parts)]
(if (seq (string/replace decimals #"0+$" ""))
(str "." (string/replace decimals #"0+$" ""))
"")
""))))