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-day.view
|
||||||
quo.components.calendar.calendar-year.view
|
quo.components.calendar.calendar-year.view
|
||||||
quo.components.calendar.calendar.view
|
quo.components.calendar.calendar.view
|
||||||
|
quo.components.cards.wallet-card.view
|
||||||
quo.components.code.snippet-preview.view
|
quo.components.code.snippet-preview.view
|
||||||
quo.components.code.snippet.view
|
quo.components.code.snippet.view
|
||||||
quo.components.colors.color-picker.view
|
quo.components.colors.color-picker.view
|
||||||
|
@ -241,6 +242,7 @@
|
||||||
;;;; Cards
|
;;;; Cards
|
||||||
(def small-option-card quo.components.onboarding.small-option-card.view/small-option-card)
|
(def small-option-card quo.components.onboarding.small-option-card.view/small-option-card)
|
||||||
(def keycard quo.components.keycard.view/keycard)
|
(def keycard quo.components.keycard.view/keycard)
|
||||||
|
(def wallet-card quo.components.cards.wallet-card.view/view)
|
||||||
|
|
||||||
;;;; Colors
|
;;;; Colors
|
||||||
(def color-picker quo.components.colors.color-picker.view/view)
|
(def color-picker quo.components.colors.color-picker.view/view)
|
||||||
|
|
|
@ -37,7 +37,9 @@
|
||||||
:nfc-success (js/require "../resources/images/ui2/nfc-success.png")
|
:nfc-success (js/require "../resources/images/ui2/nfc-success.png")
|
||||||
:preparing-status (js/require "../resources/images/ui2/preparing-status.png")
|
:preparing-status (js/require "../resources/images/ui2/preparing-status.png")
|
||||||
:syncing-devices (js/require "../resources/images/ui2/syncing_devices.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
|
(def ui-themed
|
||||||
{:angry-man
|
{: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 :as calendar]
|
||||||
[status-im.contexts.preview.quo.calendar.calendar-day :as calendar-day]
|
[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.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 :as code-snippet]
|
||||||
[status-im.contexts.preview.quo.code.snippet-preview :as code-snippet-preview]
|
[status-im.contexts.preview.quo.code.snippet-preview :as code-snippet-preview]
|
||||||
[status-im.contexts.preview.quo.colors.color :as color]
|
[status-im.contexts.preview.quo.colors.color :as color]
|
||||||
|
@ -274,6 +275,8 @@
|
||||||
:component calendar-day/view}
|
:component calendar-day/view}
|
||||||
{:name :calendar-year
|
{:name :calendar-year
|
||||||
:component calendar-year/view}]
|
:component calendar-year/view}]
|
||||||
|
:cards [{:name :wallet-card
|
||||||
|
:component wallet-card/view}]
|
||||||
:code [{:name :snippet
|
:code [{:name :snippet
|
||||||
:component code-snippet/view}
|
:component code-snippet/view}
|
||||||
{:name :snippet-preview
|
{:name :snippet-preview
|
||||||
|
|
|
@ -4,3 +4,9 @@
|
||||||
(def list-container
|
(def list-container
|
||||||
{:padding-horizontal 8
|
{:padding-horizontal 8
|
||||||
:padding-bottom constants/floating-shell-button-height})
|
: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
|
(:require
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
[react-native.core :as rn]
|
[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.common.token-value.view :as token-value]
|
||||||
[status-im.contexts.wallet.home.tabs.assets.style :as style]
|
[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]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[]
|
[]
|
||||||
(let [tokens-loading? (rf/sub [:wallet/home-tokens-loading?])
|
(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?
|
(if tokens-loading?
|
||||||
[quo/skeleton-list
|
[quo/skeleton-list
|
||||||
{:content :assets
|
{:content :assets
|
||||||
|
@ -19,4 +44,4 @@
|
||||||
{:render-fn token-value/view
|
{:render-fn token-value/view
|
||||||
:data tokens
|
:data tokens
|
||||||
:render-data {:entry-point :wallet-stack}
|
: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.send.utils :as send-utils]
|
||||||
[status-im.contexts.wallet.sheets.missing-keypair.view :as missing-keypair]
|
[status-im.contexts.wallet.sheets.missing-keypair.view :as missing-keypair]
|
||||||
[status-im.subs.wallet.add-account.address-to-watch]
|
[status-im.subs.wallet.add-account.address-to-watch]
|
||||||
|
[utils.money :as money]
|
||||||
[utils.number]
|
[utils.number]
|
||||||
[utils.security.core :as security]))
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
|
@ -694,6 +695,17 @@
|
||||||
:formatted-balance formatted-balance
|
:formatted-balance formatted-balance
|
||||||
:tokens sorted-token-values})))
|
: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
|
(rf/reg-sub
|
||||||
:wallet/network-preference-details
|
:wallet/network-preference-details
|
||||||
:<- [:wallet/current-viewing-account]
|
:<- [:wallet/current-viewing-account]
|
||||||
|
|
|
@ -761,6 +761,7 @@
|
||||||
"deleted-this-message": "deleted this message",
|
"deleted-this-message": "deleted this message",
|
||||||
"delivered": "Delivered",
|
"delivered": "Delivered",
|
||||||
"deny": "Deny",
|
"deny": "Deny",
|
||||||
|
"deposit-to-your-wallet": "Deposit to your wallet",
|
||||||
"derivation-path": "Derivation path",
|
"derivation-path": "Derivation path",
|
||||||
"derivation-path-copied": "Derivation path copied",
|
"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.",
|
"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",
|
"verified-community": "✓ Verified community",
|
||||||
"version": "App version",
|
"version": "App version",
|
||||||
"via": "via",
|
"via": "via",
|
||||||
|
"via-card-or-bank": "Via card or bank",
|
||||||
"view": "View",
|
"view": "View",
|
||||||
"view-address-on-arbiscan": "View address on Arbiscan",
|
"view-address-on-arbiscan": "View address on Arbiscan",
|
||||||
"view-address-on-etherscan": "View address on Etherscan",
|
"view-address-on-etherscan": "View address on Etherscan",
|
||||||
|
@ -2848,6 +2850,7 @@
|
||||||
"watch-only": "Watch-only",
|
"watch-only": "Watch-only",
|
||||||
"watched-account-removed": "Watched address has been removed",
|
"watched-account-removed": "Watched address has been removed",
|
||||||
"watched-address": "Watched address",
|
"watched-address": "Watched address",
|
||||||
|
"ways-to-buy": "Ways to buy",
|
||||||
"ways-to-buy-assets": "Ways to buy assets",
|
"ways-to-buy-assets": "Ways to buy assets",
|
||||||
"wc-brand-guide": "Guidance on using branding such as trademarks and logos",
|
"wc-brand-guide": "Guidance on using branding such as trademarks and logos",
|
||||||
"wc-disclaimer": "Disclaimers (including third party providers), warranties, and legal releases",
|
"wc-disclaimer": "Disclaimers (including third party providers), warranties, and legal releases",
|
||||||
|
|
Loading…
Reference in New Issue