diff --git a/resources/images/ui2/buy@2x.png b/resources/images/ui2/buy@2x.png new file mode 100644 index 00000000000..26de202921b Binary files /dev/null and b/resources/images/ui2/buy@2x.png differ diff --git a/resources/images/ui2/buy@3x.png b/resources/images/ui2/buy@3x.png new file mode 100644 index 00000000000..91b84d4886a Binary files /dev/null and b/resources/images/ui2/buy@3x.png differ diff --git a/resources/images/ui2/receive@2x.png b/resources/images/ui2/receive@2x.png new file mode 100644 index 00000000000..7eef3d8bb1f Binary files /dev/null and b/resources/images/ui2/receive@2x.png differ diff --git a/resources/images/ui2/receive@3x.png b/resources/images/ui2/receive@3x.png new file mode 100644 index 00000000000..8d1d8614e9d Binary files /dev/null and b/resources/images/ui2/receive@3x.png differ diff --git a/src/quo/components/cards/wallet_card/component_spec.cljs b/src/quo/components/cards/wallet_card/component_spec.cljs new file mode 100644 index 00000000000..3141214440c --- /dev/null +++ b/src/quo/components/cards/wallet_card/component_spec.cljs @@ -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)))) diff --git a/src/quo/components/cards/wallet_card/style.cljs b/src/quo/components/cards/wallet_card/style.cljs new file mode 100644 index 00000000000..84c79319636 --- /dev/null +++ b/src/quo/components/cards/wallet_card/style.cljs @@ -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)}) diff --git a/src/quo/components/cards/wallet_card/view.cljs b/src/quo/components/cards/wallet_card/view.cljs new file mode 100644 index 00000000000..e06642cca2f --- /dev/null +++ b/src/quo/components/cards/wallet_card/view.cljs @@ -0,0 +1,56 @@ +(ns quo.components.cards.wallet-card.view + (:require [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])) + +(def ^:private ?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]) + +(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 ?schema)) diff --git a/src/quo/core.cljs b/src/quo/core.cljs index 88f47dd2664..50a057b8fc6 100644 --- a/src/quo/core.cljs +++ b/src/quo/core.cljs @@ -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) diff --git a/src/status_im/common/resources.cljs b/src/status_im/common/resources.cljs index 420346921c0..6144811f31a 100644 --- a/src/status_im/common/resources.cljs +++ b/src/status_im/common/resources.cljs @@ -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 diff --git a/src/status_im/contexts/preview/quo/cards/wallet_card.cljs b/src/status_im/contexts/preview/quo/cards/wallet_card.cljs new file mode 100644 index 00000000000..9c09bd78d08 --- /dev/null +++ b/src/status_im/contexts/preview/quo/cards/wallet_card.cljs @@ -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]]))) diff --git a/src/status_im/contexts/preview/quo/main.cljs b/src/status_im/contexts/preview/quo/main.cljs index 67df16adfcf..dddea5d26b9 100644 --- a/src/status_im/contexts/preview/quo/main.cljs +++ b/src/status_im/contexts/preview/quo/main.cljs @@ -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 diff --git a/src/status_im/contexts/wallet/common/utils.cljs b/src/status_im/contexts/wallet/common/utils.cljs index 2eaedf60947..71b24508bb5 100644 --- a/src/status_im/contexts/wallet/common/utils.cljs +++ b/src/status_im/contexts/wallet/common/utils.cljs @@ -266,8 +266,14 @@ (defn fiat-formatted-for-ui [currency-symbol fiat-value] - (if (money/less-than fiat-value 0.01) + (cond + (money/equal-to fiat-value 0) + (str currency-symbol "0.00") + + (money/less-than fiat-value 0.01) (str "<" currency-symbol "0.01") + + :else (prettify-balance currency-symbol fiat-value))) (defn prettify-percentage-change diff --git a/src/status_im/contexts/wallet/home/tabs/assets/style.cljs b/src/status_im/contexts/wallet/home/tabs/assets/style.cljs index 60b0cd690a0..0faa687ba8a 100644 --- a/src/status_im/contexts/wallet/home/tabs/assets/style.cljs +++ b/src/status_im/contexts/wallet/home/tabs/assets/style.cljs @@ -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}) diff --git a/src/status_im/contexts/wallet/home/tabs/assets/view.cljs b/src/status_im/contexts/wallet/home/tabs/assets/view.cljs index 4aaf6646980..e347a1317c4 100644 --- a/src/status_im/contexts/wallet/home/tabs/assets/view.cljs +++ b/src/status_im/contexts/wallet/home/tabs/assets/view.cljs @@ -2,21 +2,46 @@ (: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])] - (if tokens-loading? - [quo/skeleton-list - {:content :assets - :parent-height 560 - :animated? false}] - [rn/flat-list - {:render-fn token-value/view - :data tokens - :render-data {:entry-point :wallet-stack} - :content-container-style style/list-container}]))) + {: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/buy) + :subtitle (i18n/label :t/start-investing-now) + :on-press buy-assets}] + [quo/wallet-card + {:image (resources/get-image :receive) + :title (i18n/label :t/receive) + :subtitle (i18n/label :t/bring-your-funds-over) + :on-press receive-assets}]]) + (if tokens-loading? + [quo/skeleton-list + {:content :assets + :parent-height 560 + :animated? false}] + [rn/flat-list + {:render-fn token-value/view + :data tokens + :render-data {:entry-point :wallet-stack} + :content-container-style style/list-container}])])) diff --git a/src/status_im/subs/wallet/wallet.cljs b/src/status_im/subs/wallet/wallet.cljs index da4cac87ea4..82ab986fc4b 100644 --- a/src/status_im/subs/wallet/wallet.cljs +++ b/src/status_im/subs/wallet/wallet.cljs @@ -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])) @@ -689,6 +690,15 @@ :formatted-balance formatted-balance :tokens sorted-token-values}))) +(rf/reg-sub + :wallet/zero-balance-in-all-non-watched-accounts? + :<- [:wallet/aggregated-tokens] + :<- [:profile/currency] + (fn [[aggregated-tokens currency]] + (let [balance (utils/calculate-balance-from-tokens {:currency currency + :tokens aggregated-tokens})] + (money/equal-to balance 0)))) + (rf/reg-sub :wallet/network-preference-details :<- [:wallet/current-viewing-account] diff --git a/translations/en.json b/translations/en.json index 9f4aff9e565..5809d8e7d0e 100644 --- a/translations/en.json +++ b/translations/en.json @@ -247,6 +247,7 @@ "bridge-from": "Bridge from {{bridge-name}}", "bridge-to": "Bridge {{name}} to", "bridged-to": "Bridged to {{network}}", + "bring-your-funds-over": "Bring your funds over", "browsed-websites": "Browser history will appear here", "browser": "Browser", "browser-not-secure": "Connection is not secure! Do not sign transactions or send personal data on this site.", @@ -2424,6 +2425,7 @@ "start-fresh": "Start fresh", "start-fresh-subtitle": "Create a new profile from scratch", "start-group-chat": "Start group chat", + "start-investing-now": "Start investing now", "start-new-chat": "Start new chat", "start-using-status": "Start using Status", "start-with-space": "Cannot start with space",