Connect Wallet Home Page to backend - Accounts card (#17447)
* add functionality * fix lint issues * change class component to functional component * fix refactor-data function * rename events and fix reagent-render structure * change rf/defn to re-frame/reg-event-fx * convert camelCase to kebab-case * refactor on-error callback * refactor on-success callback * replace merge with assoc and conj * refactor calculate-balance structure * rename reagent-render * move calculate-balance into a sub * use created sub in the view * fix lint issues * move calculate-balance function to wallet sub * change on-success callback * revert podfile.lock * remove extra line * add template for test * edit calculate-balance and calculate-raw-balance * add tests * revert podfile.lock and fix lint issues * rename refactor-data * add toFixed to get-balance * fix lint issues * finalize code * replace re-frame/reg-event-fx with rf/defn * resolve comments * remove use-fixtures in the test * break down calculate-balance * fix lint issues * fix placeholder color * move accounts to view-internal * remove accounts param in wallet-2/get-wallet-token * Connect Wallet Account Page to backend (basic) (#17700) * pass address to wallet-accounts screen * move get-balance-by-address to common/utils * add functionality * fix lint issues * move logic to sub * convert filter+first to some * change code structure * rename wallet-2 to wallet * add tests * fix lint issues * fix style * remove unused code * remove view-internal defn * fix lint issues * fix networks param issue * fix .toFixed issue
This commit is contained in:
parent
88b3d7d2e6
commit
ca822ff51d
|
@ -76,6 +76,7 @@
|
||||||
{:db (assoc db
|
{:db (assoc db
|
||||||
:chats/loading? true
|
:chats/loading? true
|
||||||
:networks/current-network current-network
|
:networks/current-network current-network
|
||||||
|
:wallet/tokens-loading? true
|
||||||
:networks/networks (merge networks config/default-networks-by-id)
|
:networks/networks (merge networks config/default-networks-by-id)
|
||||||
:profile/profile (merge profile settings))}
|
:profile/profile (merge profile settings))}
|
||||||
(notifications/load-preferences)
|
(notifications/load-preferences)
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
(ns status-im2.contexts.wallet.account.style)
|
(ns status-im2.contexts.wallet.account.style)
|
||||||
|
|
||||||
|
(def container
|
||||||
|
{:flex 1})
|
||||||
|
|
||||||
(def tabs
|
(def tabs
|
||||||
{:padding-left 20
|
{:padding-left 20
|
||||||
:padding-vertical 12})
|
:padding-vertical 12})
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
(:require
|
(:require
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.safe-area :as safe-area]
|
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im2.contexts.wallet.account.style :as style]
|
[status-im2.contexts.wallet.account.style :as style]
|
||||||
[status-im2.contexts.wallet.account.tabs.view :as tabs]
|
[status-im2.contexts.wallet.account.tabs.view :as tabs]
|
||||||
[status-im2.contexts.wallet.common.temp :as temp]
|
[status-im2.contexts.wallet.common.temp :as temp]
|
||||||
|
[status-im2.contexts.wallet.common.utils :as utils]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
@ -57,14 +57,13 @@
|
||||||
{:id :about :label (i18n/label :t/about) :accessibility-label :about}])
|
{:id :about :label (i18n/label :t/about) :accessibility-label :about}])
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[]
|
[account-address]
|
||||||
(let [top (safe-area/get-top)
|
(let [selected-tab (reagent/atom (:id (first tabs-data)))]
|
||||||
selected-tab (reagent/atom (:id (first tabs-data)))]
|
|
||||||
(fn []
|
(fn []
|
||||||
(let [networks (rf/sub [:wallet/network-details])]
|
(let [account-address (or account-address (rf/sub [:get-screen-params :wallet-accounts]))
|
||||||
[rn/view
|
account (rf/sub [:wallet/account account-address])
|
||||||
{:style {:flex 1
|
networks (rf/sub [:wallet/network-details])]
|
||||||
:margin-top top}}
|
[rn/view {:style style/container}
|
||||||
[quo/page-nav
|
[quo/page-nav
|
||||||
{:type :wallet-networks
|
{:type :wallet-networks
|
||||||
:background :blur
|
:background :blur
|
||||||
|
@ -79,7 +78,11 @@
|
||||||
:gradient-cover? true
|
:gradient-cover? true
|
||||||
:customization-color :purple}])
|
:customization-color :purple}])
|
||||||
:emoji "🍑"}}]
|
:emoji "🍑"}}]
|
||||||
[quo/account-overview temp/account-overview-state]
|
[quo/account-overview
|
||||||
|
{:current-value (utils/prettify-balance (:balance account))
|
||||||
|
:account-name (:name account)
|
||||||
|
:account :default
|
||||||
|
:customization-color :blue}]
|
||||||
[quo/wallet-graph {:time-frame :empty}]
|
[quo/wallet-graph {:time-frame :empty}]
|
||||||
[quo/wallet-ctas
|
[quo/wallet-ctas
|
||||||
{:send-action #(rf/dispatch [:open-modal :wallet-select-address])
|
{:send-action #(rf/dispatch [:open-modal :wallet-select-address])
|
||||||
|
|
|
@ -6,6 +6,21 @@
|
||||||
[full-name]
|
[full-name]
|
||||||
(first (string/split full-name #" ")))
|
(first (string/split full-name #" ")))
|
||||||
|
|
||||||
|
(defn get-balance-by-address
|
||||||
|
[balances address]
|
||||||
|
(->> balances
|
||||||
|
(filter #(= (:address %) address))
|
||||||
|
first
|
||||||
|
:balance))
|
||||||
|
|
||||||
|
(defn get-account-by-address
|
||||||
|
[accounts address]
|
||||||
|
(some #(when (= (:address %) address) %) accounts))
|
||||||
|
|
||||||
|
(defn prettify-balance
|
||||||
|
[balance]
|
||||||
|
(str "$" (.toFixed (if (number? balance) balance 0) 2)))
|
||||||
|
|
||||||
(defn get-derivation-path
|
(defn get-derivation-path
|
||||||
[number-of-accounts]
|
[number-of-accounts]
|
||||||
(str constants/path-wallet-root "/" number-of-accounts))
|
(str constants/path-wallet-root "/" number-of-accounts))
|
||||||
|
|
|
@ -6,6 +6,26 @@
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[utils.security.core :as security]))
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
|
(rf/defn get-wallet-token
|
||||||
|
{:events [:wallet/get-wallet-token]}
|
||||||
|
[{:keys [db]}]
|
||||||
|
(let [params (map :address (:profile/wallet-accounts db))]
|
||||||
|
{:json-rpc/call [{:method "wallet_getWalletToken"
|
||||||
|
:params [params]
|
||||||
|
:on-success #(rf/dispatch [:wallet/get-wallet-token-success %])
|
||||||
|
:on-error (fn [error]
|
||||||
|
(log/info "failed to get wallet token"
|
||||||
|
{:event :wallet/get-wallet-token
|
||||||
|
:error error
|
||||||
|
:params params}))}]}))
|
||||||
|
|
||||||
|
(rf/defn get-wallet-token-success
|
||||||
|
{:events [:wallet/get-wallet-token-success]}
|
||||||
|
[{:keys [db]} data]
|
||||||
|
{:db (assoc db
|
||||||
|
:wallet/tokens data
|
||||||
|
:wallet/tokens-loading? false)})
|
||||||
|
|
||||||
(rf/defn scan-address-success
|
(rf/defn scan-address-success
|
||||||
{:events [:wallet/scan-address-success]}
|
{:events [:wallet/scan-address-success]}
|
||||||
[{:keys [db]} address]
|
[{:keys [db]} address]
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
[status-im2.contexts.wallet.common.activity-tab.view :as activity]
|
[status-im2.contexts.wallet.common.activity-tab.view :as activity]
|
||||||
[status-im2.contexts.wallet.common.collectibles-tab.view :as collectibles]
|
[status-im2.contexts.wallet.common.collectibles-tab.view :as collectibles]
|
||||||
[status-im2.contexts.wallet.common.temp :as temp]
|
[status-im2.contexts.wallet.common.temp :as temp]
|
||||||
[status-im2.contexts.wallet.common.token-value.view :as token-value]
|
[status-im2.contexts.wallet.common.utils :as utils]
|
||||||
[status-im2.contexts.wallet.home.style :as style]
|
[status-im2.contexts.wallet.home.style :as style]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
@ -28,30 +28,43 @@
|
||||||
:on-press #(rf/dispatch [:navigate-to :wallet-address-watch])
|
:on-press #(rf/dispatch [:navigate-to :wallet-address-watch])
|
||||||
:add-divider? true}]]])
|
:add-divider? true}]]])
|
||||||
|
|
||||||
(def account-cards
|
(defn- add-account-placeholder
|
||||||
[{:name "Account 1"
|
[color]
|
||||||
:balance "€0.00"
|
{:customization-color color
|
||||||
:percentage-value "€0.00"
|
:on-press #(rf/dispatch [:show-bottom-sheet {:content new-account}])
|
||||||
:customization-color :blue
|
:type :add-account})
|
||||||
:type :empty
|
|
||||||
:emoji "🍑"
|
|
||||||
:on-press #(rf/dispatch [:navigate-to :wallet-accounts])}
|
|
||||||
{:customization-color :blue
|
|
||||||
:on-press #(rf/dispatch
|
|
||||||
[:show-bottom-sheet {:content new-account}])
|
|
||||||
:type :add-account}])
|
|
||||||
|
|
||||||
(def tabs-data
|
(def tabs-data
|
||||||
[{:id :assets :label (i18n/label :t/assets) :accessibility-label :assets-tab}
|
[{:id :assets :label (i18n/label :t/assets) :accessibility-label :assets-tab}
|
||||||
{:id :collectibles :label (i18n/label :t/collectibles) :accessibility-label :collectibles-tab}
|
{:id :collectibles :label (i18n/label :t/collectibles) :accessibility-label :collectibles-tab}
|
||||||
{:id :activity :label (i18n/label :t/activity) :accessibility-label :activity-tab}])
|
{:id :activity :label (i18n/label :t/activity) :accessibility-label :activity-tab}])
|
||||||
|
|
||||||
|
(defn account-cards
|
||||||
|
[{:keys [accounts loading? balances profile]}]
|
||||||
|
(let [accounts-with-balances
|
||||||
|
(mapv
|
||||||
|
(fn [account]
|
||||||
|
(assoc account
|
||||||
|
:type :empty
|
||||||
|
:customization-color (:customization-color profile)
|
||||||
|
:on-press #(rf/dispatch [:navigate-to :wallet-accounts (:address account)])
|
||||||
|
:loading? loading?
|
||||||
|
:balance (utils/prettify-balance
|
||||||
|
(utils/get-balance-by-address balances (:address account)))))
|
||||||
|
accounts)]
|
||||||
|
(conj accounts-with-balances (add-account-placeholder (:customization-color profile)))))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[]
|
[]
|
||||||
(let [top (safe-area/get-top)
|
(rf/dispatch [:wallet/get-wallet-token])
|
||||||
selected-tab (reagent/atom (:id (first tabs-data)))]
|
|
||||||
(fn []
|
(fn []
|
||||||
(let [networks (rf/sub [:wallet/network-details])]
|
(let [accounts (rf/sub [:profile/wallet-accounts])
|
||||||
|
top (safe-area/get-top)
|
||||||
|
selected-tab (reagent/atom (:id (first tabs-data)))
|
||||||
|
loading? (rf/sub [:wallet/tokens-loading?])
|
||||||
|
balances (rf/sub [:wallet/balances])
|
||||||
|
profile (rf/sub [:profile/profile])
|
||||||
|
networks (rf/sub [:wallet/network-details])]
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style {:margin-top top
|
{:style {:margin-top top
|
||||||
:flex 1}}
|
:flex 1}}
|
||||||
|
@ -59,16 +72,17 @@
|
||||||
[rn/view {:style style/overview-container}
|
[rn/view {:style style/overview-container}
|
||||||
[quo/wallet-overview (temp/wallet-overview-state networks)]]
|
[quo/wallet-overview (temp/wallet-overview-state networks)]]
|
||||||
[rn/pressable
|
[rn/pressable
|
||||||
{:on-long-press #(rf/dispatch [:show-bottom-sheet
|
{:on-long-press #(rf/dispatch [:show-bottom-sheet {:content temp/wallet-temporary-navigation}])}
|
||||||
{:content temp/wallet-temporary-navigation}])}
|
|
||||||
[quo/wallet-graph {:time-frame :empty}]]
|
[quo/wallet-graph {:time-frame :empty}]]
|
||||||
[rn/view {:style style/accounts-container}
|
|
||||||
[rn/flat-list
|
[rn/flat-list
|
||||||
{:style style/accounts-list
|
{:style style/accounts-list
|
||||||
:data account-cards
|
:data (account-cards {:accounts accounts
|
||||||
|
:loading? loading?
|
||||||
|
:balances balances
|
||||||
|
:profile profile})
|
||||||
:horizontal true
|
:horizontal true
|
||||||
:separator [rn/view {:style {:width 12}}]
|
:separator [rn/view {:style {:width 12}}]
|
||||||
:render-fn quo/account-card}]]
|
:render-fn quo/account-card}]
|
||||||
[quo/tabs
|
[quo/tabs
|
||||||
{:style style/tabs
|
{:style style/tabs
|
||||||
:size 32
|
:size 32
|
||||||
|
@ -77,9 +91,9 @@
|
||||||
:on-change #(reset! selected-tab %)}]
|
:on-change #(reset! selected-tab %)}]
|
||||||
(case @selected-tab
|
(case @selected-tab
|
||||||
:assets [rn/flat-list
|
:assets [rn/flat-list
|
||||||
{:render-fn token-value/view
|
{:render-fn quo/token-value
|
||||||
:data temp/tokens
|
:data temp/tokens
|
||||||
:key :assets-list
|
:key :assets-list
|
||||||
:content-container-style {:padding-horizontal 8}}]
|
:content-container-style {:padding-horizontal 8}}]
|
||||||
:collectibles [collectibles/view]
|
:collectibles [collectibles/view]
|
||||||
[activity/view])]))))
|
[activity/view])])))
|
||||||
|
|
|
@ -243,6 +243,7 @@
|
||||||
:component emoji-picker/view}
|
:component emoji-picker/view}
|
||||||
|
|
||||||
{:name :wallet-accounts
|
{:name :wallet-accounts
|
||||||
|
:options {:insets {:top? true}}
|
||||||
:component wallet-accounts/view}
|
:component wallet-accounts/view}
|
||||||
|
|
||||||
{:name :wallet-edit-account
|
{:name :wallet-edit-account
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
status-im2.subs.pairing
|
status-im2.subs.pairing
|
||||||
status-im2.subs.profile
|
status-im2.subs.profile
|
||||||
status-im2.subs.shell
|
status-im2.subs.shell
|
||||||
status-im2.subs.wallet.networks))
|
status-im2.subs.wallet.networks
|
||||||
|
status-im2.subs.wallet.wallet))
|
||||||
|
|
||||||
(defn reg-root-key-sub
|
(defn reg-root-key-sub
|
||||||
[sub-name db-key]
|
[sub-name db-key]
|
||||||
|
@ -142,6 +143,10 @@
|
||||||
(reg-root-key-sub :communities/selected-tab :communities/selected-tab)
|
(reg-root-key-sub :communities/selected-tab :communities/selected-tab)
|
||||||
(reg-root-key-sub :contract-communities :contract-communities)
|
(reg-root-key-sub :contract-communities :contract-communities)
|
||||||
|
|
||||||
|
;;wallet
|
||||||
|
(reg-root-key-sub :wallet/tokens :wallet/tokens)
|
||||||
|
(reg-root-key-sub :wallet/tokens-loading? :wallet/tokens-loading?)
|
||||||
|
|
||||||
;;activity center
|
;;activity center
|
||||||
(reg-root-key-sub :activity-center :activity-center)
|
(reg-root-key-sub :activity-center :activity-center)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
(ns status-im2.subs.wallet.wallet
|
||||||
|
(:require [clojure.string :as string]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im2.contexts.wallet.common.utils :as utils]
|
||||||
|
[utils.number]))
|
||||||
|
|
||||||
|
(defn- calculate-raw-balance
|
||||||
|
[raw-balance decimals]
|
||||||
|
(if-let [n (utils.number/parse-int raw-balance nil)]
|
||||||
|
(/ n (Math/pow 10 (utils.number/parse-int decimals)))
|
||||||
|
0))
|
||||||
|
|
||||||
|
(defn- total-per-token
|
||||||
|
[item]
|
||||||
|
(reduce (fn [ac balances]
|
||||||
|
(+ (calculate-raw-balance (:rawBalance balances)
|
||||||
|
(:decimals item))
|
||||||
|
ac))
|
||||||
|
0
|
||||||
|
(vals (:balancesPerChain item))))
|
||||||
|
|
||||||
|
(defn- calculate-balance
|
||||||
|
[address tokens]
|
||||||
|
(let [token (get tokens (keyword (string/lower-case address)))
|
||||||
|
result (reduce
|
||||||
|
(fn [acc item]
|
||||||
|
(let [total-values (* (total-per-token item)
|
||||||
|
(get-in item [:marketValuesPerCurrency :USD :price]))]
|
||||||
|
(+ acc total-values)))
|
||||||
|
0
|
||||||
|
token)]
|
||||||
|
result))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
:wallet/balances
|
||||||
|
:<- [:profile/wallet-accounts]
|
||||||
|
:<- [:wallet/tokens]
|
||||||
|
(fn [[accounts tokens]]
|
||||||
|
(for [{:keys [address]} accounts]
|
||||||
|
{:address address
|
||||||
|
:balance (calculate-balance address tokens)})))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
:wallet/account
|
||||||
|
:<- [:profile/wallet-accounts]
|
||||||
|
:<- [:wallet/balances]
|
||||||
|
(fn [[accounts balances] [_ account-address]]
|
||||||
|
(assoc
|
||||||
|
(utils/get-account-by-address accounts account-address)
|
||||||
|
:balance
|
||||||
|
(utils/get-balance-by-address balances account-address))))
|
|
@ -0,0 +1,83 @@
|
||||||
|
(ns status-im2.subs.wallet.wallet-test
|
||||||
|
(:require [cljs.test :refer [is testing]]
|
||||||
|
[re-frame.db :as rf-db]
|
||||||
|
status-im2.subs.root
|
||||||
|
[test-helpers.unit :as h]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(def tokens
|
||||||
|
{:0x1 [{:decimals 1
|
||||||
|
:symbol "ETH"
|
||||||
|
:name "Ether"
|
||||||
|
:balancesPerChain {:1 {:rawBalance "20"
|
||||||
|
:hasError false}
|
||||||
|
:2 {:rawBalance "10"
|
||||||
|
:hasError false}}
|
||||||
|
:marketValuesPerCurrency {:USD {:price 1000}}} ;; total should be 3000
|
||||||
|
{:decimals 2
|
||||||
|
:symbol "DAI"
|
||||||
|
:name "Dai Stablecoin"
|
||||||
|
:balancesPerChain {:1 {:rawBalance "100"
|
||||||
|
:hasError false}
|
||||||
|
:2 {:rawBalance "150"
|
||||||
|
:hasError false}}
|
||||||
|
:marketValuesPerCurrency {:USD {:price 100}}}] ;; total should be 250
|
||||||
|
:0x2 [{:decimals 3
|
||||||
|
:symbol "ETH"
|
||||||
|
:name "Ether"
|
||||||
|
:balancesPerChain {:1 {:rawBalance "2500"
|
||||||
|
:hasError false}
|
||||||
|
:2 {:rawBalance "3000"
|
||||||
|
:hasError false}
|
||||||
|
:3 {:rawBalance "<nil>"
|
||||||
|
:hasError false}}
|
||||||
|
:marketValuesPerCurrency {:USD {:price 200}}} ;; total should be 1100
|
||||||
|
{:decimals 10
|
||||||
|
:symbol "DAI"
|
||||||
|
:name "Dai Stablecoin"
|
||||||
|
:balancesPerChain {:1 {:rawBalance "10000000000"
|
||||||
|
:hasError false}
|
||||||
|
:2 {:rawBalance "0"
|
||||||
|
:hasError false}
|
||||||
|
:3 {:rawBalance "<nil>"
|
||||||
|
:hasError false}}
|
||||||
|
:marketValuesPerCurrency {:USD {:price 1000}}}]}) ;; total should be 1000
|
||||||
|
|
||||||
|
(def accounts
|
||||||
|
[{:address "0x1"
|
||||||
|
:name "Main account"
|
||||||
|
:hidden false
|
||||||
|
:removed false}
|
||||||
|
{:address "0x2"
|
||||||
|
:name "Secondary account"
|
||||||
|
:hidden false
|
||||||
|
:removed false}])
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/balances
|
||||||
|
[sub-name]
|
||||||
|
(testing "returns vector of maps containing :address and :balance"
|
||||||
|
(swap! rf-db/app-db assoc
|
||||||
|
:profile/wallet-accounts accounts
|
||||||
|
:wallet/tokens tokens)
|
||||||
|
(is (= [{:address "0x1"
|
||||||
|
:balance 3250}
|
||||||
|
{:address "0x2"
|
||||||
|
:balance 2100}]
|
||||||
|
(rf/sub [sub-name])))))
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/account
|
||||||
|
[sub-name]
|
||||||
|
(testing "returns current account with balance base on the account-address"
|
||||||
|
(swap! rf-db/app-db assoc
|
||||||
|
:profile/wallet-accounts accounts
|
||||||
|
:wallet/tokens tokens
|
||||||
|
:wallet/balances [{:address "0x1"
|
||||||
|
:balance 3250}
|
||||||
|
{:address "0x2"
|
||||||
|
:balance 2100}])
|
||||||
|
(is (= {:address "0x1"
|
||||||
|
:name "Main account"
|
||||||
|
:hidden false
|
||||||
|
:removed false
|
||||||
|
:balance 3250}
|
||||||
|
(rf/sub [sub-name "0x1"])))))
|
Loading…
Reference in New Issue