diff --git a/src/status_im/chat/commands/impl/transactions.cljs b/src/status_im/chat/commands/impl/transactions.cljs index 8f7a1d08db..ecf1adad99 100644 --- a/src/status_im/chat/commands/impl/transactions.cljs +++ b/src/status_im/chat/commands/impl/transactions.cljs @@ -1,30 +1,34 @@ (ns status-im.chat.commands.impl.transactions - (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [clojure.string :as string] - [reagent.core :as reagent] [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.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.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.tokens :as tokens] - [status-im.utils.datetime :as datetime] [status-im.utils.fx :as fx] [status-im.utils.money :as money] [status-im.utils.platform :as platform] - [status-im.ui.screens.wallet.db :as wallet.db] - [status-im.ui.screens.wallet.choose-recipient.events :as choose-recipient.events] - [status-im.ui.screens.navigation :as navigation] - [status-im.ui.screens.wallet.utils :as wallet.utils] - [status-im.ui.components.chat-icon.screen :as chat-icon])) + [status-im.ui.components.chat-icon.screen :as chat-icon] + [status-im.wallet.db :as wallet.db]) + (:require-macros [status-im.utils.views :refer [defview letsubs]])) ;; common `send/request` functionality @@ -179,19 +183,22 @@ ;; `/send` command (defview send-status [tx-hash outgoing] - (letsubs [confirmed? [:chats/transaction-confirmed? tx-hash] - tx-exists? [:chats/wallet-transaction-exists? tx-hash]] - [react/touchable-highlight {:on-press #(when tx-exists? + (letsubs [{:keys [exists? confirmed?]} [:chats/transaction-status tx-hash]] + [react/touchable-highlight {:on-press #(when exists? (re-frame/dispatch [:show-transaction-details tx-hash]))} [react/view transactions-styles/command-send-status-container - [vector-icons/icon (if confirmed? :tiny-icons/tiny-check :tiny-icons/tiny-pending) - {:color (if outgoing colors/blue-light colors/blue) + [vector-icons/icon (if confirmed? + :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)}] [react/view [react/text {:style (transactions-styles/command-send-status-text outgoing)} (i18n/label (cond confirmed? :status-confirmed - tx-exists? :status-pending + exists? :status-pending :else :status-tx-not-found))]]]])) (defn transaction-status [{:keys [tx-hash outgoing]}] diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 732ef73de6..8a6eb6e430 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -30,13 +30,6 @@ (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 {"mainnet" {:id "mainnet", :name "Mainnet", diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index acd9bca2db..7bb5d7b857 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -57,6 +57,7 @@ [status-im.utils.handlers :as handlers] [status-im.utils.logging.core :as logging] [status-im.utils.utils :as utils] + [status-im.wallet.db :as wallet.db] [status-im.web3.core :as web3] [taoensso.timbre :as log] [status-im.wallet.custom-tokens.core :as custom-tokens])) @@ -2144,3 +2145,20 @@ :ethereum.transactions/new (fn [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)})) diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 08db7a5076..fc2cb85f18 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -39,7 +39,8 @@ status-im.ui.screens.hardwallet.connect.subs status-im.ui.screens.hardwallet.settings.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 =========================================================================================================== @@ -690,18 +691,16 @@ (filter-contacts selected-contacts active-contacts))) (re-frame/reg-sub - :chats/transaction-confirmed? - :<- [:wallet-transactions] - (fn [txs [_ tx-hash]] - (-> (get-in txs [tx-hash :confirmations] "0") - (js/parseInt) - (>= transactions/confirmations-count-threshold)))) - -(re-frame/reg-sub - :chats/wallet-transaction-exists? - :<- [:wallet-transactions] - (fn [txs [_ tx-hash]] - (not (nil? (get txs tx-hash))))) + :chats/transaction-status + :<- [:wallet/transactions] + :<- [:ethereum/current-block] + (fn [[transactions current-block] [_ hash]] + (when-let [transaction (get transactions hash)] + {:exists? true + :confirmed? + (-> transaction + (wallet.db/get-confirmations current-block) + (>= transactions/confirmations-count-threshold))}))) ;;BOOTNODES ============================================================================================================ @@ -1026,87 +1025,133 @@ ;;WALLET TRANSACTIONS ================================================================================================== (re-frame/reg-sub - :wallet-transactions + :wallet/transactions :<- [:wallet] (fn [wallet] (get wallet :transactions))) (re-frame/reg-sub - :wallet.transactions/filters - :<- [:wallet.transactions] - (fn [txs] - (get txs :filters))) + :wallet/filters + :<- [:wallet] + (fn [wallet] + (get wallet :filters))) (defn enrich-transaction - [{:keys [type to from timestamp] :as transaction} contacts] - (let [[contact-address key-contact key-wallet] (if (= type :inbound) - [from :from-contact :to-wallet] - [to :to-contact :from-wallet]) + [{:keys [type to from value token] :as transaction} + contacts native-currency] + (let [[contact-address key-contact key-wallet] + (if (= type :inbound) + [from :from-contact :to-wallet] + [to :to-contact :from-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 contact (assoc key-contact (:name contact)) :always (assoc key-wallet wallet - :time-formatted (datetime/timestamp->time timestamp))))) + :amount-text amount-text + :currency-text currency-text)))) (re-frame/reg-sub :wallet.transactions/transactions - :<- [:wallet] + :<- [:wallet/transactions] :<- [:contacts/contacts-by-address] - (fn [[wallet contacts]] - (reduce (fn [acc [hash transaction]] - (assoc acc hash (enrich-transaction transaction contacts))) - {} - (:transactions wallet)))) + :<- [:ethereum/native-currency] + (fn [[transactions contacts native-currency]] + (reduce-kv (fn [acc hash transaction] + (assoc acc + hash + (enrich-transaction transaction contacts native-currency))) + {} + transactions))) (re-frame/reg-sub - :wallet.transactions/grouped-transactions - :<- [:wallet.transactions/transactions] - (fn [transactions] - (group-by :type (vals transactions)))) + :wallet.transactions/all-filters? + :<- [:wallet/filters] + (fn [filters] + (= 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 - :wallet.transactions/pending-transactions-list - :<- [:wallet.transactions/grouped-transactions] - (fn [{:keys [pending]}] - (when pending - {:title "Pending" - :key :pending - :data pending}))) + :wallet.transactions/filters + :<- [:wallet/filters] + (fn [filters] + (map (fn [id] + (let [checked? (filters id)] + {:id id + :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 - :wallet.transactions/failed-transactions-list - :<- [:wallet.transactions/grouped-transactions] - (fn [{:keys [failed]}] - (when failed - {:title "Failed" - :key :failed - :data failed}))) + :wallet.transactions.filters/screen + :<- [:wallet.transactions/filters] + :<- [:wallet.transactions/all-filters?] + (fn [[filters all-filters?]] + {:all-filters? all-filters? + :filters filters + :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 (group-by #(datetime/timestamp->date-key (:timestamp %))) - (sort-by key) - reverse + (sort-by key >) (map (fn [[date-key transactions]] {:title (datetime/timestamp->mini-date (:timestamp (first transactions))) :key date-key :data (sort-by :timestamp > transactions)})))) (re-frame/reg-sub - :wallet.transactions/completed-transactions-list - :<- [:wallet.transactions/grouped-transactions] - (fn [{:keys [inbound outbound failed]}] - (group-transactions-by-date (concat inbound outbound failed)))) - -(re-frame/reg-sub - :wallet.transactions/transactions-history-list - :<- [:wallet.transactions/pending-transactions-list] - :<- [:wallet.transactions/completed-transactions-list] - (fn [[pending completed]] - (cond-> [] - pending (into pending) - completed (into completed)))) + :wallet.transactions.history/screen + :<- [:wallet.transactions/transactions] + :<- [:wallet/filters] + :<- [:wallet.transactions/all-filters?] + (fn [[transactions filters all-filters?]] + {:all-filters? all-filters? + :transaction-history-sections + (->> transactions + vals + (keep #(enrich-transaction-for-list filters %)) + (group-transactions-by-date))})) (re-frame/reg-sub :wallet.transactions/current-transaction @@ -1123,55 +1168,45 @@ (fn [[transactions current-transaction native-currency chain-keyword]] (let [{:keys [gas-used gas-price hash timestamp type token value] :as transaction} - (get transactions current-transaction)] + (get transactions current-transaction) + native-currency-text (-> native-currency + :symbol-display + name)] (when transaction - (let [{: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))) - native-currency-text (-> native-currency - :symbol-display - name)] - (merge transaction - {:amount-text amount-text - :currency-text currency-text - :gas-price-eth (if gas-price - (money/wei->str :eth - gas-price - native-currency-text) - "-") - :gas-price-gwei (if gas-price - (money/wei->str :gwei - gas-price) - "-") - :date (datetime/timestamp->long-date timestamp)} - (if (= type :unsigned) - {:block (i18n/label :not-applicable) - :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)}))))))) + (merge transaction + {:gas-price-eth (if gas-price + (money/wei->str :eth + gas-price + native-currency-text) + "-") + :gas-price-gwei (if gas-price + (money/wei->str :gwei + gas-price) + "-") + :date (datetime/timestamp->long-date timestamp)} + (if (= type :unsigned) + {:block (i18n/label :not-applicable) + :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 :wallet.transactions.details/screen :<- [:wallet.transactions.details/current-transaction] :<- [:ethereum/current-block] - (fn [[{:keys [block] :as transaction} current-block]] + (fn [[transaction current-block]] :wallet.transactions.details/current-transaction - (let [confirmations (if (and current-block block) - (inc (- current-block block)) - 0)] + (let [confirmations (wallet.db/get-confirmations transaction + current-block)] (assoc transaction :confirmations confirmations :confirmations-progress diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index 2701fa47b1..050def0c90 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -16,7 +16,8 @@ status-im.browser.db status-im.ui.screens.add-new.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 (def app-db {:keyboard-height 0 @@ -32,7 +33,7 @@ :selected-participants #{} :sync-state :done :app-state "active" - :wallet.transactions constants/default-wallet-transactions + :wallet wallet.db/default-wallet :wallet/all-tokens {} :prices {} :peers-count 0 @@ -329,7 +330,6 @@ :chat/id->command :chat/access-scope->command-id :wallet/wallet - :wallet/wallet.transactions :prices/prices :prices/prices-loading? :notifications/notifications diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index ae3a3f87a9..7c1c2e1323 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -15,7 +15,6 @@ status-im.ui.screens.wallet.send.events status-im.ui.screens.wallet.request.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.collectibles.cryptokitties.events status-im.ui.screens.wallet.collectibles.cryptostrikers.events diff --git a/src/status_im/ui/screens/wallet/request/events.cljs b/src/status_im/ui/screens/wallet/request/events.cljs index a8329d176e..8bd0681127 100644 --- a/src/status_im/ui/screens/wallet/request/events.cljs +++ b/src/status_im/ui/screens/wallet/request/events.cljs @@ -1,12 +1,10 @@ (ns status-im.ui.screens.wallet.request.events - (:require [re-frame.core :as re-frame] - [status-im.ui.screens.wallet.db :as wallet-db] - [status-im.ui.screens.navigation :as navigation] - [status-im.utils.handlers :as handlers] + (:require [status-im.chat.commands.sending :as commands-sending] [status-im.chat.models :as chat-model] - [status-im.chat.commands.sending :as commands-sending] [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 :wallet-send-request @@ -23,7 +21,7 @@ (handlers/register-handler-fx :wallet.request/set-and-validate-amount (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 (assoc-in [:wallet :request-transaction :amount] (money/formatted->internal value symbol decimals)) (assoc-in [:wallet :request-transaction :amount-text] amount) diff --git a/src/status_im/ui/screens/wallet/send/events.cljs b/src/status_im/ui/screens/wallet/send/events.cljs index 82e901a89a..be7ff0c9a7 100644 --- a/src/status_im/ui/screens/wallet/send/events.cljs +++ b/src/status_im/ui/screens/wallet/send/events.cljs @@ -7,7 +7,7 @@ [status-im.native-module.core :as status] [status-im.transport.utils :as transport.utils] [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.erc20 :as erc20] [status-im.utils.ethereum.tokens :as tokens] diff --git a/src/status_im/ui/screens/wallet/transactions/events.cljs b/src/status_im/ui/screens/wallet/transactions/events.cljs deleted file mode 100644 index 148da85e86..0000000000 --- a/src/status_im/ui/screens/wallet/transactions/events.cljs +++ /dev/null @@ -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)})) diff --git a/src/status_im/ui/screens/wallet/transactions/views.cljs b/src/status_im/ui/screens/wallet/transactions/views.cljs index e2775b1698..dc1aeba6bc 100644 --- a/src/status_im/ui/screens/wallet/transactions/views.cljs +++ b/src/status_im/ui/screens/wallet/transactions/views.cljs @@ -15,154 +15,149 @@ [status-im.utils.money :as money]) (:require-macros [status-im.utils.views :refer [defview letsubs]])) -(defn history-action [filter?] +;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; TRANSACTION HISTORY +;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn history-action + [all-filters?] (cond-> {:icon :main-icons/filter :icon-opts {:accessibility-label :filters-button} :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] - (and (every? :checked? (:type filter-data)) - (every? :checked? (:tokens filter-data)))) - -(defn- toolbar-view [filter-data] +(defn- toolbar-view + [all-filters?] [toolbar/toolbar nil toolbar/default-nav-back [toolbar/content-title (i18n/label :t/transactions-history)] [toolbar/actions - [(history-action (not (all-checked? filter-data)))]]]) + [(history-action all-filters?)]]]) -(defn- inbound? [type] (= :inbound type)) -(defn- failed? [type] (= :failed type)) - -(defn- transaction-icon [k background-color color] - {:icon k +(defn- transaction-icon + [icon-key background-color color] + {:icon icon-key :icon-opts {:color color} :style (styles/transaction-icon-background background-color)}) -(defn- transaction-type->icon [k] +(defn- transaction-type->icon + [k] (case k - :inbound (transaction-icon :main-icons/arrow-left (colors/alpha colors/green 0.2) colors/green) - :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) - (:postponed :pending) (transaction-icon :main-icons/arrow-right colors/gray-light colors/gray) + :inbound (transaction-icon :main-icons/arrow-left + (colors/alpha colors/green 0.2) + colors/green) + :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)))) (defn render-transaction - [{:keys [hash from-contact to-contact to from type value time-formatted symbol]} - network all-tokens hide-details?] - (let [[label contact address contact-accessibility-label - address-accessibility-label] - (if (inbound? type) - [(i18n/label :t/from) from-contact from :sender-text :sender-address-text] - [(i18n/label :t/to) to-contact to :recipient-name-text :recipient-address-text]) - {:keys [decimals] :as token} - (tokens/asset-for all-tokens - (ethereum/network->chain-keyword network) - symbol)] - [list/touchable-item #(when-not hide-details? (re-frame/dispatch [:show-transaction-details hash])) - [react/view {:accessibility-label :transaction-item} - [list/item - (when type - [list/item-icon (transaction-type->icon (keyword type))]) - [list/item-content - [react/view {:style styles/amount-time} - [react/nested-text {:style styles/tx-amount - :ellipsize-mode "tail" - :number-of-lines 1} - [{:accessibility-label :amount-text} - (-> value (money/internal->formatted symbol decimals) money/to-fixed str)] - " " - [{:accessibility-label :currency-text} - (wallet.utils/display-symbol token)]] - [react/text {:style styles/tx-time} - time-formatted]] - [react/view {:style styles/address-row} - [react/text {:style styles/address-label} - label] - (when contact - [react/text {:style styles/address-contact - :accessibility-label contact-accessibility-label} - contact]) - [react/text {:style styles/address-hash - :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})}])]]])) + [{:keys [label contact address contact-accessibility-label + address-accessibility-label currency-text amount-text + time-formatted on-touch-fn type]}] + [list/touchable-item on-touch-fn + [react/view {:accessibility-label :transaction-item} + [list/item + (when type + [list/item-icon (transaction-type->icon (keyword type))]) + [list/item-content + [react/view {:style styles/amount-time} + [react/nested-text {:style styles/tx-amount + :ellipsize-mode "tail" + :number-of-lines 1} + [{:accessibility-label :amount-text} + amount-text] + " " + [{:accessibility-label :currency-text} + currency-text]] + [react/text {:style styles/tx-time} + time-formatted]] + [react/view {:style styles/address-row} + [react/text {:style styles/address-label} + label] + (when contact + [react/text {:style styles/address-contact + :accessibility-label contact-accessibility-label} + contact]) + [react/text {:style styles/address-hash + :ellipsize-mode "middle" + :number-of-lines 1 + :accessibility-label address-accessibility-label} + address]]] + [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] - (:checked? (some #(when (= (:type transaction) (:id %)) %) (:type filter-data)))) +(defn history-list + [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] - (update m - :data - (fn [v] - (filter #(filtered-transaction? % filter-data) v)))) +(defview transactions + [] + (letsubs [{:keys [transaction-history-sections all-filters?]} + [:wallet.transactions.history/screen]] + [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] - 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}]])) +;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; TRANSACTION FILTERS +;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Filter history - -(defn- item-filter [{:keys [icon checked? path]} content] +(defn- render-item-filter [{:keys [id label checked? on-touch]}] [react/view {:accessibility-label :filter-item} [list/list-item-with-checkbox {:checked? checked? - :on-value-change #(re-frame/dispatch [:wallet.transactions/filter path %])} + :on-value-change on-touch} [list/item - [list/item-icon icon] - 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-icon (transaction-type->icon id)] [list/item-content [list/item-primary-only {:accessibility-label :filter-name-text} - label]]])) - -(defn- wrap-filter-data [m] - [{:title (i18n/label :t/transactions-filter-type) - :key :type - :render-fn render-item-filter - :data (:type m)}]) + label]]]]]) (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 [status-bar/status-bar {:type :modal-main}] [toolbar/toolbar {} - [toolbar/nav-clear-text {:accessibility-label :done-button} (i18n/label :t/done)] - [toolbar/content-title (i18n/label :t/transactions-filter-title)] - [toolbar/text-action {:handler #(re-frame/dispatch [:wallet.transactions/filter-all]) - :disabled? (all-checked? filter-data) - :accessibility-label :select-all-button} + [toolbar/nav-clear-text + {:accessibility-label :done-button} + (i18n/label :t/done)] + [toolbar/content-title + (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)]] - [react/view {:style (merge {:background-color :white} components.styles/flex)} - [list/section-list {:sections (wrap-filter-data filter-data) - :key-fn (comp str :id)}]]])) + [react/view + {:style (merge {:background-color :white} components.styles/flex)} + [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]] - [react/view styles/transactions-view - [status-bar/status-bar] - [toolbar-view filter-data] - [history-list]])) +;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; TRANSACTION DETAILS +;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn details-header [date type amount-text currency-text] @@ -183,10 +178,10 @@ [react/view {:style (styles/progress-bar-todo (- 100 progress) failed?)}]]) (defn details-confirmations - [confirmations confirmations-progress type] + [confirmations confirmations-progress failed?] [react/view {:style styles/details-block} - [progress-bar confirmations-progress (failed? type)] - (if (failed? type) + [progress-bar confirmations-progress failed?] + (if failed? [react/i18n-text {:style styles/details-failed :key :failed}] [react/text {:style styles/details-confirmations-count} @@ -259,6 +254,6 @@ (when transaction [toolbar/actions (details-action hash url)])] [react/scroll-view {:style components.styles/main-container} [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}] [details-list transaction]]])) diff --git a/src/status_im/ui/screens/wallet/db.cljs b/src/status_im/wallet/db.cljs similarity index 86% rename from src/status_im/ui/screens/wallet/db.cljs rename to src/status_im/wallet/db.cljs index adeb321605..364a421bbb 100644 --- a/src/status_im/ui/screens/wallet/db.cljs +++ b/src/status_im/wallet/db.cljs @@ -1,4 +1,4 @@ -(ns status-im.ui.screens.wallet.db +(ns status-im.wallet.db (:require [cljs.spec.alpha :as spec] [status-im.i18n :as i18n] status-im.ui.screens.wallet.request.db @@ -22,6 +22,7 @@ (spec/def :wallet/visible-tokens any?) (spec/def :wallet/currency any?) (spec/def :wallet/balance any?) +(spec/def :wallet/filters set?) (spec/def :wallet/wallet (spec/keys :opt-un [:wallet/send-transaction :wallet/request-transaction @@ -30,6 +31,7 @@ :wallet/errors :wallet/transactions :wallet/edit + :wallet/filters :wallet/current-tab :wallet/current-transaction :wallet/modal-history? @@ -58,3 +60,15 @@ :else {: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)) diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index 85a88f04c8..4d7bb92f8e 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -12,7 +12,6 @@ [status-im.test.wallet.subs] [status-im.test.wallet.transactions] [status-im.test.wallet.transactions.subs] - [status-im.test.wallet.transactions.views] [status-im.test.mailserver.core] [status-im.test.fleet.core] [status-im.test.group-chats.core] @@ -99,7 +98,6 @@ 'status-im.test.wallet.subs 'status-im.test.wallet.transactions 'status-im.test.wallet.transactions.subs - 'status-im.test.wallet.transactions.views 'status-im.test.chat.models.loading 'status-im.test.chat.models.input 'status-im.test.chat.models.message diff --git a/test/cljs/status_im/test/ui/screens/wallet/db.cljs b/test/cljs/status_im/test/ui/screens/wallet/db.cljs index 29fb2ac34d..64e9e15dfc 100644 --- a/test/cljs/status_im/test/ui/screens/wallet/db.cljs +++ b/test/cljs/status_im/test/ui/screens/wallet/db.cljs @@ -1,6 +1,6 @@ (ns status-im.test.ui.screens.wallet.db (: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.i18n :as i18n])) diff --git a/test/cljs/status_im/test/wallet/transactions/views.cljs b/test/cljs/status_im/test/wallet/transactions/views.cljs deleted file mode 100644 index 5bce9ad188..0000000000 --- a/test/cljs/status_im/test/wallet/transactions/views.cljs +++ /dev/null @@ -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}]})))) \ No newline at end of file