Flow for sending multiple collectibles (#19386)
This commit is contained in:
parent
3ee004afab
commit
4aee5af791
Binary file not shown.
After Width: | Height: | Size: 181 B |
Binary file not shown.
After Width: | Height: | Size: 203 B |
|
@ -15,9 +15,9 @@
|
|||
[{:keys [disabled? blur? on-press on-long-press type]} label]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[pressed? set-pressed?] (rn/use-state false)
|
||||
on-press (rn/use-callback #(when on-press (on-press label)) [label])
|
||||
on-press (rn/use-callback #(when on-press (on-press label)) [on-press label])
|
||||
on-long-press (rn/use-callback #(when (fn? on-long-press) (on-long-press label))
|
||||
[label])
|
||||
[on-long-press label])
|
||||
on-press-in (rn/use-callback #(set-pressed? true))
|
||||
on-press-out (rn/use-callback #(set-pressed? false))
|
||||
label-color (style/get-label-color disabled? theme blur?)
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
(def container
|
||||
(merge (shadows/get 2)
|
||||
{:flex 1
|
||||
:align-items :center
|
||||
{:align-items :center
|
||||
:justify-content :center
|
||||
:border-radius 16}))
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
{:label (i18n/label :t/cant-fetch-info)
|
||||
:counter counter
|
||||
:theme theme}]
|
||||
[rn/view {:style {:flex 1}}
|
||||
[rn/view
|
||||
[rn/image
|
||||
{:style (style/image square? (:aspect-ratio image-size))
|
||||
:source image-src}]
|
||||
|
@ -66,7 +66,7 @@
|
|||
[:catn
|
||||
[:props
|
||||
[:map {:closed true}
|
||||
[:image-src {:optional true} string?]
|
||||
[:image-src {:optional true} [:maybe string?]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:square? {:optional true} [:maybe boolean?]]
|
||||
[:counter {:optional true} [:maybe string?]]
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
[react-native.core :as rn]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [title networks status theme blur?] :or {status :default}}]
|
||||
[{:keys [title networks status theme blur? container-style] :or {status :default}}]
|
||||
[rn/view
|
||||
{:style (style/container {:status status
|
||||
{:style (merge (style/container {:status status
|
||||
:theme theme
|
||||
:blur? blur?})}
|
||||
:blur? blur?})
|
||||
container-style)}
|
||||
[preview-list/view
|
||||
{:type :network
|
||||
:number (count networks)
|
||||
|
|
|
@ -12,32 +12,24 @@
|
|||
(h/describe "Amount input component"
|
||||
(h/test "Renders with default value"
|
||||
(let [text-expected 0]
|
||||
(render [amount-input/view {:init-value text-expected}])
|
||||
(h/is-truthy (h/query-by-label-text :amount-input))
|
||||
(h/is-equal (oops/oget (h/get-by-label-text :amount-input) "props" "value")
|
||||
(str text-expected))))
|
||||
(render [amount-input/view {:value text-expected}])
|
||||
(h/is-truthy (h/query-by-label-text :amount-input))))
|
||||
|
||||
(h/test "When the value = minimum dec button is disabled"
|
||||
(render [amount-input/view
|
||||
{:init-value 0
|
||||
{:value 0
|
||||
:min-value 0}])
|
||||
(h/is-truthy
|
||||
(oops/oget (h/get-by-label-text :amount-input-dec-button) "props" "accessibilityState" "disabled")))
|
||||
|
||||
(h/test "When the value = maximum inc button is disabled"
|
||||
(render [amount-input/view
|
||||
{:init-value 100
|
||||
{:value 100
|
||||
:max-value 100}])
|
||||
(h/is-truthy
|
||||
(oops/oget (h/get-by-label-text :amount-input-inc-button) "props" "accessibilityState" "disabled")))
|
||||
|
||||
(h/test "Renders the error state"
|
||||
(render [amount-input/view {:status :error}])
|
||||
(render [amount-input/view {:status :error :value 10}])
|
||||
(h/is-equal (colors/resolve-color :danger :light)
|
||||
(oops/oget (h/get-by-label-text :amount-input) "props" "style" "color")))
|
||||
|
||||
(h/test "on-change-text function is fired"
|
||||
(let [on-change-text (h/mock-fn)]
|
||||
(render [amount-input/view {:on-change-text on-change-text}])
|
||||
(h/fire-event :change-text (h/get-by-label-text :amount-input) "100")
|
||||
(h/was-called on-change-text))))
|
||||
(oops/oget (h/get-by-label-text :amount-input) "props" "style" "color"))))
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
(ns quo.components.wallet.amount-input.schema)
|
||||
|
||||
(def return-key-types
|
||||
[:enum :done :go :next :search :send :none :previous :default
|
||||
:emergency-call :google :join :route :yahoo])
|
||||
|
||||
(def ?schema
|
||||
[:=>
|
||||
[:catn
|
||||
|
@ -11,11 +7,10 @@
|
|||
[:map {:closed true}
|
||||
[:status {:optional true} [:maybe [:enum :default :error]]]
|
||||
[:theme :schema.common/theme]
|
||||
[:on-change-text {:optional true} [:maybe fn?]]
|
||||
[:on-inc-press {:optional true} [:maybe fn?]]
|
||||
[:on-dec-press {:optional true} [:maybe fn?]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:auto-focus? {:optional true} [:maybe :boolean]]
|
||||
[:min-value {:optional true} [:maybe :int]]
|
||||
[:max-value {:optional true} [:maybe :int]]
|
||||
[:return-key-type {:optional true} [:maybe return-key-types]]
|
||||
[:init-value {:optional true} [:maybe :int]]]]]
|
||||
[:value [:maybe :int]]]]]
|
||||
:any])
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
(defn input-text
|
||||
[theme type]
|
||||
{:padding 0
|
||||
:align :center
|
||||
:color (if (= type :error)
|
||||
(colors/resolve-color :danger theme)
|
||||
(colors/theme-colors colors/neutral-100 colors/white theme))})
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
[quo.components.wallet.amount-input.style :as style]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- amount-button
|
||||
|
@ -21,25 +20,12 @@
|
|||
:on-press on-press}
|
||||
icon])
|
||||
|
||||
(defn- process-amount
|
||||
[input-value min-value max-value]
|
||||
(let [parsed-input-value (parse-double input-value)]
|
||||
(cond
|
||||
(nil? parsed-input-value) min-value
|
||||
(>= input-value max-value) max-value
|
||||
(<= input-value min-value) min-value
|
||||
:else parsed-input-value)))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [init-value]}]
|
||||
(let [init-value (or init-value 0)
|
||||
value (reagent/atom init-value)
|
||||
on-dec-press #(swap! value dec)
|
||||
on-inc-press #(swap! value inc)]
|
||||
(fn [{:keys [theme status min-value max-value auto-focus?
|
||||
return-key-type container-style on-change-text]}]
|
||||
(let [min-value (or min-value 0)
|
||||
max-value (or max-value 999999999)]
|
||||
[{:keys [on-inc-press on-dec-press theme status value min-value max-value
|
||||
container-style]
|
||||
:or {value 0
|
||||
min-value 0
|
||||
max-value 999999999}}]
|
||||
[rn/view
|
||||
{:style (merge style/container container-style)}
|
||||
[amount-button
|
||||
|
@ -47,34 +33,22 @@
|
|||
:accessibility-label :amount-input-dec-button
|
||||
:icon :i/remove
|
||||
:on-press on-dec-press
|
||||
:disabled? (>= min-value @value)}]
|
||||
:disabled? (>= min-value value)}]
|
||||
[rn/view {:style style/input-container}
|
||||
[rn/text-input
|
||||
{:style
|
||||
(text/text-style
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:align :center
|
||||
:style (style/input-text theme (or status :default))})
|
||||
[text/text
|
||||
{:number-of-lines 1
|
||||
:accessibility-label :amount-input
|
||||
:editable true
|
||||
:auto-focus (or auto-focus? false)
|
||||
:value (str @value)
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
:return-key-type (or return-key-type :done)
|
||||
:input-mode :numeric
|
||||
:on-change-text (fn [input-value]
|
||||
(let [processed-amount (process-amount input-value min-value max-value)]
|
||||
(reset! value processed-amount)
|
||||
(when on-change-text
|
||||
(on-change-text processed-amount))
|
||||
(reagent/flush)))}]] ; Fixes the input flickering issue when typing.
|
||||
:weight :semi-bold
|
||||
:size :heading-1
|
||||
:align-self :center
|
||||
:style (style/input-text theme (or status :default))}
|
||||
value]]
|
||||
[amount-button
|
||||
{:theme theme
|
||||
:icon :i/add
|
||||
:accessibility-label :amount-input-inc-button
|
||||
:on-press on-inc-press
|
||||
:disabled? (>= @value max-value)}]]))))
|
||||
:disabled? (>= value max-value)}]])
|
||||
|
||||
(def view
|
||||
(quo.theme/with-theme
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
:type :number}
|
||||
{:key :min-value
|
||||
:type :number}
|
||||
{:key :init-value
|
||||
{:key :value
|
||||
:type :number}
|
||||
{:type :select
|
||||
:key :status
|
||||
|
@ -20,10 +20,16 @@
|
|||
[]
|
||||
(let [state (reagent/atom {:max-value 10000
|
||||
:min-value 0
|
||||
:init-value 1
|
||||
:status :default})]
|
||||
:value 1
|
||||
:status :default})
|
||||
on-inc-press (fn [] (swap! state #(assoc % :value (inc (:value %)))))
|
||||
on-dec-press (fn [] (swap! state #(assoc % :value (dec (:value %)))))]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor}
|
||||
[quo/amount-input @state]])))
|
||||
[quo/amount-input
|
||||
(merge
|
||||
@state
|
||||
{:on-dec-press on-dec-press
|
||||
:on-inc-press on-inc-press})]])))
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
(ns status-im.contexts.wallet.collectible.utils)
|
||||
|
||||
(defn collectible-balance
|
||||
[collectible]
|
||||
(-> collectible
|
||||
:ownership
|
||||
first
|
||||
:balance
|
||||
js/parseInt))
|
|
@ -101,16 +101,24 @@
|
|||
:amount
|
||||
(when (= transaction-type :collecible) :tx-type))})))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-select-collectible
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id]}]]
|
||||
(rf/reg-event-fx :wallet/send-collectibles-amount
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id amount]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :token)
|
||||
(assoc-in [:wallet :ui :send :collectible] collectible)
|
||||
(assoc-in [:wallet :ui :send :tx-type] :collectible)
|
||||
(assoc-in [:wallet :ui :send :amount] 1))
|
||||
:fx [[:dispatch [:wallet/get-suggested-routes {:amount 1}]]
|
||||
(assoc-in [:wallet :ui :send :amount] amount))
|
||||
:fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]]
|
||||
[:navigate-to-within-stack [:screen/wallet.transaction-confirmation stack-id]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-collectibles-amount
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :token)
|
||||
(assoc-in [:wallet :ui :send :collectible] collectible)
|
||||
(assoc-in [:wallet :ui :send :tx-type] :collectible))
|
||||
:fx [[:navigate-to-within-stack [:screen/wallet.select-collectible-amount stack-id]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-select-amount
|
||||
(fn [{:keys [db]} [{:keys [amount stack-id start-flow?]}]]
|
||||
{:db (assoc-in db [:wallet :ui :send :amount] amount)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.wallet.collectible.utils :as utils]
|
||||
[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.collectibles-tab.view :as collectibles-tab]
|
||||
|
@ -34,9 +35,15 @@
|
|||
{:collectibles collectibles
|
||||
:filtered? search-performed?
|
||||
:on-end-reached #(rf/dispatch [:wallet/request-collectibles-for-current-viewing-account])
|
||||
:on-collectible-press #(rf/dispatch [:wallet/send-select-collectible
|
||||
:on-collectible-press #(let [collectibles-count (utils/collectible-balance %)]
|
||||
(if (> collectibles-count 1)
|
||||
(rf/dispatch [:wallet/select-collectibles-amount
|
||||
{:collectible %
|
||||
:stack-id :screen/wallet.select-asset}])}]))
|
||||
:stack-id :screen/wallet.select-asset}])
|
||||
(rf/dispatch [:wallet/send-collectibles-amount
|
||||
{:collectible %
|
||||
:amount 1
|
||||
:stack-id :screen/wallet.select-asset}])))}]))
|
||||
(defn- tab-view
|
||||
[search-text selected-tab on-change-text]
|
||||
(let [unfiltered-collectibles (rf/sub [:wallet/current-viewing-account-collectibles])
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
(ns status-im.contexts.wallet.send.select-collectible-amount.style)
|
||||
|
||||
(def collectible-container
|
||||
{:margin-vertical 12
|
||||
:margin-horizontal 56})
|
||||
|
||||
(def network-tags-container
|
||||
{:align-self :center})
|
||||
|
||||
(def amount-input-container
|
||||
{:padding-left 20
|
||||
:padding-right 20
|
||||
:margin-vertical 12})
|
|
@ -0,0 +1,67 @@
|
|||
(ns status-im.contexts.wallet.send.select-collectible-amount.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.contexts.wallet.collectible.utils :as utils]
|
||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||
[status-im.contexts.wallet.send.select-collectible-amount.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [on-close (rn/use-callback #(rf/dispatch [:navigate-back]))
|
||||
[value set-value] (rn/use-state 1)
|
||||
inc-value (rn/use-callback (fn [] (set-value (inc value)))
|
||||
[value])
|
||||
dec-value (rn/use-callback (fn [] (set-value (dec value)))
|
||||
[value])
|
||||
add-digit (rn/use-callback (fn [digit]
|
||||
(set-value (+ (js/parseInt digit)
|
||||
(* value 10))))
|
||||
[value])
|
||||
delete-digit (rn/use-callback (fn []
|
||||
(set-value (Math/floor (/ value 10))))
|
||||
[value])
|
||||
|
||||
send-transaction-data (rf/sub [:wallet/wallet-send])
|
||||
collectible (:collectible send-transaction-data)
|
||||
balance (utils/collectible-balance collectible)
|
||||
preview-uri (get-in collectible [:preview-url :uri])
|
||||
incorrect-value? (or (< value 1) (> value balance))]
|
||||
[rn/view
|
||||
[account-switcher/view
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press on-close
|
||||
:switcher-type :select-account}]
|
||||
[quo/expanded-collectible
|
||||
{:image-src preview-uri
|
||||
:square? true
|
||||
:container-style style/collectible-container}]
|
||||
[quo/network-tags
|
||||
{:title (i18n/label :t/max {:number balance})
|
||||
:status (if incorrect-value? :error :default)
|
||||
:container-style style/network-tags-container}]
|
||||
|
||||
[quo/amount-input
|
||||
{:max-value (if (integer? balance) balance 0)
|
||||
:min-value 1
|
||||
:value value
|
||||
:on-inc-press inc-value
|
||||
:on-dec-press dec-value
|
||||
:container-style style/amount-input-container
|
||||
:status (if incorrect-value? :error :default)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-props {:on-press #(rf/dispatch [:wallet/send-collectibles-amount
|
||||
{:collectible collectible
|
||||
:amount value
|
||||
:stack-id :screen/wallet.select-asset}])
|
||||
:disabled? incorrect-value?}
|
||||
:button-one-label (i18n/label :t/confirm)}]
|
||||
[quo/numbered-keyboard
|
||||
{:left-action :none
|
||||
:delete-key? true
|
||||
:on-press add-digit
|
||||
:on-delete delete-digit}]]))
|
||||
|
|
@ -77,6 +77,7 @@
|
|||
[status-im.contexts.wallet.send.save-address.view :as wallet-save-address]
|
||||
[status-im.contexts.wallet.send.select-address.view :as wallet-select-address]
|
||||
[status-im.contexts.wallet.send.select-asset.view :as wallet-select-asset]
|
||||
[status-im.contexts.wallet.send.select-collectible-amount.view :as wallet-select-collectible-amount]
|
||||
[status-im.contexts.wallet.send.send-amount.view :as wallet-send-input-amount]
|
||||
[status-im.contexts.wallet.send.transaction-confirmation.view :as wallet-transaction-confirmation]
|
||||
[status-im.contexts.wallet.send.transaction-progress.view :as wallet-transaction-progress]
|
||||
|
@ -428,6 +429,10 @@
|
|||
{:name :screen/wallet.transaction-confirmation
|
||||
:component wallet-transaction-confirmation/view}
|
||||
|
||||
{:name :screen/wallet.select-collectible-amount
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-select-collectible-amount/view}
|
||||
|
||||
{:name :screen/wallet.transaction-progress
|
||||
:component wallet-transaction-progress/view}
|
||||
|
||||
|
|
|
@ -2561,5 +2561,6 @@
|
|||
"address-count": {
|
||||
"one": "1 address",
|
||||
"other": "{{count}} addresses"
|
||||
}
|
||||
},
|
||||
"max": "Max: {{number}}"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue