diff --git a/src/quo/components/wallet/token_input/component_spec.cljs b/src/quo/components/wallet/token_input/component_spec.cljs index 8f702fe71a..478928321c 100644 --- a/src/quo/components/wallet/token_input/component_spec.cljs +++ b/src/quo/components/wallet/token_input/component_spec.cljs @@ -6,14 +6,16 @@ (h/describe "Wallet: Token Input" (h/test "Token label renders" (h/render-with-theme-provider [token-input/view - {:token :snt - :currency :eur - :conversion 1}]) + {:token :snt + :currency :eur + :currency-symbol "€" + :conversion 1}]) (h/is-truthy (h/get-by-text "SNT"))) (h/test "Amount renders" (h/render-with-theme-provider [token-input/view - {:token :snt - :currency :eur - :conversion 1}]) + {:token :snt + :currency :eur + :currency-symbol "€" + :conversion 1}]) (h/is-truthy (h/get-by-text "€0.00")))) diff --git a/src/quo/components/wallet/token_input/style.cljs b/src/quo/components/wallet/token_input/style.cljs index 772692c2c2..f0860cf4dc 100644 --- a/src/quo/components/wallet/token_input/style.cljs +++ b/src/quo/components/wallet/token_input/style.cljs @@ -12,30 +12,22 @@ {:padding-horizontal 20 :padding-bottom 4 :height 36 - :flex-direction :row - :justify-content :space-between}) + :flex-direction :row}) (defn token-name [theme] {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme) - :margin-right 8 - :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}) + :padding-bottom 3}) (def text-input-container - {:position :absolute - :top 0 - :bottom 0 - :left 40 ; token image size + margin - :right 0}) + {:flex-direction :row + :align-items :flex-end}) + +(defn input-container + [window-width] + {:width (- window-width 120) + :margin-left 8 + :margin-right 8}) (def text-input-dimensions (-> typography/heading-1 @@ -54,7 +46,8 @@ :color (if error? (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 [theme] diff --git a/src/quo/components/wallet/token_input/view.cljs b/src/quo/components/wallet/token_input/view.cljs index be301c41c5..f800bec39b 100644 --- a/src/quo/components/wallet/token_input/view.cljs +++ b/src/quo/components/wallet/token_input/view.cljs @@ -9,32 +9,34 @@ [quo.components.utilities.token.view :as token] [quo.components.wallet.token-input.schema :as component-schema] [quo.components.wallet.token-input.style :as style] - [quo.foundations.common :as common] [quo.theme :as quo.theme] [react-native.core :as rn] - [schema.core :as schema])) + [schema.core :as schema] + [utils.number :as number])) (defn fiat-format - [currency num-value conversion] - (str (get common/currency-label currency) (.toFixed (* num-value conversion) 2))) + [currency-symbol num-value conversion] + (str currency-symbol (.toFixed (* num-value conversion) 2))) (defn crypto-format [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) "")))) (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) (or (parse-double value) 0) value)] (if crypto? - (fiat-format currency num-value conversion) + (fiat-format currency-symbol num-value conversion) (crypto-format num-value conversion crypto-decimals token)))) (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} [network-tag/view {:networks networks @@ -45,7 +47,7 @@ :weight :medium :style (style/fiat-amount theme)} (calc-value {:crypto? crypto? - :currency currency + :currency-symbol currency-symbol :token token :value amount :conversion conversion @@ -59,20 +61,6 @@ :weight :semi-bold} (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 [{:keys [on-change-text value value-internal set-value-internal on-selection-change on-token-press]}] @@ -92,36 +80,45 @@ (oops/oget "nativeEvent.selection") (js->clj :keywordize-keys true) (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}}] - (let [theme (quo.theme/use-theme)] - [rn/view {:style {:flex 1}} - [rn/pressable {:on-press on-token-press} - [token/view - {:token token - :size :size-32}]] - [rn/pressable - {:style style/text-input-container - :on-press focus-input} - [rn/text-input - (cond-> {:style (style/text-input theme error?) - :placeholder-text-color (style/placeholder-text theme) - :auto-focus true - :ref set-ref - :placeholder "0" - :keyboard-type :numeric - :max-length 12 - :on-change-text handle-on-change-text - :selection-color customization-color - :show-soft-input-on-focus show-keyboard? - :on-selection-change handle-selection-change - :selection (clj->js selection)} - controlled-input? (assoc :value value) - (not controlled-input?) (assoc :default-value value-internal))]] - [token-label - {:theme theme - :text (if crypto? token currency) - :value (if controlled-input? value value-internal)}]])))) + (let [theme (quo.theme/use-theme) + window-width (:width (rn/get-window))] + [rn/pressable + {:style {:width "100%" + :flex-direction :row} + :on-press on-token-press} + [token/view + {:token token + :size :size-32}] + [rn/view {:style (style/input-container window-width)} + [rn/pressable + {:style style/text-input-container + :on-press focus-input} + [rn/text-input + (cond-> {:style (style/text-input theme error?) + :placeholder-text-color (style/placeholder-text theme) + :auto-focus true + :ref set-ref + :placeholder "0" + :keyboard-type :numeric + :on-change-text handle-on-change-text + :selection-color customization-color + :show-soft-input-on-focus show-keyboard? + :on-selection-change handle-selection-change + :selection (clj->js selection)} + controlled-input? (assoc :value value) + (not controlled-input?) (assoc :default-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 [{:keys [container-style value on-swap] :as props}] @@ -141,15 +138,8 @@ :value-internal value-internal :theme theme :set-value-internal set-value-internal - :crypto? crypto?)] - [button/button - {:icon true - :icon-only? true - :size 32 - :on-press handle-on-swap - :type :outline - :accessibility-label :reorder} - :i/reorder]] + :handle-on-swap handle-on-swap + :crypto? crypto?)]] [divider-line/view {:container-style (style/divider theme)}] [data-info (assoc props diff --git a/src/quo/foundations/common.cljs b/src/quo/foundations/common.cljs deleted file mode 100644 index 6b324e45db..0000000000 --- a/src/quo/foundations/common.cljs +++ /dev/null @@ -1,5 +0,0 @@ -(ns quo.foundations.common) - -(def currency-label - {:eur "€" - :usd "$"}) diff --git a/src/status_im/common/controlled_input/utils.cljs b/src/status_im/common/controlled_input/utils.cljs index fb12d4ca1c..7858853e0d 100644 --- a/src/status_im/common/controlled_input/utils.cljs +++ b/src/status_im/common/controlled_input/utils.cljs @@ -37,7 +37,7 @@ [state] (set-input-error state (upper-limit-exceeded? state))) -(defn- set-input-value +(defn set-input-value [state value] (-> state (assoc :value value) diff --git a/src/status_im/contexts/wallet/common/utils.cljs b/src/status_im/contexts/wallet/common/utils.cljs index 7d4d68f238..26731b57f2 100644 --- a/src/status_im/contexts/wallet/common/utils.cljs +++ b/src/status_im/contexts/wallet/common/utils.cljs @@ -4,7 +4,7 @@ [status-im.common.qr-codes.view :as qr-codes] [status-im.constants :as constants] [utils.money :as money] - [utils.number])) + [utils.number :as number])) (defn get-first-name [full-name] @@ -56,16 +56,6 @@ (inc 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 [{:keys [market-values-per-currency]}] (let [price (get-in market-values-per-currency [:usd :price]) @@ -83,8 +73,8 @@ one-cent-value (if (pos? price) (/ 0.01 price) 0) decimals-count (calc-max-crypto-decimals one-cent-value)] (if (< token-units one-cent-value) - (str "<" (remove-trailing-zeroes (.toFixed one-cent-value decimals-count))) - (remove-trailing-zeroes (.toFixed token-units decimals-count)))))) + (str "<" (number/remove-trailing-zeroes (.toFixed one-cent-value decimals-count))) + (number/remove-trailing-zeroes (.toFixed token-units decimals-count)))))) (defn get-market-value [currency {:keys [market-values-per-currency]}] diff --git a/src/status_im/contexts/wallet/send/events.cljs b/src/status_im/contexts/wallet/send/events.cljs index 6e1c879fcd..61c44de720 100644 --- a/src/status_im/contexts/wallet/send/events.cljs +++ b/src/status_im/contexts/wallet/send/events.cljs @@ -117,6 +117,7 @@ dissoc :suggested-routes :route + :amount :from-values-by-chain :to-values-by-chain :sender-network-values diff --git a/src/status_im/contexts/wallet/send/input_amount/component_spec.cljs b/src/status_im/contexts/wallet/send/input_amount/component_spec.cljs index 5c1ee8c6ee..5a59f91c00 100644 --- a/src/status_im/contexts/wallet/send/input_amount/component_spec.cljs +++ b/src/status_im/contexts/wallet/send/input_amount/component_spec.cljs @@ -69,6 +69,7 @@ :view-id :screen/wallet.send-input-amount :wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064" :profile/currency-symbol "$" + :profile/currency :usd :wallet/token-by-symbol {:symbol :eth :total-balance 100 :market-values-per-currency {:usd {:price 10}}} @@ -86,7 +87,8 @@ :chain-id 1 :related-chain-id 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/setup-restorable-re-frame) @@ -173,6 +175,6 @@ (h/is-truthy (h/get-by-label-text :container-error)) (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 [] (h/wait-for #(h/is-truthy (h/get-by-label-text :container)))))))) diff --git a/src/status_im/contexts/wallet/send/input_amount/view.cljs b/src/status_im/contexts/wallet/send/input_amount/view.cljs index c706665d90..a9174c0ae9 100644 --- a/src/status_im/contexts/wallet/send/input_amount/view.cljs +++ b/src/status_im/contexts/wallet/send/input_amount/view.cljs @@ -16,11 +16,13 @@ [status-im.contexts.wallet.send.utils :as send-utils] [status-im.contexts.wallet.sheets.unpreferred-networks-alert.view :as unpreferred-networks-alert] [utils.address :as address] + [utils.debounce :as debounce] [utils.i18n :as i18n] [utils.money :as money] + [utils.number :as number] [utils.re-frame :as rf])) -(defn- make-limit-label +(defn- make-limit-label-crypto [amount currency] (str amount " " @@ -28,6 +30,10 @@ name string/upper-case))) +(defn- make-limit-label-fiat + [amount currency-symbol] + (str currency-symbol amount)) + (defn- estimated-fees [{:keys [loading-routes? fees amount receiver]}] [rn/view {:style style/estimated-fees-container} @@ -61,6 +67,7 @@ (every? (fn [{:keys [total-amount]}] (and total-amount + (money/bignumber? total-amount) (money/equal-to total-amount (money/bignumber "0")))) sender-network-values)) @@ -127,129 +134,138 @@ crypto-currency? (reagent/atom initial-crypto-currency?) on-navigate-back on-navigate-back] (fn [] - (let [[input-state set-input-state] (rn/use-state controlled-input/init-state) - clear-input! #(set-input-state controlled-input/delete-all) - handle-on-confirm (fn [] - (rf/dispatch [:wallet/set-token-amount-to-send - {:amount - (controlled-input/input-value - input-state) - :stack-id current-screen-id}])) - {fiat-currency :currency} (rf/sub [:profile/profile]) + (let [[input-state set-input-state] (rn/use-state controlled-input/init-state) + [just-toggled-mode? set-just-toggled-mode?] (rn/use-state false) + clear-input! #(set-input-state controlled-input/delete-all) + handle-on-confirm (fn [] + (rf/dispatch [:wallet/set-token-amount-to-send + {:amount + (controlled-input/input-value + input-state) + :stack-id current-screen-id}])) + {fiat-currency :currency} (rf/sub [:profile/profile]) {token-symbol :symbol - token-networks :networks} (rf/sub [:wallet/wallet-send-token]) - send-enabled-networks (rf/sub [:wallet/wallet-send-enabled-networks]) - enabled-from-chain-ids (rf/sub - [:wallet/wallet-send-enabled-from-chain-ids]) + token-networks :networks + token-decimals :decimals} (rf/sub [:wallet/wallet-send-token]) + send-enabled-networks (rf/sub [:wallet/wallet-send-enabled-networks]) + enabled-from-chain-ids (rf/sub + [:wallet/wallet-send-enabled-from-chain-ids]) {token-balance :total-balance available-balance :available-balance :as - token} (rf/sub - [:wallet/current-viewing-account-tokens-filtered - (str token-symbol) enabled-from-chain-ids]) - conversion-rate (-> token :market-values-per-currency :usd :price) - loading-routes? (rf/sub - [:wallet/wallet-send-loading-suggested-routes?]) - - 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) - crypto-decimals (or default-crypto-decimals - (utils/get-crypto-decimals-count token)) - current-crypto-limit (or default-limit-crypto - (utils/get-standard-crypto-format - token - token-balance)) - available-crypto-limit (or default-limit-crypto - (utils/get-standard-crypto-format - token - available-balance)) - current-fiat-limit (.toFixed (* token-balance conversion-rate) 2) - available-fiat-limit (.toFixed (* available-balance conversion-rate) 2) - current-limit (if @crypto-currency? - current-crypto-limit - current-fiat-limit) - available-limit (if @crypto-currency? - available-crypto-limit - available-fiat-limit) - valid-input? (not (or (string/blank? - (controlled-input/input-value - input-state)) - (<= (controlled-input/numeric-value - input-state) - 0) - (> (controlled-input/numeric-value - input-state) - available-limit))) - current-currency (if @crypto-currency? token-symbol fiat-currency) - input-num-value (controlled-input/numeric-value input-state) - confirm-disabled? (or (nil? route) - (empty? route) - (string/blank? (controlled-input/input-value - input-state)) - (<= input-num-value 0) - (> input-num-value current-limit)) - amount-text (str (controlled-input/input-value input-state) - " " - token-symbol) - first-route (first route) - native-currency-symbol (when-not confirm-disabled? - (get-in first-route - [:from :native-currency-symbol])) - native-token (when native-currency-symbol - (rf/sub [:wallet/token-by-symbol - native-currency-symbol])) - fee-in-native-token (when-not confirm-disabled? - (send-utils/calculate-full-route-gas-fee route)) - fee-in-crypto-formatted (when fee-in-native-token - (utils/get-standard-crypto-format - native-token - fee-in-native-token)) - fee-in-fiat (when-not confirm-disabled? - (utils/calculate-token-fiat-value - {:currency fiat-currency - :balance fee-in-native-token - :token native-token})) - currency-symbol (rf/sub [:profile/currency-symbol]) - fee-formatted (when fee-in-fiat - (utils/get-standard-fiat-format - fee-in-crypto-formatted - currency-symbol - fee-in-fiat)) - show-select-asset-sheet #(rf/dispatch - [:show-bottom-sheet - {: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} (rf/sub + [:wallet/current-viewing-account-tokens-filtered + (str token-symbol) enabled-from-chain-ids]) + currency-symbol (rf/sub [:profile/currency-symbol]) + currency (rf/sub [:profile/currency]) + conversion-rate (-> token :market-values-per-currency currency :price) + loading-routes? (rf/sub + [:wallet/wallet-send-loading-suggested-routes?]) + 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) + crypto-decimals (or token-decimals default-crypto-decimals) + current-crypto-limit (or default-limit-crypto + (utils/get-standard-crypto-format + token + token-balance)) + available-crypto-limit (or default-limit-crypto + (utils/get-standard-crypto-format + token + available-balance)) + current-fiat-limit (.toFixed (* token-balance conversion-rate) 2) + available-fiat-limit (.toFixed (* available-balance conversion-rate) 2) + current-limit (if @crypto-currency? + current-crypto-limit + current-fiat-limit) + available-limit (if @crypto-currency? + available-crypto-limit + available-fiat-limit) + valid-input? (not (or (string/blank? + (controlled-input/input-value + input-state)) + (<= (controlled-input/numeric-value + input-state) + 0) + (> (controlled-input/numeric-value + input-state) + available-limit))) + input-num-value (controlled-input/numeric-value input-state) + input-amount (controlled-input/input-value input-state) + confirm-disabled? (or (nil? route) + (empty? route) + (string/blank? (controlled-input/input-value + input-state)) + (<= input-num-value 0) + (> input-num-value current-limit)) + amount (if @crypto-currency? + input-amount + (number/remove-trailing-zeroes + (.toFixed (/ input-amount conversion-rate) + crypto-decimals))) + send-amount (rf/sub [:wallet/wallet-send-amount]) + amount-text (str (number/remove-trailing-zeroes + (.toFixed (js/parseFloat send-amount) + (min token-decimals 6))) + " " + token-symbol) + first-route (first route) + native-currency-symbol (when-not confirm-disabled? + (get-in first-route + [:from :native-currency-symbol])) + native-token (when native-currency-symbol + (rf/sub [:wallet/token-by-symbol + native-currency-symbol])) + fee-in-native-token (when-not confirm-disabled? + (send-utils/calculate-full-route-gas-fee route)) + fee-in-crypto-formatted (when fee-in-native-token + (utils/get-standard-crypto-format + native-token + fee-in-native-token)) + fee-in-fiat (when-not confirm-disabled? + (utils/calculate-token-fiat-value + {:currency fiat-currency + :balance fee-in-native-token + :token native-token})) + fee-formatted (when fee-in-fiat + (utils/get-standard-fiat-format + fee-in-crypto-formatted + currency-symbol + fee-in-fiat)) + show-select-asset-sheet #(rf/dispatch + [:show-bottom-sheet + {: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) (filter #(not= (:type %) :add) receiver-network-values)) - suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes]) - routes (when suggested-routes - (or (:best suggested-routes) [])) - no-routes-found? (and - (every-network-value-is-zero? - sender-network-values) - (not (nil? routes)) - (not loading-routes?) - (not token-not-supported-in-receiver-networks?)) - receiver-networks (rf/sub [:wallet/wallet-send-receiver-networks]) - receiver-preferred-networks (rf/sub - [:wallet/wallet-send-receiver-preferred-networks]) - receiver-preferred-networks-set (set receiver-preferred-networks) - sending-to-unpreferred-networks? (not (every? (fn [receiver-selected-network] - (contains? - receiver-preferred-networks-set - receiver-selected-network)) - receiver-networks)) - limit-insufficient? (> (controlled-input/numeric-value input-state) - current-limit) - should-try-again? (and (not limit-insufficient?) no-routes-found?)] + suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes]) + routes (when suggested-routes + (or (:best suggested-routes) [])) + no-routes-found? (and + (every-network-value-is-zero? + sender-network-values) + (not (nil? routes)) + (not loading-routes?) + (not token-not-supported-in-receiver-networks?)) + receiver-networks (rf/sub [:wallet/wallet-send-receiver-networks]) + receiver-preferred-networks (rf/sub + [:wallet/wallet-send-receiver-preferred-networks]) + receiver-preferred-networks-set (set receiver-preferred-networks) + sending-to-unpreferred-networks? (not (every? (fn [receiver-selected-network] + (contains? + receiver-preferred-networks-set + receiver-selected-network)) + receiver-networks)) + input-error (controlled-input/input-error input-state) + limit-insufficient? (> (controlled-input/numeric-value input-state) + current-limit) + should-try-again? (and (not limit-insufficient?) no-routes-found?)] (rn/use-mount (fn [] (let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!)) @@ -259,6 +275,9 @@ (fn [] (set-input-state #(controlled-input/set-upper-limit % current-limit))) [current-limit]) + (rn/use-effect + #(when input-error (debounce/clear-all)) + [input-error]) [rn/view {:style style/screen :accessibility-label (str "container" @@ -270,22 +289,40 @@ [quo/token-input {:container-style style/input-container :token token-symbol - :currency current-currency - :crypto-decimals crypto-decimals + :currency fiat-currency + :currency-symbol currency-symbol + :crypto-decimals (min token-decimals 6) :error? (controlled-input/input-error input-state) :networks (seq send-enabled-networks) - :title (i18n/label :t/send-limit - {:limit (make-limit-label current-limit current-currency)}) + :title (i18n/label + :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 :show-keyboard? false - :value (controlled-input/input-value input-state) - :on-swap #(reset! crypto-currency? %) + :value input-amount + :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}] [routes/view {:token token - :input-value (controlled-input/input-value input-state) + :input-value input-amount + :value amount :valid-input? valid-input? :token-not-supported-in-receiver-networks? token-not-supported-in-receiver-networks? + :lock-fetch-routes? just-toggled-mode? :current-screen-id current-screen-id}] (when (and (not loading-routes?) sender-network-values @@ -314,9 +351,15 @@ {:disabled? (and (not should-try-again?) confirm-disabled?) :on-press (cond should-try-again? - #(rf/dispatch [:wallet/get-suggested-routes - {:amount (controlled-input/input-value - input-state)}]) + #(let [input-amount (controlled-input/input-value + 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? #(show-unpreferred-networks-alert on-confirm) :else @@ -328,11 +371,22 @@ :left-action :dot :delete-key? true :on-press (fn [c] - (when-not loading-routes? - (set-input-state #(controlled-input/add-character % c)))) + (let [new-text (str input-amount 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 [] (when-not loading-routes? + (debounce/clear-all) + (set-just-toggled-mode? false) (set-input-state controlled-input/delete-last))) :on-long-press-delete (fn [] (when-not loading-routes? + (debounce/clear-all) + (set-just-toggled-mode? false) (set-input-state controlled-input/delete-all)))}]])))) diff --git a/src/status_im/contexts/wallet/send/routes/view.cljs b/src/status_im/contexts/wallet/send/routes/view.cljs index c1b0165aaa..d7802472d4 100644 --- a/src/status_im/contexts/wallet/send/routes/view.cljs +++ b/src/status_im/contexts/wallet/send/routes/view.cljs @@ -16,8 +16,8 @@ (def network-link-1x-height 56) (def network-link-2x-height 111) -(defn fetch-routes - [amount valid-input? bounce-duration-ms] +(defn- fetch-routes + [{:keys [amount bounce-duration-ms valid-input?]}] (if valid-input? (debounce/debounce-and-dispatch [:wallet/get-suggested-routes {:amount amount}] @@ -174,8 +174,8 @@ :text (i18n/label :t/at-least-one-network-must-be-activated)}])))) (defn view - [{:keys [token theme input-value valid-input? - on-press-to-network current-screen-id + [{:keys [token theme input-value value valid-input? + lock-fetch-routes? on-press-to-network current-screen-id token-not-supported-in-receiver-networks?]}] (let [token-symbol (:symbol token) nav-current-screen-id (rf/sub [:view-id]) @@ -198,12 +198,21 @@ :disabled-chain-ids disabled-from-chain-ids}) show-routes? (not-empty sender-network-values)] (rn/use-effect - #(when (and active-screen? (> (count token-available-networks-for-suggested-routes) 0)) - (fetch-routes input-value valid-input? 2000)) + (fn [] + (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?]) (rn/use-effect #(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]) [rn/scroll-view {:content-container-style style/routes-container} (when show-routes? @@ -238,5 +247,8 @@ :loading-routes? loading-routes? :theme theme :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})}]]])) diff --git a/src/status_im/subs/wallet/send.cljs b/src/status_im/subs/wallet/send.cljs index ac6609cd2d..38a818076a 100644 --- a/src/status_im/subs/wallet/send.cljs +++ b/src/status_im/subs/wallet/send.cljs @@ -24,6 +24,11 @@ :<- [:wallet/wallet-send] :-> :transaction-ids) +(rf/reg-sub + :wallet/wallet-send-amount + :<- [:wallet/wallet-send] + :-> :amount) + (rf/reg-sub :wallet/send-transaction-progress :<- [:wallet/send-transaction-ids] diff --git a/src/utils/number.cljs b/src/utils/number.cljs index f3406fea39..392498ca8e 100644 --- a/src/utils/number.cljs +++ b/src/utils/number.cljs @@ -1,4 +1,5 @@ -(ns utils.number) +(ns utils.number + (:require [clojure.string :as string])) (defn naive-round "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." [number lower-bound 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+$" "")) + "") + ""))))