diff --git a/resources/images/icons2/20x20/remove@2x.png b/resources/images/icons2/20x20/remove@2x.png new file mode 100644 index 0000000000..d869c520ec Binary files /dev/null and b/resources/images/icons2/20x20/remove@2x.png differ diff --git a/resources/images/icons2/20x20/remove@3x.png b/resources/images/icons2/20x20/remove@3x.png new file mode 100644 index 0000000000..ad4da8002a Binary files /dev/null and b/resources/images/icons2/20x20/remove@3x.png differ diff --git a/src/quo/components/wallet/amount_input/component_spec.cljs b/src/quo/components/wallet/amount_input/component_spec.cljs new file mode 100644 index 0000000000..062aab9007 --- /dev/null +++ b/src/quo/components/wallet/amount_input/component_spec.cljs @@ -0,0 +1,43 @@ +(ns quo.components.wallet.amount-input.component-spec + (:require + [oops.core :as oops] + [quo.components.wallet.amount-input.view :as amount-input] + [quo.foundations.colors :as colors] + [test-helpers.component :as h])) + +(defn- render + [component] + (h/render-with-theme-provider component :light)) + +(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)))) + + (h/test "When the value = minimum dec button is disabled" + (render [amount-input/view + {:init-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 + :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}]) + (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)))) diff --git a/src/quo/components/wallet/amount_input/schema.cljs b/src/quo/components/wallet/amount_input/schema.cljs new file mode 100644 index 0000000000..4923c11dcf --- /dev/null +++ b/src/quo/components/wallet/amount_input/schema.cljs @@ -0,0 +1,21 @@ +(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 + [:props + [:map {:closed true} + [:status {:optional true} [:maybe [:enum :default :error]]] + [:theme :schema.common/theme] + [:on-change-text {: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]]]]] + :any]) diff --git a/src/quo/components/wallet/amount_input/style.cljs b/src/quo/components/wallet/amount_input/style.cljs new file mode 100644 index 0000000000..873299c729 --- /dev/null +++ b/src/quo/components/wallet/amount_input/style.cljs @@ -0,0 +1,17 @@ +(ns quo.components.wallet.amount-input.style + (:require + [quo.foundations.colors :as colors])) + +(def container + {:flex-direction :row + :justify-content :center + :align-items :center}) + +(def input-container {:flex 1}) + +(defn input-text + [theme type] + {:padding 0 + :color (if (= type :error) + (colors/resolve-color :danger theme) + (colors/theme-colors colors/neutral-100 colors/white theme))}) diff --git a/src/quo/components/wallet/amount_input/view.cljs b/src/quo/components/wallet/amount_input/view.cljs new file mode 100644 index 0000000000..2d21862bbf --- /dev/null +++ b/src/quo/components/wallet/amount_input/view.cljs @@ -0,0 +1,81 @@ +(ns quo.components.wallet.amount-input.view + (:require + [quo.components.buttons.button.view :as button] + [quo.components.markdown.text :as text] + [quo.components.wallet.amount-input.schema :as amount-input.schema] + [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 + [{:keys [theme accessibility-label disabled? icon on-press]}] + [button/button + {:icon-only? true + :theme theme + :disabled? disabled? + :type :outline + :accessibility-label accessibility-label + :size 32 + :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)] + [rn/view + {:style (merge style/container container-style)} + [amount-button + {:theme theme + :accessibility-label :amount-input-dec-button + :icon :i/remove + :on-press on-dec-press + :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))}) + :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. + [amount-button + {:theme theme + :icon :i/add + :accessibility-label :amount-input-inc-button + :on-press on-inc-press + :disabled? (>= @value max-value)}]])))) + +(def view + (quo.theme/with-theme + (schema/instrument #'view-internal amount-input.schema/?schema))) diff --git a/src/quo/core.cljs b/src/quo/core.cljs index c0a5286065..32fa837af6 100644 --- a/src/quo/core.cljs +++ b/src/quo/core.cljs @@ -157,6 +157,7 @@ quo.components.wallet.account-overview.view quo.components.wallet.account-permissions.view quo.components.wallet.address-text.view + quo.components.wallet.amount-input.view quo.components.wallet.confirmation-progress.view quo.components.wallet.keypair.view quo.components.wallet.network-amount.view @@ -416,6 +417,7 @@ (def account-overview quo.components.wallet.account-overview.view/view) (def account-permissions quo.components.wallet.account-permissions.view/view) (def address-text quo.components.wallet.address-text.view/view) +(def amount-input quo.components.wallet.amount-input.view/view) (def confirmation-propgress quo.components.wallet.confirmation-progress.view/view) (def keypair quo.components.wallet.keypair.view/view) (def network-amount quo.components.wallet.network-amount.view/view) diff --git a/src/quo/core_spec.cljs b/src/quo/core_spec.cljs index f6a46054c7..f4d9fc0d93 100644 --- a/src/quo/core_spec.cljs +++ b/src/quo/core_spec.cljs @@ -90,6 +90,7 @@ quo.components.wallet.account-origin.component-spec quo.components.wallet.account-overview.component-spec quo.components.wallet.account-permissions.component-spec + quo.components.wallet.amount-input.component-spec quo.components.wallet.confirmation-progress.component-spec quo.components.wallet.keypair.component-spec quo.components.wallet.network-amount.component-spec diff --git a/src/status_im/contexts/preview/quo/main.cljs b/src/status_im/contexts/preview/quo/main.cljs index d79cb88f40..2389a2197a 100644 --- a/src/status_im/contexts/preview/quo/main.cljs +++ b/src/status_im/contexts/preview/quo/main.cljs @@ -179,6 +179,7 @@ [status-im.contexts.preview.quo.wallet.account-overview :as account-overview] [status-im.contexts.preview.quo.wallet.account-permissions :as account-permissions] + [status-im.contexts.preview.quo.wallet.amount-input :as amount-input] [status-im.contexts.preview.quo.wallet.confirmation-progress :as confirmation-progress] [status-im.contexts.preview.quo.wallet.keypair :as keypair] @@ -496,6 +497,8 @@ :component account-overview/view} {:name :account-permissions :component account-permissions/view} + {:name :amount-input + :component amount-input/view} {:name :confirmation-progress :component confirmation-progress/view} {:name :keypair :component keypair/view} diff --git a/src/status_im/contexts/preview/quo/wallet/amount_input.cljs b/src/status_im/contexts/preview/quo/wallet/amount_input.cljs new file mode 100644 index 0000000000..6e94d96845 --- /dev/null +++ b/src/status_im/contexts/preview/quo/wallet/amount_input.cljs @@ -0,0 +1,29 @@ +(ns status-im.contexts.preview.quo.wallet.amount-input + (:require + [quo.core :as quo] + [reagent.core :as reagent] + [status-im.contexts.preview.quo.preview :as preview])) + +(def descriptor + [{:key :max-value + :type :number} + {:key :min-value + :type :number} + {:key :init-value + :type :number} + {:type :select + :key :status + :options [{:key :default} + {:key :error}]}]) + +(defn view + [] + (let [state (reagent/atom {:max-value 10000 + :min-value 0 + :init-value 1 + :status :default})] + (fn [] + [preview/preview-container + {:state state + :descriptor descriptor} + [quo/amount-input @state]])))