Community detail token gating component (#19532)

This commit is contained in:
Ajay Sivan 2024-04-16 21:41:18 +05:30 committed by GitHub
parent f3aeddb53a
commit 98762c74f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 282 additions and 65 deletions

View File

@ -0,0 +1,71 @@
(ns quo.components.community.community-detail-token-gating.component-spec
(:require
[quo.core :as quo]
[test-helpers.component :as h]))
(h/describe "Community Detail Token Gating Component"
(h/test "render with member permissions"
(h/render
[quo/community-detail-token-gating
{:permissions [{:role 2
:role-text "Member"
:satisfied? true
:tokens [[{:symbol "ETH"
:sufficient? true
:collectible? false
:amount 0.8
:img-src nil}]
[{:symbol "ETH"
:sufficient? false
:collectible? false
:amount 1
:img-src nil}
{:symbol "STT"
:sufficient? false
:collectible? false
:amount 10
:img-src nil}]]}]}])
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Member"}))
(h/is-truthy (h/get-by-text "0.8 ETH"))
(h/is-truthy (h/get-by-text "1 ETH"))
(h/is-truthy (h/get-by-text "10 STT")))
(h/test "render with admin permissions"
(h/render
[quo/community-detail-token-gating
{:permissions [{:role 1
:role-text "Admin"
:satisfied? true
:tokens [[{:symbol "ETH"
:sufficient? true
:collectible? false
:amount 2
:img-src nil}]]}]}])
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Admin"}))
(h/is-truthy (h/get-by-text "2 ETH")))
(h/test "render with token master permissions"
(h/render-with-theme-provider
[quo/community-detail-token-gating
{:permissions [{:role 5
:role-text "Token Master"
:satisfied? true
:tokens [[{:symbol "TMANI "
:sufficient? true
:collectible? true
:img-src {:uri "mock-image"}}]]}]}])
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Token Master"}))
(h/is-truthy (h/get-by-text "TMANI")))
(h/test "render with token owner permissions"
(h/render-with-theme-provider
[quo/community-detail-token-gating
{:permissions [{:role 6
:role-text "Token Owner"
:satisfied? true
:tokens [[{:symbol "TOANI"
:sufficient? true
:collectible? true
:img-src {:uri "mock-image"}}]]}]}])
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Token Owner"}))
(h/is-truthy (h/get-by-text "TOANI"))))

View File

@ -0,0 +1,20 @@
(ns quo.components.community.community-detail-token-gating.style)
(def container
{:padding-horizontal 20
:margin-vertical -4})
(defn token-row
[first?]
{:flex-direction :row
:margin-top (if first? 8 4)
:row-gap 10
:column-gap 8
:flex-wrap :wrap
:margin-bottom 16})
(def divider
{:padding-left 0
:height 28
:padding-top 0
:align-items :flex-start})

View File

@ -0,0 +1,74 @@
(ns quo.components.community.community-detail-token-gating.view
(:require [clojure.string :as string]
[quo.components.community.community-detail-token-gating.style :as style]
[quo.components.dividers.divider-label.view :as divider-label]
[quo.components.markdown.text :as text]
[quo.components.tags.collectible-tag.view :as collectible-tag]
[quo.components.tags.token-tag.view :as token-tag]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[utils.i18n :as i18n]))
(defn- token-view
[{:keys [collectible? img-src amount sufficient?] :as token}]
(let [token-symbol (:symbol token)]
(if collectible?
[collectible-tag/view
{:collectible-name token-symbol
:size :size-24
:collectible-img-src img-src
:options (when sufficient?
:hold)}]
[token-tag/view
{:token-symbol token-symbol
:size :size-24
:token-value amount
:token-img-src img-src
:options (when sufficient? :hold)}])))
(defn- tokens-row
[{:keys [tokens divider? first?]}]
[:<>
[rn/view
{:style (style/token-row first?)}
(map-indexed (fn [token-index token]
^{:key (str "token-" token-index)}
[token-view token])
tokens)]
(when-not divider?
[divider-label/view
{:container-style style/divider}
[text/text
{:size :label
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
(string/lower-case (i18n/label :t/or))]])])
(defn- role-view
[{:keys [role tokens satisfied? role-text]}]
(when (seq tokens)
^{:key (str "role-" role)}
[:<>
[text/text
{:size :paragraph-1
:weight :medium
:style {:margin-top 4}}
(if satisfied?
(i18n/label :t/you-eligible-to-join-as {:role role-text})
(i18n/label :t/you-not-eligible-to-join-as {:role role-text}))]
[text/text
{:size :paragraph-2
:style {:margin-bottom 8}}
(i18n/label (if satisfied? :t/you-hodl :t/you-must-hold))]
(map-indexed (fn [index tokens-item]
^{:key (str role "-tokens-" index)}
[tokens-row
{:tokens tokens-item
:first? (zero? index)
:divider? (= index (dec (count tokens)))}])
tokens)]))
(defn view
[{:keys [permissions]}]
[rn/view {:style style/container}
(map role-view permissions)])

View File

@ -10,5 +10,5 @@
[:blur? {:optional true} [:maybe :boolean]] [:blur? {:optional true} [:maybe :boolean]]
[:collectible-img-src :schema.common/image-source] [:collectible-img-src :schema.common/image-source]
[:collectible-name :string] [:collectible-name :string]
[:collectible-id :string]]]] [:collectible-id {:optional true} [:maybe :string]]]]]
:any]) :any])

View File

@ -41,12 +41,13 @@
:weight :medium :weight :medium
:style (style/label theme)} :style (style/label theme)}
collectible-name] collectible-name]
[text/text (when collectible-id
{:size :paragraph-2 [text/text
:weight :medium {:size :paragraph-2
:margin-left 5 :weight :medium
:style (style/label theme)} :margin-left 5
collectible-id]]] :style (style/label theme)}
collectible-id])]]
(when options (when options
[rn/view {:style (style/options-icon size)} [rn/view {:style (style/options-icon size)}
[icons/icon (if (= options :hold) :i/hold :i/add-token) [icons/icon (if (= options :hold) :i/hold :i/add-token)

View File

@ -32,6 +32,7 @@
quo.components.community.channel-action.view quo.components.community.channel-action.view
quo.components.community.channel-actions.view quo.components.community.channel-actions.view
quo.components.community.community-card-view quo.components.community.community-card-view
quo.components.community.community-detail-token-gating.view
quo.components.community.community-list-view quo.components.community.community-list-view
quo.components.community.community-stat.view quo.components.community.community-stat.view
quo.components.community.community-view quo.components.community.community-view
@ -224,6 +225,7 @@
;;;; Community ;;;; Community
(def community-card-view-item quo.components.community.community-card-view/view) (def community-card-view-item quo.components.community.community-card-view/view)
(def community-detail-token-gating quo.components.community.community-detail-token-gating.view/view)
(def communities-membership-list-item (def communities-membership-list-item
quo.components.community.community-list-view/communities-membership-list-item) quo.components.community.community-list-view/communities-membership-list-item)
(def community-stats-column quo.components.community.community-view/community-stats-column) (def community-stats-column quo.components.community.community-view/community-stats-column)

View File

@ -16,6 +16,7 @@
quo.components.calendar.calendar.component-spec quo.components.calendar.calendar.component-spec
quo.components.calendar.calendar.month-picker.component-spec quo.components.calendar.calendar.month-picker.component-spec
quo.components.colors.color-picker.component-spec quo.components.colors.color-picker.component-spec
quo.components.community.community-detail-token-gating.component-spec
quo.components.community.community-stat.component-spec quo.components.community.community-stat.component-spec
quo.components.counter.collectible-counter.component-spec quo.components.counter.collectible-counter.component-spec
quo.components.counter.counter.component-spec quo.components.counter.counter.component-spec

View File

@ -1,5 +0,0 @@
(ns status-im.contexts.communities.actions.permissions-sheet.style)
(def container
{:flex 1
:padding-horizontal 20})

View File

@ -1,38 +1,12 @@
(ns status-im.contexts.communities.actions.permissions-sheet.view (ns status-im.contexts.communities.actions.permissions-sheet.view
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture] [react-native.gesture :as gesture]
[status-im.contexts.communities.actions.permissions-sheet.style :as style]
[status-im.contexts.communities.utils :as communities.utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn- role-text
[role]
(i18n/label
(communities.utils/role->translation-key role
:t/token-master)))
(defn- permission-view
[{:keys [tokens role satisfied?]}]
(when (seq tokens)
^{:key role}
[rn/view {:style {:margin-bottom 20}}
[quo/text {:weight :medium}
(if satisfied?
(i18n/label :t/you-eligible-to-join-as {:role (role-text role)})
(i18n/label :t/you-not-eligible-to-join-as {:role (role-text role)}))]
[quo/text {:size :paragraph-2 :style {:padding-bottom 8}}
(if satisfied?
(i18n/label :t/you-hodl)
(i18n/label :t/you-must-hold))]
[quo/token-requirement-list
{:tokens tokens
:container-style {:padding-horizontal 20}}]]))
(defn view (defn view
[id] [id]
(let [permissions (rf/sub [:community/token-permissions id])] (let [permissions (rf/sub [:community/token-permissions id])]
[gesture/scroll-view {:style style/container} [gesture/scroll-view
(map permission-view permissions)])) [quo/community-detail-token-gating {:permissions permissions}]
]))

View File

@ -0,0 +1,68 @@
(ns status-im.contexts.preview.quo.community.community-detail-token-gating
(:require [quo.core :as quo]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :role
:type :select
:options [{:key :one-role}
{:key :two-roles}
{:key :three-roles}
{:key :four-roles}]}])
(def roles
{:member
{:role 2
:role-text "Member"
:satisfied? true
:tokens
[[{:symbol "ETH" :sufficient? true :collectible? false :loading? false :amount 0.8 :img-src nil}]
[{:symbol "ETH" :sufficient? false :collectible? false :loading? false :amount 1 :img-src nil}
{:symbol "STT" :sufficient? false :collectible? false :loading? false :amount 10 :img-src nil}]]}
:admin
{:role 1
:role-text "Admin"
:satisfied? true
:tokens
[[{:symbol "ETH" :sufficient? true :collectible? false :loading? false :amount 2 :img-src nil}]]}
:token-master
{:role 5
:role-text "Token Master"
:satisfied? true
:tokens
[[{:symbol "TMANI"
:sufficient? true
:collectible? true
:loading? false
:amount nil
:img-src (resources/mock-images :collectible1)}]]}
:token-owner
{:role 6
:role-text "Token Owner"
:satisfied? true
:tokens
[[{:symbol "TOANI"
:sufficient? true
:collectible? true
:loading? false
:amount nil
:img-src (resources/mock-images :collectible)}]]}})
(def permissions
{:one-role [(:member roles)]
:two-roles [(:admin roles) (:member roles)]
:three-roles [(:token-master roles) (:admin roles) (:member roles)]
:four-roles [(:token-owner roles) (:token-master roles) (:admin roles) (:member roles)]})
(defn view
[]
(let [state (reagent/atom {:role :one-role})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:blur? @state)
:show-blur-background? true}
[quo/community-detail-token-gating {:permissions ((:role @state) permissions)}]])))

View File

@ -39,6 +39,8 @@
channel-actions] channel-actions]
[status-im.contexts.preview.quo.community.community-card-view :as [status-im.contexts.preview.quo.community.community-card-view :as
community-card] community-card]
[status-im.contexts.preview.quo.community.community-detail-token-gating :as
community-detail-token-gating]
[status-im.contexts.preview.quo.community.community-membership-list-view [status-im.contexts.preview.quo.community.community-membership-list-view
:as community-membership-list-view] :as community-membership-list-view]
[status-im.contexts.preview.quo.community.community-stat :as community-stat] [status-im.contexts.preview.quo.community.community-stat :as community-stat]
@ -260,6 +262,8 @@
:component color/view}] :component color/view}]
:community [{:name :community-card-view :community [{:name :community-card-view
:component community-card/view} :component community-card/view}
{:name :community-detail-token-gating
:component community-detail-token-gating/view}
{:name :community-membership-list-view {:name :community-membership-list-view
:component community-membership-list-view/view} :component community-membership-list-view/view}
{:name :community-stat {:name :community-stat

View File

@ -4,6 +4,7 @@
[legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils] [legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.communities.utils :as utils]
[status-im.subs.chat.utils :as subs.utils] [status-im.subs.chat.utils :as subs.utils]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.money :as money])) [utils.money :as money]))
@ -325,11 +326,12 @@
(let [sym (:symbol criteria) (let [sym (:symbol criteria)
amount-in-wei (:amountInWei criteria) amount-in-wei (:amountInWei criteria)
decimals (:decimals criteria)] decimals (:decimals criteria)]
{:symbol sym {:symbol sym
:sufficient? satisfied :sufficient? satisfied
:loading? checking-permissions? :collectible? (= (:type criteria) constants/community-token-type-erc721)
:amount (money/to-fixed (money/token->unit amount-in-wei decimals)) :loading? checking-permissions?
:img-src (get token-images sym)})) :amount (money/to-fixed (money/token->unit amount-in-wei decimals))
:img-src (get token-images sym)}))
(re-frame/reg-sub (re-frame/reg-sub
:communities/checking-permissions-by-id :communities/checking-permissions-by-id
@ -407,6 +409,7 @@
roles)] roles)]
(mapv (fn [role] (mapv (fn [role]
{:role (:type role) {:role (:type role)
:role-text (i18n/label (utils/role->translation-key (:type role)))
:satisfied? (:satisfied role) :satisfied? (:satisfied role)
:tokens (map (fn [{:keys [tokenRequirement]}] :tokens (map (fn [{:keys [tokenRequirement]}]
(map (map

View File

@ -321,15 +321,17 @@
(swap! rf-db/app-db assoc-in [:communities/permissions-check community-id] checks) (swap! rf-db/app-db assoc-in [:communities/permissions-check community-id] checks)
(is (match? {:can-request-access? true (is (match? {:can-request-access? true
:networks-not-supported? nil :networks-not-supported? nil
:tokens [[{:symbol "DAI" :tokens [[{:symbol "DAI"
:amount "5" :amount "5"
:sufficient? true :collectible? false
:loading? checking-permissions?}] :sufficient? true
[{:symbol "ETH" :loading? checking-permissions?}]
:amount "0.002" [{:symbol "ETH"
:sufficient? false :amount "0.002"
:loading? checking-permissions? :collectible? false
:img-src token-image-eth}]]} :sufficient? false
:loading? checking-permissions?
:img-src token-image-eth}]]}
(rf/sub [sub-name community-id]))))) (rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/community-color (h/deftest-sub :communities/community-color
@ -417,18 +419,20 @@
(match? [{:role 1 (match? [{:role 1
:satisfied? true :satisfied? true
:tokens :tokens
[[{:symbol "ETH" [[{:symbol "ETH"
:sufficient? true :sufficient? true
:loading? false :loading? false
:amount "1" :collectible? false
:img-src token-image-eth}]]} :amount "1"
:img-src token-image-eth}]]}
{:role 2 {:role 2
:satisfied? false :satisfied? false
:tokens [[{:symbol "DAI" :tokens [[{:symbol "DAI"
:sufficient? false :sufficient? false
:loading? false :collectible? false
:amount "10" :loading? false
:img-src nil}]]}] :amount "10"
:img-src nil}]]}]
(rf/sub [sub-name community-id]))))) (rf/sub [sub-name community-id])))))
(testing (testing
"without any visible permissions" "without any visible permissions"