* Update wallet events and subs to handle collectibles per account Additionally, - Move collectibles related events to a new events namespace (`status-im.contexts.wallet.events.collectibles`). - Update tests to consider collectibles per account. * Update collectibles tab to handle a current viewing account
This commit is contained in:
parent
fc591f303c
commit
4ff5e4da8b
|
@ -10,7 +10,10 @@
|
||||||
|
|
||||||
(defn- view-internal
|
(defn- view-internal
|
||||||
[{:keys [theme]}]
|
[{:keys [theme]}]
|
||||||
(let [collectible-list (rf/sub [:wallet/collectibles])]
|
(let [specific-address (rf/sub [:wallet/current-viewing-account-address])
|
||||||
|
collectible-list (if specific-address
|
||||||
|
(rf/sub [:wallet/collectibles-per-account specific-address])
|
||||||
|
(rf/sub [:wallet/all-collectibles]))]
|
||||||
(if (empty? collectible-list)
|
(if (empty? collectible-list)
|
||||||
[empty-tab/view
|
[empty-tab/view
|
||||||
{:title (i18n/label :t/no-collectibles)
|
{:title (i18n/label :t/no-collectibles)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[react-native.background-timer :as background-timer]
|
[react-native.background-timer :as background-timer]
|
||||||
[status-im.common.data-store.wallet :as data-store]
|
[status-im.common.data-store.wallet :as data-store]
|
||||||
|
[status-im.contexts.wallet.events.collectibles]
|
||||||
[status-im.contexts.wallet.item-types :as item-types]
|
[status-im.contexts.wallet.item-types :as item-types]
|
||||||
[status-im.contexts.wallet.temp :as temp]
|
[status-im.contexts.wallet.temp :as temp]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
|
@ -13,8 +14,7 @@
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.money :as money]
|
[utils.money :as money]
|
||||||
[utils.number]
|
[utils.number]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]))
|
||||||
[utils.transforms :as types]))
|
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/show-account-created-toast
|
(rf/reg-event-fx :wallet/show-account-created-toast
|
||||||
(fn [{:keys [db]} [address]]
|
(fn [{:keys [db]} [address]]
|
||||||
|
@ -65,10 +65,7 @@
|
||||||
db
|
db
|
||||||
(data-store/rpc->accounts wallet-accounts))
|
(data-store/rpc->accounts wallet-accounts))
|
||||||
:fx [[:dispatch [:wallet/get-wallet-token]]
|
:fx [[:dispatch [:wallet/get-wallet-token]]
|
||||||
[:dispatch
|
[:dispatch [:wallet/request-collectibles {:start-at-index 0 :new-request? true}]]
|
||||||
[:wallet/request-collectibles
|
|
||||||
{:start-at-index 0
|
|
||||||
:new-request? true}]]
|
|
||||||
(when new-account?
|
(when new-account?
|
||||||
[:dispatch [:wallet/navigate-to-new-account navigate-to-account]])]})))
|
[:dispatch [:wallet/navigate-to-new-account navigate-to-account]])]})))
|
||||||
|
|
||||||
|
@ -224,121 +221,6 @@
|
||||||
data)}]
|
data)}]
|
||||||
{:db (assoc db :wallet/networks network-data)})))
|
{:db (assoc db :wallet/networks network-data)})))
|
||||||
|
|
||||||
(def collectibles-request-batch-size 1000)
|
|
||||||
|
|
||||||
(defn displayable-collectible?
|
|
||||||
[collectible]
|
|
||||||
(let [{:keys [image-url animation-url]} (:collectible-data collectible)]
|
|
||||||
(or (not (string/blank? animation-url))
|
|
||||||
(not (string/blank? image-url)))))
|
|
||||||
|
|
||||||
(defn store-collectibles
|
|
||||||
[{:keys [db]} [collectibles]]
|
|
||||||
(let [stored-collectibles (get-in db [:wallet :collectibles])
|
|
||||||
displayable-collectibles (filter displayable-collectible? collectibles)]
|
|
||||||
{:db (assoc-in db
|
|
||||||
[:wallet :collectibles]
|
|
||||||
(reduce conj displayable-collectibles stored-collectibles))}))
|
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/store-collectibles store-collectibles)
|
|
||||||
|
|
||||||
(defn clear-stored-collectibles
|
|
||||||
[{:keys [db]}]
|
|
||||||
{:db (update db :wallet dissoc :collectibles)})
|
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/clear-stored-collectibles clear-stored-collectibles)
|
|
||||||
|
|
||||||
(defn store-last-collectible-details
|
|
||||||
[{:keys [db]} [collectible]]
|
|
||||||
{:db (assoc-in db
|
|
||||||
[:wallet :last-collectible-details]
|
|
||||||
collectible)})
|
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/store-last-collectible-details store-last-collectible-details)
|
|
||||||
|
|
||||||
(def collectible-data-types
|
|
||||||
{:unique-id 0
|
|
||||||
:header 1
|
|
||||||
:details 2
|
|
||||||
:community-header 3})
|
|
||||||
|
|
||||||
(def fetch-type
|
|
||||||
{:never-fetch 0
|
|
||||||
:always-fetch 1
|
|
||||||
:fetch-if-not-cached 2
|
|
||||||
:fetch-if-cache-old 3})
|
|
||||||
|
|
||||||
(def max-cache-age-seconds 3600)
|
|
||||||
|
|
||||||
(rf/reg-event-fx
|
|
||||||
:wallet/request-collectibles
|
|
||||||
(fn [{:keys [db]} [{:keys [start-at-index new-request?]}]]
|
|
||||||
(let [request-id 0
|
|
||||||
collectibles-filter nil
|
|
||||||
data-type (collectible-data-types :header)
|
|
||||||
fetch-criteria {:fetch-type (fetch-type :fetch-if-not-cached)
|
|
||||||
:max-cache-age-seconds max-cache-age-seconds}
|
|
||||||
request-params [request-id
|
|
||||||
[(chain/chain-id db)]
|
|
||||||
(keys (get-in db [:wallet :accounts]))
|
|
||||||
collectibles-filter
|
|
||||||
start-at-index
|
|
||||||
collectibles-request-batch-size
|
|
||||||
data-type
|
|
||||||
fetch-criteria]]
|
|
||||||
{:fx [[:json-rpc/call
|
|
||||||
[{:method "wallet_getOwnedCollectiblesAsync"
|
|
||||||
:params request-params
|
|
||||||
:on-success #()
|
|
||||||
:on-error (fn [error]
|
|
||||||
(log/error "failed to request collectibles"
|
|
||||||
{:event :wallet/request-collectibles
|
|
||||||
:error error
|
|
||||||
:params request-params}))}]]
|
|
||||||
(when new-request?
|
|
||||||
[:dispatch [:wallet/clear-stored-collectibles]])]})))
|
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/owned-collectibles-filtering-done
|
|
||||||
(fn [_ [{:keys [message]}]]
|
|
||||||
(let [response (cske/transform-keys csk/->kebab-case-keyword
|
|
||||||
(types/json->clj message))
|
|
||||||
{:keys [collectibles has-more offset]} response
|
|
||||||
start-at-index (+ offset (count collectibles))]
|
|
||||||
{:fx
|
|
||||||
[[:dispatch [:wallet/store-collectibles collectibles]]
|
|
||||||
(when has-more
|
|
||||||
[:dispatch
|
|
||||||
[:wallet/request-collectibles
|
|
||||||
{:start-at-index start-at-index}]])]})))
|
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/get-collectible-details
|
|
||||||
(fn [_ [collectible-id]]
|
|
||||||
(let [request-id 0
|
|
||||||
collectible-id-converted (cske/transform-keys csk/->PascalCaseKeyword collectible-id)
|
|
||||||
data-type (collectible-data-types :details)
|
|
||||||
request-params [request-id [collectible-id-converted] data-type]]
|
|
||||||
{:fx [[:json-rpc/call
|
|
||||||
[{:method "wallet_getCollectiblesByUniqueIDAsync"
|
|
||||||
:params request-params
|
|
||||||
:on-error (fn [error]
|
|
||||||
(log/error "failed to request collectible"
|
|
||||||
{:event :wallet/get-collectible-details
|
|
||||||
:error error
|
|
||||||
:params request-params}))}]]]})))
|
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/get-collectible-details-done
|
|
||||||
(fn [_ [{:keys [message]}]]
|
|
||||||
(let [response (cske/transform-keys csk/->kebab-case-keyword
|
|
||||||
(types/json->clj message))
|
|
||||||
{:keys [collectibles]} response
|
|
||||||
collectible (first collectibles)]
|
|
||||||
(if collectible
|
|
||||||
{:fx
|
|
||||||
[[:dispatch [:wallet/store-last-collectible-details collectible]]]}
|
|
||||||
(log/error "failed to get collectible details"
|
|
||||||
{:event :wallet/get-collectible-details-done
|
|
||||||
:response response})))))
|
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/find-ens
|
(rf/reg-event-fx :wallet/find-ens
|
||||||
(fn [{:keys [db]} [input contacts chain-id cb]]
|
(fn [{:keys [db]} [input contacts chain-id cb]]
|
||||||
(let [result (if (empty? input)
|
(let [result (if (empty? input)
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
(ns status-im.contexts.wallet.events.collectibles
|
||||||
|
(:require [camel-snake-kebab.core :as csk]
|
||||||
|
[camel-snake-kebab.extras :as cske]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[re-frame.core :as rf]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.ethereum.chain :as chain]
|
||||||
|
[utils.transforms :as types]))
|
||||||
|
|
||||||
|
(def collectible-data-types
|
||||||
|
{:unique-id 0
|
||||||
|
:header 1
|
||||||
|
:details 2
|
||||||
|
:community-header 3})
|
||||||
|
|
||||||
|
(def fetch-type
|
||||||
|
{:never-fetch 0
|
||||||
|
:always-fetch 1
|
||||||
|
:fetch-if-not-cached 2
|
||||||
|
:fetch-if-cache-old 3})
|
||||||
|
|
||||||
|
(def max-cache-age-seconds 3600)
|
||||||
|
(def collectibles-request-batch-size 1000)
|
||||||
|
|
||||||
|
(defn displayable-collectible?
|
||||||
|
[collectible]
|
||||||
|
(let [{:keys [image-url animation-url]} (:collectible-data collectible)]
|
||||||
|
(or (not (string/blank? animation-url))
|
||||||
|
(not (string/blank? image-url)))))
|
||||||
|
|
||||||
|
(defn- add-collectibles-to-accounts
|
||||||
|
[accounts collectibles]
|
||||||
|
(reduce (fn [acc {:keys [ownership] :as collectible}]
|
||||||
|
(->> ownership
|
||||||
|
(map :address) ; In ERC1155 tokens a collectible can be owned by multiple addresses.
|
||||||
|
(reduce (fn add-collectible-to-address [acc address]
|
||||||
|
(update-in acc [address :collectibles] conj collectible))
|
||||||
|
acc)))
|
||||||
|
accounts
|
||||||
|
collectibles))
|
||||||
|
|
||||||
|
(defn store-collectibles
|
||||||
|
[{:keys [db]} [collectibles]]
|
||||||
|
(let [displayable-collectibles (filter displayable-collectible? collectibles)]
|
||||||
|
{:db (update-in db [:wallet :accounts] add-collectibles-to-accounts displayable-collectibles)}))
|
||||||
|
|
||||||
|
(rf/reg-event-fx :wallet/store-collectibles store-collectibles)
|
||||||
|
|
||||||
|
(defn clear-stored-collectibles
|
||||||
|
[{:keys [db]}]
|
||||||
|
{:db (update-in db [:wallet :accounts] update-vals #(dissoc % :collectibles))})
|
||||||
|
|
||||||
|
(rf/reg-event-fx :wallet/clear-stored-collectibles clear-stored-collectibles)
|
||||||
|
|
||||||
|
(defn store-last-collectible-details
|
||||||
|
[{:keys [db]} [collectible]]
|
||||||
|
{:db (assoc-in db [:wallet :last-collectible-details] collectible)})
|
||||||
|
|
||||||
|
(rf/reg-event-fx :wallet/store-last-collectible-details store-last-collectible-details)
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:wallet/request-collectibles
|
||||||
|
(fn [{:keys [db]} [{:keys [start-at-index new-request?]}]]
|
||||||
|
(let [request-id 0
|
||||||
|
collectibles-filter nil
|
||||||
|
data-type (collectible-data-types :header)
|
||||||
|
fetch-criteria {:fetch-type (fetch-type :fetch-if-not-cached)
|
||||||
|
:max-cache-age-seconds max-cache-age-seconds}
|
||||||
|
request-params [request-id
|
||||||
|
[(chain/chain-id db)]
|
||||||
|
(keys (get-in db [:wallet :accounts]))
|
||||||
|
collectibles-filter
|
||||||
|
start-at-index
|
||||||
|
collectibles-request-batch-size
|
||||||
|
data-type
|
||||||
|
fetch-criteria]]
|
||||||
|
{:fx [[:json-rpc/call
|
||||||
|
[{:method "wallet_getOwnedCollectiblesAsync"
|
||||||
|
:params request-params
|
||||||
|
:on-error (fn [error]
|
||||||
|
(log/error "failed to request collectibles"
|
||||||
|
{:event :wallet/request-collectibles
|
||||||
|
:error error
|
||||||
|
:params request-params}))}]]
|
||||||
|
(when new-request?
|
||||||
|
[:dispatch [:wallet/clear-stored-collectibles]])]})))
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:wallet/owned-collectibles-filtering-done
|
||||||
|
(fn [_ [{:keys [message]}]]
|
||||||
|
(let [{:keys [has-more offset
|
||||||
|
collectibles]} (cske/transform-keys csk/->kebab-case-keyword (types/json->clj message))
|
||||||
|
start-at-index (+ offset (count collectibles))]
|
||||||
|
{:fx [[:dispatch [:wallet/store-collectibles collectibles]]
|
||||||
|
(when has-more
|
||||||
|
[:dispatch [:wallet/request-collectibles {:start-at-index start-at-index}]])]})))
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:wallet/get-collectible-details
|
||||||
|
(fn [_ [collectible-id]]
|
||||||
|
(let [request-id 0
|
||||||
|
collectible-id-converted (cske/transform-keys csk/->PascalCaseKeyword collectible-id)
|
||||||
|
data-type (collectible-data-types :details)
|
||||||
|
request-params [request-id [collectible-id-converted] data-type]]
|
||||||
|
{:fx [[:json-rpc/call
|
||||||
|
[{:method "wallet_getCollectiblesByUniqueIDAsync"
|
||||||
|
:params request-params
|
||||||
|
:on-error (fn [error]
|
||||||
|
(log/error "failed to request collectible"
|
||||||
|
{:event :wallet/get-collectible-details
|
||||||
|
:error error
|
||||||
|
:params request-params}))}]]]})))
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:wallet/get-collectible-details-done
|
||||||
|
(fn [_ [{:keys [message]}]]
|
||||||
|
(let [response (cske/transform-keys csk/->kebab-case-keyword
|
||||||
|
(types/json->clj message))
|
||||||
|
{:keys [collectibles]} response
|
||||||
|
collectible (first collectibles)]
|
||||||
|
(if collectible
|
||||||
|
{:fx [[:dispatch [:wallet/store-last-collectible-details collectible]]]}
|
||||||
|
(log/error "failed to get collectible details"
|
||||||
|
{:event :wallet/get-collectible-details-done
|
||||||
|
:response response})))))
|
|
@ -2,7 +2,8 @@
|
||||||
(:require
|
(:require
|
||||||
[cljs.test :refer-macros [deftest is testing]]
|
[cljs.test :refer-macros [deftest is testing]]
|
||||||
matcher-combinators.test
|
matcher-combinators.test
|
||||||
[status-im.contexts.wallet.events :as events]))
|
[status-im.contexts.wallet.events :as events]
|
||||||
|
[status-im.contexts.wallet.events.collectibles :as collectibles]))
|
||||||
|
|
||||||
(def address "0x2f88d65f3cb52605a54a833ae118fb1363acccd2")
|
(def address "0x2f88d65f3cb52605a54a833ae118fb1363acccd2")
|
||||||
|
|
||||||
|
@ -35,27 +36,40 @@
|
||||||
[false {:collectible-data {:image-url nil :animation-url ""}}]
|
[false {:collectible-data {:image-url nil :animation-url ""}}]
|
||||||
[false {:collectible-data {:image-url "" :animation-url ""}}]]]
|
[false {:collectible-data {:image-url "" :animation-url ""}}]]]
|
||||||
(doseq [[result collection] expected-results]
|
(doseq [[result collection] expected-results]
|
||||||
(is (match? result (events/displayable-collectible? collection))))))
|
(is (match? result (collectibles/displayable-collectible? collection))))))
|
||||||
|
|
||||||
(testing "save-collectibles-request-details"
|
(testing "save-collectibles-request-details"
|
||||||
(let [db {:wallet {}}
|
(let [db {:wallet {:accounts {"0x1" {}
|
||||||
collectibles [{:collectible-data {:image-url "https://..." :animation-url "https://..."}}
|
"0x3" {}}}}
|
||||||
{:collectible-data {:image-url "" :animation-url "https://..."}}
|
collectible-1 {:collectible-data {:image-url "https://..." :animation-url "https://..."}
|
||||||
{:collectible-data {:image-url "" :animation-url nil}}]
|
:ownership [{:address "0x1"
|
||||||
expected-db {:wallet {:collectibles [{:collectible-data
|
:balance "1"}]}
|
||||||
{:image-url "https://..." :animation-url "https://..."}}
|
collectible-2 {:collectible-data {:image-url "" :animation-url "https://..."}
|
||||||
{:collectible-data
|
:ownership [{:address "0x1"
|
||||||
{:image-url "" :animation-url "https://..."}}]}}
|
:balance "1"}]}
|
||||||
effects (events/store-collectibles {:db db} [collectibles])
|
collectible-3 {:collectible-data {:image-url "" :animation-url nil}
|
||||||
|
:ownership [{:address "0x2"
|
||||||
|
:balance "1"}]}
|
||||||
|
collectibles [collectible-1 collectible-2 collectible-3]
|
||||||
|
expected-db {:wallet {:accounts {"0x1" {:collectibles (list collectible-2 collectible-1)}
|
||||||
|
"0x2" {:collectibles (list collectible-3)}
|
||||||
|
"0x3" {}}}}
|
||||||
|
effects (collectibles/store-collectibles {:db db} [collectibles])
|
||||||
result-db (:db effects)]
|
result-db (:db effects)]
|
||||||
(is (match? result-db expected-db)))))
|
(is (match? result-db expected-db)))))
|
||||||
|
|
||||||
(deftest clear-stored-collectibles
|
(deftest clear-stored-collectibles
|
||||||
(let [db {:wallet {:collectibles [{:id 1} {:id 2}]}}]
|
(let [db {:wallet {:accounts {"0x1" {:collectibles [{:id 1} {:id 2}]}
|
||||||
|
"0x2" {"some other stuff" "with any value"
|
||||||
|
:collectibles [{:id 3}]}
|
||||||
|
"0x3" {}}}}]
|
||||||
(testing "clear-stored-collectibles"
|
(testing "clear-stored-collectibles"
|
||||||
(let [expected-db {:wallet {}}
|
(let [expected-db {:wallet {:accounts {"0x1" {}
|
||||||
effects (events/clear-stored-collectibles {:db db})
|
"0x2" {"some other stuff" "with any value"}
|
||||||
|
"0x3" {}}}}
|
||||||
|
effects (collectibles/clear-stored-collectibles {:db db})
|
||||||
result-db (:db effects)]
|
result-db (:db effects)]
|
||||||
|
|
||||||
(is (match? result-db expected-db))))))
|
(is (match? result-db expected-db))))))
|
||||||
|
|
||||||
(deftest store-last-collectible-details
|
(deftest store-last-collectible-details
|
||||||
|
@ -65,6 +79,6 @@
|
||||||
:image-url "https://..."}
|
:image-url "https://..."}
|
||||||
expected-db {:wallet {:last-collectible-details {:description "Pandaria"
|
expected-db {:wallet {:last-collectible-details {:description "Pandaria"
|
||||||
:image-url "https://..."}}}
|
:image-url "https://..."}}}
|
||||||
effects (events/store-last-collectible-details {:db db} [last-collectible])
|
effects (collectibles/store-last-collectible-details {:db db} [last-collectible])
|
||||||
result-db (:db effects)]
|
result-db (:db effects)]
|
||||||
(is (match? result-db expected-db)))))
|
(is (match? result-db expected-db)))))
|
||||||
|
|
|
@ -11,12 +11,24 @@
|
||||||
image-url))
|
image-url))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:wallet/collectibles
|
:wallet/collectibles-per-account
|
||||||
|
:<- [:wallet]
|
||||||
|
(fn [wallet [_ address]]
|
||||||
|
(as-> wallet $
|
||||||
|
(get-in $ [:accounts address :collectibles])
|
||||||
|
(map (fn [{:keys [collectible-data] :as collectible}]
|
||||||
|
(assoc collectible :preview-url (preview-url collectible-data)))
|
||||||
|
$))))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
:wallet/all-collectibles
|
||||||
:<- [:wallet]
|
:<- [:wallet]
|
||||||
(fn [wallet]
|
(fn [wallet]
|
||||||
(map (fn [collectible]
|
(->> wallet
|
||||||
(assoc collectible :preview-url (preview-url (:collectible-data collectible))))
|
:accounts
|
||||||
(:collectibles wallet))))
|
(mapcat (comp :collectibles val))
|
||||||
|
(map (fn [{:keys [collectible-data] :as collectible}]
|
||||||
|
(assoc collectible :preview-url (preview-url collectible-data)))))))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:wallet/last-collectible-details
|
:wallet/last-collectible-details
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
:<- [:wallet/ui]
|
:<- [:wallet/ui]
|
||||||
:-> :tokens-loading?)
|
:-> :tokens-loading?)
|
||||||
|
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet/current-viewing-account-address
|
:wallet/current-viewing-account-address
|
||||||
:<- [:wallet]
|
:<- [:wallet]
|
||||||
|
|
Loading…
Reference in New Issue