mirror of
https://github.com/status-im/status-react.git
synced 2025-02-13 11:27:08 +00:00
Refactoring of token input screen in send flow (#19750)
* Refactoring for send input screen * lint fixes * small comments fixed * Controlled input logic reimplemented without atom * remove leftover
This commit is contained in:
parent
782d038fb0
commit
3a5122a50c
@ -139,6 +139,7 @@
|
|||||||
[input-section
|
[input-section
|
||||||
(assoc props
|
(assoc props
|
||||||
:value-internal value-internal
|
:value-internal value-internal
|
||||||
|
:theme theme
|
||||||
:set-value-internal set-value-internal
|
:set-value-internal set-value-internal
|
||||||
:crypto? crypto?)]
|
:crypto? crypto?)]
|
||||||
[button/button
|
[button/button
|
||||||
|
94
src/status_im/common/controlled_input/utils.cljs
Normal file
94
src/status_im/common/controlled_input/utils.cljs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
(ns status-im.common.controlled-input.utils
|
||||||
|
(:require
|
||||||
|
[clojure.string :as string]))
|
||||||
|
|
||||||
|
(def init-state
|
||||||
|
{:value ""
|
||||||
|
:error? false
|
||||||
|
:upper-limit nil})
|
||||||
|
|
||||||
|
(defn input-value
|
||||||
|
[state]
|
||||||
|
(:value state))
|
||||||
|
|
||||||
|
(defn numeric-value
|
||||||
|
[state]
|
||||||
|
(or (parse-double (input-value state)) 0))
|
||||||
|
|
||||||
|
(defn input-error
|
||||||
|
[state]
|
||||||
|
(:error? state))
|
||||||
|
|
||||||
|
(defn- set-input-error
|
||||||
|
[state error?]
|
||||||
|
(assoc state :error? error?))
|
||||||
|
|
||||||
|
(defn- upper-limit
|
||||||
|
[state]
|
||||||
|
(:upper-limit state))
|
||||||
|
|
||||||
|
(defn upper-limit-exceeded?
|
||||||
|
[state]
|
||||||
|
(and
|
||||||
|
(upper-limit state)
|
||||||
|
(> (numeric-value state) (upper-limit state))))
|
||||||
|
|
||||||
|
(defn- recheck-errorness
|
||||||
|
[state]
|
||||||
|
(set-input-error state (upper-limit-exceeded? state)))
|
||||||
|
|
||||||
|
(defn- set-input-value
|
||||||
|
[state value]
|
||||||
|
(-> state
|
||||||
|
(assoc :value value)
|
||||||
|
recheck-errorness))
|
||||||
|
|
||||||
|
(defn set-upper-limit
|
||||||
|
[state limit]
|
||||||
|
(-> state
|
||||||
|
(assoc :upper-limit limit)
|
||||||
|
recheck-errorness))
|
||||||
|
|
||||||
|
(def ^:private not-digits-or-dot-pattern
|
||||||
|
#"[^0-9+\.]")
|
||||||
|
|
||||||
|
(def ^:private dot ".")
|
||||||
|
|
||||||
|
(defn- can-add-character?
|
||||||
|
[state character]
|
||||||
|
(let [max-length 12
|
||||||
|
current (input-value state)
|
||||||
|
length-overflow? (>= (count current) max-length)
|
||||||
|
extra-dot? (and (= character dot) (string/includes? current dot))
|
||||||
|
extra-leading-zero? (and (= current "0") (= "0" (str character)))
|
||||||
|
non-numeric? (re-find not-digits-or-dot-pattern (str character))]
|
||||||
|
(not (or non-numeric? extra-dot? extra-leading-zero? length-overflow?))))
|
||||||
|
|
||||||
|
(defn- normalize-value-as-numeric
|
||||||
|
[value character]
|
||||||
|
(cond
|
||||||
|
(and (string/blank? value) (= character dot))
|
||||||
|
(str "0" character)
|
||||||
|
|
||||||
|
(and (= value "0") (not= character dot))
|
||||||
|
(str character)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(str value character)))
|
||||||
|
|
||||||
|
(defn add-character
|
||||||
|
[state character]
|
||||||
|
(when (can-add-character? state character)
|
||||||
|
(set-input-value state
|
||||||
|
(normalize-value-as-numeric (input-value state) character))))
|
||||||
|
|
||||||
|
(defn delete-last
|
||||||
|
[state]
|
||||||
|
(let [value (input-value state)
|
||||||
|
new-value (subs value 0 (dec (count value)))]
|
||||||
|
(set-input-value state new-value)))
|
||||||
|
|
||||||
|
(defn delete-all
|
||||||
|
[state]
|
||||||
|
(set-input-value state ""))
|
||||||
|
|
@ -5,6 +5,7 @@
|
|||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.safe-area :as safe-area]
|
[react-native.safe-area :as safe-area]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
|
[status-im.common.controlled-input.utils :as controlled-input]
|
||||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||||
[status-im.contexts.wallet.common.asset-list.view :as asset-list]
|
[status-im.contexts.wallet.common.asset-list.view :as asset-list]
|
||||||
[status-im.contexts.wallet.common.utils :as utils]
|
[status-im.contexts.wallet.common.utils :as utils]
|
||||||
@ -12,86 +13,17 @@
|
|||||||
[status-im.contexts.wallet.send.input-amount.style :as style]
|
[status-im.contexts.wallet.send.input-amount.style :as style]
|
||||||
[status-im.contexts.wallet.send.routes.view :as routes]
|
[status-im.contexts.wallet.send.routes.view :as routes]
|
||||||
[utils.address :as address]
|
[utils.address :as address]
|
||||||
[utils.debounce :as debounce]
|
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn- make-limit-label
|
(defn- make-limit-label
|
||||||
[{:keys [amount currency]}]
|
[amount currency]
|
||||||
(str amount
|
(str amount
|
||||||
" "
|
" "
|
||||||
(some-> currency
|
(some-> currency
|
||||||
name
|
name
|
||||||
string/upper-case)))
|
string/upper-case)))
|
||||||
|
|
||||||
(def not-digits-or-dot-pattern
|
|
||||||
#"[^0-9+\.]")
|
|
||||||
|
|
||||||
(def dot ".")
|
|
||||||
|
|
||||||
(defn valid-input?
|
|
||||||
[current v]
|
|
||||||
(let [max-length 12
|
|
||||||
length-overflow? (>= (count current) max-length)
|
|
||||||
extra-dot? (and (= v dot) (string/includes? current dot))
|
|
||||||
extra-leading-zero? (and (= current "0") (= "0" (str v)))
|
|
||||||
non-numeric? (re-find not-digits-or-dot-pattern (str v))]
|
|
||||||
(not (or non-numeric? extra-dot? extra-leading-zero? length-overflow?))))
|
|
||||||
|
|
||||||
(defn- add-char-to-string
|
|
||||||
[s c idx]
|
|
||||||
(let [size (count s)]
|
|
||||||
(if (= size idx)
|
|
||||||
(str s c)
|
|
||||||
(str (subs s 0 idx)
|
|
||||||
c
|
|
||||||
(subs s idx size)))))
|
|
||||||
|
|
||||||
(defn- move-input-cursor
|
|
||||||
([input-selection-atom new-idx]
|
|
||||||
(move-input-cursor input-selection-atom new-idx new-idx))
|
|
||||||
([input-selection-atom new-start-idx new-end-idx]
|
|
||||||
(let [start-idx (if (< new-start-idx 0) 0 new-start-idx)
|
|
||||||
end-idx (if (< new-end-idx 0) 0 new-start-idx)]
|
|
||||||
(swap! input-selection-atom assoc :start start-idx :end end-idx))))
|
|
||||||
|
|
||||||
(defn- normalize-input
|
|
||||||
[current v input-selection-atom]
|
|
||||||
(let [{:keys [start end]} @input-selection-atom]
|
|
||||||
(if (= start end)
|
|
||||||
(cond
|
|
||||||
(and (string/blank? current) (= v dot))
|
|
||||||
(do
|
|
||||||
(move-input-cursor input-selection-atom 2)
|
|
||||||
(str "0" v))
|
|
||||||
|
|
||||||
(and (= current "0") (not= v dot))
|
|
||||||
(do
|
|
||||||
(move-input-cursor input-selection-atom 1)
|
|
||||||
(str v))
|
|
||||||
|
|
||||||
:else
|
|
||||||
(do
|
|
||||||
(move-input-cursor input-selection-atom (inc start))
|
|
||||||
(add-char-to-string current v start)))
|
|
||||||
current)))
|
|
||||||
|
|
||||||
(defn- make-new-input
|
|
||||||
[current v input-selection-atom]
|
|
||||||
(if (valid-input? current v)
|
|
||||||
(normalize-input current v input-selection-atom)
|
|
||||||
current))
|
|
||||||
|
|
||||||
(defn- reset-input-error
|
|
||||||
[new-value prev-value input-error]
|
|
||||||
(reset! input-error
|
|
||||||
(> new-value prev-value)))
|
|
||||||
|
|
||||||
(defn delete-from-string
|
|
||||||
[s idx]
|
|
||||||
(let [size (count s)]
|
|
||||||
(str (subs s 0 (dec idx)) (subs s idx size))))
|
|
||||||
|
|
||||||
(defn- estimated-fees
|
(defn- estimated-fees
|
||||||
[{:keys [loading-suggested-routes? fees amount receiver]}]
|
[{:keys [loading-suggested-routes? fees amount receiver]}]
|
||||||
[rn/view {:style style/estimated-fees-container}
|
[rn/view {:style style/estimated-fees-container}
|
||||||
@ -149,77 +81,20 @@
|
|||||||
:or {initial-crypto-currency? true}}]
|
:or {initial-crypto-currency? true}}]
|
||||||
(let [_ (rn/dismiss-keyboard!)
|
(let [_ (rn/dismiss-keyboard!)
|
||||||
bottom (safe-area/get-bottom)
|
bottom (safe-area/get-bottom)
|
||||||
input-value (reagent/atom "")
|
|
||||||
clear-input! #(reset! input-value "")
|
|
||||||
input-error (reagent/atom false)
|
|
||||||
crypto-currency? (reagent/atom initial-crypto-currency?)
|
crypto-currency? (reagent/atom initial-crypto-currency?)
|
||||||
input-selection (reagent/atom {:start 0 :end 0})
|
on-navigate-back on-navigate-back]
|
||||||
handle-swap (fn [{:keys [crypto? limit-fiat limit-crypto]}]
|
(fn []
|
||||||
(let [num-value (parse-double @input-value)
|
(let [[input-state set-input-state] (rn/use-state controlled-input/init-state)
|
||||||
current-limit (if crypto? limit-crypto limit-fiat)]
|
clear-input! #(set-input-state controlled-input/delete-all)
|
||||||
(reset! crypto-currency? crypto?)
|
|
||||||
(reset-input-error num-value current-limit input-error)))
|
|
||||||
handle-keyboard-press (fn [v loading-routes? current-limit-amount]
|
|
||||||
(when-not loading-routes?
|
|
||||||
(let [current-value @input-value
|
|
||||||
new-value (make-new-input current-value v input-selection)
|
|
||||||
num-value (or (parse-double new-value) 0)]
|
|
||||||
(reset! input-value new-value)
|
|
||||||
(reset-input-error num-value current-limit-amount input-error)
|
|
||||||
(reagent/flush))))
|
|
||||||
handle-delete (fn [loading-routes? current-limit-amount]
|
|
||||||
(when-not loading-routes?
|
|
||||||
(let [{:keys [start end]} @input-selection
|
|
||||||
new-value (delete-from-string @input-value start)]
|
|
||||||
(when (= start end)
|
|
||||||
(reset-input-error new-value current-limit-amount input-error)
|
|
||||||
(swap! input-value delete-from-string start)
|
|
||||||
(move-input-cursor input-selection (dec start)))
|
|
||||||
(reagent/flush))))
|
|
||||||
on-long-press-delete (fn [loading-routes?]
|
|
||||||
(when-not loading-routes?
|
|
||||||
(reset! input-value "")
|
|
||||||
(reset! input-error false)
|
|
||||||
(move-input-cursor input-selection 0)
|
|
||||||
(reagent/flush)))
|
|
||||||
handle-on-change (fn [v current-limit-amount]
|
|
||||||
(when (valid-input? @input-value v)
|
|
||||||
(let [num-value (or (parse-double v) 0)]
|
|
||||||
(reset! input-value v)
|
|
||||||
(reset-input-error num-value current-limit-amount input-error)
|
|
||||||
(reagent/flush))))
|
|
||||||
on-navigate-back on-navigate-back
|
|
||||||
fetch-routes (fn [input-num-value current-limit-amount bounce-duration-ms]
|
|
||||||
(let [nav-current-screen-id (rf/sub [:view-id])
|
|
||||||
input-num-value (or input-num-value 0)]
|
|
||||||
; this check is to prevent effect being triggered when screen is
|
|
||||||
; loaded but not being shown to the user (deep in the navigation
|
|
||||||
; stack) and avoid undesired behaviors
|
|
||||||
(when (= nav-current-screen-id current-screen-id)
|
|
||||||
(if-not (or (empty? @input-value)
|
|
||||||
(<= input-num-value 0)
|
|
||||||
(> input-num-value current-limit-amount))
|
|
||||||
(debounce/debounce-and-dispatch
|
|
||||||
[:wallet/get-suggested-routes {:amount @input-value}]
|
|
||||||
bounce-duration-ms)
|
|
||||||
(rf/dispatch [:wallet/clean-suggested-routes])))))
|
|
||||||
handle-on-confirm (fn []
|
handle-on-confirm (fn []
|
||||||
(rf/dispatch [:wallet/send-select-amount
|
(rf/dispatch [:wallet/send-select-amount
|
||||||
{:amount @input-value
|
{:amount (controlled-input/input-value
|
||||||
|
input-state)
|
||||||
:stack-id current-screen-id}]))
|
:stack-id current-screen-id}]))
|
||||||
selection-change (fn [selection]
|
{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||||
;; `reagent/flush` is needed to properly propagate the
|
|
||||||
;; input cursor state. Since this is a controlled
|
|
||||||
;; component the cursor will become static if
|
|
||||||
;; `reagent/flush` is removed.
|
|
||||||
(reset! input-selection selection)
|
|
||||||
(reagent/flush))]
|
|
||||||
(fn []
|
|
||||||
(let [{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} (rf/sub [:wallet/wallet-send-token])
|
||||||
{token-balance :total-balance
|
{token-balance :total-balance
|
||||||
token-balances-per-chain :balances-per-chain
|
|
||||||
:as
|
:as
|
||||||
token} (rf/sub
|
token} (rf/sub
|
||||||
[:wallet/current-viewing-account-tokens-filtered
|
[:wallet/current-viewing-account-tokens-filtered
|
||||||
@ -227,15 +102,11 @@
|
|||||||
conversion-rate (-> token :market-values-per-currency :usd :price)
|
conversion-rate (-> token :market-values-per-currency :usd :price)
|
||||||
loading-routes? (rf/sub
|
loading-routes? (rf/sub
|
||||||
[:wallet/wallet-send-loading-suggested-routes?])
|
[:wallet/wallet-send-loading-suggested-routes?])
|
||||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
|
||||||
best-routes (when suggested-routes
|
|
||||||
(or (:best suggested-routes) []))
|
|
||||||
route (rf/sub [:wallet/wallet-send-route])
|
route (rf/sub [:wallet/wallet-send-route])
|
||||||
to-address (rf/sub [:wallet/wallet-send-to-address])
|
to-address (rf/sub [:wallet/wallet-send-to-address])
|
||||||
disabled-from-chain-ids (rf/sub
|
nav-current-screen-id (rf/sub [:view-id])
|
||||||
[:wallet/wallet-send-disabled-from-chain-ids])
|
|
||||||
from-values-by-chain (rf/sub [:wallet/wallet-send-from-values-by-chain])
|
|
||||||
to-values-by-chain (rf/sub [:wallet/wallet-send-to-values-by-chain])
|
|
||||||
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 default-crypto-decimals
|
||||||
(utils/get-crypto-decimals-count token))
|
(utils/get-crypto-decimals-count token))
|
||||||
@ -245,16 +116,22 @@
|
|||||||
token-balance))
|
token-balance))
|
||||||
fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
||||||
current-limit #(if @crypto-currency? crypto-limit fiat-limit)
|
current-limit #(if @crypto-currency? crypto-limit fiat-limit)
|
||||||
|
routes-can-be-fetched? (and (= nav-current-screen-id current-screen-id)
|
||||||
|
(not
|
||||||
|
(or (empty? (controlled-input/input-value input-state))
|
||||||
|
(<= (controlled-input/numeric-value input-state) 0)
|
||||||
|
(> (controlled-input/numeric-value input-state)
|
||||||
|
(current-limit)))))
|
||||||
current-currency (if @crypto-currency? token-symbol fiat-currency)
|
current-currency (if @crypto-currency? token-symbol fiat-currency)
|
||||||
limit-label (make-limit-label {:amount (current-limit)
|
input-num-value (controlled-input/numeric-value input-state)
|
||||||
:currency current-currency})
|
|
||||||
input-num-value (parse-double @input-value)
|
|
||||||
confirm-disabled? (or (nil? route)
|
confirm-disabled? (or (nil? route)
|
||||||
(empty? route)
|
(empty? route)
|
||||||
(empty? @input-value)
|
(empty? (controlled-input/input-value input-state))
|
||||||
(<= input-num-value 0)
|
(<= input-num-value 0)
|
||||||
(> input-num-value (current-limit)))
|
(> input-num-value (current-limit)))
|
||||||
amount-text (str @input-value " " token-symbol)
|
amount-text (str (controlled-input/input-value input-state)
|
||||||
|
" "
|
||||||
|
token-symbol)
|
||||||
first-route (first route)
|
first-route (first route)
|
||||||
native-currency-symbol (when-not confirm-disabled?
|
native-currency-symbol (when-not confirm-disabled?
|
||||||
(get-in first-route [:from :native-currency-symbol]))
|
(get-in first-route [:from :native-currency-symbol]))
|
||||||
@ -282,29 +159,20 @@
|
|||||||
[:show-bottom-sheet
|
[:show-bottom-sheet
|
||||||
{:content (fn []
|
{:content (fn []
|
||||||
[select-asset-bottom-sheet
|
[select-asset-bottom-sheet
|
||||||
clear-input!])}])
|
clear-input!])}])]
|
||||||
selected-networks (rf/sub [:wallet/wallet-send-receiver-networks])
|
|
||||||
affordable-networks (send-utils/find-affordable-networks
|
|
||||||
{:balances-per-chain token-balances-per-chain
|
|
||||||
:input-value @input-value
|
|
||||||
:selected-networks selected-networks
|
|
||||||
:disabled-chain-ids disabled-from-chain-ids})]
|
|
||||||
(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!))
|
||||||
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
|
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
|
||||||
#(.remove app-keyboard-listener))))
|
#(.remove app-keyboard-listener))))
|
||||||
(rn/use-effect
|
(rn/use-effect
|
||||||
#(when (> (count affordable-networks) 0)
|
(fn []
|
||||||
(fetch-routes input-num-value (current-limit) 2000))
|
(set-input-state #(controlled-input/set-upper-limit % (current-limit))))
|
||||||
[@input-value])
|
[@crypto-currency?])
|
||||||
(rn/use-effect
|
|
||||||
#(when (> (count affordable-networks) 0)
|
|
||||||
(fetch-routes input-num-value (current-limit) 0))
|
|
||||||
[disabled-from-chain-ids])
|
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style style/screen
|
{:style style/screen
|
||||||
:accessibility-label (str "container" (when @input-error "-error"))}
|
:accessibility-label (str "container"
|
||||||
|
(when (controlled-input/input-error input-state) "-error"))}
|
||||||
[account-switcher/view
|
[account-switcher/view
|
||||||
{:icon-name :i/arrow-left
|
{:icon-name :i/arrow-left
|
||||||
:on-press on-navigate-back
|
:on-press on-navigate-back
|
||||||
@ -314,45 +182,19 @@
|
|||||||
:token token-symbol
|
:token token-symbol
|
||||||
:currency current-currency
|
:currency current-currency
|
||||||
:crypto-decimals crypto-decimals
|
:crypto-decimals crypto-decimals
|
||||||
:error? @input-error
|
:error? (controlled-input/input-error input-state)
|
||||||
:networks (seq token-networks)
|
:networks (seq token-networks)
|
||||||
:title (i18n/label :t/send-limit {:limit limit-label})
|
:title (i18n/label :t/send-limit
|
||||||
|
{:limit (make-limit-label (current-limit) current-currency)})
|
||||||
:conversion conversion-rate
|
:conversion conversion-rate
|
||||||
:show-keyboard? false
|
:show-keyboard? false
|
||||||
:value @input-value
|
:value (controlled-input/input-value input-state)
|
||||||
:selection @input-selection
|
:on-swap #(reset! crypto-currency? %)
|
||||||
:on-change-text #(handle-on-change % (current-limit))
|
|
||||||
:on-selection-change selection-change
|
|
||||||
:on-swap #(handle-swap
|
|
||||||
{:crypto? %
|
|
||||||
:currency current-currency
|
|
||||||
:token-symbol token-symbol
|
|
||||||
:limit-fiat fiat-limit
|
|
||||||
:limit-crypto crypto-limit})
|
|
||||||
:on-token-press show-select-asset-sheet}]
|
:on-token-press show-select-asset-sheet}]
|
||||||
[routes/view
|
[routes/view
|
||||||
{:from-values-by-chain from-values-by-chain
|
{:token token
|
||||||
:to-values-by-chain to-values-by-chain
|
:input-value (controlled-input/input-value input-state)
|
||||||
:affordable-networks affordable-networks
|
:routes-can-be-fetched? routes-can-be-fetched?}]
|
||||||
:routes best-routes
|
|
||||||
:token token
|
|
||||||
:input-value @input-value
|
|
||||||
:fetch-routes #(fetch-routes % (current-limit) 2000)
|
|
||||||
:disabled-from-networks disabled-from-chain-ids
|
|
||||||
:on-press-from-network (fn [chain-id _]
|
|
||||||
(let [disabled-chain-ids (if (contains? (set
|
|
||||||
disabled-from-chain-ids)
|
|
||||||
chain-id)
|
|
||||||
(vec (remove #(= % chain-id)
|
|
||||||
disabled-from-chain-ids))
|
|
||||||
(conj disabled-from-chain-ids
|
|
||||||
chain-id))
|
|
||||||
re-enabling-chain? (< (count disabled-chain-ids)
|
|
||||||
(count disabled-from-chain-ids))]
|
|
||||||
(when (or re-enabling-chain?
|
|
||||||
(> (count affordable-networks) 1))
|
|
||||||
(rf/dispatch [:wallet/disable-from-networks
|
|
||||||
disabled-chain-ids]))))}]
|
|
||||||
(when (or loading-routes? (seq route))
|
(when (or loading-routes? (seq route))
|
||||||
[estimated-fees
|
[estimated-fees
|
||||||
{:loading-suggested-routes? loading-routes?
|
{:loading-suggested-routes? loading-routes?
|
||||||
@ -369,6 +211,12 @@
|
|||||||
{:container-style (style/keyboard-container bottom)
|
{:container-style (style/keyboard-container bottom)
|
||||||
:left-action :dot
|
:left-action :dot
|
||||||
:delete-key? true
|
:delete-key? true
|
||||||
:on-press #(handle-keyboard-press % loading-routes? (current-limit))
|
:on-press (fn [c]
|
||||||
:on-delete #(handle-delete loading-routes? (current-limit))
|
(when-not loading-routes?
|
||||||
:on-long-press-delete #(on-long-press-delete loading-routes?)}]]))))
|
(set-input-state #(controlled-input/add-character % c))))
|
||||||
|
:on-delete (fn []
|
||||||
|
(when-not loading-routes?
|
||||||
|
(set-input-state controlled-input/delete-last)))
|
||||||
|
:on-long-press-delete (fn []
|
||||||
|
(when-not loading-routes?
|
||||||
|
(set-input-state controlled-input/delete-all)))}]]))))
|
||||||
|
@ -4,12 +4,13 @@
|
|||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
[quo.foundations.colors :as colors]
|
[quo.foundations.colors :as colors]
|
||||||
[quo.foundations.resources :as resources]
|
[quo.foundations.resources :as resources]
|
||||||
[quo.theme :as quo.theme]
|
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.contexts.wallet.common.utils :as utils]
|
[status-im.contexts.wallet.common.utils :as utils]
|
||||||
|
[status-im.contexts.wallet.common.utils.send :as send-utils]
|
||||||
[status-im.contexts.wallet.send.routes.style :as style]
|
[status-im.contexts.wallet.send.routes.style :as style]
|
||||||
|
[utils.debounce :as debounce]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[utils.vector :as vector-utils]))
|
[utils.vector :as vector-utils]))
|
||||||
@ -200,19 +201,59 @@
|
|||||||
:on-press-from-network on-press-from-network
|
:on-press-from-network on-press-from-network
|
||||||
:on-press-to-network on-press-to-network}]))
|
:on-press-to-network on-press-to-network}]))
|
||||||
|
|
||||||
|
(defn fetch-routes
|
||||||
|
[amount routes-can-be-fetched? bounce-duration-ms]
|
||||||
|
(if routes-can-be-fetched?
|
||||||
|
(debounce/debounce-and-dispatch
|
||||||
|
[:wallet/get-suggested-routes {:amount amount}]
|
||||||
|
bounce-duration-ms)
|
||||||
|
(rf/dispatch [:wallet/clean-suggested-routes])))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[{:keys [from-values-by-chain to-values-by-chain routes token fetch-routes
|
[{:keys [token theme input-value routes-can-be-fetched?
|
||||||
affordable-networks disabled-from-networks on-press-from-network on-press-to-network]}]
|
on-press-to-network]}]
|
||||||
(let [theme (quo.theme/use-theme)
|
|
||||||
token-symbol (:symbol token)
|
(let [token-symbol (:symbol token)
|
||||||
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
loading-suggested-routes? (rf/sub
|
||||||
network-links (if loading-suggested-routes? affordable-networks routes)]
|
[:wallet/wallet-send-loading-suggested-routes?])
|
||||||
(if (or (and (not-empty affordable-networks) loading-suggested-routes?) (not-empty routes))
|
from-values-by-chain (rf/sub
|
||||||
|
[:wallet/wallet-send-from-values-by-chain])
|
||||||
|
to-values-by-chain (rf/sub [:wallet/wallet-send-to-values-by-chain])
|
||||||
|
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||||
|
selected-networks (rf/sub [:wallet/wallet-send-receiver-networks])
|
||||||
|
disabled-from-chain-ids (rf/sub
|
||||||
|
[:wallet/wallet-send-disabled-from-chain-ids])
|
||||||
|
routes (when suggested-routes
|
||||||
|
(or (:best suggested-routes) []))
|
||||||
|
{token-balances-per-chain :balances-per-chain} (rf/sub
|
||||||
|
[:wallet/current-viewing-account-tokens-filtered
|
||||||
|
(str token-symbol)])
|
||||||
|
affordable-networks (send-utils/find-affordable-networks
|
||||||
|
{:balances-per-chain token-balances-per-chain
|
||||||
|
:input-value input-value
|
||||||
|
:selected-networks selected-networks
|
||||||
|
:disabled-chain-ids disabled-from-chain-ids})
|
||||||
|
network-links (if loading-suggested-routes?
|
||||||
|
affordable-networks
|
||||||
|
routes)
|
||||||
|
show-routes? (or (and (not-empty affordable-networks)
|
||||||
|
loading-suggested-routes?)
|
||||||
|
(not-empty routes))]
|
||||||
|
|
||||||
|
(rn/use-effect
|
||||||
|
#(when (> (count affordable-networks) 0)
|
||||||
|
(fetch-routes input-value routes-can-be-fetched? 2000))
|
||||||
|
[input-value routes-can-be-fetched?])
|
||||||
|
(rn/use-effect
|
||||||
|
#(when (> (count affordable-networks) 0)
|
||||||
|
(fetch-routes input-value routes-can-be-fetched? 0))
|
||||||
|
[disabled-from-chain-ids])
|
||||||
|
(if show-routes?
|
||||||
(let [initial-network-links-count (count network-links)
|
(let [initial-network-links-count (count network-links)
|
||||||
disabled-count (count disabled-from-networks)
|
disabled-count (count disabled-from-chain-ids)
|
||||||
network-links (if (not-empty disabled-from-networks)
|
network-links (if (not-empty disabled-from-chain-ids)
|
||||||
(add-disabled-networks network-links
|
(add-disabled-networks network-links
|
||||||
disabled-from-networks
|
disabled-from-chain-ids
|
||||||
loading-suggested-routes?)
|
loading-suggested-routes?)
|
||||||
network-links)
|
network-links)
|
||||||
network-links-with-add-button (if (and (< (- (count network-links) disabled-count)
|
network-links-with-add-button (if (and (< (- (count network-links) disabled-count)
|
||||||
@ -230,11 +271,25 @@
|
|||||||
[quo/section-label
|
[quo/section-label
|
||||||
{:section (i18n/label :t/to-label)
|
{:section (i18n/label :t/to-label)
|
||||||
:container-style style/section-label-right}]]
|
:container-style style/section-label-right}]]
|
||||||
:render-data {:from-values-by-chain from-values-by-chain
|
:render-data
|
||||||
|
{:from-values-by-chain from-values-by-chain
|
||||||
:to-values-by-chain to-values-by-chain
|
:to-values-by-chain to-values-by-chain
|
||||||
:theme theme
|
:theme theme
|
||||||
:fetch-routes fetch-routes
|
:fetch-routes #(fetch-routes % routes-can-be-fetched? 2000)
|
||||||
:on-press-from-network on-press-from-network
|
:on-press-from-network (fn [chain-id _]
|
||||||
|
(let [disabled-chain-ids (if (contains? (set
|
||||||
|
disabled-from-chain-ids)
|
||||||
|
chain-id)
|
||||||
|
(vec (remove #(= % chain-id)
|
||||||
|
disabled-from-chain-ids))
|
||||||
|
(conj disabled-from-chain-ids
|
||||||
|
chain-id))
|
||||||
|
re-enabling-chain? (< (count disabled-chain-ids)
|
||||||
|
(count disabled-from-chain-ids))]
|
||||||
|
(when (or re-enabling-chain?
|
||||||
|
(> (count affordable-networks) 1))
|
||||||
|
(rf/dispatch [:wallet/disable-from-networks
|
||||||
|
disabled-chain-ids]))))
|
||||||
:on-press-to-network on-press-to-network
|
:on-press-to-network on-press-to-network
|
||||||
:token-symbol token-symbol
|
:token-symbol token-symbol
|
||||||
:loading-suggested-routes? loading-suggested-routes?}
|
:loading-suggested-routes? loading-suggested-routes?}
|
||||||
@ -242,3 +297,4 @@
|
|||||||
[rn/view {:style style/empty-container}
|
[rn/view {:style style/empty-container}
|
||||||
(when (and (not (nil? routes)) (not loading-suggested-routes?))
|
(when (and (not (nil? routes)) (not loading-suggested-routes?))
|
||||||
[quo/text (i18n/label :t/no-routes-found)])])))
|
[quo/text (i18n/label :t/no-routes-found)])])))
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user