From 98762c74f183d5ed9491eb29e5b5c089ef77f176 Mon Sep 17 00:00:00 2001 From: Ajay Sivan Date: Tue, 16 Apr 2024 21:41:18 +0530 Subject: [PATCH] Community detail token gating component (#19532) --- .../component_spec.cljs | 71 ++++++++++++++++++ .../community_detail_token_gating/style.cljs | 20 +++++ .../community_detail_token_gating/view.cljs | 74 +++++++++++++++++++ .../tags/collectible_tag/schema.cljs | 2 +- .../components/tags/collectible_tag/view.cljs | 13 ++-- src/quo/core.cljs | 2 + src/quo/core_spec.cljs | 1 + .../actions/permissions_sheet/style.cljs | 5 -- .../actions/permissions_sheet/view.cljs | 32 +------- .../community_detail_token_gating.cljs | 68 +++++++++++++++++ src/status_im/contexts/preview/quo/main.cljs | 4 + src/status_im/subs/communities.cljs | 13 ++-- src/status_im/subs/communities_test.cljs | 42 ++++++----- 13 files changed, 282 insertions(+), 65 deletions(-) create mode 100644 src/quo/components/community/community_detail_token_gating/component_spec.cljs create mode 100644 src/quo/components/community/community_detail_token_gating/style.cljs create mode 100644 src/quo/components/community/community_detail_token_gating/view.cljs delete mode 100644 src/status_im/contexts/communities/actions/permissions_sheet/style.cljs create mode 100644 src/status_im/contexts/preview/quo/community/community_detail_token_gating.cljs diff --git a/src/quo/components/community/community_detail_token_gating/component_spec.cljs b/src/quo/components/community/community_detail_token_gating/component_spec.cljs new file mode 100644 index 0000000000..5ce4091985 --- /dev/null +++ b/src/quo/components/community/community_detail_token_gating/component_spec.cljs @@ -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")))) diff --git a/src/quo/components/community/community_detail_token_gating/style.cljs b/src/quo/components/community/community_detail_token_gating/style.cljs new file mode 100644 index 0000000000..c80812d6a3 --- /dev/null +++ b/src/quo/components/community/community_detail_token_gating/style.cljs @@ -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}) diff --git a/src/quo/components/community/community_detail_token_gating/view.cljs b/src/quo/components/community/community_detail_token_gating/view.cljs new file mode 100644 index 0000000000..1db3df9cab --- /dev/null +++ b/src/quo/components/community/community_detail_token_gating/view.cljs @@ -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)]) diff --git a/src/quo/components/tags/collectible_tag/schema.cljs b/src/quo/components/tags/collectible_tag/schema.cljs index efd2e28aea..a2292584fb 100644 --- a/src/quo/components/tags/collectible_tag/schema.cljs +++ b/src/quo/components/tags/collectible_tag/schema.cljs @@ -10,5 +10,5 @@ [:blur? {:optional true} [:maybe :boolean]] [:collectible-img-src :schema.common/image-source] [:collectible-name :string] - [:collectible-id :string]]]] + [:collectible-id {:optional true} [:maybe :string]]]]] :any]) diff --git a/src/quo/components/tags/collectible_tag/view.cljs b/src/quo/components/tags/collectible_tag/view.cljs index 96852903a3..f5059573f0 100644 --- a/src/quo/components/tags/collectible_tag/view.cljs +++ b/src/quo/components/tags/collectible_tag/view.cljs @@ -41,12 +41,13 @@ :weight :medium :style (style/label theme)} collectible-name] - [text/text - {:size :paragraph-2 - :weight :medium - :margin-left 5 - :style (style/label theme)} - collectible-id]]] + (when collectible-id + [text/text + {:size :paragraph-2 + :weight :medium + :margin-left 5 + :style (style/label theme)} + collectible-id])]] (when options [rn/view {:style (style/options-icon size)} [icons/icon (if (= options :hold) :i/hold :i/add-token) diff --git a/src/quo/core.cljs b/src/quo/core.cljs index 1f482a3b36..3b18f28ce0 100644 --- a/src/quo/core.cljs +++ b/src/quo/core.cljs @@ -32,6 +32,7 @@ quo.components.community.channel-action.view quo.components.community.channel-actions.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-stat.view quo.components.community.community-view @@ -224,6 +225,7 @@ ;;;; Community (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 quo.components.community.community-list-view/communities-membership-list-item) (def community-stats-column quo.components.community.community-view/community-stats-column) diff --git a/src/quo/core_spec.cljs b/src/quo/core_spec.cljs index 7ca3f76380..e40b660733 100644 --- a/src/quo/core_spec.cljs +++ b/src/quo/core_spec.cljs @@ -16,6 +16,7 @@ quo.components.calendar.calendar.component-spec quo.components.calendar.calendar.month-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.counter.collectible-counter.component-spec quo.components.counter.counter.component-spec diff --git a/src/status_im/contexts/communities/actions/permissions_sheet/style.cljs b/src/status_im/contexts/communities/actions/permissions_sheet/style.cljs deleted file mode 100644 index 0f2ccda313..0000000000 --- a/src/status_im/contexts/communities/actions/permissions_sheet/style.cljs +++ /dev/null @@ -1,5 +0,0 @@ -(ns status-im.contexts.communities.actions.permissions-sheet.style) - -(def container - {:flex 1 - :padding-horizontal 20}) diff --git a/src/status_im/contexts/communities/actions/permissions_sheet/view.cljs b/src/status_im/contexts/communities/actions/permissions_sheet/view.cljs index 1ed0f42ae1..3b9d1b584b 100644 --- a/src/status_im/contexts/communities/actions/permissions_sheet/view.cljs +++ b/src/status_im/contexts/communities/actions/permissions_sheet/view.cljs @@ -1,38 +1,12 @@ (ns status-im.contexts.communities.actions.permissions-sheet.view (:require [quo.core :as quo] - [react-native.core :as rn] [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])) -(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 [id] (let [permissions (rf/sub [:community/token-permissions id])] - [gesture/scroll-view {:style style/container} - (map permission-view permissions)])) + [gesture/scroll-view + [quo/community-detail-token-gating {:permissions permissions}] + ])) diff --git a/src/status_im/contexts/preview/quo/community/community_detail_token_gating.cljs b/src/status_im/contexts/preview/quo/community/community_detail_token_gating.cljs new file mode 100644 index 0000000000..6b66bdb70e --- /dev/null +++ b/src/status_im/contexts/preview/quo/community/community_detail_token_gating.cljs @@ -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)}]]))) diff --git a/src/status_im/contexts/preview/quo/main.cljs b/src/status_im/contexts/preview/quo/main.cljs index ac3adad20f..247f16de05 100644 --- a/src/status_im/contexts/preview/quo/main.cljs +++ b/src/status_im/contexts/preview/quo/main.cljs @@ -39,6 +39,8 @@ channel-actions] [status-im.contexts.preview.quo.community.community-card-view :as 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 :as community-membership-list-view] [status-im.contexts.preview.quo.community.community-stat :as community-stat] @@ -260,6 +262,8 @@ :component color/view}] :community [{:name :community-card-view :component community-card/view} + {:name :community-detail-token-gating + :component community-detail-token-gating/view} {:name :community-membership-list-view :component community-membership-list-view/view} {:name :community-stat diff --git a/src/status_im/subs/communities.cljs b/src/status_im/subs/communities.cljs index b49282b237..2967f24b76 100644 --- a/src/status_im/subs/communities.cljs +++ b/src/status_im/subs/communities.cljs @@ -4,6 +4,7 @@ [legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils] [re-frame.core :as re-frame] [status-im.constants :as constants] + [status-im.contexts.communities.utils :as utils] [status-im.subs.chat.utils :as subs.utils] [utils.i18n :as i18n] [utils.money :as money])) @@ -325,11 +326,12 @@ (let [sym (:symbol criteria) amount-in-wei (:amountInWei criteria) decimals (:decimals criteria)] - {:symbol sym - :sufficient? satisfied - :loading? checking-permissions? - :amount (money/to-fixed (money/token->unit amount-in-wei decimals)) - :img-src (get token-images sym)})) + {:symbol sym + :sufficient? satisfied + :collectible? (= (:type criteria) constants/community-token-type-erc721) + :loading? checking-permissions? + :amount (money/to-fixed (money/token->unit amount-in-wei decimals)) + :img-src (get token-images sym)})) (re-frame/reg-sub :communities/checking-permissions-by-id @@ -407,6 +409,7 @@ roles)] (mapv (fn [role] {:role (:type role) + :role-text (i18n/label (utils/role->translation-key (:type role))) :satisfied? (:satisfied role) :tokens (map (fn [{:keys [tokenRequirement]}] (map diff --git a/src/status_im/subs/communities_test.cljs b/src/status_im/subs/communities_test.cljs index 75adb05ccb..bea8cb54bc 100644 --- a/src/status_im/subs/communities_test.cljs +++ b/src/status_im/subs/communities_test.cljs @@ -321,15 +321,17 @@ (swap! rf-db/app-db assoc-in [:communities/permissions-check community-id] checks) (is (match? {:can-request-access? true :networks-not-supported? nil - :tokens [[{:symbol "DAI" - :amount "5" - :sufficient? true - :loading? checking-permissions?}] - [{:symbol "ETH" - :amount "0.002" - :sufficient? false - :loading? checking-permissions? - :img-src token-image-eth}]]} + :tokens [[{:symbol "DAI" + :amount "5" + :collectible? false + :sufficient? true + :loading? checking-permissions?}] + [{:symbol "ETH" + :amount "0.002" + :collectible? false + :sufficient? false + :loading? checking-permissions? + :img-src token-image-eth}]]} (rf/sub [sub-name community-id]))))) (h/deftest-sub :communities/community-color @@ -417,18 +419,20 @@ (match? [{:role 1 :satisfied? true :tokens - [[{:symbol "ETH" - :sufficient? true - :loading? false - :amount "1" - :img-src token-image-eth}]]} + [[{:symbol "ETH" + :sufficient? true + :loading? false + :collectible? false + :amount "1" + :img-src token-image-eth}]]} {:role 2 :satisfied? false - :tokens [[{:symbol "DAI" - :sufficient? false - :loading? false - :amount "10" - :img-src nil}]]}] + :tokens [[{:symbol "DAI" + :sufficient? false + :collectible? false + :loading? false + :amount "10" + :img-src nil}]]}] (rf/sub [sub-name community-id]))))) (testing "without any visible permissions"