fix(wallet): Improvements on activity tab (#20703)

* Fix schema for networks in context-tags

* Fix wallet-activity component overflowing the activity tab

* Improve robustness of the activity tab fetching mechanism

* Handle `wallet-activity-filtering-entries-updated` signal

* Improve processing of data received for the activity tab
This commit is contained in:
Ulises Manuel 2024-07-16 15:07:33 -06:00 committed by GitHub
parent 43651ef0d0
commit 2d0437dd5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 291 additions and 141 deletions

View File

@ -53,7 +53,7 @@
(def ^:private ?network (def ^:private ?network
[:map [:map
[:network-logo {:optional true} [:maybe :schema.common/image-source]] [:network-logo {:optional true} [:maybe :schema.common/image-source]]
[:network-name {:optional true} [:maybe :string]]]) [:network-name {:optional true} [:maybe [:or :string :keyword]]]])
(def ^:private ?multinetwork (def ^:private ?multinetwork
[:map [:map

View File

@ -41,7 +41,8 @@
:align-items :center :align-items :center
:height size :height size
:background-color background-color :background-color background-color
:border-radius border-radius} :border-radius border-radius
:flex-shrink 1}
(= state :selected) (assoc :height (+ size 2) (= state :selected) (assoc :height (+ size 2)
:border-color border-color :border-color border-color
:border-width 1)))) :border-width 1))))
@ -50,11 +51,13 @@
[size] [size]
{:margin-right (if (= size 24) 6 10) {:margin-right (if (= size 24) 6 10)
:flex-direction :row :flex-direction :row
:flex-shrink 1
:align-items :center}) :align-items :center})
(defn tag-spacing (defn tag-spacing
[size] [size shrinkable?]
{:margin-left (if (= size 24) 4 8)}) (cond-> {:margin-left (if (= size 24) 4 8)}
shrinkable? (assoc :flex-shrink 1)))
(defn text (defn text
[theme] [theme]

View File

@ -17,17 +17,19 @@
[schema.core :as schema])) [schema.core :as schema]))
(defn- tag-skeleton (defn- tag-skeleton
[{:keys [size text theme] [{:keys [size text theme shrinkable?]
:or {size 24 :or {size 24
theme (quo.theme/use-theme)}} theme (quo.theme/use-theme)}}
logo-component] logo-component]
[rn/view {:style (style/tag-container size)} [rn/view {:style (style/tag-container size)}
logo-component logo-component
[rn/view {:style (style/tag-spacing size)} [rn/view {:style (style/tag-spacing size shrinkable?)}
[text/text [text/text
{:style (style/text theme) {:style (style/text theme)
:weight :medium :weight :medium
:size (if (= size 24) :paragraph-2 :paragraph-1)} :size (if (= size 24) :paragraph-2 :paragraph-1)
:number-of-lines 1
:ellipsize-mode :middle}
text]]]) text]]])
(defn- communities-tag (defn- communities-tag
@ -37,7 +39,7 @@
icon-size (if (= size 24) 16 20)] icon-size (if (= size 24) 16 20)]
[rn/view {:style (style/tag-container size)} [rn/view {:style (style/tag-container size)}
[fast-image/fast-image {:style (style/circle-logo size) :source community-logo}] [fast-image/fast-image {:style (style/circle-logo size) :source community-logo}]
[rn/view {:style (style/tag-spacing size)} [rn/view {:style (style/tag-spacing size false)}
[text/text [text/text
{:style (style/text theme) {:style (style/text theme)
:weight :medium :weight :medium
@ -148,9 +150,10 @@
:collectible :collectible
[tag-skeleton [tag-skeleton
{:theme theme {:theme theme
:size size :size size
:text (str collectible-name " #" collectible-number)} :text (str collectible-name " #" collectible-number)
:shrinkable? true}
[rn/image {:style (style/rounded-logo size) :source collectible}]] [rn/image {:style (style/rounded-logo size) :source collectible}]]
:account :account

View File

@ -51,8 +51,7 @@
(defn prop-text (defn prop-text
[theme] [theme]
{:margin-right 4 {:color (colors/theme-colors colors/neutral-100 colors/white theme)})
:color (colors/theme-colors colors/neutral-100 colors/white theme)})
(def icon-container (def icon-container
{:width 32 {:width 32
@ -61,12 +60,15 @@
(def container (def container
{:flex-direction :row {:flex-direction :row
:flex 1
:column-gap 8}) :column-gap 8})
(def content-line (def content-line
{:flex-direction :row {:flex-direction :row
:margin-top 2 :margin-top 2
:align-items :center}) :align-items :center
:column-gap 4
:justify-content :flex-start})
(def icon-hole-view (def icon-hole-view
{:width 32 {:width 32

View File

@ -98,8 +98,11 @@
(defn prop-tag (defn prop-tag
[props blur?] [props blur?]
[rn/view {:style {:margin-right 4}} [context-tag/view
[context-tag/view (merge props {:size 24 :blur? blur?})]]) (assoc props
:size 24
:blur? blur?
:container-style {:flex-shrink 1})])
(defn- view-internal (defn- view-internal
[{:keys [state blur? first-tag second-tag third-tag fourth-tag on-press [{:keys [state blur? first-tag second-tag third-tag fourth-tag on-press
@ -121,7 +124,7 @@
:on-press-out on-press-out} :on-press-out on-press-out}
[rn/view {:style style/container} [rn/view {:style style/container}
[transaction-icon-view props theme] [transaction-icon-view props theme]
[rn/view [rn/view {:style {:flex 1}}
[transaction-header props theme] [transaction-header props theme]
[rn/view {:style style/content-line} [rn/view {:style style/content-line}
(when first-tag [prop-tag first-tag blur?]) (when first-tag [prop-tag first-tag blur?])

View File

@ -4,12 +4,19 @@
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.transforms :as transforms])) [utils.transforms :as transforms]))
(defonce ^:private request-id-atom (atom 0))
(defn- get-unique-request-id
[]
(swap! request-id-atom inc)
@request-id-atom)
(rf/reg-event-fx (rf/reg-event-fx
:wallet/fetch-activities-for-current-account :wallet/fetch-activities-for-current-account
(fn [{:keys [db]}] (fn [{:keys [db]}]
(let [address (-> db :wallet :current-viewing-account-address) (let [address (-> db :wallet :current-viewing-account-address)
chain-ids (chain/chain-ids db) chain-ids (chain/chain-ids db)
request-id 0 request-id (get-unique-request-id)
filters {:period {:startTimestamp 0 filters {:period {:startTimestamp 0
:endTimestamp 0} :endTimestamp 0}
:types [] :types []
@ -20,9 +27,10 @@
:filterOutAssets false :filterOutAssets false
:filterOutCollectibles false} :filterOutCollectibles false}
offset 0 offset 0
limit 35 limit 50
request-params [request-id [address] chain-ids filters offset limit]] request-params [request-id [address] chain-ids filters offset limit]]
{:fx [[:json-rpc/call {:db (assoc-in db [:wallet :ui :activity-tab :request request-id] address)
:fx [[:json-rpc/call
[{;; This method is deprecated and will be replaced by [{;; This method is deprecated and will be replaced by
;; "wallet_startActivityFilterSession" ;; "wallet_startActivityFilterSession"
;; https://github.com/status-im/status-mobile/issues/19864 ;; https://github.com/status-im/status-mobile/issues/19864
@ -32,13 +40,31 @@
{:event :wallet/fetch-activities-for-current-account {:event :wallet/fetch-activities-for-current-account
:params request-params}]}]]]}))) :params request-params}]}]]]})))
(def ^:private activity-transaction-id (comp hash :transaction))
(rf/reg-event-fx (rf/reg-event-fx
:wallet/activity-filtering-for-current-account-done :wallet/activity-filtering-for-current-account-done
(fn [{:keys [db]} [{:keys [message]}]] (fn [{:keys [db]} [{:keys [message requestId]}]]
(let [address (-> db :wallet :current-viewing-account-address) (let [address (get-in db [:wallet :ui :activity-tab :request requestId])
activities (->> message activities (->> message
(transforms/json->clj) (transforms/json->clj)
(:activities) (:activities)
(cske/transform-keys transforms/->kebab-case-keyword)) (cske/transform-keys transforms/->kebab-case-keyword))
sorted-activities (sort :timestamp activities)] activities-indexed (zipmap (map activity-transaction-id activities)
{:db (assoc-in db [:wallet :activities address] sorted-activities)}))) activities)]
{:db (assoc-in db [:wallet :activities address] activities-indexed)})))
(def ^:private nested-merge (partial merge-with merge))
(rf/reg-event-fx
:wallet/activities-filtering-entries-updated
(fn [{:keys [db]} [{:keys [message requestId]}]]
(let [address (get-in db [:wallet :ui :activity-tab :request requestId])
activities (->> message
(transforms/json->clj)
(cske/transform-keys transforms/->kebab-case-keyword))
activities-indexed (zipmap (map activity-transaction-id activities)
activities)]
{:db (-> db
(update-in [:wallet :ui :activity-tab :request] dissoc requestId)
(update-in [:wallet :activities address] nested-merge activities-indexed))})))

View File

@ -11,31 +11,81 @@
(defn send-and-receive-activity (defn send-and-receive-activity
[{:keys [transaction relative-date status sender recipient token amount network-name [{:keys [transaction relative-date status sender recipient token amount network-name
network-logo]}] network-logo token-id nft-url nft-name]}]
[quo/wallet-activity (if token-id
{:transaction transaction [quo/wallet-activity
:timestamp relative-date {:transaction transaction
:status status :timestamp relative-date
:counter 1 :status status
:first-tag {:size 24 :counter 1
:type :token :first-tag {:size 24
:token token :type :collectible
:amount amount} :collectible nft-url
:second-tag-prefix :t/from :collectible-name (if (> amount 1)
:second-tag {:type :address :address sender} (str amount " " nft-name)
:third-tag-prefix :t/to nft-name)
:third-tag {:type :address :address recipient} :collectible-number token-id}
:fourth-tag-prefix :t/via :second-tag-prefix :t/from
:fourth-tag {:size 24 :second-tag {:type :address :address sender}
:type :network :third-tag-prefix :t/to
:network-name network-name :third-tag {:type :address :address recipient}
:network-logo network-logo} :fourth-tag-prefix :t/via
:blur? false}]) :fourth-tag {:size 24
:type :network
:network-name network-name
:network-logo network-logo}
:blur? false}]
[quo/wallet-activity
{:transaction transaction
:timestamp relative-date
:status status
:counter 1
:first-tag {:size 24
:type :token
:token token
:amount amount}
:second-tag-prefix :t/from
:second-tag {:type :address :address sender}
:third-tag-prefix :t/to
:third-tag {:type :address :address recipient}
:fourth-tag-prefix :t/via
:fourth-tag {:size 24
:type :network
:network-name network-name
:network-logo network-logo}
:blur? false}]))
;; WIP to add the mint activity.
;(defn mint-activity
; [{:keys [transaction relative-date status recipient network-name
; network-logo nft-name nft-url token-id]}]
; [quo/wallet-activity
; {:transaction transaction
; :timestamp relative-date
; :status status
; :counter 1
; :first-tag {:size 24
; :type :collectible
; :collectible nft-url
; :collectible-name nft-name
; :collectible-number token-id}
; :second-tag-prefix :t/at
; :second-tag {:type :address :address recipient}
; :third-tag-prefix :t/to
; :third-tag {:type :address :address recipient}
; :fourth-tag-prefix :t/via
; :fourth-tag {:size 24
; :type :network
; :network-name network-name
; :network-logo network-logo}
; :blur? false}])
(defn activity-item (defn activity-item
[{:keys [transaction] :as activity}] [{:keys [transaction] :as activity}]
(case transaction (case transaction
(:send :receive) [send-and-receive-activity activity] (:send :receive) [send-and-receive-activity activity]
;; WIP to add the mint activity.
;; :mint [mint-activity activity]
nil)) nil))
(defn view (defn view

View File

@ -23,22 +23,39 @@
:block-number blockNumber :block-number blockNumber
:accounts accounts}) :accounts accounts})
(case event-type (case event-type
"pending-transaction-status-changed" {:fx "pending-transaction-status-changed"
[[:dispatch {:fx
[:wallet/pending-transaction-status-changed-received [[:dispatch
(transforms/js->clj event-js)]]]} [:wallet/pending-transaction-status-changed-received
"wallet-owned-collectibles-filtering-done" {:fx [[:dispatch (transforms/js->clj event-js)]]]}
[:wallet/owned-collectibles-filtering-done
(transforms/js->clj event-js)]]]} "wallet-owned-collectibles-filtering-done"
"wallet-get-collectibles-details-done" {:fx [[:dispatch {:fx [[:dispatch
[:wallet/get-collectible-details-done [:wallet/owned-collectibles-filtering-done
(transforms/js->clj event-js)]]]} (transforms/js->clj event-js)]]]}
"wallet-tick-reload" {:fx [[:dispatch [:wallet/reload]]]}
"wallet-blockchain-status-changed" {:fx [[:dispatch "wallet-get-collectibles-details-done"
[:wallet/blockchain-status-changed {:fx [[:dispatch
(transforms/js->clj event-js)]]]} [:wallet/get-collectible-details-done
"wallet-activity-filtering-done" {:fx (transforms/js->clj event-js)]]]}
[[:dispatch
[:wallet/activity-filtering-for-current-account-done "wallet-tick-reload"
(transforms/js->clj event-js)]]]} {:fx [[:dispatch [:wallet/reload]]]}
"wallet-blockchain-status-changed"
{:fx [[:dispatch
[:wallet/blockchain-status-changed
(transforms/js->clj event-js)]]]}
"wallet-activity-filtering-done"
{:fx
[[:dispatch
[:wallet/activity-filtering-for-current-account-done
(transforms/js->clj event-js)]]]}
"wallet-activity-filtering-entries-updated"
{:fx [[:dispatch
[:wallet/activities-filtering-entries-updated
(transforms/js->clj event-js)]]]}
(log/debug ::unknown-wallet-event :type event-type))))) (log/debug ::unknown-wallet-event :type event-type)))))

View File

@ -1,5 +1,6 @@
(ns status-im.subs.wallet.activities (ns status-im.subs.wallet.activities
(:require (:require
[clojure.string :as string]
[native-module.core :as native-module] [native-module.core :as native-module]
[quo.foundations.resources :as quo.resources] [quo.foundations.resources :as quo.resources]
[quo.foundations.resources] [quo.foundations.resources]
@ -16,49 +17,91 @@
:<- [:wallet] :<- [:wallet]
:-> :activities) :-> :activities)
(defn- activity-amount (defn- hex-wei->amount
[amount] [hex-str-amount]
(-> amount (-> hex-str-amount
(utils.hex/normalize-hex) (utils.hex/normalize-hex)
(native-module/hex-to-number) (native-module/hex-to-number)
(money/wei->ether) (money/wei->ether)
(money/with-precision precision) (money/with-precision precision)
(str))) (str)))
(defn- hex-string->number
[hex-str-amount]
(-> hex-str-amount
(utils.hex/normalize-hex)
(native-module/hex-to-number)
(str)))
(defn- normalize-nft-name
[token-id nft-name]
(if (and (some? token-id) (string/blank? nft-name))
"Unknown"
nft-name))
(defn- get-token-amount
[token amount]
(let [token-type (:token-type token)]
(if (#{constants/wallet-activity-token-type-erc-721
constants/wallet-activity-token-type-erc-1155}
token-type)
(hex-string->number amount)
(hex-wei->amount amount))))
(defn- process-send-activity (defn- process-send-activity
[{:keys [symbol-out chain-id-out amount-out]} activity chain-id->network-name] [{:keys [symbol-out amount-out token-out]
(let [network-name (chain-id->network-name chain-id-out)] :as data}]
(assoc activity (assoc data
:transaction :send :transaction :send
:token symbol-out :token symbol-out
:amount (activity-amount amount-out) :amount (get-token-amount token-out amount-out)))
:network-name network-name
:network-logo (quo.resources/get-network network-name))))
(defn- process-receive-activity (defn- process-receive-activity
[{:keys [symbol-in amount-in chain-id-in]} activity chain-id->network-name] [{:keys [symbol-in amount-in token-in] :as data}]
(let [network-name (chain-id->network-name chain-id-in)] (assoc data
(assoc activity :transaction :receive
:transaction :receive :token symbol-in
:token symbol-in :amount (get-token-amount token-in amount-in)))
:amount (activity-amount amount-in)
:network-name network-name ;; WIP to add the mint activity.
:network-logo (quo.resources/get-network network-name)))) ;(defn- process-mint-activity
; [{:keys [token-in symbol-in amount-in chain-id-in nft-name] :as data}
; chain-id->network-name]
; (-> data
; (merge activity)
; (assoc :transaction :mint
; ;:token symbol-in
; ;:amount (activity-amount amount-in)
; :nft-name (normalize-nft-name token-id nft-name))))
(defn- process-activity-by-type (defn- process-activity-by-type
[chain-id->network-name [chain-id->network-name
{:keys [activity-type activity-status timestamp sender recipient] :as data}] {:keys [activity-type activity-status timestamp sender recipient token-in token-out
(let [activity {:relative-date (datetime/timestamp->relative (* timestamp 1000)) chain-id-in chain-id-out nft-name]
:timestamp timestamp :as data}]
:status (constants/wallet-activity-status->name activity-status) (let [network-name (chain-id->network-name (or chain-id-in chain-id-out))
:sender sender token-id (some-> (or token-in token-out)
:recipient recipient}] :token-id
hex-string->number)
activity (assoc data
:relative-date (datetime/timestamp->relative (* timestamp 1000))
:sender sender
:recipient recipient
:timestamp timestamp
:network-name network-name
:token-id token-id
:status (constants/wallet-activity-status->name activity-status)
:network-logo (quo.resources/get-network network-name)
:nft-name (normalize-nft-name token-id nft-name))]
(condp = activity-type (condp = activity-type
constants/wallet-activity-type-send constants/wallet-activity-type-send
(process-send-activity data activity chain-id->network-name) (process-send-activity activity)
constants/wallet-activity-type-receive constants/wallet-activity-type-receive
(process-receive-activity data activity chain-id->network-name) (process-receive-activity activity)
;; WIP to add the mint activity. Constants/wallet-activity-type-mint
;; (process-mint-activity activity chain-id->network-name)
nil))) nil)))
@ -69,9 +112,11 @@
:<- [:wallet/network-details] :<- [:wallet/network-details]
(fn [[activities current-viewing-account-address network-details]] (fn [[activities current-viewing-account-address network-details]]
(let [chain-id->network-name (update-vals (group-by :chain-id network-details) (let [chain-id->network-name (update-vals (group-by :chain-id network-details)
(comp :network-name first))] (comp :network-name first))
(->> current-viewing-account-address address-activities (->> (get activities current-viewing-account-address)
(get activities) (vals)
(sort :timestamp))]
(->> address-activities
(keep #(process-activity-by-type chain-id->network-name %)) (keep #(process-activity-by-type chain-id->network-name %))
(group-by (fn [{:keys [timestamp]}] (group-by (fn [{:keys [timestamp]}]
(datetime/timestamp->relative-short-date (* timestamp 1000)))) (datetime/timestamp->relative-short-date (* timestamp 1000))))

View File

@ -24,26 +24,26 @@
(fn [db] (fn [db]
(-> db (-> db
(assoc-in [:wallet :activities] (assoc-in [:wallet :activities]
{"acc1" [{:activity-type constants/wallet-activity-type-send {"acc1" {1 {:activity-type constants/wallet-activity-type-send
:amount-out "0x1" :amount-out "0x1"
:sender "acc1" :sender "acc1"
:recipient "acc2" :recipient "acc2"
:timestamp 1588291200} :timestamp 1588291200}
{:activity-type constants/wallet-activity-type-receive 2 {:activity-type constants/wallet-activity-type-receive
:amount-in "0x1" :amount-in "0x1"
:sender "acc2" :sender "acc2"
:recipient "acc1" :recipient "acc1"
:timestamp 1588377600} :timestamp 1588377600}
{:activity-type constants/wallet-activity-type-send 3 {:activity-type constants/wallet-activity-type-send
:amount-out "0x1" :amount-out "0x1"
:sender "acc1" :sender "acc1"
:recipient "acc4" :recipient "acc4"
:timestamp 1588464000}] :timestamp 1588464000}}
"acc3" [{:activity-type constants/wallet-activity-type-receive "acc3" {4 {:activity-type constants/wallet-activity-type-receive
:amount-in "0x1" :amount-in "0x1"
:sender "acc4" :sender "acc4"
:recipient "acc3" :recipient "acc3"
:timestamp 1588464000}]}) :timestamp 1588464000}}})
(assoc-in [:wallet :current-viewing-account-address] "acc1")))) (assoc-in [:wallet :current-viewing-account-address] "acc1"))))
(is (is
(match? [{:title "May 3, 2020" (match? [{:title "May 3, 2020"

View File

@ -49,8 +49,9 @@
:<- [:wallet/all-activities] :<- [:wallet/all-activities]
:<- [:wallet/current-viewing-account-address] :<- [:wallet/current-viewing-account-address]
(fn [[all-activities current-viewing-account-address]] (fn [[all-activities current-viewing-account-address]]
(let [address-activity (get all-activities current-viewing-account-address)] (let [address-activity (vals (get all-activities current-viewing-account-address))]
(->> address-activity (->> address-activity
(sort :timestamp)
(keep (fn [{:keys [activity-type recipient]}] (keep (fn [{:keys [activity-type recipient]}]
(when (= constants/wallet-activity-type-send activity-type) (when (= constants/wallet-activity-type-send activity-type)
recipient))) recipient)))

View File

@ -62,25 +62,25 @@
(fn [db] (fn [db]
(-> db (-> db
(assoc-in [:wallet :activities] (assoc-in [:wallet :activities]
{"acc1" [{:activity-type constants/wallet-activity-type-send {"acc1" {1 {:activity-type constants/wallet-activity-type-send
:amount-out "0x1" :amount-out "0x1"
:sender "acc1" :sender "acc1"
:recipient "acc2" :recipient "acc2"
:timestamp 1588291200} :timestamp 1588291200}
{:activity-type constants/wallet-activity-type-receive 2 {:activity-type constants/wallet-activity-type-receive
:amount-in "0x1" :amount-in "0x1"
:sender "acc2" :sender "acc2"
:recipient "acc1" :recipient "acc1"
:timestamp 1588377600} :timestamp 1588377600}
{:activity-type constants/wallet-activity-type-send 3 {:activity-type constants/wallet-activity-type-send
:amount-out "0x1" :amount-out "0x1"
:sender "acc1" :sender "acc1"
:recipient "acc4" :recipient "acc4"
:timestamp 1588464000}] :timestamp 1588464000}}
"acc3" [{:activity-type constants/wallet-activity-type-receive "acc3" {4 {:activity-type constants/wallet-activity-type-receive
:amount-in "0x1" :amount-in "0x1"
:sender "acc4" :sender "acc4"
:recipient "acc3" :recipient "acc3"
:timestamp 1588464000}]}) :timestamp 1588464000}}})
(assoc-in [:wallet :current-viewing-account-address] "acc1")))) (assoc-in [:wallet :current-viewing-account-address] "acc1"))))
(is (match? ["acc2" "acc4"] (rf/sub [sub-name]))))) (is (match? ["acc2" "acc4"] (rf/sub [sub-name])))))