[refactor] transaction history and filters

This commit is contained in:
yenda 2019-05-17 12:02:16 +02:00
parent f1b8ba8764
commit 2cd26c585d
No known key found for this signature in database
GPG Key ID: 0095623C0069DCE6
14 changed files with 327 additions and 313 deletions

View File

@ -1,30 +1,34 @@
(ns status-im.chat.commands.impl.transactions (ns status-im.chat.commands.impl.transactions
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [clojure.string :as string] (:require [clojure.string :as string]
[reagent.core :as reagent]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.chat.commands.impl.transactions.styles
:as
transactions-styles]
[status-im.chat.commands.protocol :as protocol] [status-im.chat.commands.protocol :as protocol]
[status-im.chat.commands.impl.transactions.styles :as transactions-styles]
[status-im.data-store.messages :as messages-store]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.animation :as animation]
[status-im.ui.components.svgimage :as svgimage]
[status-im.i18n :as i18n]
[status-im.contact.db :as db.contact] [status-im.contact.db :as db.contact]
[status-im.data-store.messages :as messages-store]
[status-im.i18n :as i18n]
[status-im.ui.components.animation :as animation]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.svgimage :as svgimage]
[status-im.ui.screens.navigation :as navigation]
[status-im.ui.screens.wallet.choose-recipient.events
:as
choose-recipient.events]
[status-im.ui.screens.wallet.utils :as wallet.utils]
[status-im.utils.datetime :as datetime]
[status-im.utils.ethereum.core :as ethereum] [status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.tokens :as tokens] [status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.datetime :as datetime]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[status-im.utils.money :as money] [status-im.utils.money :as money]
[status-im.utils.platform :as platform] [status-im.utils.platform :as platform]
[status-im.ui.screens.wallet.db :as wallet.db] [status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.screens.wallet.choose-recipient.events :as choose-recipient.events] [status-im.wallet.db :as wallet.db])
[status-im.ui.screens.navigation :as navigation] (:require-macros [status-im.utils.views :refer [defview letsubs]]))
[status-im.ui.screens.wallet.utils :as wallet.utils]
[status-im.ui.components.chat-icon.screen :as chat-icon]))
;; common `send/request` functionality ;; common `send/request` functionality
@ -179,19 +183,22 @@
;; `/send` command ;; `/send` command
(defview send-status [tx-hash outgoing] (defview send-status [tx-hash outgoing]
(letsubs [confirmed? [:chats/transaction-confirmed? tx-hash] (letsubs [{:keys [exists? confirmed?]} [:chats/transaction-status tx-hash]]
tx-exists? [:chats/wallet-transaction-exists? tx-hash]] [react/touchable-highlight {:on-press #(when exists?
[react/touchable-highlight {:on-press #(when tx-exists?
(re-frame/dispatch [:show-transaction-details tx-hash]))} (re-frame/dispatch [:show-transaction-details tx-hash]))}
[react/view transactions-styles/command-send-status-container [react/view transactions-styles/command-send-status-container
[vector-icons/icon (if confirmed? :tiny-icons/tiny-check :tiny-icons/tiny-pending) [vector-icons/icon (if confirmed?
{:color (if outgoing colors/blue-light colors/blue) :tiny-icons/tiny-check
:tiny-icons/tiny-pending)
{:color (if outgoing
colors/blue-light
colors/blue)
:container-style (transactions-styles/command-send-status-icon outgoing)}] :container-style (transactions-styles/command-send-status-icon outgoing)}]
[react/view [react/view
[react/text {:style (transactions-styles/command-send-status-text outgoing)} [react/text {:style (transactions-styles/command-send-status-text outgoing)}
(i18n/label (cond (i18n/label (cond
confirmed? :status-confirmed confirmed? :status-confirmed
tx-exists? :status-pending exists? :status-pending
:else :status-tx-not-found))]]]])) :else :status-tx-not-found))]]]]))
(defn transaction-status [{:keys [tx-hash outgoing]}] (defn transaction-status [{:keys [tx-hash outgoing]}]

View File

@ -30,13 +30,6 @@
(def system "system") (def system "system")
(def default-wallet-transactions
{:filters
{:type [{:id :inbound :label (i18n/label :t/incoming) :checked? true}
{:id :outbound :label (i18n/label :t/outgoing) :checked? true}
{:id :pending :label (i18n/label :t/pending) :checked? true}
{:id :failed :label (i18n/label :t/failed) :checked? true}]}})
(def mainnet-networks (def mainnet-networks
{"mainnet" {:id "mainnet", {"mainnet" {:id "mainnet",
:name "Mainnet", :name "Mainnet",

View File

@ -57,6 +57,7 @@
[status-im.utils.handlers :as handlers] [status-im.utils.handlers :as handlers]
[status-im.utils.logging.core :as logging] [status-im.utils.logging.core :as logging]
[status-im.utils.utils :as utils] [status-im.utils.utils :as utils]
[status-im.wallet.db :as wallet.db]
[status-im.web3.core :as web3] [status-im.web3.core :as web3]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[status-im.wallet.custom-tokens.core :as custom-tokens])) [status-im.wallet.custom-tokens.core :as custom-tokens]))
@ -2144,3 +2145,20 @@
:ethereum.transactions/new :ethereum.transactions/new
(fn [cofx [_ transaction]] (fn [cofx [_ transaction]]
(ethereum.transactions/new cofx transaction))) (ethereum.transactions/new cofx transaction)))
;; wallet events
(handlers/register-handler-fx
:wallet.transactions/add-filter
(fn [{:keys [db]} [_ id]]
{:db (update-in db [:wallet :filters] conj id)}))
(handlers/register-handler-fx
:wallet.transactions/remove-filter
(fn [{:keys [db]} [_ id]]
{:db (update-in db [:wallet :filters] disj id)}))
(handlers/register-handler-fx
:wallet.transactions/add-all-filters
(fn [{:keys [db]} _]
{:db (assoc-in db [:wallet :filters]
wallet.db/default-wallet-filters)}))

View File

@ -39,7 +39,8 @@
status-im.ui.screens.hardwallet.connect.subs status-im.ui.screens.hardwallet.connect.subs
status-im.ui.screens.hardwallet.settings.subs status-im.ui.screens.hardwallet.settings.subs
status-im.ui.screens.hardwallet.pin.subs status-im.ui.screens.hardwallet.pin.subs
status-im.ui.screens.hardwallet.setup.subs)) status-im.ui.screens.hardwallet.setup.subs
[status-im.wallet.db :as wallet.db]))
;; TOP LEVEL =========================================================================================================== ;; TOP LEVEL ===========================================================================================================
@ -690,18 +691,16 @@
(filter-contacts selected-contacts active-contacts))) (filter-contacts selected-contacts active-contacts)))
(re-frame/reg-sub (re-frame/reg-sub
:chats/transaction-confirmed? :chats/transaction-status
:<- [:wallet-transactions] :<- [:wallet/transactions]
(fn [txs [_ tx-hash]] :<- [:ethereum/current-block]
(-> (get-in txs [tx-hash :confirmations] "0") (fn [[transactions current-block] [_ hash]]
(js/parseInt) (when-let [transaction (get transactions hash)]
(>= transactions/confirmations-count-threshold)))) {:exists? true
:confirmed?
(re-frame/reg-sub (-> transaction
:chats/wallet-transaction-exists? (wallet.db/get-confirmations current-block)
:<- [:wallet-transactions] (>= transactions/confirmations-count-threshold))})))
(fn [txs [_ tx-hash]]
(not (nil? (get txs tx-hash)))))
;;BOOTNODES ============================================================================================================ ;;BOOTNODES ============================================================================================================
@ -1026,87 +1025,133 @@
;;WALLET TRANSACTIONS ================================================================================================== ;;WALLET TRANSACTIONS ==================================================================================================
(re-frame/reg-sub (re-frame/reg-sub
:wallet-transactions :wallet/transactions
:<- [:wallet] :<- [:wallet]
(fn [wallet] (fn [wallet]
(get wallet :transactions))) (get wallet :transactions)))
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions/filters :wallet/filters
:<- [:wallet.transactions] :<- [:wallet]
(fn [txs] (fn [wallet]
(get txs :filters))) (get wallet :filters)))
(defn enrich-transaction (defn enrich-transaction
[{:keys [type to from timestamp] :as transaction} contacts] [{:keys [type to from value token] :as transaction}
(let [[contact-address key-contact key-wallet] (if (= type :inbound) contacts native-currency]
[from :from-contact :to-wallet] (let [[contact-address key-contact key-wallet]
[to :to-contact :from-wallet]) (if (= type :inbound)
[from :from-contact :to-wallet]
[to :to-contact :from-wallet])
wallet (i18n/label :main-wallet) wallet (i18n/label :main-wallet)
contact (get contacts (utils.hex/normalize-hex contact-address))] contact (get contacts contact-address)
{:keys [symbol-display symbol decimals] :as asset}
(or token native-currency)
amount-text (if value
(wallet.utils/format-amount value decimals)
"...")
currency-text (when asset
(clojure.core/name (or symbol-display symbol)))]
(cond-> transaction (cond-> transaction
contact (assoc key-contact (:name contact)) contact (assoc key-contact (:name contact))
:always (assoc key-wallet wallet :always (assoc key-wallet wallet
:time-formatted (datetime/timestamp->time timestamp))))) :amount-text amount-text
:currency-text currency-text))))
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions/transactions :wallet.transactions/transactions
:<- [:wallet] :<- [:wallet/transactions]
:<- [:contacts/contacts-by-address] :<- [:contacts/contacts-by-address]
(fn [[wallet contacts]] :<- [:ethereum/native-currency]
(reduce (fn [acc [hash transaction]] (fn [[transactions contacts native-currency]]
(assoc acc hash (enrich-transaction transaction contacts))) (reduce-kv (fn [acc hash transaction]
{} (assoc acc
(:transactions wallet)))) hash
(enrich-transaction transaction contacts native-currency)))
{}
transactions)))
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions/grouped-transactions :wallet.transactions/all-filters?
:<- [:wallet.transactions/transactions] :<- [:wallet/filters]
(fn [transactions] (fn [filters]
(group-by :type (vals transactions)))) (= wallet.db/default-wallet-filters
filters)))
(def filters-labels
{:inbound (i18n/label :t/incoming)
:outbound (i18n/label :t/outgoing)
:pending (i18n/label :t/pending)
:failed (i18n/label :t/failed)})
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions/pending-transactions-list :wallet.transactions/filters
:<- [:wallet.transactions/grouped-transactions] :<- [:wallet/filters]
(fn [{:keys [pending]}] (fn [filters]
(when pending (map (fn [id]
{:title "Pending" (let [checked? (filters id)]
:key :pending {:id id
:data pending}))) :label (filters-labels id)
:checked? checked?
:on-touch #(if checked?
(re-frame/dispatch [:wallet.transactions/remove-filter id])
(re-frame/dispatch [:wallet.transactions/add-filter id]))}))
wallet.db/default-wallet-filters)))
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions/failed-transactions-list :wallet.transactions.filters/screen
:<- [:wallet.transactions/grouped-transactions] :<- [:wallet.transactions/filters]
(fn [{:keys [failed]}] :<- [:wallet.transactions/all-filters?]
(when failed (fn [[filters all-filters?]]
{:title "Failed" {:all-filters? all-filters?
:key :failed :filters filters
:data failed}))) :on-touch-select-all (when-not all-filters?
#(re-frame/dispatch
[:wallet.transactions/add-all-filters]))}))
(defn group-transactions-by-date [transactions] (defn- enrich-transaction-for-list
[filters
{:keys [type from-contact from to-contact to hash timestamp] :as transaction}]
(when (filters type)
(assoc (case type
:inbound
(assoc transaction
:label (i18n/label :t/from)
:contact-accessibility-label :sender-text
:address-accessibility-label :sender-address-text
:contact from-contact
:address from)
(assoc transaction
:label (i18n/label :t/to)
:contact-accessibility-label :recipient-name-text
:address-accessibility-label :recipient-address-text
:contact to-contact
:address to))
:time-formatted (datetime/timestamp->time timestamp)
:on-touch-fn #(re-frame/dispatch [:show-transaction-details hash]))))
(defn- group-transactions-by-date
[transactions]
(->> transactions (->> transactions
(group-by #(datetime/timestamp->date-key (:timestamp %))) (group-by #(datetime/timestamp->date-key (:timestamp %)))
(sort-by key) (sort-by key >)
reverse
(map (fn [[date-key transactions]] (map (fn [[date-key transactions]]
{:title (datetime/timestamp->mini-date (:timestamp (first transactions))) {:title (datetime/timestamp->mini-date (:timestamp (first transactions)))
:key date-key :key date-key
:data (sort-by :timestamp > transactions)})))) :data (sort-by :timestamp > transactions)}))))
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions/completed-transactions-list :wallet.transactions.history/screen
:<- [:wallet.transactions/grouped-transactions] :<- [:wallet.transactions/transactions]
(fn [{:keys [inbound outbound failed]}] :<- [:wallet/filters]
(group-transactions-by-date (concat inbound outbound failed)))) :<- [:wallet.transactions/all-filters?]
(fn [[transactions filters all-filters?]]
(re-frame/reg-sub {:all-filters? all-filters?
:wallet.transactions/transactions-history-list :transaction-history-sections
:<- [:wallet.transactions/pending-transactions-list] (->> transactions
:<- [:wallet.transactions/completed-transactions-list] vals
(fn [[pending completed]] (keep #(enrich-transaction-for-list filters %))
(cond-> [] (group-transactions-by-date))}))
pending (into pending)
completed (into completed))))
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions/current-transaction :wallet.transactions/current-transaction
@ -1123,55 +1168,45 @@
(fn [[transactions current-transaction native-currency chain-keyword]] (fn [[transactions current-transaction native-currency chain-keyword]]
(let [{:keys [gas-used gas-price hash timestamp type token value] (let [{:keys [gas-used gas-price hash timestamp type token value]
:as transaction} :as transaction}
(get transactions current-transaction)] (get transactions current-transaction)
native-currency-text (-> native-currency
:symbol-display
name)]
(when transaction (when transaction
(let [{:keys [symbol-display symbol decimals] :as asset} (merge transaction
(or token native-currency) {:gas-price-eth (if gas-price
amount-text (if value (money/wei->str :eth
(wallet.utils/format-amount value decimals) gas-price
"...") native-currency-text)
currency-text (when asset "-")
(clojure.core/name (or symbol-display symbol))) :gas-price-gwei (if gas-price
native-currency-text (-> native-currency (money/wei->str :gwei
:symbol-display gas-price)
name)] "-")
(merge transaction :date (datetime/timestamp->long-date timestamp)}
{:amount-text amount-text (if (= type :unsigned)
:currency-text currency-text {:block (i18n/label :not-applicable)
:gas-price-eth (if gas-price :cost (i18n/label :not-applicable)
(money/wei->str :eth :gas-limit (i18n/label :not-applicable)
gas-price :gas-used (i18n/label :not-applicable)
native-currency-text) :nonce (i18n/label :not-applicable)
"-") :hash (i18n/label :not-applicable)}
:gas-price-gwei (if gas-price {:cost (when gas-used
(money/wei->str :gwei (money/wei->str :eth
gas-price) (money/fee-value gas-used gas-price)
"-") native-currency-text))
:date (datetime/timestamp->long-date timestamp)} :url (transactions.etherscan/get-transaction-details-url
(if (= type :unsigned) chain-keyword
{:block (i18n/label :not-applicable) hash)}))))))
:cost (i18n/label :not-applicable)
:gas-limit (i18n/label :not-applicable)
:gas-used (i18n/label :not-applicable)
:nonce (i18n/label :not-applicable)
:hash (i18n/label :not-applicable)}
{:cost (when gas-used
(money/wei->str :eth
(money/fee-value gas-used gas-price)
native-currency-text))
:url (transactions.etherscan/get-transaction-details-url
chain-keyword
hash)})))))))
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions.details/screen :wallet.transactions.details/screen
:<- [:wallet.transactions.details/current-transaction] :<- [:wallet.transactions.details/current-transaction]
:<- [:ethereum/current-block] :<- [:ethereum/current-block]
(fn [[{:keys [block] :as transaction} current-block]] (fn [[transaction current-block]]
:wallet.transactions.details/current-transaction :wallet.transactions.details/current-transaction
(let [confirmations (if (and current-block block) (let [confirmations (wallet.db/get-confirmations transaction
(inc (- current-block block)) current-block)]
0)]
(assoc transaction (assoc transaction
:confirmations confirmations :confirmations confirmations
:confirmations-progress :confirmations-progress

View File

@ -16,7 +16,8 @@
status-im.browser.db status-im.browser.db
status-im.ui.screens.add-new.db status-im.ui.screens.add-new.db
status-im.ui.screens.add-new.new-public-chat.db status-im.ui.screens.add-new.new-public-chat.db
status-im.ui.components.bottom-sheet.core)) status-im.ui.components.bottom-sheet.core
[status-im.wallet.db :as wallet.db]))
;; initial state of app-db ;; initial state of app-db
(def app-db {:keyboard-height 0 (def app-db {:keyboard-height 0
@ -32,7 +33,7 @@
:selected-participants #{} :selected-participants #{}
:sync-state :done :sync-state :done
:app-state "active" :app-state "active"
:wallet.transactions constants/default-wallet-transactions :wallet wallet.db/default-wallet
:wallet/all-tokens {} :wallet/all-tokens {}
:prices {} :prices {}
:peers-count 0 :peers-count 0
@ -329,7 +330,6 @@
:chat/id->command :chat/id->command
:chat/access-scope->command-id :chat/access-scope->command-id
:wallet/wallet :wallet/wallet
:wallet/wallet.transactions
:prices/prices :prices/prices
:prices/prices-loading? :prices/prices-loading?
:notifications/notifications :notifications/notifications

View File

@ -15,7 +15,6 @@
status-im.ui.screens.wallet.send.events status-im.ui.screens.wallet.send.events
status-im.ui.screens.wallet.request.events status-im.ui.screens.wallet.request.events
status-im.ui.screens.wallet.settings.events status-im.ui.screens.wallet.settings.events
status-im.ui.screens.wallet.transactions.events
status-im.ui.screens.wallet.choose-recipient.events status-im.ui.screens.wallet.choose-recipient.events
status-im.ui.screens.wallet.collectibles.cryptokitties.events status-im.ui.screens.wallet.collectibles.cryptokitties.events
status-im.ui.screens.wallet.collectibles.cryptostrikers.events status-im.ui.screens.wallet.collectibles.cryptostrikers.events

View File

@ -1,12 +1,10 @@
(ns status-im.ui.screens.wallet.request.events (ns status-im.ui.screens.wallet.request.events
(:require [re-frame.core :as re-frame] (:require [status-im.chat.commands.sending :as commands-sending]
[status-im.ui.screens.wallet.db :as wallet-db]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.handlers :as handlers]
[status-im.chat.models :as chat-model] [status-im.chat.models :as chat-model]
[status-im.chat.commands.sending :as commands-sending]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[status-im.utils.money :as money])) [status-im.utils.handlers :as handlers]
[status-im.utils.money :as money]
[status-im.wallet.db :as wallet.db]))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet-send-request :wallet-send-request
@ -23,7 +21,7 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.request/set-and-validate-amount :wallet.request/set-and-validate-amount
(fn [{:keys [db]} [_ amount symbol decimals]] (fn [{:keys [db]} [_ amount symbol decimals]]
(let [{:keys [value error]} (wallet-db/parse-amount amount decimals)] (let [{:keys [value error]} (wallet.db/parse-amount amount decimals)]
{:db (-> db {:db (-> db
(assoc-in [:wallet :request-transaction :amount] (money/formatted->internal value symbol decimals)) (assoc-in [:wallet :request-transaction :amount] (money/formatted->internal value symbol decimals))
(assoc-in [:wallet :request-transaction :amount-text] amount) (assoc-in [:wallet :request-transaction :amount-text] amount)

View File

@ -7,7 +7,7 @@
[status-im.native-module.core :as status] [status-im.native-module.core :as status]
[status-im.transport.utils :as transport.utils] [status-im.transport.utils :as transport.utils]
[status-im.ui.screens.navigation :as navigation] [status-im.ui.screens.navigation :as navigation]
[status-im.ui.screens.wallet.db :as wallet.db] [status-im.wallet.db :as wallet.db]
[status-im.utils.ethereum.core :as ethereum] [status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.erc20 :as erc20] [status-im.utils.ethereum.erc20 :as erc20]
[status-im.utils.ethereum.tokens :as tokens] [status-im.utils.ethereum.tokens :as tokens]

View File

@ -1,31 +0,0 @@
(ns status-im.ui.screens.wallet.transactions.events
(:require [status-im.utils.handlers :as handlers]))
(defn- mark-all-checked [filters]
(update filters
:type
#(map (fn [m]
(assoc m :checked? true))
%)))
(defn- mark-checked [filters {:keys [type]} checked?]
(update filters
:type
#(map (fn [{:keys [id] :as m}]
(if (= type id)
(assoc m :checked? checked?)
m))
%)))
(defn- update-filters [db f]
(update-in db [:wallet.transactions :filters] f))
(handlers/register-handler-fx
:wallet.transactions/filter
(fn [{:keys [db]} [_ path checked?]]
{:db (update-filters db #(mark-checked % path checked?))}))
(handlers/register-handler-fx
:wallet.transactions/filter-all
(fn [{:keys [db]} _]
{:db (update-filters db mark-all-checked)}))

View File

@ -15,154 +15,149 @@
[status-im.utils.money :as money]) [status-im.utils.money :as money])
(:require-macros [status-im.utils.views :refer [defview letsubs]])) (:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn history-action [filter?] ;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TRANSACTION HISTORY
;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn history-action
[all-filters?]
(cond-> (cond->
{:icon :main-icons/filter {:icon :main-icons/filter
:icon-opts {:accessibility-label :filters-button} :icon-opts {:accessibility-label :filters-button}
:handler #(re-frame/dispatch [:navigate-to :wallet-transactions-filter])} :handler #(re-frame/dispatch [:navigate-to :wallet-transactions-filter])}
filter? (assoc-in [:icon-opts :overlay-style] styles/corner-dot))) (not all-filters?) (assoc-in [:icon-opts :overlay-style] styles/corner-dot)))
(defn- all-checked? [filter-data] (defn- toolbar-view
(and (every? :checked? (:type filter-data)) [all-filters?]
(every? :checked? (:tokens filter-data))))
(defn- toolbar-view [filter-data]
[toolbar/toolbar nil [toolbar/toolbar nil
toolbar/default-nav-back toolbar/default-nav-back
[toolbar/content-title (i18n/label :t/transactions-history)] [toolbar/content-title (i18n/label :t/transactions-history)]
[toolbar/actions [toolbar/actions
[(history-action (not (all-checked? filter-data)))]]]) [(history-action all-filters?)]]])
(defn- inbound? [type] (= :inbound type)) (defn- transaction-icon
(defn- failed? [type] (= :failed type)) [icon-key background-color color]
{:icon icon-key
(defn- transaction-icon [k background-color color]
{:icon k
:icon-opts {:color color} :icon-opts {:color color}
:style (styles/transaction-icon-background background-color)}) :style (styles/transaction-icon-background background-color)})
(defn- transaction-type->icon [k] (defn- transaction-type->icon
[k]
(case k (case k
:inbound (transaction-icon :main-icons/arrow-left (colors/alpha colors/green 0.2) colors/green) :inbound (transaction-icon :main-icons/arrow-left
:outbound (transaction-icon :main-icons/arrow-right (colors/alpha colors/blue 0.1) colors/blue) (colors/alpha colors/green 0.2)
:failed (transaction-icon :main-icons/warning colors/gray-light colors/red) colors/green)
(:postponed :pending) (transaction-icon :main-icons/arrow-right colors/gray-light colors/gray) :outbound (transaction-icon :main-icons/arrow-right
(colors/alpha colors/blue 0.1)
colors/blue)
:failed (transaction-icon :main-icons/warning
colors/gray-light
colors/red)
:pending (transaction-icon :main-icons/arrow-right
colors/gray-light colors/gray)
(throw (str "Unknown transaction type: " k)))) (throw (str "Unknown transaction type: " k))))
(defn render-transaction (defn render-transaction
[{:keys [hash from-contact to-contact to from type value time-formatted symbol]} [{:keys [label contact address contact-accessibility-label
network all-tokens hide-details?] address-accessibility-label currency-text amount-text
(let [[label contact address contact-accessibility-label time-formatted on-touch-fn type]}]
address-accessibility-label] [list/touchable-item on-touch-fn
(if (inbound? type) [react/view {:accessibility-label :transaction-item}
[(i18n/label :t/from) from-contact from :sender-text :sender-address-text] [list/item
[(i18n/label :t/to) to-contact to :recipient-name-text :recipient-address-text]) (when type
{:keys [decimals] :as token} [list/item-icon (transaction-type->icon (keyword type))])
(tokens/asset-for all-tokens [list/item-content
(ethereum/network->chain-keyword network) [react/view {:style styles/amount-time}
symbol)] [react/nested-text {:style styles/tx-amount
[list/touchable-item #(when-not hide-details? (re-frame/dispatch [:show-transaction-details hash])) :ellipsize-mode "tail"
[react/view {:accessibility-label :transaction-item} :number-of-lines 1}
[list/item [{:accessibility-label :amount-text}
(when type amount-text]
[list/item-icon (transaction-type->icon (keyword type))]) " "
[list/item-content [{:accessibility-label :currency-text}
[react/view {:style styles/amount-time} currency-text]]
[react/nested-text {:style styles/tx-amount [react/text {:style styles/tx-time}
:ellipsize-mode "tail" time-formatted]]
:number-of-lines 1} [react/view {:style styles/address-row}
[{:accessibility-label :amount-text} [react/text {:style styles/address-label}
(-> value (money/internal->formatted symbol decimals) money/to-fixed str)] label]
" " (when contact
[{:accessibility-label :currency-text} [react/text {:style styles/address-contact
(wallet.utils/display-symbol token)]] :accessibility-label contact-accessibility-label}
[react/text {:style styles/tx-time} contact])
time-formatted]] [react/text {:style styles/address-hash
[react/view {:style styles/address-row} :ellipsize-mode "middle"
[react/text {:style styles/address-label} :number-of-lines 1
label] :accessibility-label address-accessibility-label}
(when contact address]]]
[react/text {:style styles/address-contact [list/item-icon {:icon :main-icons/next
:accessibility-label contact-accessibility-label} :style {:margin-top 10}
contact]) :icon-opts (merge styles/forward
[react/text {:style styles/address-hash {:accessibility-label :show-transaction-button})}]]]])
:ellipsize-mode "middle"
:number-of-lines 1
:accessibility-label address-accessibility-label}
address]]]
(when-not hide-details?
[list/item-icon {:icon :main-icons/next
:style {:margin-top 10}
:icon-opts (merge styles/forward
{:accessibility-label :show-transaction-button})}])]]]))
(defn filtered-transaction? [transaction filter-data] (defn history-list
(:checked? (some #(when (= (:type transaction) (:id %)) %) (:type filter-data)))) [transactions-history-sections]
[react/view components.styles/flex
[list/section-list {:sections transactions-history-sections
:key-fn :hash
:render-fn #(render-transaction %)
:empty-component
[react/i18n-text {:style styles/empty-text
:key :transactions-history-empty}]
:refreshing false}]])
(defn update-transactions [m filter-data] (defview transactions
(update m []
:data (letsubs [{:keys [transaction-history-sections all-filters?]}
(fn [v] [:wallet.transactions.history/screen]]
(filter #(filtered-transaction? % filter-data) v)))) [react/view styles/transactions-view
[status-bar/status-bar]
[toolbar-view all-filters?]
[history-list transaction-history-sections]]))
(defview history-list [& [hide-details?]] ;;;;;;;;;;;;;;;;;;;;;;;;;;;
(letsubs [transactions-history-list [:wallet.transactions/transactions-history-list] ;; TRANSACTION FILTERS
filter-data [:wallet.transactions/filters] ;;;;;;;;;;;;;;;;;;;;;;;;;;;
network [:account/network]
all-tokens [:wallet/all-tokens]]
[react/view components.styles/flex
[list/section-list {:sections (map #(update-transactions % filter-data) transactions-history-list)
:key-fn :hash
:render-fn #(render-transaction % network all-tokens hide-details?)
:empty-component [react/i18n-text {:style styles/empty-text
:key :transactions-history-empty}]
:refreshing false}]]))
;; Filter history (defn- render-item-filter [{:keys [id label checked? on-touch]}]
(defn- item-filter [{:keys [icon checked? path]} content]
[react/view {:accessibility-label :filter-item} [react/view {:accessibility-label :filter-item}
[list/list-item-with-checkbox [list/list-item-with-checkbox
{:checked? checked? {:checked? checked?
:on-value-change #(re-frame/dispatch [:wallet.transactions/filter path %])} :on-value-change on-touch}
[list/item [list/item
[list/item-icon icon] [list/item-icon (transaction-type->icon id)]
content]]])
(defn- render-item-filter [{:keys [id label checked?]}]
(when id
[item-filter {:icon (transaction-type->icon id) :checked? checked? :path {:type id}}
[list/item-content [list/item-content
[list/item-primary-only {:accessibility-label :filter-name-text} [list/item-primary-only {:accessibility-label :filter-name-text}
label]]])) label]]]]])
(defn- wrap-filter-data [m]
[{:title (i18n/label :t/transactions-filter-type)
:key :type
:render-fn render-item-filter
:data (:type m)}])
(defview filter-history [] (defview filter-history []
(letsubs [filter-data [:wallet.transactions/filters]] (letsubs [{:keys [filters all-filters? on-touch-select-all]}
[:wallet.transactions.filters/screen]]
[react/view styles/filter-container [react/view styles/filter-container
[status-bar/status-bar {:type :modal-main}] [status-bar/status-bar {:type :modal-main}]
[toolbar/toolbar {} [toolbar/toolbar {}
[toolbar/nav-clear-text {:accessibility-label :done-button} (i18n/label :t/done)] [toolbar/nav-clear-text
[toolbar/content-title (i18n/label :t/transactions-filter-title)] {:accessibility-label :done-button}
[toolbar/text-action {:handler #(re-frame/dispatch [:wallet.transactions/filter-all]) (i18n/label :t/done)]
:disabled? (all-checked? filter-data) [toolbar/content-title
:accessibility-label :select-all-button} (i18n/label :t/transactions-filter-title)]
[toolbar/text-action
{:handler on-touch-select-all
:disabled? all-filters?
:accessibility-label :select-all-button}
(i18n/label :t/transactions-filter-select-all)]] (i18n/label :t/transactions-filter-select-all)]]
[react/view {:style (merge {:background-color :white} components.styles/flex)} [react/view
[list/section-list {:sections (wrap-filter-data filter-data) {:style (merge {:background-color :white} components.styles/flex)}
:key-fn (comp str :id)}]]])) [list/section-list {:sections [{:title
(i18n/label :t/transactions-filter-type)
:key :type
:render-fn render-item-filter
:data filters}]
:key-fn :id}]]]))
(defview transactions [] ;;;;;;;;;;;;;;;;;;;;;;;;;;;
(letsubs [filter-data [:wallet.transactions/filters]] ;; TRANSACTION DETAILS
[react/view styles/transactions-view ;;;;;;;;;;;;;;;;;;;;;;;;;;;
[status-bar/status-bar]
[toolbar-view filter-data]
[history-list]]))
(defn details-header (defn details-header
[date type amount-text currency-text] [date type amount-text currency-text]
@ -183,10 +178,10 @@
[react/view {:style (styles/progress-bar-todo (- 100 progress) failed?)}]]) [react/view {:style (styles/progress-bar-todo (- 100 progress) failed?)}]])
(defn details-confirmations (defn details-confirmations
[confirmations confirmations-progress type] [confirmations confirmations-progress failed?]
[react/view {:style styles/details-block} [react/view {:style styles/details-block}
[progress-bar confirmations-progress (failed? type)] [progress-bar confirmations-progress failed?]
(if (failed? type) (if failed?
[react/i18n-text {:style styles/details-failed [react/i18n-text {:style styles/details-failed
:key :failed}] :key :failed}]
[react/text {:style styles/details-confirmations-count} [react/text {:style styles/details-confirmations-count}
@ -259,6 +254,6 @@
(when transaction [toolbar/actions (details-action hash url)])] (when transaction [toolbar/actions (details-action hash url)])]
[react/scroll-view {:style components.styles/main-container} [react/scroll-view {:style components.styles/main-container}
[details-header date type amount-text currency-text] [details-header date type amount-text currency-text]
[details-confirmations confirmations confirmations-progress type] [details-confirmations confirmations confirmations-progress (= :failed type)]
[react/view {:style styles/details-separator}] [react/view {:style styles/details-separator}]
[details-list transaction]]])) [details-list transaction]]]))

View File

@ -1,4 +1,4 @@
(ns status-im.ui.screens.wallet.db (ns status-im.wallet.db
(:require [cljs.spec.alpha :as spec] (:require [cljs.spec.alpha :as spec]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
status-im.ui.screens.wallet.request.db status-im.ui.screens.wallet.request.db
@ -22,6 +22,7 @@
(spec/def :wallet/visible-tokens any?) (spec/def :wallet/visible-tokens any?)
(spec/def :wallet/currency any?) (spec/def :wallet/currency any?)
(spec/def :wallet/balance any?) (spec/def :wallet/balance any?)
(spec/def :wallet/filters set?)
(spec/def :wallet/wallet (spec/keys :opt-un [:wallet/send-transaction (spec/def :wallet/wallet (spec/keys :opt-un [:wallet/send-transaction
:wallet/request-transaction :wallet/request-transaction
@ -30,6 +31,7 @@
:wallet/errors :wallet/errors
:wallet/transactions :wallet/transactions
:wallet/edit :wallet/edit
:wallet/filters
:wallet/current-tab :wallet/current-tab
:wallet/current-transaction :wallet/current-transaction
:wallet/modal-history? :wallet/modal-history?
@ -58,3 +60,15 @@
:else :else
{:value value})))) {:value value}))))
(def default-wallet-filters
#{:inbound :outbound :pending :failed})
(def default-wallet
{:filters default-wallet-filters})
(defn get-confirmations
[{:keys [block]} current-block]
(if (and current-block block)
(inc (- current-block block))
0))

View File

@ -12,7 +12,6 @@
[status-im.test.wallet.subs] [status-im.test.wallet.subs]
[status-im.test.wallet.transactions] [status-im.test.wallet.transactions]
[status-im.test.wallet.transactions.subs] [status-im.test.wallet.transactions.subs]
[status-im.test.wallet.transactions.views]
[status-im.test.mailserver.core] [status-im.test.mailserver.core]
[status-im.test.fleet.core] [status-im.test.fleet.core]
[status-im.test.group-chats.core] [status-im.test.group-chats.core]
@ -99,7 +98,6 @@
'status-im.test.wallet.subs 'status-im.test.wallet.subs
'status-im.test.wallet.transactions 'status-im.test.wallet.transactions
'status-im.test.wallet.transactions.subs 'status-im.test.wallet.transactions.subs
'status-im.test.wallet.transactions.views
'status-im.test.chat.models.loading 'status-im.test.chat.models.loading
'status-im.test.chat.models.input 'status-im.test.chat.models.input
'status-im.test.chat.models.message 'status-im.test.chat.models.message

View File

@ -1,6 +1,6 @@
(ns status-im.test.ui.screens.wallet.db (ns status-im.test.ui.screens.wallet.db
(:require [cljs.test :refer-macros [deftest is testing]] (:require [cljs.test :refer-macros [deftest is testing]]
[status-im.ui.screens.wallet.db :as wallet.db] [status-im.wallet.db :as wallet.db]
[status-im.utils.money :as money] [status-im.utils.money :as money]
[status-im.i18n :as i18n])) [status-im.i18n :as i18n]))

View File

@ -1,12 +0,0 @@
(ns status-im.test.wallet.transactions.views
(:require [cljs.test :refer [deftest is testing]]
[status-im.ui.screens.wallet.transactions.views :as views]))
(deftest filtered-transaction?
(is (not (true? (views/filtered-transaction? {:type :inbound} {:type [{:id :outbound :checked? true}]}))))
(is (not (true? (views/filtered-transaction? {:type :inbound} {:type [{:id :inbound :checked? false}]}))))
(is (true? (views/filtered-transaction? {:type :inbound} {:type [{:id :inbound :checked? true}]})))
(is (true? (views/filtered-transaction? {:type :inbound} {:type [{:id :outbound :checked? true} {:id :inbound :checked? true}]}))))
(deftest update-transactions
(is (= {:data '()} (views/update-transactions {:data {:type :inbound}} {:type [{:id :outbound :checked? true}]}))))