Communities: Show relevant tokens (#18636)

Show "relevant tokens" in account selection step. Related status-go PR
https://github.com/status-im/status-go/pull/4631.

- Balances are fetched on the account selection screen. Assuming most users
  won't care about selecting addresses, this eliminates unnecessary calls to get
  balances, at the expense of refetching them every time the component is
  mounted. I think for now this is acceptable.
- Relevant tokens is a terminology used in Figma, but more specifically, it
  means "balances for all assets that have at least one Token Criteria
  associated, and for a given address". Or, as I tried to give it a more
  distinct name, "permissioned balances".

Areas that may be impacted: None because all affected code is behind a disabled
feature flag.

Fixes https://github.com/status-im/status-mobile/issues/18126
This commit is contained in:
Icaro Motta 2024-02-08 11:17:15 -03:00 committed by GitHub
parent ac32de89f9
commit 505f2fe624
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 203 additions and 94 deletions

View File

@ -42,18 +42,22 @@
(render [account-permissions/view
{:account account
:token-details [{:token "SNT"
:amount "100"}]}])
:amount "100"
:type :token}]}])
(h/is-truthy (h/get-by-text "100 SNT")))
(h/test "render with multiple token details"
(render [account-permissions/view
{:account account
:token-details [{:token "SNT"
:amount "100"}
:amount "100"
:type :token}
{:token "ETH"
:amount "18"}
:amount "18"
:type :token}
{:token "BTM"
:amount "1000"}]}])
:amount "1000"
:type :token}]}])
(h/is-truthy (h/get-by-text "100 SNT"))
(h/is-truthy (h/get-by-text "18 ETH"))
(h/is-truthy (h/get-by-text "1000 BTM")))

View File

@ -24,7 +24,7 @@
[:address [:maybe :string]]
[:emoji [:maybe :string]]
[:customization-color [:maybe [:or :string :keyword]]]]]
[:token-details {:optional true} [:maybe [:vector required-tokens/?schema]]]
[:token-details {:optional true} [:maybe [:sequential required-tokens/?schema]]]
[:keycard? {:optional true} [:maybe :boolean]]
[:checked? {:optional true} [:maybe :boolean]]
[:disabled? {:optional true} [:maybe :boolean]]
@ -47,14 +47,16 @@
(i18n/label :t/no-relevant-tokens)]
(let [token-length (dec (count tokens))]
(map-indexed (fn [idx {:keys [token amount]}]
(map-indexed (fn [idx {:keys [type token amount collectible-name collectible-img-src]}]
^{:key idx}
[required-tokens/view
{:container-style style/token-and-text
:type :token
:amount amount
:token token
:divider? (not= token-length idx)}])
{:container-style style/token-and-text
:type type
:amount amount
:token token
:collectible-img-src collectible-img-src
:collectible-name collectible-name
:divider? (not= token-length idx)}])
tokens)))]]))
(defn- view-internal

View File

@ -15,7 +15,7 @@
[:amount {:optional true} [:maybe [:or :string :int]]]
[:token {:optional true} [:maybe :string]]
[:token-img-src {:optional true} [:maybe :schema.common/image-source]]
[:collectible-img-src {:optional true} :schema.common/image-source]
[:collectible-img-src {:optional true} [:maybe :schema.common/image-source]]
[:collectible-name {:optional true} [:maybe :string]]
[:divider? {:optional true} [:maybe :boolean]]
[:theme :schema.common/theme]

View File

@ -22,7 +22,7 @@
{:min 1}
[:map
{:closed true}
[:method :string]
[:method [:or :keyword :string]]
[:params [:sequential :any]]
[:js-response {:optional true} :any]
[:on-success [:or fn? [:cat keyword? [:* :any]]]]

View File

@ -159,6 +159,9 @@
community-token-permission-become-token-master
community-token-permission-become-token-owner})
(def ^:const community-token-type-erc20 1)
(def ^:const community-token-type-erc721 2)
;; Community rules for joining
(def ^:const community-rule-ens-only "ens-only")

View File

@ -18,7 +18,7 @@
{:community-id id :password %}])}])
(rf/dispatch [:navigate-back]))
(defn f-view-internal
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
@ -83,7 +83,3 @@
:track-icon :i/face-id
:customization-color color
:on-complete #(join-community-and-navigate-back id)}]]]))
(defn view
[]
[:f> f-view-internal])

View File

@ -0,0 +1,58 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.events
(:require
[schema.core :as schema]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn get-permissioned-balances
[{[event-id _] :original-event} [community-id]]
{:fx [[:json-rpc/call
[{:method :wakuext_getCommunityPermissionedBalances
:params [{:communityId community-id}]
:on-success [:communities/get-permissioned-balances-success community-id]
:on-error (fn [error]
(log/error "failed to get balances"
{:community-id community-id
:event event-id
:error error}))}]]]})
(schema/=> get-permissioned-balances
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args [:schema [:catn [:community-id :string]]]]]
[:map {:closed true}
[:fx
[:tuple
[:tuple [:= :json-rpc/call] :schema.common/rpc-call]]]]])
(rf/reg-event-fx :communities/get-permissioned-balances get-permissioned-balances)
(defn get-permissioned-balances-success
[{:keys [db]} [community-id response]]
{:db (assoc-in db [:communities/permissioned-balances community-id] response)})
(def ^:private ?account-address keyword?)
(def ^:private ?permissioned-balances-response
[:map-of
?account-address
[:sequential
[:map
[:type int?]
[:symbol string?]
[:decimals int?]
[:amount string?]]]])
(schema/=> get-permissioned-balances-success
[:=>
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:schema
[:catn
[:community-id string?]
[:response ?permissioned-balances-response]]]]]
map?])
(rf/reg-event-fx :communities/get-permissioned-balances-success get-permissioned-balances-success)

View File

@ -0,0 +1,15 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.events-test
(:require
[cljs.test :refer [is deftest]]
[status-im.contexts.communities.actions.addresses-for-permissions.events :as sut]))
(def community-id "0x1")
(deftest get-permissioned-balances-test
(let [cofx {:db {}}]
(is (match? {:fx [[:json-rpc/call
[{:method :wakuext_getCommunityPermissionedBalances
:params [{:communityId community-id}]
:on-success [:communities/get-permissioned-balances-success community-id]
:on-error fn?}]]]}
(sut/get-permissioned-balances cofx [community-id])))))

View File

@ -3,90 +3,114 @@
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.resources :as resources]
[status-im.constants :as constants]
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
[status-im.contexts.communities.utils :as communities.utils]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))
(defn- balances->components-props
[balances]
(for [{:keys [amount decimals type name] :as balance} balances]
(cond-> balance
true
(assoc :type
(condp = type
constants/community-token-type-erc20 :token
constants/community-token-type-erc721 :collectible
:token))
(= type constants/community-token-type-erc721)
(assoc :collectible-name name
:collectible-img-src (resources/get-mock-image :collectible))
(= type constants/community-token-type-erc20)
(assoc :amount (str (money/with-precision (money/token->unit amount decimals) 3))
:token (:symbol balance)))))
(defn- account-item
[item _ _ [selected-addresses community-id]]
[quo/account-permissions
{:account {:name (:name item)
:address (:address item)
:emoji (:emoji item)
:customization-color (:customization-color item)}
:token-details []
:checked? (contains? selected-addresses (:address item))
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
(:address item) community-id])
:container-style {:margin-bottom 8}}])
[{:keys [customization-color address name emoji]} _ _ [selected-addresses community-id]]
(let [balances (rf/sub [:communities/permissioned-balances-by-address community-id address])]
[quo/account-permissions
{:account {:name name
:address address
:emoji emoji
:customization-color customization-color}
:token-details (balances->components-props balances)
:checked? (contains? selected-addresses address)
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
address community-id])
:container-style {:margin-bottom 8}}]))
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images]} (rf/sub [:communities/community id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
highest-role-text
(i18n/label
(communities.utils/role->translation-key highest-permission-role))]
[rn/safe-area-view {:style style/container}
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
(let [{id :community-id} (rf/sub [:get-screen-params])]
(rf/dispatch [:communities/get-permissioned-balances id])
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role))]
[rn/safe-area-view {:style style/container}
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
[rn/flat-list
{:render-fn account-item
:render-data [selected-addresses id]
:content-container-style {:padding 20}
:key-fn :address
:data accounts}]
[rn/flat-list
{:render-fn account-item
:render-data [selected-addresses id]
:content-container-style {:padding 20}
:key-fn :address
:data accounts}]
(when (and highest-permission-role (seq selected-addresses))
[rn/view
{:style style/highest-role}
[quo/text
{:size :paragraph-2
:style {:color colors/neutral-50}}
(i18n/label :t/eligible-to-join-as)]
[quo/context-tag
{:type :icon
:icon :i/members
:size 24
:context highest-role-text}]])
(when (and highest-permission-role (seq selected-addresses))
[rn/view
{:style style/highest-role}
[quo/text
{:size :paragraph-2
:style {:color colors/neutral-50}}
(i18n/label :t/eligible-to-join-as)]
[quo/context-tag
{:type :icon
:icon :i/members
:size 24
:context highest-role-text}]])
(when (empty? selected-addresses)
[rn/view
{:style style/error-message}
[quo/icon
:i/info
{:color colors/danger-50
:size 16}]
[quo/text
{:size :paragraph-2
:style {:color colors/danger-50}}
(i18n/label :t/no-addresses-selected)]])
(when (empty? selected-addresses)
[rn/view
{:style style/error-message}
[quo/icon
:i/info
{:color colors/danger-50
:size 16}]
[quo/text
{:size :paragraph-2
:style {:color colors/danger-50}}
(i18n/label :t/no-addresses-selected)]])
[rn/view {:style style/buttons}
[quo/button
{:type :grey
:container-style {:flex 1}
:on-press (fn []
(rf/dispatch [:communities/reset-selected-permission-addresses id])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/cancel)]
[quo/button
{:container-style {:flex 1}
:customization-color color
:disabled? (empty? selected-addresses)
:on-press (fn []
(rf/dispatch [:communities/update-previous-permission-addresses id])
[rn/view {:style style/buttons}
[quo/button
{:type :grey
:container-style {:flex 1}
:on-press (fn []
(rf/dispatch [:communities/reset-selected-permission-addresses id])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/confirm-changes)]]]))
(i18n/label :t/cancel)]
[quo/button
{:container-style {:flex 1}
:customization-color color
:disabled? (empty? selected-addresses)
:on-press (fn []
(rf/dispatch [:communities/update-previous-permission-addresses id])
(rf/dispatch [:navigate-back]))}
(i18n/label :t/confirm-changes)]]]))))

View File

@ -9,6 +9,7 @@
[schema.core :as schema]
[status-im.constants :as constants]
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
status-im.contexts.communities.actions.addresses-for-permissions.events
status-im.contexts.communities.actions.community-options.events
status-im.contexts.communities.actions.leave.events
[status-im.navigation.events :as navigation]

View File

@ -363,6 +363,11 @@
(fn [communities [_ community-id]]
(get-in communities [community-id :intro-message])))
(re-frame/reg-sub :communities/permissioned-balances-by-address
:<- [:communities/permissioned-balances]
(fn [balances [_ community-id account-address]]
(get-in balances [community-id (keyword account-address)])))
(re-frame/reg-sub
:communities/selected-permission-addresses
(fn [[_ community-id]]

View File

@ -145,6 +145,7 @@
(reg-root-key-sub :communities/collapsed-categories :communities/collapsed-categories)
(reg-root-key-sub :communities/selected-tab :communities/selected-tab)
(reg-root-key-sub :contract-communities :contract-communities)
(reg-root-key-sub :communities/permissioned-balances :communities/permissioned-balances)
;;activity center
(reg-root-key-sub :activity-center :activity-center)

View File

@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.174.2",
"commit-sha1": "cd228d97dde2063352654f426d7fc50df90c3d30",
"src-sha256": "1kpyyrv0kjzlzmm6mwhh6lv3bilza18ngx1vq1drrp8m8wggwmfa"
"version": "v0.174.3",
"commit-sha1": "c15f9e73654ed2f21887af680d7730dec5bec3e3",
"src-sha256": "09jvamavnkii2fikpz2a5d345aspfp5lzlg5lpymz7lyjif4qn1s"
}