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
|
||||
:chats/loading? true
|
||||
:networks/current-network current-network
|
||||
:wallet/tokens-loading? true
|
||||
:networks/networks (merge networks config/default-networks-by-id)
|
||||
:profile/profile (merge profile settings))}
|
||||
(notifications/load-preferences)
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
(ns status-im2.contexts.wallet.account.style)
|
||||
|
||||
(def container
|
||||
{:flex 1})
|
||||
|
||||
(def tabs
|
||||
{:padding-left 20
|
||||
:padding-vertical 12})
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.wallet.account.style :as style]
|
||||
[status-im2.contexts.wallet.account.tabs.view :as tabs]
|
||||
[status-im2.contexts.wallet.common.temp :as temp]
|
||||
[status-im2.contexts.wallet.common.utils :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -57,14 +57,13 @@
|
|||
{:id :about :label (i18n/label :t/about) :accessibility-label :about}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [top (safe-area/get-top)
|
||||
selected-tab (reagent/atom (:id (first tabs-data)))]
|
||||
[account-address]
|
||||
(let [selected-tab (reagent/atom (:id (first tabs-data)))]
|
||||
(fn []
|
||||
(let [networks (rf/sub [:wallet/network-details])]
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:margin-top top}}
|
||||
(let [account-address (or account-address (rf/sub [:get-screen-params :wallet-accounts]))
|
||||
account (rf/sub [:wallet/account account-address])
|
||||
networks (rf/sub [:wallet/network-details])]
|
||||
[rn/view {:style style/container}
|
||||
[quo/page-nav
|
||||
{:type :wallet-networks
|
||||
:background :blur
|
||||
|
@ -79,7 +78,11 @@
|
|||
:gradient-cover? true
|
||||
:customization-color :purple}])
|
||||
: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-ctas
|
||||
{:send-action #(rf/dispatch [:open-modal :wallet-select-address])
|
||||
|
|
|
@ -6,6 +6,21 @@
|
|||
[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
|
||||
[number-of-accounts]
|
||||
(str constants/path-wallet-root "/" number-of-accounts))
|
||||
|
|
|
@ -6,6 +6,26 @@
|
|||
[utils.re-frame :as rf]
|
||||
[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
|
||||
{:events [:wallet/scan-address-success]}
|
||||
[{:keys [db]} address]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
[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.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]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
@ -28,58 +28,72 @@
|
|||
:on-press #(rf/dispatch [:navigate-to :wallet-address-watch])
|
||||
:add-divider? true}]]])
|
||||
|
||||
(def account-cards
|
||||
[{:name "Account 1"
|
||||
:balance "€0.00"
|
||||
:percentage-value "€0.00"
|
||||
:customization-color :blue
|
||||
: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}])
|
||||
(defn- add-account-placeholder
|
||||
[color]
|
||||
{:customization-color color
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet {:content new-account}])
|
||||
:type :add-account})
|
||||
|
||||
(def tabs-data
|
||||
[{:id :assets :label (i18n/label :t/assets) :accessibility-label :assets-tab}
|
||||
{:id :collectibles :label (i18n/label :t/collectibles) :accessibility-label :collectibles-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
|
||||
[]
|
||||
(let [top (safe-area/get-top)
|
||||
selected-tab (reagent/atom (:id (first tabs-data)))]
|
||||
(fn []
|
||||
(let [networks (rf/sub [:wallet/network-details])]
|
||||
[rn/view
|
||||
{:style {:margin-top top
|
||||
:flex 1}}
|
||||
[common.top-nav/view]
|
||||
[rn/view {:style style/overview-container}
|
||||
[quo/wallet-overview (temp/wallet-overview-state networks)]]
|
||||
[rn/pressable
|
||||
{:on-long-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content temp/wallet-temporary-navigation}])}
|
||||
[quo/wallet-graph {:time-frame :empty}]]
|
||||
[rn/view {:style style/accounts-container}
|
||||
[rn/flat-list
|
||||
{:style style/accounts-list
|
||||
:data account-cards
|
||||
:horizontal true
|
||||
:separator [rn/view {:style {:width 12}}]
|
||||
:render-fn quo/account-card}]]
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
:default-active @selected-tab
|
||||
:data tabs-data
|
||||
:on-change #(reset! selected-tab %)}]
|
||||
(case @selected-tab
|
||||
:assets [rn/flat-list
|
||||
{:render-fn token-value/view
|
||||
:data temp/tokens
|
||||
:key :assets-list
|
||||
:content-container-style {:padding-horizontal 8}}]
|
||||
:collectibles [collectibles/view]
|
||||
[activity/view])]))))
|
||||
(rf/dispatch [:wallet/get-wallet-token])
|
||||
(fn []
|
||||
(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
|
||||
{:style {:margin-top top
|
||||
:flex 1}}
|
||||
[common.top-nav/view]
|
||||
[rn/view {:style style/overview-container}
|
||||
[quo/wallet-overview (temp/wallet-overview-state networks)]]
|
||||
[rn/pressable
|
||||
{:on-long-press #(rf/dispatch [:show-bottom-sheet {:content temp/wallet-temporary-navigation}])}
|
||||
[quo/wallet-graph {:time-frame :empty}]]
|
||||
[rn/flat-list
|
||||
{:style style/accounts-list
|
||||
:data (account-cards {:accounts accounts
|
||||
:loading? loading?
|
||||
:balances balances
|
||||
:profile profile})
|
||||
:horizontal true
|
||||
:separator [rn/view {:style {:width 12}}]
|
||||
:render-fn quo/account-card}]
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
:default-active @selected-tab
|
||||
:data tabs-data
|
||||
:on-change #(reset! selected-tab %)}]
|
||||
(case @selected-tab
|
||||
:assets [rn/flat-list
|
||||
{:render-fn quo/token-value
|
||||
:data temp/tokens
|
||||
:key :assets-list
|
||||
:content-container-style {:padding-horizontal 8}}]
|
||||
:collectibles [collectibles/view]
|
||||
[activity/view])])))
|
||||
|
|
|
@ -243,6 +243,7 @@
|
|||
:component emoji-picker/view}
|
||||
|
||||
{:name :wallet-accounts
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-accounts/view}
|
||||
|
||||
{:name :wallet-edit-account
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
status-im2.subs.pairing
|
||||
status-im2.subs.profile
|
||||
status-im2.subs.shell
|
||||
status-im2.subs.wallet.networks))
|
||||
status-im2.subs.wallet.networks
|
||||
status-im2.subs.wallet.wallet))
|
||||
|
||||
(defn reg-root-key-sub
|
||||
[sub-name db-key]
|
||||
|
@ -142,6 +143,10 @@
|
|||
(reg-root-key-sub :communities/selected-tab :communities/selected-tab)
|
||||
(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
|
||||
(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