diff --git a/src/quo/components/avatars/token_avatar/view.cljs b/src/quo/components/avatars/token_avatar/view.cljs index a5a1100d90..6f97695fb5 100644 --- a/src/quo/components/avatars/token_avatar/view.cljs +++ b/src/quo/components/avatars/token_avatar/view.cljs @@ -1,5 +1,6 @@ (ns quo.components.avatars.token-avatar.view (:require [quo.components.avatars.token-avatar.style :as style] + [quo.components.utilities.token.view :as token] [react-native.core :as rn] [react-native.hole-view :as hole-view] [react-native.platform :as platform] @@ -12,13 +13,14 @@ [:map {:closed true} [:type {:optional true} [:enum :asset :collectible]] [:context? {:optional true} [:maybe :boolean]] - [:image :schema.common/image-source] + [:image {:optional true} [:maybe :schema.common/image-source]] + [:token {:optional true} [:maybe [:or :keyword :string]]] [:network-image {:optional true} [:maybe :schema.common/image-source]] [:container-style {:optional true} [:maybe :map]]]]] :any]) (defn- view-internal - [{:keys [type context? image network-image container-style]}] + [{:keys [type context? image token network-image container-style]}] [rn/view {:style (merge style/container container-style) :accessibility-label :token-avatar} @@ -32,9 +34,11 @@ []) :style style/hole-view} platform/android? (assoc :key context?)) - [rn/image - {:source image - :style (style/image type)}]] + [token/view + {:size :size-32 + :token token + :style (style/image type) + :image-source image}]] (when context? [rn/image {:source network-image diff --git a/src/quo/components/wallet/swap_input/component_spec.cljs b/src/quo/components/wallet/swap_input/component_spec.cljs new file mode 100644 index 0000000000..607ac1ebba --- /dev/null +++ b/src/quo/components/wallet/swap_input/component_spec.cljs @@ -0,0 +1,31 @@ +(ns quo.components.wallet.swap-input.component-spec + (:require [quo.components.wallet.swap-input.view :as swap-input] + [test-helpers.component :as h])) + +(h/describe "Wallet: Swap Input" + (h/test "should render correctly with props" + (h/render-with-theme-provider + [swap-input/view + {:type :pay + :error? false + :token "SNT" + :status :default + :currency-symbol "€" + :value "5" + :fiat-value "1.50" + :network-tag-props {:title "Max: 200 SNT"}}]) + (h/is-truthy (h/get-by-label-text :swap-input)) + (h/is-truthy (h/get-by-text "SNT")) + (h/is-truthy (h/get-by-text "€1.50")) + (h/is-truthy (h/get-by-text "Max: 200 SNT"))) + + (h/test "should render correctly with approval label" + (h/render-with-theme-provider + [swap-input/view + {:type :pay + :show-approval-label? true + :approval-label-props + {:status :approve + :token-value "10" + :token-symbol "SNT"}}]) + (h/is-truthy (h/get-by-text "Approve 10 SNT")))) diff --git a/src/quo/components/wallet/swap_input/style.cljs b/src/quo/components/wallet/swap_input/style.cljs new file mode 100644 index 0000000000..a32e944c1f --- /dev/null +++ b/src/quo/components/wallet/swap_input/style.cljs @@ -0,0 +1,74 @@ +(ns quo.components.wallet.swap-input.style + (:require [quo.foundations.colors :as colors] + [quo.foundations.typography :as typography])) + +(defn- border-color + [theme] + (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)) + +(defn- loader-color + [theme] + (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)) + +(defn content + [theme] + {:border-width 1 + :border-radius 16 + :border-color (border-color theme) + :background-color (colors/theme-colors colors/white colors/neutral-95 theme)}) + +(defn row-1 + [loading?] + {:padding 12 + :gap 8 + :align-items (if loading? :center :flex-end) + :flex-direction :row}) + +(defn row-1-loader + [theme] + {:width 74 + :height 14 + :border-radius 6 + :background-color (loader-color theme)}) + +(def input-container + {:flex 1 + :flex-direction :row + :gap 5 + :height 32 + :align-items :flex-end}) + +(defn input + [disabled? error? theme] + (assoc typography/font-semi-bold + :font-size 27 + :flex-shrink 1 + :padding 0 + :color (cond + error? (colors/resolve-color :danger theme) + disabled? (colors/theme-colors colors/neutral-50 colors/neutral-40 theme) + :else (colors/theme-colors colors/neutral-100 colors/white theme)) + :line-height 32)) + +(defn token-symbol + [theme] + {:padding-bottom 3 + :color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}) + +(defn row-2 + [align-right?] + {:flex-direction :row + :justify-content (if align-right? :flex-end :space-between) + :align-items :center + :padding 12}) + +(defn row-2-loader + [theme] + {:width 80 + :height 10 + :margin-vertical 7 + :border-radius 6 + :background-color (loader-color theme)}) + +(def fiat-amount + {:color colors/neutral-50}) diff --git a/src/quo/components/wallet/swap_input/view.cljs b/src/quo/components/wallet/swap_input/view.cljs new file mode 100644 index 0000000000..4f5b7767b2 --- /dev/null +++ b/src/quo/components/wallet/swap_input/view.cljs @@ -0,0 +1,121 @@ +(ns quo.components.wallet.swap-input.view + (:require [oops.core :as oops] + [quo.components.avatars.token-avatar.view :as token-avatar] + [quo.components.buttons.button.view :as buttons] + [quo.components.dividers.divider-line.view :as divider-line] + [quo.components.markdown.text :as text] + [quo.components.tags.network-tags.view :as network-tag] + [quo.components.wallet.approval-label.schema :as approval-label.schema] + [quo.components.wallet.approval-label.view :as approval-label] + [quo.components.wallet.swap-input.style :as style] + [quo.foundations.colors :as colors] + quo.theme + [react-native.core :as rn] + [schema.core :as schema])) + +(def ?schema + [:=> + [:catn + [:props + [:map {:closed true} + [:type {:optional true} [:maybe [:enum :pay :receive]]] + [:status {:optional true} [:maybe [:enum :default :disabled :loading]]] + [:token {:optional true} [:maybe :string]] + [:value {:optional true} [:maybe :string]] + [:default-value {:optional true} [:maybe :string]] + [:currency-symbol {:optional true} [:maybe :string]] + [:fiat-value {:optional true} [:maybe :string]] + [:show-approval-label? {:optional true} [:maybe :boolean]] + [:error? {:optional true} [:maybe :boolean]] + [:show-keyboard? {:optional true} [:maybe :boolean]] + [:approval-label-props {:optional true} [:maybe approval-label.schema/?schema]] + [:network-tag-props {:optional true} [:maybe :map]] + [:on-change-text {:optional true} [:maybe fn?]] + [:enable-swap? {:optional true} [:maybe :boolean]] + [:on-swap-press {:optional true} [:maybe fn?]] + [:on-token-press {:optional true} [:maybe fn?]] + [:on-max-press {:optional true} [:maybe fn?]] + [:customization-color {:optional true} [:maybe :schema.common/customization-color]] + [:container-style {:optional true} [:maybe :map]]]]] + :any]) + +(defn view-internal + [{:keys [type status token value fiat-value show-approval-label? error? network-tag-props + approval-label-props default-value enable-swap? + currency-symbol on-change-text show-keyboard? + container-style on-swap-press on-token-press on-max-press]}] + (let [theme (quo.theme/use-theme) + pay? (= type :pay) + disabled? (= status :disabled) + loading? (= status :loading) + controlled-input? (some? value) + input-ref (rn/use-ref-atom nil) + set-input-ref (rn/use-callback (fn [ref] (reset! input-ref ref)) []) + focus-input (rn/use-callback (fn [] + (some-> @input-ref + (oops/ocall "focus"))) + [input-ref])] + [rn/view + {:style container-style + :accessibility-label :swap-input} + [rn/view {:style (style/content theme)} + [rn/view + {:style (style/row-1 loading?)} + [rn/pressable {:on-press on-token-press} + [token-avatar/view + {:type :asset + :token token}]] + (if loading? + [rn/view {:style (style/row-1-loader theme)}] + [:<> + [rn/pressable + {:style style/input-container + :on-press focus-input} + [rn/text-input + (cond-> {:ref set-input-ref + :style (style/input disabled? error? theme) + :placeholder-text-color (colors/theme-colors colors/neutral-40 + colors/neutral-50 + theme) + :keyboard-type :numeric + :auto-focus true + :on-change-text on-change-text + :show-soft-input-on-focus show-keyboard? + :default-value default-value + :placeholder "0"} + controlled-input? (assoc :value value))] + [text/text + {:size :paragraph-2 + :weight :semi-bold + :style (style/token-symbol theme)} + token]] + (when (and pay? enable-swap?) + [buttons/button + {:type :outline + :size 32 + :on-press on-swap-press + :icon-only? true} + :i/reorder])])] + [divider-line/view] + [rn/view + {:style (style/row-2 (or (not pay?) loading?))} + (when-not loading? + [:<> + (when pay? + [rn/pressable {:on-press on-max-press} + [network-tag/view + (assoc network-tag-props + :status + (if error? :error :default))]]) + [text/text + {:size :paragraph-2 + :style style/fiat-amount + :weight :medium} + (str currency-symbol fiat-value)]]) + (when loading? + [rn/view {:style (style/row-2-loader theme)}])]] + (when (and (not= status :loading) (= type :pay) show-approval-label?) + [approval-label/view + approval-label-props])])) + +(def view (schema/instrument #'view-internal ?schema)) diff --git a/src/quo/core.cljs b/src/quo/core.cljs index a819ee74d7..808ff8e3d2 100644 --- a/src/quo/core.cljs +++ b/src/quo/core.cljs @@ -186,6 +186,7 @@ quo.components.wallet.progress-bar.view quo.components.wallet.required-tokens.view quo.components.wallet.summary-info.view + quo.components.wallet.swap-input.view quo.components.wallet.token-input.view quo.components.wallet.transaction-progress.view quo.components.wallet.transaction-summary.view @@ -472,6 +473,7 @@ (def progress-bar quo.components.wallet.progress-bar.view/view) (def required-tokens quo.components.wallet.required-tokens.view/view) (def summary-info quo.components.wallet.summary-info.view/view) +(def swap-input quo.components.wallet.swap-input.view/view) (def network-link quo.components.wallet.network-link.view/view) (def token-input quo.components.wallet.token-input.view/view) (def wallet-overview quo.components.wallet.wallet-overview.view/view) diff --git a/src/quo/core_spec.cljs b/src/quo/core_spec.cljs index 59d76a356e..0daf83ee30 100644 --- a/src/quo/core_spec.cljs +++ b/src/quo/core_spec.cljs @@ -112,6 +112,7 @@ quo.components.wallet.progress-bar.component-spec quo.components.wallet.required-tokens.component-spec quo.components.wallet.summary-info.component-spec + quo.components.wallet.swap-input.component-spec quo.components.wallet.token-input.component-spec quo.components.wallet.transaction-progress.component-spec quo.components.wallet.transaction-summary.component-spec diff --git a/src/status_im/contexts/preview/quo/main.cljs b/src/status_im/contexts/preview/quo/main.cljs index 795cb39300..8c846eda92 100644 --- a/src/status_im/contexts/preview/quo/main.cljs +++ b/src/status_im/contexts/preview/quo/main.cljs @@ -212,6 +212,7 @@ [status-im.contexts.preview.quo.wallet.progress-bar :as progress-bar] [status-im.contexts.preview.quo.wallet.required-tokens :as required-tokens] [status-im.contexts.preview.quo.wallet.summary-info :as summary-info] + [status-im.contexts.preview.quo.wallet.swap-input :as swap-input] [status-im.contexts.preview.quo.wallet.token-input :as token-input] [status-im.contexts.preview.quo.wallet.transaction-progress :as transaction-progress] [status-im.contexts.preview.quo.wallet.transaction-summary :as @@ -570,6 +571,7 @@ {:name :required-tokens :component required-tokens/view} {:name :summary-info :component summary-info/view} + {:name :swap-input :component swap-input/view} {:name :token-input :component token-input/view} {:name :wallet-activity :component wallet-activity/view} {:name :transaction-progress :component transaction-progress/view} diff --git a/src/status_im/contexts/preview/quo/wallet/swap_input.cljs b/src/status_im/contexts/preview/quo/wallet/swap_input.cljs new file mode 100644 index 0000000000..ffdcec2022 --- /dev/null +++ b/src/status_im/contexts/preview/quo/wallet/swap_input.cljs @@ -0,0 +1,68 @@ +(ns status-im.contexts.preview.quo.wallet.swap-input + (:require + [quo.core :as quo] + [quo.foundations.resources :as resources] + [react-native.core :as rn] + [status-im.contexts.preview.quo.preview :as preview])) + +(def descriptor + [{:type :select + :key :type + :options [{:key :pay} + {:key :receive}]} + {:type :select + :key :status + :options [{:key :default} + {:key :disabled} + {:key :loading}]} + {:type :select + :key :value + :options [{:key :token} + {:key :fiat}]} + {:type :boolean + :key :error?} + {:type :boolean + :key :enable-swap?} + {:type :boolean + :key :show-approval-label?} + (preview/customization-color-option)]) + +(defn view + [] + (let [[state set-state] (rn/use-state {:type :pay + :error? false + :token "SNT" + :customization-color :blue + :show-approval-label? false + :enable-swap? true + :status :default + :currency-symbol "€"}) + [value set-value] (rn/use-state "") + on-press (fn [v] (set-value (str value v))) + delete (fn [] (set-value #(subs % 0 (dec (count %)))))] + [preview/preview-container + {:state state + :set-state set-state + :descriptor descriptor} + [quo/swap-input + (assoc state + :on-swap-press #(js/alert "Swap Pressed") + :on-token-press #(js/alert "Token Pressed") + :on-max-press #(js/alert "Max Pressed") + :value value + :fiat-value (str (.toFixed (* value 0.3) 2)) + :container-style {:margin-bottom 20} + :network-tag-props {:title "Max: 200 SNT" + :networks [{:source (resources/get-network :ethereum)}]} + :approval-label-props + {:status :approve + :token-value "10" + :button-props {:on-press + #(js/alert "Approve Pressed")} + :customization-color (:customization-color state) + :token-symbol "SNT"})] + [quo/numbered-keyboard + {:left-action :dot + :delete-key? true + :on-press on-press + :on-delete delete}]]))