feat(wallet)_: Show buy and receive cta on zero balance (#21690)
This commit: - adds wallet-card component - adds Buy and Receive CTAs above the assets list in the wallet home if the balance is zero Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
This commit is contained in:
parent
6859fb8f8e
commit
52a8f8fc22
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,34 @@
|
|||
(ns quo.components.cards.wallet-card.component-spec
|
||||
(:require
|
||||
[quo.components.cards.wallet-card.view :as wallet-card]
|
||||
[quo.foundations.resources :as resources]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(def ^:private base-props
|
||||
{:image (resources/get-image :keycard-logo)
|
||||
:title "Buy"
|
||||
:subtitle "Start investing now"})
|
||||
|
||||
(h/describe "cards: wallet card"
|
||||
(h/test "Test default render"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render-with-theme-provider [wallet-card/view
|
||||
(assoc base-props
|
||||
:on-press
|
||||
event)])
|
||||
(h/is-truthy (h/get-by-label-text :wallet-card))
|
||||
(h/is-truthy (h/get-by-text "Buy"))
|
||||
(h/is-truthy (h/get-by-text "Start investing now"))
|
||||
(h/is-truthy (h/get-by-label-text :image))
|
||||
(h/fire-event :press (h/get-by-label-text :wallet-card))
|
||||
(h/was-called event)))
|
||||
|
||||
(h/test "Test render with dismissible prop"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render-with-theme-provider [wallet-card/view
|
||||
(assoc base-props
|
||||
:dismissible? true
|
||||
:on-press-close event)])
|
||||
(h/is-truthy (h/get-by-label-text :close-icon))
|
||||
(h/fire-event :press (h/get-by-label-text :icon-container))
|
||||
(h/was-called event))))
|
|
@ -0,0 +1,14 @@
|
|||
(ns quo.components.cards.wallet-card.schema)
|
||||
|
||||
(def ?schema
|
||||
[:=>
|
||||
[:catn
|
||||
[:props
|
||||
[:map {:closed true}
|
||||
[:image :schema.common/image-source]
|
||||
[:title :string]
|
||||
[:subtitle :string]
|
||||
[:dismissible? {:optional true} :boolean]
|
||||
[:on-press {:optional true} fn?]
|
||||
[:on-press-close {:optional true} fn?]]]]
|
||||
:any])
|
|
@ -0,0 +1,30 @@
|
|||
(ns quo.components.cards.wallet-card.style
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[quo.foundations.shadows :as shadows]))
|
||||
|
||||
(defn root-container
|
||||
[theme]
|
||||
(assoc (shadows/get 2 theme)
|
||||
:border-radius 16
|
||||
:padding-vertical 10
|
||||
:padding-horizontal 12
|
||||
:width 161
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-90 theme)))
|
||||
|
||||
(def top-container
|
||||
{:flex-direction :row
|
||||
:height 32
|
||||
:justify-content :space-between
|
||||
:margin-bottom 8})
|
||||
|
||||
(def image
|
||||
{:height 32
|
||||
:width 32})
|
||||
|
||||
(defn title
|
||||
[theme]
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
|
||||
|
||||
(defn subtitle
|
||||
[theme]
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)})
|
|
@ -0,0 +1,44 @@
|
|||
(ns quo.components.cards.wallet-card.view
|
||||
(:require [quo.components.cards.wallet-card.schema :as component-schema]
|
||||
[quo.components.cards.wallet-card.style :as style]
|
||||
[quo.components.icon :as icon]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [image title subtitle dismissible? on-press on-press-close]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/pressable
|
||||
{:on-press on-press
|
||||
:accessibility-label :wallet-card}
|
||||
[rn/view {:style (style/root-container theme)}
|
||||
[rn/view {:style style/top-container}
|
||||
[fast-image/fast-image
|
||||
{:style style/image
|
||||
:source image
|
||||
:accessibility-label :image}]
|
||||
(when dismissible?
|
||||
[rn/pressable
|
||||
{:on-press on-press-close
|
||||
:accessibility-label :icon-container
|
||||
:hit-slop {:top 5 :bottom 5 :left 5 :right 5}}
|
||||
[icon/icon :i/close
|
||||
{:size 12
|
||||
:accessibility-label :close-icon}]])]
|
||||
[text/text
|
||||
{:style (style/title theme)
|
||||
:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:number-of-lines 1}
|
||||
title]
|
||||
[text/text
|
||||
{:style (style/subtitle theme)
|
||||
:size :paragraph-2
|
||||
:weight :regular
|
||||
:number-of-lines 1}
|
||||
subtitle]]]))
|
||||
|
||||
(def view (schema/instrument #'view-internal component-schema/?schema))
|
|
@ -28,6 +28,7 @@
|
|||
quo.components.calendar.calendar-day.view
|
||||
quo.components.calendar.calendar-year.view
|
||||
quo.components.calendar.calendar.view
|
||||
quo.components.cards.wallet-card.view
|
||||
quo.components.code.snippet-preview.view
|
||||
quo.components.code.snippet.view
|
||||
quo.components.colors.color-picker.view
|
||||
|
@ -241,6 +242,7 @@
|
|||
;;;; Cards
|
||||
(def small-option-card quo.components.onboarding.small-option-card.view/small-option-card)
|
||||
(def keycard quo.components.keycard.view/keycard)
|
||||
(def wallet-card quo.components.cards.wallet-card.view/view)
|
||||
|
||||
;;;; Colors
|
||||
(def color-picker quo.components.colors.color-picker.view/view)
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
:nfc-success (js/require "../resources/images/ui2/nfc-success.png")
|
||||
:preparing-status (js/require "../resources/images/ui2/preparing-status.png")
|
||||
:syncing-devices (js/require "../resources/images/ui2/syncing_devices.png")
|
||||
:syncing-wrong (js/require "../resources/images/ui2/syncing_wrong.png")})
|
||||
:syncing-wrong (js/require "../resources/images/ui2/syncing_wrong.png")
|
||||
:buy (js/require "../resources/images/ui2/buy.png")
|
||||
:receive (js/require "../resources/images/ui2/receive.png")})
|
||||
|
||||
(def ui-themed
|
||||
{:angry-man
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
(ns status-im.contexts.preview.quo.cards.wallet-card
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.preview.quo.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:key :title
|
||||
:type :text}
|
||||
{:key :subtitle
|
||||
:type :text}
|
||||
{:key :dismissible?
|
||||
:type :boolean}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:image (resources/get-image :buy)
|
||||
:title "Buy"
|
||||
:subtitle "Start investing now"
|
||||
:on-press #(js/alert "Item pressed")
|
||||
:on-press-close #(js/alert "Close pressed")
|
||||
:dismissible? false})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:component-container-style {:align-items :center}}
|
||||
[quo/wallet-card @state]])))
|
|
@ -34,6 +34,7 @@
|
|||
[status-im.contexts.preview.quo.calendar.calendar :as calendar]
|
||||
[status-im.contexts.preview.quo.calendar.calendar-day :as calendar-day]
|
||||
[status-im.contexts.preview.quo.calendar.calendar-year :as calendar-year]
|
||||
[status-im.contexts.preview.quo.cards.wallet-card :as wallet-card]
|
||||
[status-im.contexts.preview.quo.code.snippet :as code-snippet]
|
||||
[status-im.contexts.preview.quo.code.snippet-preview :as code-snippet-preview]
|
||||
[status-im.contexts.preview.quo.colors.color :as color]
|
||||
|
@ -274,6 +275,8 @@
|
|||
:component calendar-day/view}
|
||||
{:name :calendar-year
|
||||
:component calendar-year/view}]
|
||||
:cards [{:name :wallet-card
|
||||
:component wallet-card/view}]
|
||||
:code [{:name :snippet
|
||||
:component code-snippet/view}
|
||||
{:name :snippet-preview
|
||||
|
|
|
@ -4,3 +4,9 @@
|
|||
(def list-container
|
||||
{:padding-horizontal 8
|
||||
:padding-bottom constants/floating-shell-button-height})
|
||||
|
||||
(def buy-and-receive-cta-container
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 20
|
||||
:padding-vertical 8})
|
||||
|
|
|
@ -2,14 +2,39 @@
|
|||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.wallet.common.token-value.view :as token-value]
|
||||
[status-im.contexts.wallet.home.tabs.assets.style :as style]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [tokens-loading? (rf/sub [:wallet/home-tokens-loading?])
|
||||
{:keys [tokens]} (rf/sub [:wallet/aggregated-token-values-and-balance])]
|
||||
{:keys [tokens]} (rf/sub [:wallet/aggregated-token-values-and-balance])
|
||||
zero-balance? (rf/sub [:wallet/zero-balance-in-all-non-watched-accounts?])
|
||||
buy-assets (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])))
|
||||
receive-assets (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:open-modal :screen/share-shell {:initial-tab :wallet}])))]
|
||||
[:<>
|
||||
(when (and (some? tokens-loading?) (not tokens-loading?) zero-balance?)
|
||||
[rn/view
|
||||
{:style style/buy-and-receive-cta-container}
|
||||
[quo/wallet-card
|
||||
{:image (resources/get-image :buy)
|
||||
:title (i18n/label :t/ways-to-buy)
|
||||
:subtitle (i18n/label :t/via-card-or-bank)
|
||||
:on-press buy-assets}]
|
||||
[quo/wallet-card
|
||||
{:image (resources/get-image :receive)
|
||||
:title (i18n/label :t/receive)
|
||||
:subtitle (i18n/label :t/deposit-to-your-wallet)
|
||||
:on-press receive-assets}]])
|
||||
(if tokens-loading?
|
||||
[quo/skeleton-list
|
||||
{:content :assets
|
||||
|
@ -19,4 +44,4 @@
|
|||
{:render-fn token-value/view
|
||||
:data tokens
|
||||
:render-data {:entry-point :wallet-stack}
|
||||
:content-container-style style/list-container}])))
|
||||
:content-container-style style/list-container}])]))
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[status-im.contexts.wallet.sheets.missing-keypair.view :as missing-keypair]
|
||||
[status-im.subs.wallet.add-account.address-to-watch]
|
||||
[utils.money :as money]
|
||||
[utils.number]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
|
@ -694,6 +695,17 @@
|
|||
:formatted-balance formatted-balance
|
||||
:tokens sorted-token-values})))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/zero-balance-in-all-non-watched-accounts?
|
||||
:<- [:wallet/aggregated-tokens]
|
||||
:<- [:profile/currency]
|
||||
:<- [:wallet/prices-per-token]
|
||||
(fn [[aggregated-tokens currency prices-per-token]]
|
||||
(let [balance (utils/calculate-balance-from-tokens {:currency currency
|
||||
:tokens aggregated-tokens
|
||||
:prices-per-token prices-per-token})]
|
||||
(and (not-empty aggregated-tokens) (money/equal-to balance 0)))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/network-preference-details
|
||||
:<- [:wallet/current-viewing-account]
|
||||
|
|
|
@ -761,6 +761,7 @@
|
|||
"deleted-this-message": "deleted this message",
|
||||
"delivered": "Delivered",
|
||||
"deny": "Deny",
|
||||
"deposit-to-your-wallet": "Deposit to your wallet",
|
||||
"derivation-path": "Derivation path",
|
||||
"derivation-path-copied": "Derivation path copied",
|
||||
"derivation-path-desc": "Derivation paths are the routes your Status Wallet uses to generate addresses from your private key.",
|
||||
|
@ -2750,6 +2751,7 @@
|
|||
"verified-community": "✓ Verified community",
|
||||
"version": "App version",
|
||||
"via": "via",
|
||||
"via-card-or-bank": "Via card or bank",
|
||||
"view": "View",
|
||||
"view-address-on-arbiscan": "View address on Arbiscan",
|
||||
"view-address-on-etherscan": "View address on Etherscan",
|
||||
|
@ -2848,6 +2850,7 @@
|
|||
"watch-only": "Watch-only",
|
||||
"watched-account-removed": "Watched address has been removed",
|
||||
"watched-address": "Watched address",
|
||||
"ways-to-buy": "Ways to buy",
|
||||
"ways-to-buy-assets": "Ways to buy assets",
|
||||
"wc-brand-guide": "Guidance on using branding such as trademarks and logos",
|
||||
"wc-disclaimer": "Disclaimers (including third party providers), warranties, and legal releases",
|
||||
|
|
Loading…
Reference in New Issue