[#15756] Token gated communities

This commit is contained in:
andrey 2023-04-27 09:53:04 +02:00 committed by Andrea Maria Piana
parent 78621207e1
commit 6858884c83
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
42 changed files with 613 additions and 816 deletions

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
pipeline {
agent { label 'linux' }

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
pipeline {
agent { label params.AGENT_LABEL }

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
pipeline {

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
pipeline {

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
pipeline {

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
pipeline {
agent { label 'macos' }

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
pipeline {
agent { label 'linux' }

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.5'
library 'status-jenkins-lib@v1.7.6'
pipeline {
agent {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -53,8 +53,13 @@
;; @testing-library/react-native.
test-helpers.component]}
:closure-defines
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
status-im2.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
status-im2.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
status-im2.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im2.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"}
:compiler-options {:output-feature-set :es5
:closure-defines
{re-frame.trace/trace-enabled? true}
@ -67,8 +72,13 @@
:chunks {:fleets status-im.fleet.default-fleet/default-fleets}
:release
{:closure-defines
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
status-im2.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
status-im2.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
status-im2.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im2.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"}
:compiler-options {:output-feature-set :es6
;;disable for android build as there
;;is an intermittent warning with deftype
@ -95,8 +105,13 @@
:ui-driven
true
:closure-defines
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
status-im2.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
status-im2.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
status-im2.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im2.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"}
:compiler-options
{;; needed because we override require and it
;; messes with source-map which reports callstack

View File

@ -226,9 +226,8 @@
[_ _]
(let [pressed (reagent/atom false)]
(fn
[{:keys [on-press disabled type size community-color community-text-color before after above
width customization-color
override-theme override-background-color
[{:keys [on-press disabled type size before after above
width customization-color override-theme override-background-color
on-long-press accessibility-label icon icon-no-color style inner-style test-ID]
:or {type :primary
size 40
@ -247,18 +246,13 @@
[rn/touchable-without-feedback
(merge {:test-ID test-ID
:disabled disabled
:accessibility-label accessibility-label}
:accessibility-label accessibility-label
:on-press-in #(reset! pressed true)
:on-press-out #(reset! pressed nil)}
(when on-press
{:on-press (fn []
(on-press))})
{:on-press on-press})
(when on-long-press
{:on-long-press (fn []
(on-long-press))})
{:on-press-in (fn []
(reset! pressed true))}
{:on-press-out (fn []
(reset! pressed nil))})
{:on-long-press on-long-press}))
[rn/view
{:style (merge
(shape-style-container type icon size)
@ -277,11 +271,7 @@
width
before
after)
(when
(community-themed? type community-color)
(merge
{:background-color community-color}
(when (= state :pressed) {:opacity 0.9})))
(when (= state :pressed) {:opacity 0.9})
inner-style)}
(when above
[rn/view
@ -309,12 +299,7 @@
{:size (when (#{56 24} size) :paragraph-2)
:weight :medium
:number-of-lines 1
:style {:color (if
(and
(community-themed? type community-color)
(string? community-text-color))
community-text-color
label-color)}}
:style {:color label-color}}
children]

View File

@ -112,3 +112,39 @@
{:position :absolute
:top 8
:right 8})
(def token-tag-spacing
{:margin-top 10
:margin-right 8})
(defn token-row
[padding?]
(merge
{:flex-direction :row
:flex-wrap :wrap
:align-items :center}
(when padding?
{:padding-horizontal 12})))
(def token-row-container
{:flex-direction :row
:align-items :center
:margin-bottom 12})
(defn token-row-or-text
[padding?]
(merge
{:margin-top 4
:color (colors/theme-colors
colors/neutral-50
colors/neutral-40)}
(when padding?
{:padding-left 12})))
(defn token-row-or-border
[]
{:height 1
:background-color (colors/theme-colors
colors/neutral-20
colors/neutral-80)})

View File

@ -1,295 +1,45 @@
(ns quo2.components.community.token-gating
(:require [quo2.components.avatars.channel-avatar :as channel-avatar]
[quo2.components.buttons.button :as button]
[quo2.components.icon :as icon]
[quo2.components.info.information-box :as information-box]
[quo2.components.markdown.text :as text]
(:require [quo2.components.markdown.text :as text]
[quo2.components.tags.token-tag :as token-tag]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[utils.i18n :as i18n]
[react-native.fast-image :as fast-image]
[react-native.core :as rn]))
(def ^:private token-tag-horizontal-spacing 7)
(def token-tag-vertical-spacing 5)
(def styles
{:container {:flex 1
:padding-horizontal 20}
:header-container {:flex-direction :row
:align-items :center}
:header-spacing-community {:margin-bottom 16}
:header-spacing-channel {:margin-bottom 24}
:header-avatar {:margin-right 8}
:header-community-avatar-image {:width 32 :height 32}
:header-title-container {:flex 1
:flex-direction :row
:align-items :center}
:header-title-lock {:margin-left 6}
:header-info-button {:margin-left 8}
:token-requirement-text-spacing {:margin-vertical 8}
:token-requirement-list-spacing {:padding-vertical (- 8 token-tag-vertical-spacing)}
:token-row {:flex-direction :row
:flex-wrap :wrap
:align-items :center}
:token-row-container {:flex-direction :row
:align-items :center
:margin-horizontal (- token-tag-horizontal-spacing)}
:token-row-container-no-shift {:margin-left 0}
:token-row-or-text {:margin-right 3}
:token-tag-spacing {:margin-horizontal token-tag-horizontal-spacing
:margin-vertical token-tag-vertical-spacing}
:divider {:height 1
:margin-horizontal -20
:margin-top (- 12 token-tag-vertical-spacing)
:margin-bottom 8}
:membership-request-denied {:margin-top 13}
:enter-button {:margin-top 16}
:info-text {:margin-top 12
:text-align :center
:padding-horizontal 20}})
(defn multiple-token-requirements?
[token-requirement-lists]
(when (vector? (first token-requirement-lists))
(> (count token-requirement-lists) 1)))
(defn is-token-requirement-met?
[token-requirement-list]
(and (seq token-requirement-list)
(every?
(fn [token]
(get token :is-sufficient?))
token-requirement-list)))
(defn are-multiple-token-requirements-met?
[token-requirement-lists]
(if (multiple-token-requirements? token-requirement-lists)
(some is-token-requirement-met? token-requirement-lists)
(is-token-requirement-met? token-requirement-lists)))
[clojure.string :as string]
[quo2.components.community.style :as style]))
(defn token-requirement-list-row
[tokens community-color]
[tokens padding?]
[rn/view
{:style (merge
(get styles :token-row)
(get styles :token-requirement-list-spacing))}
(map-indexed (fn [token-index token]
(let [{:keys [token-img-src token amount is-sufficient? is-purchasable?]} token]
^{:key token-index}
[rn/view {:style (get styles :token-tag-spacing)}
[token-tag/token-tag
{:token token
:value amount
:size 24
:border-color community-color
:is-required is-sufficient?
:is-purchasable is-purchasable?
:token-img-src token-img-src}]]))
tokens)])
{:style (style/token-row padding?)}
(doall
(map-indexed (fn [token-index token]
(let [{:keys [img-src symbol amount sufficient? purchasable? loading?]} token]
^{:key token-index}
[rn/view {:style style/token-tag-spacing}
[token-tag/token-tag
{:symbol symbol
:value amount
:size 24
:sufficient? sufficient?
:purchasable purchasable?
:loading? loading?
:img-src img-src}]]))
tokens))])
(defn token-requirement-list
[props community-color]
(let [{:keys [gate token-requirements-changed?
required-tokens-lost?]} props
[gate-type token-requirement-lists] gate
multiple-token-requirements? (multiple-token-requirements? token-requirement-lists)
is-sufficient? (are-multiple-token-requirements-met?
token-requirement-lists)
you-must-hold-label (if (= gate-type :join)
(cond
token-requirements-changed? :t/you-must-now-hold
required-tokens-lost? :t/you-must-always-hold
:else :t/you-must-hold)
:t/you-must-hold)
message-label (cond
(= gate-type :join)
(cond
token-requirements-changed?
:t/community-join-requirements-changed
required-tokens-lost?
:t/community-join-requirements-tokens-lost
:else (if is-sufficient?
:t/community-join-requirements-met
:t/community-join-requirements-not-met))
(= gate-type :read)
(if is-sufficient?
:t/community-channel-read-requirements-met
:t/community-channel-read-requirements-not-met)
(= gate-type :write)
(if is-sufficient?
:t/community-channel-write-requirements-met
:t/community-channel-write-requirements-not-met))]
[rn/view
[rn/view {:style (get styles :token-requirement-text-spacing)}
[text/text
{:weight :medium
:number-of-lines 1}
(i18n/label
message-label)]
[text/text
{:size :paragraph-2
:number-of-lines 1}
(i18n/label
you-must-hold-label)]]
(if multiple-token-requirements?
(map-indexed
(fn [token-requirement-index tokens]
^{:key token-requirement-index}
[rn/view
{:style (merge
(get styles :token-row-container)
(when-not (= token-requirement-index 0)
(get styles :token-row-container-no-shift)))}
(when-not (= token-requirement-index 0)
[text/text
{:style (get styles :token-row-or-text)
:size :paragraph-2} "or"])
[token-requirement-list-row tokens community-color]])
token-requirement-lists)
[rn/view {:style (get styles :token-row-container)}
[token-requirement-list-row token-requirement-lists community-color]])]))
(defn is-community-locked?
[community]
(not (are-multiple-token-requirements-met? (get-in community [:gates :join]))))
(defn is-channel-locked?
[channel]
(not (are-multiple-token-requirements-met?
(or (get-in channel [:gates :read])
(get-in channel [:gates :write])))))
(defn token-gating
"[token-gating opts]
opts
{
:community {
:name string
:community-avatar-img-src string
:community-color string
:community-text-color string
:token-requirements-changed? boolean
:required-tokens-lost? boolean
}
:channel {
:name string
:emoji string
:emoji-background-color :string
:on-enter-channel callback
:membership-request-denied? boolean
}
}"
[_ _]
(fn [{:keys [community channel]}]
(let [type (if (some? community) :community :channel)
{:keys [name
emoji
emoji-background-color
on-enter-channel
community-avatar-img-src
community-color
community-text-color
membership-request-denied?
token-requirements-changed?
required-tokens-lost?
gates]}
(if (= type :community) community channel)
locked? (if
(= type :community)
(is-community-locked? community)
(is-channel-locked? channel))]
[rn/view
{:style (merge (get styles :container)
{:background-color (colors/theme-colors colors/white colors/neutral-90)})}
[rn/view
{:style (merge
(get styles :header-container)
(if
(= type :community)
(get styles :header-spacing-community)
(get styles :header-spacing-channel)))}
[rn/view {:style (get styles :header-avatar)}
(if (= type :community)
[fast-image/fast-image
{:source community-avatar-img-src
:style (get styles :header-community-avatar-image)}]
[channel-avatar/channel-avatar
{:big? true
:locked? locked?
:emoji emoji
:emoji-background-color emoji-background-color}])]
[rn/view {:style (get styles :header-title-container)}
[text/text
{:weight :semi-bold
:number-of-lines 1
:size :heading-1
:style (get styles :header-text)} (if (= type :community) name (str "# " name))]
(when (= type :community)
[icon/icon
(if locked?
:main-icons2/locked
:main-icons2/unlocked)
{:container-style (get styles :header-title-lock)
:color (colors/theme-colors
colors/neutral-50
colors/neutral-40)}])]
[button/button
{:type :outline
:size 32
:icon true
:style (get styles :header-info-button)} :main-icons2/info]]
(map-indexed (fn [gate-index gate]
^{:key gate-index}
[:<>
(when-not (= gate-index 0)
[rn/view
{:style (merge
(get styles :divider)
{:background-color (colors/theme-colors
colors/neutral-10
colors/neutral-80)})}])
[token-requirement-list
{:gate gate
:token-requirements-changed? token-requirements-changed?
:required-tokens-lost? required-tokens-lost?} community-color]])
gates)
(when (= type :channel)
(if membership-request-denied?
[information-box/information-box
{:type :error
:icon :main-icons2/untrustworthy
:no-icon-color? true
:style (get styles :membership-request-denied)}
(i18n/label
:t/membership-request-denied)]
[:<>
[button/button
{:type :community
:community-color community-color
:community-text-color community-text-color
:style (get styles :enter-button)
:disabled locked?
:on-press on-enter-channel}
(str "# "
(i18n/label
:t/enter-channel))]
[{:keys [tokens padding?]}]
[:<>
(if (> (count tokens) 1)
(doall
(map-indexed
(fn [token-requirement-index tokens]
^{:key token-requirement-index}
[rn/view {:margin-bottom 12}
(when-not (= token-requirement-index 0)
[rn/view {:style (style/token-row-or-border)}])
(when-not (= token-requirement-index 0)
[text/text
{:size :paragraph-2
:style (merge
(get styles :info-text)
{:color (colors/theme-colors
colors/neutral-50
colors/neutral-40)})}
(i18n/label
:t/community-enter-channel-info)]]))])))
{:style (style/token-row-or-text padding?)
:size :label} (string/lower-case (i18n/label :t/or))])
[token-requirement-list-row tokens padding?]])
tokens))
[token-requirement-list-row (first tokens) padding?])])

View File

@ -20,6 +20,7 @@
(def context-tag-text-container
{:align-items :center
:margin-left 4
:flex-direction :row})
(def audio-tag-container

View File

@ -47,23 +47,24 @@
empty-photo? (empty? photo)
avatar-size :xxs
avatar-outer-size (get-in user-avatar-style/sizes [avatar-size :outer])]
[base-tag (assoc-in params [:style :padding-left] 3)
(if (and empty-photo? no-avatar-placeholder?)
[rn/view {:style {:width avatar-outer-size}}]
[user-avatar/user-avatar
{:full-name name
:profile-picture photo
:size avatar-size
:status-indicator? false}])
[rn/view {:style style/context-tag-text-container}
[text/text text-params (str " " name)]
(when channel-name
[:<>
[icons/icon
:i/chevron-right
{:color (style/context-tag-icon-color blur?)
:size 16}]
[text/text text-params (str "# " channel-name)]])]]))
[rn/view {:flex-direction :row}
[base-tag (assoc-in params [:style :padding-left] 3)
(if (and empty-photo? no-avatar-placeholder?)
[rn/view {:style {:width avatar-outer-size}}]
[user-avatar/user-avatar
{:full-name name
:profile-picture photo
:size avatar-size
:status-indicator? false}])
[rn/view {:style style/context-tag-text-container}
[text/text text-params (str " " name)]
(when channel-name
[:<>
[icons/icon
:i/chevron-right
{:color (style/context-tag-icon-color blur?)
:size 16}]
[text/text text-params (str "# " channel-name)]])]]]))
(defn user-avatar-tag
[params username photo]

View File

@ -39,8 +39,9 @@
:overlay child-elements
}"
[_ _]
(fn [{:keys [size token-img-src token-img-style border-color overlay]
:or {size :small}} label]
(fn [{:keys [size img-src img-style border-color overlay]
:or {size :small}}
label]
[rn/view
{:style (when border-color
{:border-color border-color
@ -49,13 +50,13 @@
[rn/view
{:style (merge (tag-container size) (get themes (theme/get-theme)))}
[rn/image
{:source token-img-src
:style (merge
{:height (get-value-from-size size 28 20)
:width (get-value-from-size size 28 20)
:margin-left 2
:margin-right (get-value-from-size size 8 6)}
token-img-style)}]
{:src img-src
:style (merge
{:height (get-value-from-size size 28 20)
:width (get-value-from-size size 28 20)
:margin-left 2
:margin-right (get-value-from-size size 8 6)}
img-style)}]
[text/text
{:weight :medium
:number-of-lines 1
@ -64,38 +65,58 @@
:size (get-value-from-size size :paragraph-2 :label)} label]
overlay]]))
(defn loading-icon
[]
[rn/view
{:style {:align-items :center
:justify-content :center
:position :absolute
:right -8
:top -8}}
[icons/icon :t/checktoken
{:no-color true
:size 20}]])
(defn icon
[size border-color sufficient?]
[rn/view
{:style (merge
icon-container-styles
{:background-color border-color
:border-color (if (= (theme/get-theme) :dark) colors/neutral-100 colors/white)
:border-width 1
:right (get-value-from-size size -3.75 -5.75)
:bottom (get-value-from-size size (- 32 7.75 4) (- 24 7.75 2))})}
[icons/icon (if sufficient? :i/hold :i/add)
{:no-color true
:size 12}]])
(defn token-tag
"[token-tag opts]
opts
{
:token string
:symbol string
:value string
:size :small/:big
:token-img-src :token-img-src
:border-color :color
:is-required true/false
:is-purchasable true/false
:sufficient? true/false
:purchasable? true/false
:loading? true/false
}"
[_ _]
(fn [{:keys [token value size token-img-src border-color is-required is-purchasable]
(fn [{:keys [symbol value size img-src border-color purchasable? sufficient? loading?]
:or
{size :small border-color (colors/custom-color-by-theme :purple 50 60)}}]
[tag
{:size size
:token-img-src token-img-src
:border-color (when is-required border-color)
:overlay
(when (or is-required is-purchasable)
[rn/view
{:style (merge
icon-container-styles
{:background-color border-color
:border-color (if (= (theme/get-theme) :dark) colors/neutral-100 colors/white)
:border-width 1
:right (get-value-from-size size -3.75 -5.75)
:bottom (get-value-from-size size (- 32 7.75 4) (- 24 7.75 2))})}
[icons/icon (if is-required :i/hold :i/add)
{:no-color true
:size 12}]])}
(str value " " token)]))
{size :small}}]
(let [sufficient? (when-not loading? sufficient?)
border-color (if sufficient? colors/success-50 border-color)]
[tag
{:size size
:img-src img-src
:border-color (if sufficient? colors/success-50 border-color)
:overlay
(if loading?
[loading-icon]
(when (or purchasable? sufficient?)
[icon size border-color sufficient?]))}
(str value " " symbol)])))

View File

@ -145,8 +145,8 @@
(def community-title quo2.components.community.community-view/community-title)
(def permission-tag-container quo2.components.community.community-view/permission-tag-container)
(def discover-card quo2.components.community.banner.view/view)
(def token-gating quo2.components.community.token-gating/token-gating)
(def community-icon quo2.components.community.icon/community-icon)
(def token-requirement-list quo2.components.community.token-gating/token-requirement-list)
;;;; COUNTER
(def counter quo2.components.counter.counter/counter)

View File

@ -74,13 +74,19 @@
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?
:adminSettings :admin-settings})
:adminSettings :admin-settings
:tokenPermissions :token-permissions
:communityTokensMetadata :tokens-metadata})
(update :admin-settings
set/rename-keys
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
(update :members walk/stringify-keys)
(update :chats <-chats-rpc)
(update :categories <-categories-rpc)))
(update :categories <-categories-rpc)
(assoc :token-images
(reduce (fn [acc {:keys [symbol image]}] (assoc acc symbol image))
{}
(:communityTokensMetadata c)))))
(defn- fetch-community-id-input
[{:keys [db]}]
@ -174,6 +180,7 @@
(let [community-name (aget response-js "communities" 0 "name")]
(rf/merge cofx
(handle-response cofx response-js)
(navigation/hide-bottom-sheet)
(toasts/upsert {:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label
@ -215,14 +222,12 @@
(rf/defn join
{:events [:communities/join]}
[cofx community-id]
[_ community-id]
{:json-rpc/call [{:method "wakuext_joinCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::joined %])
:on-error #(do
(log/error "failed to join community" community-id %)
(re-frame/dispatch [::failed-to-join %]))}]})
:on-error #(log/error "failed to join community" community-id %)}]})
(rf/defn request-to-join
{:events [:communities/request-to-join]}
@ -231,9 +236,24 @@
:params [{:communityId community-id}]
:js-response true
:on-success #(re-frame/dispatch [:communities/requested-to-join %])
:on-error (fn []
(log/error "failed to request to join community" community-id)
(re-frame/dispatch [::failed-to-request-to-join]))}]})
:on-error #(log/error "failed to request to join community" community-id)}]})
(rf/defn requested-to-join-with-password-error
{:events [:communities/requested-to-join-with-password-error]}
[{:keys [db]} error]
{:db (assoc-in db [:password-authentication :error] error)})
(rf/defn request-to-join-with-password
{:events [:communities/request-to-join-with-password]}
[_ community-id password]
{:json-rpc/call [{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id :password password}]
:js-response true
:on-success #(re-frame/dispatch [:communities/requested-to-join %])
:on-error (fn [error]
(log/error "failed to request to join community" community-id error)
(re-frame/dispatch [:communities/requested-to-join-with-password-error
error]))}]})
(rf/defn get-user-requests-to-join
{:events [:communities/get-user-requests-to-join]}

View File

@ -1,77 +0,0 @@
(ns status-im.ui.screens.communities.requests-to-join
(:require [quo.components.animated.pressable :as animation]
[quo.core :as quo]
[quo.design-system.colors :as colors]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.communities.core :as communities]
[utils.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react]
[status-im.ui.components.topbar :as topbar]
[utils.re-frame :as rf]))
(defn request-actions
[community-id request-id]
[react/view {:flex-direction :row}
[animation/pressable
{:on-press #(re-frame/dispatch [:communities.ui/accept-request-to-join-pressed community-id
request-id])}
[icons/icon :main-icons/checkmark-circle
{:width 35
:height 35
:color colors/green}]]
[animation/pressable
{:on-press #(re-frame/dispatch [:communities.ui/decline-request-to-join-pressed community-id
request-id])}
[icons/icon :main-icons/cancel
{:width 35
:height 35
:container-style {:margin-left 16}
:color colors/red}]]])
(defn render-request
[{:keys [id public-key]} _ _
{:keys [community-id
can-manage-users?]}]
(let [member (or (rf/sub [:contacts/contact-by-identity public-key])
{:public-key public-key})]
[quo/list-item
{:title (multiaccounts/displayed-name member)
:accessibility-label :member-item
:accessory-style (when can-manage-users?
{:flex-basis 120})
:accessory (when can-manage-users?
[request-actions community-id id])
:icon [chat-icon/contact-icon-contacts-tab member]
:on-press #(re-frame/dispatch [:chat.ui/show-profile public-key])}]))
(defn requests-to-join
[]
(let [{:keys [community-id]} (rf/sub [:get-screen-params])]
(fn []
(let [requests (rf/sub [:communities/requests-to-join-for-community
community-id])
{:keys [can-manage-users?]} (rf/sub [:communities/community community-id])]
[:<>
[topbar/topbar
{:title (i18n/label :t/community-requests-to-join-title)
:subtitle (str (count requests))}]
[rn/flat-list
{:data requests
:render-data {:community-id community-id
:can-manage-users? can-manage-users?}
:key-fn :id
:render-fn render-request}]]))))
(defn requests-to-join-container
[]
(reagent/create-class
{:display-name "community-requests-to-join-view"
:component-did-mount (fn []
(communities/fetch-requests-to-join! (get (rf/sub [:get-screen-params])
:community-id)))
:reagent-render requests-to-join}))

View File

@ -26,7 +26,6 @@
[status-im.ui.screens.communities.membership :as membership]
[status-im.ui.screens.communities.profile :as community.profile]
[status-im.ui.screens.communities.reorder-categories :as reorder-categories]
[status-im.ui.screens.communities.requests-to-join :as requests-to-join]
[status-im.ui.screens.communities.select-category :as select-category]
[status-im.ui.screens.contacts-list.views :as contacts-list]
[status-im.ui.screens.currency-settings.views :as currency-settings]
@ -229,10 +228,6 @@
;;TODO custom subtitle
:options {:insets {:top? true}}
:component members/members-container}
{:name :community-requests-to-join
;;TODO custom subtitle
:options {:insets {:top? true}}
:component requests-to-join/requests-to-join-container}
{:name :create-community-channel
:options {:topBar {:title {:text (i18n/label :t/create-channel-title)}}
:insets {:bottom? true

View File

@ -0,0 +1,12 @@
(ns status-im2.common.password-authentication.events
(:require [utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]))
(rf/defn close
{:events [:password-authentication/show]}
[{:keys [db]} content button]
(rf/merge {:db (assoc db
:password-authentication
{:error nil
:button button})}
(navigation/show-bottom-sheet content)))

View File

@ -0,0 +1,41 @@
(ns status-im2.common.password-authentication.view
(:require [react-native.core :as rn]
[quo2.core :as quo]
[utils.re-frame :as rf]
[status-im.multiaccounts.core :as multiaccounts]
[utils.i18n :as i18n]
[status-im.ethereum.core :as ethereum]
[reagent.core :as reagent]))
(defn view
[]
(let [entered-password (reagent/atom "")]
(fn []
(let [account (rf/sub [:profile/multiaccount])
{:keys [error button]} (rf/sub [:password-authentication])]
[rn/view {:padding-horizontal 20}
[quo/text {:size :heading-1 :weight :semi-bold}
(i18n/label :t/enter-password)]
[quo/user-avatar-tag
{:size :small
:style {:margin-top 8 :margin-bottom 20}}
(multiaccounts/displayed-name account)
(multiaccounts/displayed-photo account)]
[quo/input
{:type :password
:label (i18n/label :t/profile-password)
:placeholder (i18n/label :t/type-your-password)
:error? (when (not-empty error) error)
:auto-focus true
:on-change-text #(reset! entered-password %)}]
(when (not-empty error)
[quo/info-message
{:type :error
:size :default
:icon :i/info
:style {:margin-top 8}}
(i18n/label :t/oops-wrong-password)])
[quo/button
{:style {:margin-bottom 12 :margin-top 40}
:on-press #((:on-press button) (ethereum/sha3 @entered-password))}
(:label button)]]))))

View File

@ -8,7 +8,12 @@
(defn enabled? [v] (= "1" v))
(goog-define INFURA_TOKEN "")
(goog-define POKT_TOKEN "3ef2018191814b7e1009b8d9")
(goog-define ALCHEMY_ARBITRUM_GOERLI_TOKEN "")
(goog-define ALCHEMY_OPTIMISM_GOERLI_TOKEN "")
(goog-define ALCHEMY_OPTIMISM_MAINNET_TOKEN "")
(goog-define ALCHEMY_ARBITRUM_MAINNET_TOKEN "")
(goog-define OPENSEA_API_KEY "")
(def mainnet-rpc-url (str "https://eth-archival.gateway.pokt.network/v1/lb/" POKT_TOKEN))

View File

@ -37,8 +37,8 @@
(h/test "joined options - Token Gated"
(setup-subs {:communities/my-pending-request-to-join nil
:communities/community {:joined true
:token-gated? true}})
:communities/community {:joined true
:token-permissions []}})
(h/render [options/community-options-bottom-sheet {:id "test"}])
(-> (h/expect (h/get-by-translation-text :view-members))
(.toBeTruthy))
@ -86,8 +86,8 @@
(h/test "admin options - Token Gated"
(setup-subs {:communities/my-pending-request-to-join nil
:communities/community {:admin true
:token-gated? true}})
:communities/community {:admin true
:token-permissions []}})
(h/render [options/community-options-bottom-sheet {:id "test"}])
(-> (h/expect (h/get-by-translation-text :view-members))
(.toBeTruthy))
@ -127,7 +127,7 @@
(h/test "request sent options - Token Gated"
(setup-subs {:communities/my-pending-request-to-join "mock-id"
:communities/community {:token-gated? true}})
:communities/community {:token-permissions []}})
(h/render [options/community-options-bottom-sheet {:id "test"}])
(-> (h/expect (h/get-by-translation-text :invite-people-from-contacts))
(.toBeTruthy))
@ -157,8 +157,8 @@
(h/test "banned options - Token Gated"
(setup-subs {:communities/my-pending-request-to-join nil
:communities/community {:banList 100
:token-gated? true}})
:communities/community {:banList 100
:token-permissions []}})
(h/render [options/community-options-bottom-sheet {:id "test"}])
(-> (h/expect (h/get-by-translation-text :invite-people-from-contacts))
(.toBeTruthy))
@ -171,8 +171,8 @@
(h/test "banned options - Token Gated"
(setup-subs {:communities/my-pending-request-to-join nil
:communities/community {:banList 100
:token-gated? true}})
:communities/community {:banList 100
:token-permissions []}})
(h/render [options/community-options-bottom-sheet {:id "test"}])
(-> (h/expect (h/get-by-translation-text :invite-people-from-contacts))
(.toBeTruthy))
@ -185,11 +185,9 @@
(h/test "joined and muted community"
(setup-subs {:communities/my-pending-request-to-join nil
:communities/community {:joined true
:muted true
:token-gated? true}})
:communities/community {:joined true
:muted true
:token-permissions []}})
(h/render [options/community-options-bottom-sheet {:id "test"}])
(-> (h/expect (h/get-by-translation-text :unmute-community))
(.toBeTruthy))))

View File

@ -3,7 +3,8 @@
[utils.re-frame :as rf]
[quo2.core :as quo]
[status-im2.contexts.communities.actions.see-rules.view :as see-rules]
[status-im2.contexts.communities.actions.leave.view :as leave-menu]))
[status-im2.contexts.communities.actions.leave.view :as leave-menu]
[status-im2.contexts.communities.actions.token-gating.view :as token-gating]))
(defn hide-sheet-and-dispatch
[event]
@ -29,10 +30,11 @@
(defn view-token-gating
[id]
{:icon :i/bullet-list
:right-icon :i/token
{:icon :i/token
:right-icon :i/chevron-right
:accessibility-label :view-token-gating
:on-press #(js/alert (str "implement action" id))
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [token-gating/token-requirements id])}])
:label (i18n/label :t/view-token-gating)})
(defn mark-as-read
@ -152,15 +154,15 @@
(defn get-context-drawers
[{:keys [id]}]
(let [{:keys [token-gated? admin joined
(let [{:keys [token-permissions admin joined
muted banList]} (rf/sub [:communities/community id])
request-id (rf/sub [:communities/my-pending-request-to-join id])]
(cond
admin (owner-options id token-gated? muted)
joined (joined-options id token-gated? muted)
request-id (join-request-sent-options id token-gated? request-id)
banList (banned-options id token-gated?)
:else (not-joined-options id token-gated?))))
admin (owner-options id token-permissions muted)
joined (joined-options id token-permissions muted)
request-id (join-request-sent-options id token-permissions request-id)
banList (banned-options id token-permissions)
:else (not-joined-options id token-permissions))))
(defn community-options-bottom-sheet
[id]

View File

@ -0,0 +1,23 @@
(ns status-im2.contexts.communities.actions.token-gating.view
(:require [quo2.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[react-native.core :as rn]))
(defn token-requirements
[id]
(rf/dispatch [:communities/check-permissions-to-join-community id])
(fn []
(let [{:keys [can-request-access?
number-of-hold-tokens tokens]} (rf/sub [:community/token-gated-overview id])]
[rn/view {:style {:padding-horizontal 12}}
[quo/text {:weight :medium}
(if can-request-access?
(i18n/label :t/you-eligible-to-join)
(i18n/label :t/you-not-eligible-to-join))]
[quo/text {:style {:padding-bottom 18} :size :paragraph-2}
(if can-request-access?
(i18n/label :t/you-hold-number-of-hold-tokens-of-these
{:number-of-hold-tokens number-of-hold-tokens})
(i18n/label :t/you-must-hold))]
[quo/token-requirement-list {:tokens tokens}]])))

View File

@ -0,0 +1,22 @@
(ns status-im2.contexts.communities.overview.events
(:require [utils.re-frame :as rf]
[taoensso.timbre :as log]))
(rf/defn check-permissions-to-join-community-success
{:events [:communities/check-permissions-to-join-community-success]}
[{:keys [db]} community-id result]
{:db (-> db
(assoc-in [:communities community-id :checking-permissions?] false)
(assoc-in [:communities community-id :token-permissions-check] result))})
(rf/defn check-permissions-to-join-community
{:events [:communities/check-permissions-to-join-community]}
[{:keys [db]} community-id]
{:db (-> db
(assoc-in [:communities community-id :checking-permissions?] true)
(assoc-in [:communities community-id :can-request-access?] false))
:json-rpc/call [{:method "wakuext_checkPermissionsToJoinCommunity"
:params [{:communityId community-id}]
:on-success #(rf/dispatch [:communities/check-permissions-to-join-community-success
community-id %])
:on-error #(log/error "failed to request to join community" community-id %)}]})

View File

@ -32,3 +32,10 @@
:left 0
:right 0
:bottom 0})
(defn token-gated-container
[]
{:border-radius 16
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80)
:border-width 1
:padding-top 10})

View File

@ -13,47 +13,23 @@
[status-im2.contexts.communities.actions.community-options.view :as options]
[quo2.components.navigation.floating-shell-button :as floating-shell-button]
[status-im2.contexts.communities.overview.utils :as utils]
[status-im2.common.password-authentication.view :as password-authentication]
[utils.re-frame :as rf]))
(defn preview-user-list
[user-list]
[rn/view style/preview-user
[quo/preview-list
{:type :user
:list-size (count user-list)
:size 24}
user-list]
[quo/text
{:accessibility-label :communities-screen-title
:style {:margin-left 8}
:size :label}
(utils/join-existing-users-string user-list)]])
(defn channel-token-gating-details
[name token-gating emoji channel-color]
[rn/view {:height 350 :margin-top 20}
[quo/token-gating
{:channel {:name name
:community-color channel-color
:emoji emoji
:emoji-background-color channel-color
:on-enter-channel (fn []
(js/alert
"Entered channel"
"Wuhuu!! You successfully entered the channel :)"))
:gates token-gating}}]])
(defn open-channel-token-gating-details
[name token-gating emoji channel-color]
(rf/dispatch
[:show-bottom-sheet
{:content
(fn []
[channel-token-gating-details name token-gating emoji channel-color])}]))
(defn layout-y
[event]
(oops/oget event "nativeEvent.layout.y"))
(when (seq user-list)
[rn/view style/preview-user
[quo/preview-list
{:type :user
:list-size (count user-list)
:size 24}
user-list]
[quo/text
{:accessibility-label :communities-screen-title
:style {:margin-left 8}
:size :label}
(utils/join-existing-users-string user-list)]]))
(defn add-category-height
[categories-heights category height]
@ -65,17 +41,18 @@
[community-id category-id collapsed?]
(rf/dispatch [:communities/toggle-collapsed-category community-id category-id (not collapsed?)]))
(defn layout-y
[event]
(oops/oget event "nativeEvent.layout.y"))
(defn channel-list-component
[{:keys [on-category-layout
community-id
on-first-channel-height-changed]}
[{:keys [on-category-layout community-id on-first-channel-height-changed]}
channels-list]
[rn/view
{:on-layout #(on-first-channel-height-changed (+ (if platform/ios?
0
38)
(int (Math/ceil (layout-y %))))
(into #{} (map (comp :name second) channels-list)))
{:on-layout #(on-first-channel-height-changed
(+ (if platform/ios? 0 38)
(int (Math/ceil (layout-y %))))
(into #{} (map (comp :name second) channels-list)))
:style {:margin-top 20 :flex 1}}
(map
(fn [[category-id {:keys [chats name collapsed?]}]]
@ -123,10 +100,68 @@
constants/community-on-request-access :request-access
:unknown-access))
(defn join-gated-community
[id]
(rf/dispatch [:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/join-open-community)
:on-press #(rf/dispatch [:communities/request-to-join-with-password id %])}]))
(defn info-button
[]
[rn/touchable-without-feedback
{:on-press
#(rf/dispatch
[:show-bottom-sheet
{:content
(fn []
[quo/documentation-drawers
{:title (i18n/label :t/token-gated-communities)
:show-button? true
:button-label (i18n/label :t/read-more)
:button-icon :info}
[quo/text (i18n/label :t/token-gated-communities-info)]])}])}
[rn/view
[quo/icon :i/info {:no-color true}]]])
(defn token-gates
[{:keys [id]}]
(rf/dispatch [:communities/check-permissions-to-join-community id])
(fn [{:keys [id community-color]}]
(let [{:keys [can-request-access?
number-of-hold-tokens tokens]} (rf/sub [:community/token-gated-overview id])]
[rn/view {:style (style/token-gated-container)}
[rn/view
{:style {:padding-horizontal 12
:flex-direction :row
:align-items :center
:justify-content :space-between
:flex 1}}
[quo/text {:weight :medium}
(if can-request-access?
(i18n/label :t/you-eligible-to-join)
(i18n/label :t/you-not-eligible-to-join))]
[info-button]]
[quo/text {:style {:padding-horizontal 12 :padding-bottom 18} :size :paragraph-2}
(if can-request-access?
(i18n/label :t/you-hold-number-of-hold-tokens-of-these
{:number-of-hold-tokens number-of-hold-tokens})
(i18n/label :t/you-must-hold))]
[quo/token-requirement-list
{:tokens tokens
:padding? true}]
[quo/button
{:on-press #(join-gated-community id)
:accessibility-label :join-community-button
:override-background-color community-color
:style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
:disabled (not can-request-access?)
:before (if can-request-access? :i/unlocked :i/locked)}
(i18n/label :t/join-open-community)]])))
(defn join-community
[{:keys [joined can-join?
community-color permissions]
:as community} pending?]
[{:keys [joined can-join? community-color permissions token-permissions] :as community}
pending?]
(let [access-type (get-access-type (:access permissions))
unknown-access? (= access-type :unknown-access)
invite-only? (= access-type :invite-only)
@ -134,15 +169,16 @@
node-offline? (and can-join? (not joined) pending?)]
[:<>
(when-not (or joined pending? invite-only? unknown-access?)
[quo/button
{:on-press #(rf/dispatch [:open-modal :community-requests-to-join community])
:accessibility-label :show-request-to-join-screen-button
:override-background-color community-color
:style style/join-button
:before :i/communities}
(request-to-join-text is-open?)])
(if token-permissions
[token-gates community]
[quo/button
{:on-press #(rf/dispatch [:open-modal :community-requests-to-join community])
:accessibility-label :show-request-to-join-screen-button
:override-background-color community-color
:before :i/communities}
(request-to-join-text is-open?)]))
(when (and (not (or joined pending?)) (not (or is-open? node-offline?)))
(when (and (not (or joined pending? token-permissions)) (not (or is-open? node-offline?)))
[quo/text
{:size :paragraph-2
:style style/review-notice}
@ -155,38 +191,24 @@
:style {:margin-top 12}}
(i18n/label :t/request-processed-after-node-online)])]))
(defn get-tag
[joined]
[quo/status-tag
{:status {:type (if joined :positive :pending)}
:label (if joined
(i18n/label :t/joined)
(i18n/label :t/pending))}])
(defn community-token-gating-details
[name thumbnail-image tokens]
[rn/view {:height 200 :margin-top 20}
[quo/token-gating
{:community {:name name
:community-color colors/primary-50
:community-avatar-img-src thumbnail-image
:gates tokens}}]])
(defn status-tag
[pending? joined]
(when (or pending? joined)
[rn/view {:position :absolute :top 12 :right 12}
[quo/status-tag
{:status {:type (if joined :positive :pending)}
:label (if joined
(i18n/label :t/joined)
(i18n/label :t/pending))}]]))
(defn add-on-press-handler
[community-id {:keys [name emoji id locked? token-gating] :or {locked? false} :as chat}]
[community-id {:keys [id locked?] :or {locked? false} :as chat}]
(merge
chat
(if (and locked? token-gating)
{:on-press #(open-channel-token-gating-details
name
token-gating
emoji
(colors/custom-color :pink 50))}
(when (and (not locked?) id)
{:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:chat/navigate-to-chat (str community-id id)]))}))))
(when (and (not locked?) id)
{:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:chat/navigate-to-chat (str community-id id)]))})))
(defn add-on-press-handler-to-chats
[community-id chats]
@ -206,7 +228,8 @@
:number-of-lines 1
:ellipsize-mode :tail
:weight :semi-bold
:size :heading-1}
:size :heading-1
:style {:margin-top 56}}
name])
(defn community-description
@ -221,49 +244,20 @@
description])
(defn community-content
[{:keys [name description locked joined images
status tokens tags id]
[{:keys [name description joined tags id]
:as community}
pending?
{:keys [on-category-layout
on-first-channel-height-changed]}]
(let [thumbnail-image (:thumbnail images)
chats-by-category (rf/sub [:communities/categorized-channels id])
users (rf/sub [:communities/users id])]
[rn/view
{:keys [on-category-layout on-first-channel-height-changed]}]
(let [chats-by-category (rf/sub [:communities/categorized-channels id])]
[:<>
[rn/view {:padding-horizontal 20}
(when (and (not joined)
(not pending?)
(= status :gated))
[rn/view
{:position :absolute
:top 8
:right 8}
[quo/permission-tag-container
{:locked locked
:status status
:tokens tokens
:on-press #(rf/dispatch
[:show-bottom-sheet
{:content
(fn []
[community-token-gating-details
name
thumbnail-image
tokens])}])}]])
(when (or pending? joined)
[rn/view
{:position :absolute
:top 12
:right 12}
[get-tag joined]])
[rn/view {:margin-top 56}
[community-header name]]
[status-tag pending? joined]
[community-header name]
[community-description description]
[quo/community-stats-column :card-view]
;; [quo/community-stats-column :card-view] not implemented
[rn/view {:margin-top 12}]
[quo/community-tags tags]
[preview-user-list users]
;;[preview-user-list users] not implemented
[join-community community pending?]]
[channel-list-component
{:on-category-layout on-category-layout

View File

@ -79,29 +79,38 @@
effect (if seed-phrase
:multiaccount/restore-account-and-login
:multiaccount/create-account-and-login)
request {:displayName display-name
:password (ethereum/sha3 (security/safe-unmask-data password))
:mnemonic (when seed-phrase
(security/safe-unmask-data seed-phrase))
:imagePath (strip-file-prefix image-path)
:customizationColor color
:backupDisabledDataDir (native-module/backup-disabled-data-dir)
:rootKeystoreDir (native-module/keystore-dir)
request {:displayName display-name
:password (ethereum/sha3 (security/safe-unmask-data
password))
:mnemonic (when seed-phrase
(security/safe-unmask-data seed-phrase))
:imagePath (strip-file-prefix image-path)
:customizationColor color
:backupDisabledDataDir (native-module/backup-disabled-data-dir)
:rootKeystoreDir (native-module/keystore-dir)
;; Temporary fix until https://github.com/status-im/status-go/issues/3024 is
;; resolved
:wakuV2Nameserver "1.1.1.1"
:logLevel (when log-enabled? config/log-level)
:logEnabled log-enabled?
:logFilePath (native-module/log-file-directory)
:openseaAPIKey config/opensea-api-key
:verifyTransactionURL config/verify-transaction-url
:verifyENSURL config/verify-ens-url
:verifyENSContractAddress config/verify-ens-contract-address
:verifyTransactionChainID config/verify-transaction-chain-id
:upstreamConfig config/default-network-rpc-url
:networkId config/default-network-id
:currentNetwork config/default-network
:previewPrivacy config/blank-preview?}]
:wakuV2Nameserver "1.1.1.1"
:logLevel (when log-enabled? config/log-level)
:logEnabled log-enabled?
:logFilePath (native-module/log-file-directory)
:openseaAPIKey config/opensea-api-key
:verifyTransactionURL config/verify-transaction-url
:verifyENSURL config/verify-ens-url
:verifyENSContractAddress config/verify-ens-contract-address
:verifyTransactionChainID config/verify-transaction-chain-id
:upstreamConfig config/default-network-rpc-url
:networkId config/default-network-id
:poktToken config/POKT_TOKEN
:infuraToken config/INFURA_TOKEN
:alchemyOptimismMainnetToken config/ALCHEMY_OPTIMISM_MAINNET_TOKEN
:alchemyOptimismGoerliToken config/ALCHEMY_OPTIMISM_GOERLI_TOKEN
:alchemyArbitrumMainnetToken config/ALCHEMY_ARBITRUM_MAINNET_TOKEN
:alchemyArbitrumGoerliToken config/ALCHEMY_ARBITRUM_GOERLI_TOKEN
:currentNetwork config/default-network
:previewPrivacy config/blank-preview?}]
{effect request
:dispatch [:navigate-to :generating-keys]
:db (-> db

View File

@ -1,171 +1,90 @@
(ns status-im2.contexts.quo-preview.community.token-gating
(:require [quo.previews.preview :as preview]
[quo.react-native :as rn]
[quo2.components.community.token-gating :as quo2]
[quo2.foundations.colors :as colors]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]))
(def styles
{:container-sandbox {:flex 1
:padding-vertical 20
:border-top-left-radius 20
:border-top-right-radius 20}})
(:require [reagent.core :as reagent]
[status-im2.common.resources :as resources]
[react-native.core :as rn]
[status-im2.contexts.quo-preview.preview :as preview]
[quo2.core :as quo]))
(def descriptor
[{:label "Type:"
:key :type
:type :select
:options [{:key :community
:value "Community"}
{:key :channel
:value "Channel"}]}
{:label "Tokens sufficient:"
:key :is-sufficient?
[{:label "Tokens sufficient"
:key :sufficient?
:type :boolean}
{:label "Many tokens:"
{:label "Many tokens ?"
:key :many-tokens?
:type :boolean}
{:label "Membership request denied:"
:key :membership-request-denied?
{:label "Loading ?"
:key :loading?
:type :boolean}
{:label "Сondition ?"
:key :condition?
:type :boolean}
{:label "Padding ?"
:key :padding?
:type :boolean}])
(defn join-gate-options-base
[is-sufficient? many-tokens?]
[sufficient? many-tokens? loading?]
(into
[{:token "KNC"
:token-img-src (resources/get-token :knc)
:amount 200
:is-sufficient? true}
{:token "MANA"
:token-img-src (resources/get-token :mana)
:amount 10
:is-sufficient? is-sufficient?
:is-purchasable? true}
{:token "RARE"
:token-img-src (resources/get-token :rare)
:amount 10
:is-sufficient? is-sufficient?}]
[{:symbol "KNC"
:img-src (resources/get-token :knc)
:amount 200
:sufficient? true
:loading? loading?}
{:symbol "MANA"
:img-src (resources/get-token :mana)
:amount 10
:sufficient? sufficient?
:purchasable? true
:loading? loading?}
{:symbol "RARE"
:img-src (resources/get-token :rare)
:amount 10
:sufficient? sufficient?
:loading? loading?}]
(when many-tokens?
[{:token "FXC"
:token-img-src (resources/get-token :fxc)
:amount 20
:is-sufficient? true}
{:token "SNT"
:token-img-src (resources/get-token :snt)
:amount 10000
:is-sufficient? is-sufficient?}])))
(defn write-gate-options-base
[is-sufficient?]
[{:token "KNC"
:token-img-src (resources/get-token :knc)
:amount 200
:is-sufficient? true}
{:token "DAI"
:token-img-src (resources/get-token :dai)
:amount 20
:is-purchasable? true
:is-sufficient? is-sufficient?}
{:token "ETH"
:token-img-src (resources/get-token :eth)
:amount 0.5
:is-sufficient? is-sufficient?}])
[{:symbol "FXC"
:img-src (resources/get-token :fxc)
:amount 20
:sufficient? true
:loading? loading?}
{:symbol "SNT"
:img-src (resources/get-token :snt)
:amount 10000
:sufficient? sufficient?
:loading? loading?}])))
(defn get-mocked-props
[props]
(let [{:keys [type is-sufficient? many-tokens? membership-request-denied?]} props]
(if (= type :community)
{:community {:name "Ethereum"
:community-color "#14044d"
:community-avatar-img-src (resources/get-token :eth)
:gates {:join (if
many-tokens?
[(join-gate-options-base is-sufficient?
many-tokens?)
[{:token "FXC"
:token-img-src (resources/get-token :fxc)
:amount 20
:is-sufficient? true}
{:token "USDT"
:token-img-src (resources/get-token :usdt)
:amount 20
:is-sufficient? false}]]
(join-gate-options-base is-sufficient?
many-tokens?))}}}
{:channel {:name "onboarding"
:community-color (colors/custom-color :pink 50)
:community-text-color colors/white
:emoji "🍑"
:emoji-background-color "#F38888"
:on-enter-channel #(js/alert
"Entered channel - Wuhuu!! You successfully entered the channel :)")
:membership-request-denied? membership-request-denied?
:gates {:read (into [{:token "KNC"
:token-img-src (resources/get-token :knc)
:amount 200
:is-sufficient? true}
{:token "MANA"
:token-img-src (resources/get-token :mana)
:amount 10
:is-sufficient? is-sufficient?
:is-purchasable? true}
{:token "RARE"
:token-img-src (resources/get-token :rare)
:amount 10
:is-sufficient? is-sufficient?}]
(when many-tokens?
[{:token "FXC"
:token-img-src (resources/get-token :fxc)
:amount 20
:is-sufficient? true}
{:token "SNT"
:token-img-src (resources/get-token :snt)
:amount 10000
:is-sufficient? is-sufficient?}]))
:write (if
many-tokens?
[(write-gate-options-base is-sufficient?)
[{:token "FXC"
:token-img-src (resources/get-token :fxc)
:amount 20
:is-sufficient? true}
{:token "MANA"
:token-img-src (resources/get-token :mana)
:amount 10
:is-sufficient? is-sufficient?}
{:token "USDT"
:token-img-src (resources/get-token :usdt)
:amount 20
:is-sufficient? false}]]
(write-gate-options-base is-sufficient?))}}})))
(let [{:keys [sufficient? condition? many-tokens? padding? loading?]} props]
{:tokens
(if condition?
[(join-gate-options-base sufficient?
many-tokens?
loading?)
[{:symbol "FXC"
:img-src (resources/get-token :fxc)
:amount 20
:sufficient? true}
{:symbol "USDT"
:img-src (resources/get-token :usdt)
:amount 20
:sufficient? false}]]
[(join-gate-options-base sufficient?
many-tokens?
loading?)])
:padding? padding?}))
(def state
(reagent/atom {:type :channel
:is-sufficient? false
:many-tokens? false
:membership-request-denied? false}))
(reagent/atom {:sufficient? false
:many-tokens? false
:condition? false
:padding? false}))
(defn preview-token-gating
[]
(let [preview-props (get-mocked-props @state)]
[rn/view
{:style {:background-color (colors/theme-colors
colors/neutral-10
colors/neutral-80)
:flex 1}}
[rn/view {:style {:flex 1}}
[rn/view
{:style {:position :absolute
:left 0
:right 0
:top 0}}
[preview/customizer state descriptor]]]
[rn/view {:height (if (= (:type @state) :community) 280 495) :margin-top 20}
[rn/view
{:style (merge
(get styles :container-sandbox)
{:background-color (colors/theme-colors
colors/white
colors/neutral-90)})}
[quo2/token-gating preview-props]]]]))
[rn/view {:flex 1}
[rn/scroll-view {:style {:flex 1}}
[preview/customizer state descriptor]]
[rn/view {:padding-horizontal 20 :padding-vertical 20}
[quo/token-requirement-list preview-props]]]))

View File

@ -150,7 +150,8 @@
:options {:topBar {:visible true}}
:component discover-card/preview-discoverd-card}
{:name :token-gating
:options {:topBar {:visible true}}
:options {:insets {:bottom? true}
:topBar {:visible true}}
:component token-gating/preview-token-gating}]
:counter [{:name :counter
:options {:topBar {:visible true}}

View File

@ -27,19 +27,11 @@
:value "1000"}
{:key 10000
:value "10000"}]}
{:label "Community Color:"
:key :border-color
:type :select
:options [{:key "#00a191"
:value "green"}
{:key "red"
:value "red"}]}
{:label "Is Required:"
:key :is-required
{:label "Is Sufficient:"
:key :sufficient?
:type :boolean}
{:label "Is Purchasable:"
:key :is-purchasable
:key :purchasable?
:type :boolean}
{:label "Token:"
:key :token
@ -54,7 +46,7 @@
(defn cool-preview
[]
(let [state (reagent/atom {:size :big :value 10 :token "ETH" :is-required true :is-purchasable false})]
(let [state (reagent/atom {:size :big :value 10 :token "ETH" :sufficient? false :purchasable? false})]
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}

View File

@ -16,7 +16,9 @@
[utils.datetime :as datetime]
status-im2.contexts.share.events
status-im2.contexts.syncing.events
status-im2.contexts.chat.events))
status-im2.contexts.chat.events
status-im2.common.password-authentication.events
status-im2.contexts.communities.overview.events))
(re-frame/reg-cofx
:now

View File

@ -262,17 +262,33 @@
categories-and-chats)))
(re-frame/reg-sub
:communities/users
:<- [:communities]
(fn [_ [_ _]]
[{:full-name "Alicia K"}
{:full-name "Marcus C"}
{:full-name "MNO PQR"}
{:full-name "STU VWX"}]))
(re-frame/reg-sub
:communities/collapsed-categories-for-community
:<- [:communities/collapsed-categories]
(fn [collapsed-categories [_ community-id]]
(get collapsed-categories community-id)))
(re-frame/reg-sub
:community/token-gated-overview
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [token-permissions-check token-permissions checking-permissions? token-images]}] _]
{:can-request-access? (:satisfied token-permissions-check)
:number-of-hold-tokens (reduce
(fn [acc [_ {:keys [criteria]}]]
(reduce #(+ %1 (if %2 1 0)) acc criteria))
0
(:permissions token-permissions-check))
:tokens (map (fn [[perm-key {:keys [token_criteria]}]]
(let [check-criteria (get-in token-permissions-check
[:permissions perm-key :criteria])]
(map
(fn [{:keys [symbol amount]} sufficient?]
{:symbol symbol
:sufficient? (when (seq check-criteria) sufficient?)
:loading? checking-permissions?
:amount amount
:img-src (get token-images symbol)})
token_criteria
(or check-criteria token_criteria))))
token-permissions)}))

View File

@ -74,6 +74,7 @@
(reg-root-key-sub :waku/v2-peer-stats :peer-stats)
(reg-root-key-sub :visibility-status-updates :visibility-status-updates)
(reg-root-key-sub :shell/switcher-cards :shell/switcher-cards)
(reg-root-key-sub :password-authentication :password-authentication)
;;NOTE this one is not related to ethereum network
;; it is about cellular network/ wifi network

View File

@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.151.12",
"commit-sha1": "6fa8c113821509d744b81d90dc21c1e79c575577",
"src-sha256": "02mmhy4z6gd9xlqjhw4i4j48gd85pijyyga48if9dd3zasqkp3y1"
"version": "v0.151.14",
"commit-sha1": "959e3703891286853574f4974e87bd53e079e72d",
"src-sha256": "11l9p1psl331b4vaw1694z09z9rlaps5w1cildmdgnx2pnkgcr7q"
}

View File

@ -1447,7 +1447,7 @@
"view-details": "View Details",
"view-signing": "View signing phrase",
"view-superrare": "View in SuperRare",
"view-token-gating": "View token gating",
"view-token-gating": "View token requirements",
"vote-to-feature": "Vote to feature this community",
"waiting-for-wifi": "No Wi-fi, message syncing disabled.",
"waiting-for-wifi-change": "Settings",
@ -2168,5 +2168,11 @@
"sync-devices-error-sub-title":"Make sure both devices are powered on and connected to the internet.",
"sync-devices-complete-title": "Device sync complete!",
"sync-devices-complete-sub-title": "Your devices are now in sync",
"sync-with": "Synced with"
}
"sync-with": "Synced with",
"you-eligible-to-join": "Youre eligible to join",
"you-not-eligible-to-join": "Youre not eligible to join",
"you-hold-number-of-hold-tokens-of-these": "You hold {{number-of-hold-tokens}} of these:",
"token-gated-communities": "Token gated communities",
"read-more": "Read more",
"token-gated-communities-info": "Here will be something relevant about this topic. This will help the user get more context and therefore have a better understanding of it."
}