Account selection: Implement features related to editing shared addresses (#19177)

* Fix schema error

* Implement feature to edit shared addresses

* fix: show tokens when sharing all future addresses toggled

* fix: eligibility not checked when toggling all addresses

* Revert "fix: show tokens when sharing all future addresses toggled"

This reverts commit 8443a3432e.

* fix: don't fetch balances on mount if toggled share all

---------

Co-authored-by: Cristian Lungu <lungucristian95@gmail.com>
This commit is contained in:
Icaro Motta 2024-03-18 12:07:15 -03:00 committed by GitHub
parent 6c5242b3e0
commit 7948582e46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 1403 additions and 566 deletions

View File

@ -59,4 +59,15 @@
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "Eligible to join as"))
(h/is-truthy (h/get-by-text "Admin"))
(h/is-truthy (h/get-by-text "Request to join")))
(h/test "render with top description with custom text & 1 action"
(render [bottom-actions/view
{:description :top
:role :admin
:actions :one-action
:description-top-text "You'll be an"
:button-one-label "Request to join"}])
(h/is-truthy (h/get-by-text "You'll be an"))
(h/is-truthy (h/get-by-text "Admin"))
(h/is-truthy (h/get-by-text "Request to join"))))

View File

@ -19,6 +19,7 @@
[:actions [:maybe [:enum :one-action :two-actions]]]
[:description {:optional true} [:maybe [:enum :top :bottom :top-error]]]
[:description-text {:optional true} [:maybe :string]]
[:description-top-text {:optional true} [:maybe :string]]
[:error-message {:optional true} [:maybe :string]]
[:role {:optional true} [:maybe [:enum :admin :member :token-master :owner]]]
[:button-one-label {:optional true} [:maybe :string]]
@ -38,8 +39,8 @@
:owner :i/crown})
(defn- view-internal
[{:keys [actions description description-text error-message role button-one-label button-two-label
blur? button-one-props button-two-props theme scroll? container-style]}]
[{:keys [actions description description-text description-top-text error-message role button-one-label
button-two-label blur? button-one-props button-two-props theme scroll? container-style]}]
[rn/view
{:style (merge (style/container scroll? blur? theme) container-style)}
(when (= description :top-error)
@ -54,12 +55,11 @@
error-message]])
(when (and (= description :top) role)
[rn/view
{:style style/description-top}
[rn/view {:style style/description-top}
[text/text
{:size :paragraph-2
:style (style/description-top-text scroll? blur? theme)}
(i18n/label :t/eligible-to-join-as)]
(or description-top-text (i18n/label :t/eligible-to-join-as))]
[context-tag/view
{:type :icon
:size 24

View File

@ -5,6 +5,14 @@
(def ^:private ?cofx
[:map])
(def ^:private ?event
[:and
[:vector {:min 1} :any]
[:catn
[:event-id keyword?]
[:event-args [:* :any]]]])
(defn register-schemas
[]
(registry/register ::cofx ?cofx))
(registry/register ::cofx ?cofx)
(registry/register ::event ?event))

View File

@ -0,0 +1,102 @@
(ns status-im.contexts.communities.actions.accounts-selection.effects
(:require
[promesa.core :as p]
[schema.core :as schema]
[status-im.common.json-rpc.events :as rpc]
[utils.re-frame :as rf]))
(defn- generate-requests-for-signing
[pub-key community-id addresses-to-reveal]
(p/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_generateJoiningCommunityRequestsForSigning
:params [pub-key community-id addresses-to-reveal]
:on-success p-resolve
:on-error #(p-reject (str "failed to generate requests for signing\n" %))}))))
(defn- sign-data
[sign-params password]
(p/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_signData
:params [(map #(assoc % :password password) sign-params)]
:on-success p-resolve
:on-error #(p-reject (str "failed to sign data\n" %))}))))
(defn- edit-shared-addresses-for-community
[community-id signatures addresses-to-reveal airdrop-address]
(p/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_editSharedAddressesForCommunity
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:airdropAddress airdrop-address}]
:js-response true
:on-success p-resolve
:on-error p-reject}))))
(defn- request-to-join
[community-id signatures addresses-to-reveal airdrop-address]
(p/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_requestToJoinCommunity
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:airdropAddress airdrop-address}]
:js-response true
:on-success p-resolve
:on-error p-reject}))))
(defn- run-callback-or-event
[callback-or-event result]
(cond (fn? callback-or-event)
(callback-or-event result)
(vector? callback-or-event)
(rf/dispatch (conj callback-or-event result))))
(defn- sign-and-call-endpoint
[{:keys [community-id password pub-key
addresses-to-reveal airdrop-address
on-success on-error
callback]}]
(-> (p/let [sign-params (generate-requests-for-signing pub-key community-id addresses-to-reveal)
signatures (sign-data sign-params password)
result (callback community-id
signatures
addresses-to-reveal
airdrop-address)]
(run-callback-or-event on-success result))
(p/catch #(run-callback-or-event on-error %))))
(schema/=> sign-and-call-endpoint
[:=>
[:cat
[:map {:closed true}
[:community-id string?]
[:password string?]
[:pub-key string?]
[:addresses-to-reveal
[:or [:set string?]
[:sequential string?]]]
[:airdrop-address string?]
[:on-success [:or fn? :schema.re-frame/event]]
[:on-error [:or fn? :schema.re-frame/event]]
[:callback fn?]]]
:any])
(rf/reg-fx :effects.community/edit-shared-addresses
(fn [opts]
(sign-and-call-endpoint
(assoc opts :callback edit-shared-addresses-for-community))))
(rf/reg-fx :effects.community/request-to-join
(fn [opts]
(sign-and-call-endpoint
(assoc opts :callback request-to-join))))

View File

@ -0,0 +1,103 @@
(ns status-im.contexts.communities.actions.accounts-selection.events
(:require
status-im.contexts.communities.actions.accounts-selection.effects
[status-im.contexts.communities.utils :as utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn initialize-permission-addresses
[{:keys [db]} [community-id]]
(let [{:keys [joined]} (get-in db [:communities community-id])
pending-requests (get-in db [:communities/my-pending-requests-to-join community-id])
init-using-revealed-accounts? (or joined (seq pending-requests))]
{:fx [(if init-using-revealed-accounts?
[:dispatch
[:communities/get-revealed-accounts community-id
[:communities/do-init-permission-addresses community-id]]]
[:dispatch [:communities/do-init-permission-addresses community-id]])]}))
(rf/reg-event-fx :communities/initialize-permission-addresses initialize-permission-addresses)
(defn do-init-permission-addresses
[{:keys [db]} [community-id revealed-accounts]]
(let [wallet-accounts (utils/sorted-non-watch-only-accounts db)
addresses-to-reveal (if (seq revealed-accounts)
(set (keys revealed-accounts))
;; Reveal all addresses as fallback.
(set (map :address wallet-accounts)))
;; When there are no revealed addresses, such as when joining a
;; community, use first address for airdrops.
airdrop-address (or (->> revealed-accounts
vals
(filter :airdrop-address?)
first
:address)
(->> wallet-accounts
first
:address))]
{:db (-> db
;; Set to false by default while we don't persist the user's choice
;; in status-go, otherwise whenever the view is mounted, the choice
;; of selected addresses won't be respected.
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal)
(assoc-in [:communities/all-airdrop-addresses community-id] airdrop-address))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id addresses-to-reveal :based-on-client-selection]]
;; Pre-fetch permissions check so that when first opening the
;; Addresses for Permissions screen the highest permission role is
;; already available and no incorrect information flashes on screen.
[:dispatch
[:communities/check-permissions-to-join-during-selection community-id
addresses-to-reveal]]]}))
(rf/reg-event-fx :communities/do-init-permission-addresses do-init-permission-addresses)
(defn edit-shared-addresses
"This event will effectively persist the choice of addresses and airdrop address
in status-go. It can either take addresses to share AND an airdrop address, or
just addresses to share OR an airdrop address. This is because when the user
is selecting an airdrop address, we must submit to status-go the current
choice of addresses to share, and vice-versa. If we omit addresses to share,
status-go will default to all available."
[{:keys [db]} [{:keys [community-id password on-success addresses airdrop-address]}]]
(let [pub-key (get-in db [:profile/profile :public-key])
wallet-accounts (utils/sorted-non-watch-only-accounts db)
addresses-to-reveal (if (seq addresses)
(set addresses)
(get-in db [:communities/all-addresses-to-reveal community-id]))
new-airdrop-address (if (contains? addresses-to-reveal airdrop-address)
airdrop-address
(->> wallet-accounts
(filter #(contains? addresses-to-reveal (:address %)))
first
:address))]
{:fx [[:effects.community/edit-shared-addresses
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal addresses-to-reveal
:airdrop-address new-airdrop-address
:on-success (fn []
(when (fn? on-success)
(on-success addresses-to-reveal new-airdrop-address))
(rf/dispatch [:communities/edit-shared-addresses-success
community-id addresses-to-reveal airdrop-address]))
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}))
(rf/reg-event-fx :communities/edit-shared-addresses edit-shared-addresses)
(rf/reg-event-fx :communities/edit-shared-addresses-success
(fn [_ [community-id addresses-to-reveal airdrop-address]]
{:fx [[:dispatch [:communities/set-airdrop-address community-id airdrop-address]]
[:dispatch [:communities/set-addresses-to-reveal community-id addresses-to-reveal]]]}))
(rf/reg-event-fx :communities/edit-shared-addresses-failure
(fn [{:keys [db]} [community-id error]]
(log/error "failed to edit shared addresses"
{:event :communities/edit-shared-addresses
:community-id community-id
:error error})
{:db (assoc-in db [:password-authentication :error] error)}))

View File

@ -0,0 +1,169 @@
(ns status-im.contexts.communities.actions.accounts-selection.events-test
(:require [cljs.test :refer [deftest is testing]]
matcher-combinators.test
[status-im.contexts.communities.actions.accounts-selection.events :as sut]))
(def community-id "0x99")
(def password "password")
(def wallet-accounts
{"0xA" {:address "0xA"
:watch-only? true
:position 2
:color :red
:emoji "🦇"}
"0xB" {:address "0xB"
:position 0
:color :blue
:emoji "🐈"}
"0xC" {:address "0xC"
:position 1
:color :orange
:emoji "🛏️"}})
(def permissioned-accounts
[{:address "0xB"
:position 0
:color :blue
:emoji "🐈"
:airdrop-address? true
:reveal? true}
{:address "0xC"
:position 1
:color :orange
:emoji "🛏️"
:airdrop-address? false
:reveal? false}])
(deftest initialize-permission-addresses-test
(testing "fetches revealed accounts when pending and not joined"
(let [cofx {:db {:communities {community-id {:joined false}}
:communities/my-pending-requests-to-join {community-id [:anything]}}}]
(is (match?
{:fx [[:dispatch
[:communities/get-revealed-accounts community-id
[:communities/do-init-permission-addresses community-id]]]]}
(sut/initialize-permission-addresses cofx [community-id])))))
(testing "fetches revealed accounts when not pending and joined"
(let [cofx {:db {:communities {community-id {:joined true}}
:communities/my-pending-requests-to-join {}}}]
(is (match?
{:fx [[:dispatch
[:communities/get-revealed-accounts community-id
[:communities/do-init-permission-addresses community-id]]]]}
(sut/initialize-permission-addresses cofx [community-id])))))
(testing "does not fetch revealed accounts when not pending and not joined"
(let [cofx {:db {:communities {community-id {:joined false}}
:communities/my-pending-requests-to-join {}}}]
(is (match?
{:fx [[:dispatch [:communities/do-init-permission-addresses community-id]]]}
(sut/initialize-permission-addresses cofx [community-id]))))))
(deftest do-init-permission-addresses-test
(testing "uses already revealed accounts to initialize shareable accounts"
(let [cofx {:db {:wallet {:accounts wallet-accounts}}}
revealed-accounts {"0xC" {:address "0xC"
:airdrop-address? true
:position 1}}
airdrop-address "0xC"
addresses-to-reveal #{"0xC"}]
(is
(match?
{:db (-> (:db cofx)
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal)
(assoc-in [:communities/all-airdrop-addresses community-id] airdrop-address))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id addresses-to-reveal :based-on-client-selection]]
;; Pre-fetch permissions check so that when first opening the
;; Addresses for Permissions screen the highest permission role is
;; already available and no incorrect information flashes on screen.
[:dispatch
[:communities/check-permissions-to-join-during-selection community-id
addresses-to-reveal]]]}
(sut/do-init-permission-addresses cofx [community-id revealed-accounts])))))
;; Expect to mark all addresses to be revealed and first one to receive
;; airdrops when no addresses were previously revealed.
(testing "handles case where there are no previously revealed addresses"
(let [cofx {:db {:wallet {:accounts wallet-accounts}}}
addresses-to-reveal #{"0xB" "0xC"}
revealed-accounts []]
(is
(match?
{:db (-> (:db cofx)
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id addresses-to-reveal :based-on-client-selection]]
[:dispatch
[:communities/check-permissions-to-join-during-selection community-id
addresses-to-reveal]]]}
(sut/do-init-permission-addresses cofx [community-id revealed-accounts]))))))
(deftest edit-shared-addresses-test
(testing
"when airdrop address is passed, but addresses to reveal is not, then
fallback to all wallet addresses"
(let [pub-key "abcdef"
revealed-addresses #{"0xB" "0xC"}
cofx {:db {:profile/profile {:public-key pub-key}
:communities/all-addresses-to-reveal {community-id revealed-addresses}}}
airdrop-address "0xB"
actual
(sut/edit-shared-addresses
cofx
[{:community-id community-id
:password password
:airdrop-address airdrop-address
:on-success (fn [new-addresses-to-reveal]
(is (match? revealed-addresses new-addresses-to-reveal)))}])
on-success-wrapper (-> actual :fx first second :on-success)]
(is (match?
{:fx [[:effects.community/edit-shared-addresses
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal revealed-addresses
:airdrop-address airdrop-address
:on-success fn?
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}
actual))
(on-success-wrapper)))
(testing "when addresses to reveal are passed, but airdrop address is not"
(let [pub-key "abcdef"
cofx {:db {:profile/profile {:public-key pub-key}
:wallet {:accounts wallet-accounts}
:communities/all-addresses-to-reveal {community-id #{"0xB" "0xC"}}}}
actual (sut/edit-shared-addresses
cofx
[{:community-id community-id
:password password
:addresses ["0xC"]
:on-success (fn [new-addresses-to-reveal new-airdrop-address]
(is (= #{"0xC"} new-addresses-to-reveal))
(is (= "0xC" new-airdrop-address)))}])
on-success-wrapper
(-> actual :fx first second :on-success)]
(is (match?
{:fx [[:effects.community/edit-shared-addresses
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal #{"0xC"}
:airdrop-address "0xC"
:on-success fn?
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}
actual))
(on-success-wrapper))))

View File

@ -14,83 +14,110 @@
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
show-addresses-for-permissions (fn []
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content addresses-for-permissions/view}]))
show-airdrop-addresses (fn []
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content airdrop-addresses/view}]))
navigate-back #(rf/dispatch [:navigate-back])
join-and-go-back (fn []
(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-addresses
{:community-id id :password %}])}])
(navigate-back))]
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
airdrop-account (rf/sub [:communities/airdrop-account id])
selected-accounts (rf/sub [:communities/selected-permission-accounts id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))]
[rn/safe-area-view {:style style/container}
[quo/page-nav
{:text-align :left
:icon-name :i/close
:on-press navigate-back
:accessibility-label :back-button}]
[quo/page-top
{:title (i18n/label :t/request-to-join)
:description :context-tag
:context-tag {:type :community
:size 24
:community-logo (get-in images [:thumbnail :uri])
:community-name name}}]
[gesture/scroll-view
[:<>
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/address-to-share)]
[quo/category
{:list-type :settings
:data [{:title (i18n/label :t/join-as-a {:role highest-role-text})
:on-press show-addresses-for-permissions
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data selected-accounts}
:description-props {:text (i18n/label :t/all-addresses)}}
{:title (i18n/label :t/for-airdrops)
:on-press show-airdrop-addresses
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data [airdrop-account]}
:description-props {:text (:name airdrop-account)}}]}]
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/community-rules)]
[community-rules/view id]]]
[rn/view {:style (style/bottom-actions)}
[quo/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-request-to-join)
:track-icon :i/face-id
:customization-color color
:on-complete join-and-go-back}]]]))))
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images joined]} (rf/sub [:communities/community id])
airdrop-account (rf/sub [:communities/airdrop-account id])
revealed-accounts (rf/sub [:communities/accounts-to-reveal id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
navigate-back (rn/use-callback #(rf/dispatch [:navigate-back]))
show-addresses-for-permissions
(rn/use-callback
(fn []
(if can-edit-addresses?
(rf/dispatch [:open-modal :addresses-for-permissions {:community-id id}])
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content (fn [] [addresses-for-permissions/view])}])))
[can-edit-addresses?])
show-airdrop-addresses
(rn/use-callback
(fn []
(if can-edit-addresses?
(rf/dispatch [:open-modal :address-for-airdrop {:community-id id}])
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content (fn [] [airdrop-addresses/view])}])))
[can-edit-addresses?])
confirm-choices
(rn/use-callback
(fn []
(rf/dispatch
[:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/join-open-community)
:on-press (fn [password]
(rf/dispatch [:communities/request-to-join-with-addresses
{:community-id id :password password}]))}])
(navigate-back)))]
(rn/use-mount
(fn []
(rf/dispatch [:communities/initialize-permission-addresses id])))
[rn/safe-area-view {:style style/container}
[quo/page-nav
{:text-align :left
:icon-name :i/close
:on-press navigate-back
:accessibility-label :back-button}]
[quo/page-top
{:title (if can-edit-addresses?
(i18n/label :t/edit-shared-addresses)
(i18n/label :t/request-to-join))
:description :context-tag
:context-tag {:type :community
:size 24
:community-logo (get-in images [:thumbnail :uri])
:community-name name}}]
[gesture/scroll-view
[:<>
(when-not can-edit-addresses?
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/address-to-share)])
[quo/category
{:list-type :settings
:data [{:title (if joined
(i18n/label :t/you-are-a-role {:role highest-role-text})
(i18n/label :t/join-as-a {:role highest-role-text}))
:on-press show-addresses-for-permissions
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data revealed-accounts}
:description-props {:text (i18n/label :t/all-addresses)}}
{:title (i18n/label :t/for-airdrops)
:on-press show-airdrop-addresses
:description :text
:action :arrow
:label :preview
:label-props {:type :accounts
:data [airdrop-account]}
:description-props {:text (:name airdrop-account)}}]}]
(when-not can-edit-addresses?
[quo/text
{:style style/section-title
:accessibility-label :community-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/community-rules)])
(when-not can-edit-addresses?
[community-rules/view id])]]
(when-not can-edit-addresses?
[rn/view {:style (style/bottom-actions)}
[quo/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-request-to-join)
:track-icon :i/face-id
:customization-color color
:on-complete confirm-choices}]])]))

View File

@ -1,6 +1,7 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.events
(:require
[schema.core :as schema]
[status-im.contexts.communities.utils :as utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@ -56,3 +57,97 @@
map?])
(rf/reg-event-fx :communities/get-permissioned-balances-success get-permissioned-balances-success)
(rf/reg-event-fx :communities/addresses-for-permissions-cancel-request
(fn [_ [request-id]]
{:fx [[:dispatch [:communities/cancel-request-to-join request-id]]
[:dispatch [:pop-to-root :shell-stack]]
[:dispatch [:hide-bottom-sheet]]]}))
(rf/reg-event-fx :communities/addresses-for-permissions-leave
(fn [_ [community-id]]
{:fx [[:dispatch [:communities/leave community-id]]
[:dispatch [:hide-bottom-sheet]]
[:dispatch [:dismiss-modal :addresses-for-permissions]]
[:dispatch [:pop-to-root :shell-stack]]]}))
(defn check-permissions-to-join-for-selection
[{:keys [db]} [community-id addresses]]
(if (empty? addresses)
;; When there are no addresses we can't just check permissions, otherwise
;; status-go will consider all possible addresses and the user will see the
;; incorrect highest permission role.
{:db (update db :communities/permissions-checks-for-selection dissoc community-id)}
(let [{:keys [checking?]} (get-in db [:communities/permissions-checks-for-selection community-id])]
(when-not checking?
{:db (assoc-in db [:communities/permissions-checks-for-selection community-id :checking?] true)
:fx [[:json-rpc/call
[{:method :wakuext_checkPermissionsToJoinCommunity
:params [{:communityId community-id :addresses addresses}]
:on-success [:communities/check-permissions-to-join-during-selection-success
community-id]
:on-error [:communities/check-permissions-to-join-during-selection-failure
community-id addresses]}]]]}))))
;; This event should be used to check permissions temporarily because it won't
;; mutate the state `:communities/permissions-check` (used by many other
;; screens).
(rf/reg-event-fx :communities/check-permissions-to-join-during-selection
check-permissions-to-join-for-selection)
(rf/reg-event-fx :communities/check-permissions-to-join-during-selection-success
(fn [{:keys [db]} [community-id result]]
{:db (assoc-in db
[:communities/permissions-checks-for-selection community-id]
{:checking? false
:based-on-client-selection? true
:check result})}))
(rf/reg-event-fx :communities/check-permissions-to-join-during-selection-failure
(fn [_ [community-id addresses error]]
(log/error "failed to check permissions for currently selected addresses"
{:event :communities/check-permissions-to-join-during-selection
:community-id community-id
:addresses addresses
:error error})))
(defn set-permissioned-accounts
[{:keys [db]} [community-id addresses-to-reveal]]
(let [addresses-to-reveal (set addresses-to-reveal)
wallet-accounts (utils/sorted-non-watch-only-accounts db)
current-airdrop-address (get-in db [:communities/all-airdrop-addresses community-id])
new-airdrop-address (if (contains? addresses-to-reveal current-airdrop-address)
current-airdrop-address
(->> wallet-accounts
(filter #(contains? addresses-to-reveal (:address %)))
first
:address))]
{:db (-> db
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal)
(assoc-in [:communities/all-airdrop-addresses community-id] new-airdrop-address))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id addresses-to-reveal :based-on-client-selection]]
[:dispatch [:hide-bottom-sheet]]]}))
(rf/reg-event-fx :communities/set-addresses-to-reveal set-permissioned-accounts)
(defn set-share-all-addresses
[{:keys [db]} [community-id new-value]]
(let [current-addresses (get-in db [:communities/all-addresses-to-reveal community-id])
addresses-to-reveal (if new-value
(->> (utils/sorted-non-watch-only-accounts db)
(map :address)
set)
current-addresses)]
{:db (-> db
(assoc-in [:communities/selected-share-all-addresses community-id] new-value)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal))
;; We should check permissions again because the flag is being enabled and
;; different addresses will be revealed.
:fx [(when new-value
[:dispatch
[:communities/check-permissions-to-join-during-selection
community-id addresses-to-reveal]])]}))
(rf/reg-event-fx :communities/set-share-all-addresses set-share-all-addresses)

View File

@ -1,6 +1,6 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.events-test
(:require
[cljs.test :refer [deftest is]]
[cljs.test :refer [deftest is testing]]
[status-im.contexts.communities.actions.addresses-for-permissions.events :as sut]))
(def community-id "0x1")
@ -13,3 +13,101 @@
:on-success [:communities/get-permissioned-balances-success community-id]
:on-error fn?}]]]}
(sut/get-permissioned-balances cofx [community-id])))))
(deftest set-permissioned-accounts-test
(testing "new accounts contain the current airdrop address"
(let [cofx {:db {:communities/all-addresses-to-reveal
{community-id #{"0xA" "0xB"}}}}
addresses-to-reveal ["0xA"]
expected-addresses-to-reveal (set addresses-to-reveal)]
(is (match?
{:db {:communities/all-addresses-to-reveal
{community-id expected-addresses-to-reveal}}
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id expected-addresses-to-reveal :based-on-client-selection]]
[:dispatch [:hide-bottom-sheet]]]}
(sut/set-permissioned-accounts cofx [community-id addresses-to-reveal])))))
(testing "new accounts do not contain the current airdrop address"
(let [cofx
{:db {:communities/all-addresses-to-reveal {community-id #{"0xA" "0xB" "0xC"}}
:communities/all-airdrop-addresses {community-id "0xB"}
:wallet {:accounts {"0xB" {:address "0xB" :position 0}
"0xA" {:address "0xA" :position 1}
"0xC" {:address "0xC" :position 2}}}}}
addresses-to-reveal ["0xA" "0xC"]]
(is (match?
{:db {:communities/all-addresses-to-reveal
{community-id (set addresses-to-reveal)}
:communities/all-airdrop-addresses
{community-id "0xA"}}
:fx [[:dispatch
[:communities/check-permissions-to-join-community
community-id (set addresses-to-reveal) :based-on-client-selection]]
[:dispatch [:hide-bottom-sheet]]]}
(sut/set-permissioned-accounts cofx [community-id addresses-to-reveal]))))))
(deftest set-share-all-addresses-test
(testing "sets flag from false -> true will mark all addresses to be revealed"
(let [cofx {:db
{:wallet
{:accounts {"0xB" {:address "0xB" :position 0}
"0xA" {:address "0xA" :position 1}
"0xC" {:address "0xC" :position 2}}}
:communities/all-addresses-to-reveal {community-id #{"0xA"}}
:communities/selected-share-all-addresses {community-id false}}}
addresses-to-reveal #{"0xA" "0xB" "0xC"}]
(is (match?
{:db {:communities/selected-share-all-addresses {community-id true}
:communities/all-addresses-to-reveal
{community-id addresses-to-reveal}}
:fx [[:dispatch
[:communities/check-permissions-to-join-during-selection
community-id addresses-to-reveal]]]}
(sut/set-share-all-addresses cofx [community-id true])))))
(testing "sets flag from true -> false will not change addresses to be revealed"
(let [cofx {:db {:communities/all-addresses-to-reveal {community-id #{"0xA"}}}}]
(is (match?
{:db {:communities/selected-share-all-addresses {community-id false}
:communities/all-addresses-to-reveal {community-id #{"0xA"}}}
:fx [nil]}
(sut/set-share-all-addresses cofx [community-id false]))))))
(deftest check-permissions-to-join-for-selection-test
(testing "when no addresses are passed don't check permissions"
(let [addresses []
cofx {:db {:foo :bar
:communities/permissions-checks-for-selection
{"0xC" :another-check
community-id :some-check}}}]
(is (match?
{:db {:foo :bar
:communities/permissions-checks-for-selection {"0xC" :another-check}}}
(sut/check-permissions-to-join-for-selection cofx [community-id addresses])))))
(testing "when there are addresses to check permissions and not currently checking"
(let [addresses ["0xA"]
cofx {:db {:communities/permissions-checks-for-selection
{"other-comm-id" {}
community-id {:checking? false}}}}]
(is (match?
{:db {:communities/permissions-checks-for-selection
{"other-comm-id" {}
community-id {:checking? true}}}
:fx [[:json-rpc/call
[{:method :wakuext_checkPermissionsToJoinCommunity
:params [{:communityId community-id :addresses addresses}]
:on-success [:communities/check-permissions-to-join-during-selection-success
community-id]
:on-error [:communities/check-permissions-to-join-during-selection-failure
community-id addresses]}]]]}
(sut/check-permissions-to-join-for-selection cofx [community-id addresses])))))
(testing "when there are addresses to check permissions, but currently checking, then skip the check"
(let [addresses ["0xA"]
cofx {:db {:communities/permissions-checks-for-selection
{"other-comm-id" {}
community-id {:checking? true}}}}]
(is (nil? (sut/check-permissions-to-join-for-selection cofx [community-id addresses]))))))

View File

@ -0,0 +1,6 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.style)
(def drawer-body
{:padding-top 4
:padding-horizontal 20
:padding-bottom 12})

View File

@ -1,11 +1,16 @@
(ns status-im.contexts.communities.actions.addresses-for-permissions.view
(:require [quo.core :as quo]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))
(:require
[clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.password-authentication.view :as password-authentication]
[status-im.constants :as constants]
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))
(defn- role-keyword
[role]
@ -36,96 +41,316 @@
:token (:symbol balance)
:token-img-src (images-by-symbol sym)))))
(defn- cancel-join-request-drawer
[community-id]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])
request-id (rf/sub [:communities/my-pending-request-to-join community-id])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/cancel-request?)
:community-name name
:community-logo logo
:customization-color color}]
[rn/view {:style style/drawer-body}
[quo/text (i18n/label :t/pending-join-request-farewell)]]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/confirm-and-cancel)
:button-one-props {:customization-color color
:on-press
(fn []
(rf/dispatch [:communities/addresses-for-permissions-cancel-request
request-id]))}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
(defn- confirm-discard-drawer
[community-id]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/discard-changes?)
:community-name name
:community-logo logo
:customization-color color}]
[rn/view {:style style/drawer-body}
[quo/text (i18n/label :t/all-changes-will-be-discarded)]]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/discard)
:button-one-props {:customization-color color
:on-press
(fn []
(rf/dispatch [:dismiss-modal :addresses-for-permissions])
(rf/dispatch [:hide-bottom-sheet]))}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
(defn- leave-community-drawer
[community-id outro-message]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/leave-community?)
:community-name name
:community-logo logo
:customization-color color}]
[rn/view {:style style/drawer-body}
[quo/text
(if (string/blank? outro-message)
(i18n/label :t/leave-community-farewell)
outro-message)]]
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/confirm-and-leave)
:button-one-props {:customization-color color
:on-press
#(rf/dispatch [:communities/addresses-for-permissions-leave community-id])}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
(defn- account-item
[{:keys [color address name emoji]} _ _
{:keys [selected-addresses community-id share-all-addresses? community-color]}]
[{:keys [customization-color address name emoji]} _ _
[addresses-to-reveal set-addresses-to-reveal community-id community-color share-all-addresses?]]
(let [balances (rf/sub [:communities/permissioned-balances-by-address community-id address])
images-by-symbol (rf/sub [:communities/token-images-by-symbol community-id])]
images-by-symbol (rf/sub [:communities/token-images-by-symbol community-id])
checked? (contains? addresses-to-reveal address)
toggle-address (fn []
(let [new-addresses (if checked?
(disj addresses-to-reveal address)
(conj addresses-to-reveal address))]
(set-addresses-to-reveal new-addresses)))]
[quo/account-permissions
{:account {:name name
:address address
:emoji emoji
:customization-color color}
:token-details (balances->components-props balances images-by-symbol)
:checked? (contains? selected-addresses address)
:customization-color customization-color}
:token-details (when-not share-all-addresses?
(balances->components-props balances images-by-symbol))
:checked? checked?
:disabled? share-all-addresses?
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
address community-id])
:on-change toggle-address
:container-style {:margin-bottom 8}
:customization-color community-color}]))
(defn- page-top
[{:keys [community-id identical-choices? can-edit-addresses?]}]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])
confirm-discard-changes (rn/use-callback
(fn []
(if identical-choices?
(rf/dispatch [:dismiss-modal :addresses-for-permissions])
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [confirm-discard-drawer
community-id])}])))
[identical-choices?])]
[:<>
(when can-edit-addresses?
[quo/page-nav
{:type :no-title
:icon-name :i/arrow-left
:on-press confirm-discard-changes}])
(if can-edit-addresses?
[quo/page-top
{:title (i18n/label :t/addresses-for-permissions)
:title-accessibility-label :title-label
:description :context-tag
:context-tag {:type :community
:community-logo logo
:community-name name}}]
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:button-type :grey
:on-button-press not-implemented/alert
:community-logo logo
:customization-color color}])]))
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
toggle-share-all-addresses #(rf/dispatch [:communities/toggle-share-all-addresses id])
update-previous-addresses (fn []
(rf/dispatch [:communities/update-previous-permission-addresses id])
(rf/dispatch [:hide-bottom-sheet]))
reset-selected-addresses (fn []
(rf/dispatch [:communities/reset-selected-permission-addresses id])
(rf/dispatch [:hide-bottom-sheet]))]
(rf/dispatch [:communities/get-permissioned-balances id])
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
{:keys [checking?
highest-permission-role]} (rf/sub [:community/token-gated-overview id])
accounts (rf/sub [:wallet/accounts-without-watched-accounts])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
share-all-addresses? (rf/sub [:communities/share-all-addresses? id])
unsaved-address-changes? (rf/sub [:communities/unsaved-address-changes? id])]
[:<>
[quo/drawer-top
{:type :context-tag
:title (i18n/label :t/addresses-for-permissions)
:context-tag-type :community
:community-name name
:button-icon :i/info
:button-type :grey
: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])
{:keys [color joined] outro-message :outroMessage} (rf/sub [:communities/community id])
[gesture/flat-list
{:render-fn account-item
:render-data {:selected-addresses selected-addresses
:community-id id
:share-all-addresses? share-all-addresses?
:community-color color}
:header [quo/category
{:list-type :settings
:data [{:title
(i18n/label
:t/share-all-current-and-future-addresses)
:action :selector
:action-props
{:on-change toggle-share-all-addresses
:customization-color color
:checked? share-all-addresses?}}]
:container-style {:padding-bottom 16 :padding-horizontal 0}}]
:content-container-style {:padding-horizontal 20}
:key-fn :address
:data accounts}]
highest-role (rf/sub [:communities/highest-role-for-selection id])
[unmodified-role _] (rn/use-state highest-role)
[quo/bottom-actions
{:actions :two-actions
:button-one-label (i18n/label :t/confirm-changes)
:button-one-props {:customization-color color
:disabled? (or checking?
(empty? selected-addresses)
(not highest-permission-role)
(not unsaved-address-changes?))
:on-press update-previous-addresses}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press reset-selected-addresses}
:description (if (or (empty? selected-addresses)
(not highest-permission-role))
:top-error
:top)
:role (when-not checking? (role-keyword highest-permission-role))
:error-message (cond
(empty? selected-addresses)
(i18n/label :t/no-addresses-selected)
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
pending? (boolean (rf/sub [:communities/my-pending-request-to-join id]))
(not highest-permission-role)
(i18n/label :t/addresses-dont-contain-tokens-needed))}]]))))
wallet-accounts (rf/sub [:wallet/accounts-without-watched-accounts])
unmodified-addresses-to-reveal (rf/sub [:communities/addresses-to-reveal id])
[addresses-to-reveal set-addresses-to-reveal] (rn/use-state unmodified-addresses-to-reveal)
unmodified-flag-share-all-addresses (rf/sub [:communities/share-all-addresses? id])
[flag-share-all-addresses
set-flag-share-all-addresses] (rn/use-state unmodified-flag-share-all-addresses)
identical-choices? (and (= unmodified-addresses-to-reveal addresses-to-reveal)
(= unmodified-flag-share-all-addresses flag-share-all-addresses))
toggle-flag-share-all-addresses
(fn []
(let [new-value (not flag-share-all-addresses)]
(set-flag-share-all-addresses new-value)
(when new-value
(set-addresses-to-reveal (set (map :address wallet-accounts))))))
cancel-join-request
(rn/use-callback
(fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [cancel-join-request-drawer id])}])))
leave-community
(rn/use-callback
(fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [leave-community-drawer id outro-message])}]))
[outro-message])
cancel-selection
(fn []
(rf/dispatch [:communities/check-permissions-to-join-community
id
unmodified-addresses-to-reveal
:based-on-client-selection])
(rf/dispatch [:hide-bottom-sheet]))
confirm-changes
(fn []
(if can-edit-addresses?
(rf/dispatch
[:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/enter-password)
:on-press (fn [password]
(rf/dispatch
[:communities/edit-shared-addresses
{:community-id id
:password password
:addresses addresses-to-reveal
:on-success (fn []
(rf/dispatch [:dismiss-modal :addresses-for-permissions])
(rf/dispatch [:hide-bottom-sheet]))}]))}])
(do
(rf/dispatch [:communities/set-share-all-addresses id flag-share-all-addresses])
(rf/dispatch [:communities/set-addresses-to-reveal id addresses-to-reveal]))))]
(rn/use-mount
(fn []
(when-not flag-share-all-addresses
(rf/dispatch [:communities/get-permissioned-balances id]))))
(rn/use-effect
(fn []
(rf/dispatch [:communities/check-permissions-to-join-during-selection id addresses-to-reveal]))
[id addresses-to-reveal])
[:<>
[page-top
{:community-id id
:identical-choices? identical-choices?
:can-edit-addresses? can-edit-addresses?}]
[gesture/flat-list
{:render-fn account-item
:render-data [addresses-to-reveal
set-addresses-to-reveal
id
color
flag-share-all-addresses]
:header [quo/category
{:list-type :settings
:data [{:title
(i18n/label
:t/share-all-current-and-future-addresses)
:action :selector
:action-props
{:on-change toggle-flag-share-all-addresses
:customization-color color
:checked? flag-share-all-addresses}}]
:container-style {:padding-bottom 16 :padding-horizontal 0}}]
:content-container-style {:padding-horizontal 20}
:key-fn :address
:data wallet-accounts}]
[quo/bottom-actions
(cond-> {:role (role-keyword highest-role)
:description (if highest-role
:top
:top-error)
:button-one-props {:customization-color color
:on-press confirm-changes
:disabled? (or (empty? addresses-to-reveal)
(not highest-role)
identical-choices?)}}
can-edit-addresses?
(->
(assoc :actions :one-action
:button-one-label (cond
(and pending? (not highest-role))
(i18n/label :t/cancel-request)
(and joined (not highest-role))
(i18n/label :t/leave-community)
:else
(i18n/label :t/confirm-changes))
:description-top-text (cond
(and pending? highest-role)
(i18n/label :t/eligible-to-join-as)
(and joined (= highest-role unmodified-role))
(i18n/label :t/you-are-a)
(and joined (not= highest-role unmodified-role))
(i18n/label :t/you-will-be-a))
:error-message (cond
(and pending? (not highest-role))
(i18n/label :t/community-join-requirements-not-met)
(and joined (not highest-role))
(i18n/label :t/membership-requirements-not-met)))
(update :button-one-props
merge
(cond (and pending? (not highest-role))
{:type :danger
:disabled? false
:on-press cancel-join-request}
(and joined (not highest-role))
{:type :danger
:disabled? false
:on-press leave-community})))
(not can-edit-addresses?)
(assoc :actions :two-actions
:button-one-label (i18n/label :t/confirm-changes)
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press cancel-selection}
:error-message (cond
(empty? addresses-to-reveal)
(i18n/label :t/no-addresses-selected)
(not highest-role)
(i18n/label :t/addresses-dont-contain-tokens-needed))))]]))

View File

@ -0,0 +1,9 @@
(ns status-im.contexts.communities.actions.airdrop-addresses.events
(:require
[utils.re-frame :as rf]))
(defn set-airdrop-address
[{:keys [db]} [community-id airdrop-address]]
{:db (assoc-in db [:communities/all-airdrop-addresses community-id] airdrop-address)})
(rf/reg-event-fx :communities/set-airdrop-address set-airdrop-address)

View File

@ -0,0 +1,18 @@
(ns status-im.contexts.communities.actions.airdrop-addresses.events-test
(:require
[cljs.test :refer [deftest is testing]]
[status-im.contexts.communities.actions.airdrop-addresses.events :as sut]))
(def community-id "community-id")
(deftest set-airdrop-address-test
(testing "updates all reveal? flags"
(let [new-airdrop-address "0xA"
cofx {:db {:communities/all-airdrop-addresses
{"another-community" "0xF"
community-id "0xB"}}}]
(is (match?
(assoc-in cofx
[:db :communities/all-airdrop-addresses community-id]
new-airdrop-address)
(sut/set-airdrop-address cofx [community-id new-airdrop-address]))))))

View File

@ -1,41 +1,81 @@
(ns status-im.contexts.communities.actions.airdrop-addresses.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.password-authentication.view :as password-authentication]
[status-im.contexts.communities.actions.airdrop-addresses.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- render-item
[item _ _ [airdrop-address community-id]]
[quo/account-item
{:account-props item
:state (when (= airdrop-address (:address item)) :selected)
:on-press (fn []
(rf/dispatch [:communities/set-airdrop-address (:address item) community-id])
(rf/dispatch [:hide-bottom-sheet]))
:emoji (:emoji item)}])
(defn- account-item
[{:keys [address emoji] :as account}
_ _
[community-id airdrop-address can-edit-addresses?]]
(let [airdrop-address? (= address airdrop-address)
on-press
(when-not airdrop-address?
(fn []
(if can-edit-addresses?
(rf/dispatch
[:password-authentication/show
{:content (fn [] [password-authentication/view])}
{:label (i18n/label :t/enter-password)
:on-press (fn [password]
(rf/dispatch
[:communities/edit-shared-addresses
{:community-id community-id
:password password
:airdrop-address address
:on-success (fn []
(rf/dispatch [:dismiss-modal :address-for-airdrop])
(rf/dispatch [:hide-bottom-sheet]))}]))}])
(do
(rf/dispatch [:communities/set-airdrop-address community-id address])
(rf/dispatch [:hide-bottom-sheet])))))]
[quo/account-item
{:account-props account
:emoji emoji
:state (if airdrop-address? :selected :default)
:on-press on-press}]))
(defn view
[]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name images color]} (rf/sub [:communities/community id])
selected-accounts (rf/sub [:communities/selected-permission-accounts id])
airdrop-address (rf/sub [:communities/airdrop-address id])]
(let [{id :community-id} (rf/sub [:get-screen-params])
{:keys [name logo color]} (rf/sub [:communities/for-context-tag id])
accounts (rf/sub [:communities/accounts-to-reveal id])
airdrop-address (rf/sub [:communities/airdrop-address id])
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
go-back (rn/use-callback #(rf/dispatch [:dismiss-modal :address-for-airdrop]))]
[:<>
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/airdrop-addresses)
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
(when can-edit-addresses?
[quo/page-nav
{:type :no-title
:icon-name :i/arrow-left
:on-press go-back}])
(if can-edit-addresses?
[quo/page-top
{:title (i18n/label :t/airdrop-addresses)
:title-accessibility-label :title-label
:description :context-tag
:context-tag {:type :community
:community-logo logo
:community-name name}}]
[quo/drawer-top
{:type :context-tag
:context-tag-type :community
:title (i18n/label :t/airdrop-addresses)
:community-name name
:button-icon :i/info
:on-button-press not-implemented/alert
:community-logo logo
:customization-color color}])
[gesture/flat-list
{:data selected-accounts
:render-fn render-item
:render-data [airdrop-address id]
{:data accounts
:render-fn account-item
:render-data [id airdrop-address can-edit-addresses?]
:content-container-style style/account-list-container
:key-fn :address}]]))

View File

@ -7,6 +7,7 @@
[status-im.contexts.communities.actions.leave.view :as leave-menu]
[status-im.contexts.communities.actions.see-rules.view :as see-rules]
[status-im.contexts.communities.actions.token-gating.view :as token-gating]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@ -41,6 +42,15 @@
{:content (fn [] [token-gating/token-requirements id])}])
:label (i18n/label :t/view-token-gating)})
(defn edit-shared-addresses
[id]
{:icon :i/wallet
:right-icon :i/chevron-right
:accessibility-label :edit-shared-addresses
:on-press (fn []
(rf/dispatch [:open-modal :community-account-selection {:community-id id}]))
:label (i18n/label :t/edit-shared-addresses)})
(defn mark-as-read
[id]
{:icon :i/up-to-date
@ -119,28 +129,33 @@
request-id])}])})
(defn not-joined-options
[id token-gated?]
[id token-gated? pending?]
[[(when-not token-gated? (view-members id))
(when-not token-gated? (view-rules id))
(invite-contacts id)
(when token-gated? (view-token-gating id))
(when (and pending? (ff/enabled? ::ff/community.edit-account-selection))
(edit-shared-addresses id))
(show-qr id)
(share-community id)]])
(defn join-request-sent-options
[id token-gated? request-id]
[(conj (first (not-joined-options id token-gated?))
[(conj (first (not-joined-options id token-gated? request-id))
(assoc (cancel-request-to-join id request-id) :add-divider? true))])
(defn banned-options
[id token-gated?]
(not-joined-options id token-gated?))
(let [pending? false]
(not-joined-options id token-gated? pending?)))
(defn joined-options
[id token-gated? muted? muted-till]
[[(view-members id)
(view-rules id)
(when token-gated? (view-token-gating id))
(when (ff/enabled? ::ff/community.edit-account-selection)
(edit-shared-addresses id))
(mark-as-read id)
(mute-community id muted? muted-till)
(community-notification-settings id)
@ -171,7 +186,7 @@
joined (joined-options id token-permissions muted muted-till)
request-id (join-request-sent-options id token-permissions request-id)
banList (banned-options id token-permissions)
:else (not-joined-options id token-permissions))))
:else (not-joined-options id token-permissions request-id))))
(defn community-options-bottom-sheet
[id]

View File

@ -29,10 +29,11 @@
{:type :positive
:text (i18n/label :t/left-community {:community community-name})}]]
[:dispatch [:activity-center.notifications/fetch-unread-count]]
[:dispatch [:hide-bottom-sheet]]
[:dispatch [:navigate-back]]]})))
(rf/reg-event-fx :communities/leave
(fn [{:keys [db]} [community-id]]
(fn [{:keys [db]} [community-id on-success]]
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:effects/push-notifications-clear-message-notifications community-chat-ids
@ -41,5 +42,8 @@
[{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(rf/dispatch [:communities/left %])
:on-success (fn [^js response]
(when (fn? on-success)
(on-success))
(rf/dispatch [:communities/left response]))
:on-error #(log/error "failed to leave community" community-id %)}]})))

View File

@ -9,10 +9,11 @@
[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.accounts-selection.events
status-im.contexts.communities.actions.addresses-for-permissions.events
status-im.contexts.communities.actions.airdrop-addresses.events
status-im.contexts.communities.actions.community-options.events
status-im.contexts.communities.actions.leave.events
[status-im.contexts.communities.utils :as utils]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
@ -29,13 +30,10 @@
{:db (assoc-in db
[:communities id]
(assoc community :last-opened-at (max last-opened-at previous-last-opened-at)))
:fx [[:dispatch [:communities/initialize-permission-addresses id]]
(when (not joined)
:fx [(when (not joined)
[:dispatch [:chat.ui/spectate-community id]])
(when (nil? token-permissions-check)
[:dispatch [:communities/check-permissions-to-join-community id]])
(when joined
[:dispatch [:communities/get-revealed-accounts id]])]}))))
[:dispatch [:communities/check-permissions-to-join-community id]])]}))))
(rf/reg-event-fx :communities/handle-community handle-community)
@ -157,97 +155,6 @@
:on-success #(rf/dispatch [:communities/fetched-collapsed-categories-success %])
:on-error #(log/error "failed to fetch collapsed community categories" %)}]}))
(defn initialize-permission-addresses
[{:keys [db]} [community-id]]
(when community-id
(let [accounts (utils/sorted-non-watch-only-accounts db)
addresses (set (map :address accounts))]
{:db (update-in db
[:communities community-id]
assoc
:previous-share-all-addresses? true
:share-all-addresses? true
:previous-permission-addresses addresses
:selected-permission-addresses addresses
:airdrop-address (:address (first accounts)))})))
(rf/reg-event-fx :communities/initialize-permission-addresses
initialize-permission-addresses)
(defn update-previous-permission-addresses
[{:keys [db]} [community-id]]
(when community-id
(let [accounts (utils/sorted-non-watch-only-accounts db)
selected-permission-addresses (get-in db
[:communities community-id
:selected-permission-addresses])
selected-accounts (filter #(contains? selected-permission-addresses (:address %))
accounts)
current-airdrop-address (get-in db [:communities community-id :airdrop-address])
share-all-addresses? (get-in db [:communities community-id :share-all-addresses?])]
{:db (update-in db
[:communities community-id]
assoc
:previous-share-all-addresses? share-all-addresses?
:previous-permission-addresses selected-permission-addresses
:airdrop-address (if (contains? selected-permission-addresses
current-airdrop-address)
current-airdrop-address
(:address (first selected-accounts))))})))
(rf/reg-event-fx :communities/update-previous-permission-addresses
update-previous-permission-addresses)
(defn toggle-selected-permission-address
[{:keys [db]} [address community-id]]
(let [selected-permission-addresses
(get-in db [:communities community-id :selected-permission-addresses])
updated-selected-permission-addresses
(if (contains? selected-permission-addresses address)
(disj selected-permission-addresses address)
(conj selected-permission-addresses address))]
{:db (assoc-in db
[:communities community-id :selected-permission-addresses]
updated-selected-permission-addresses)
:fx [(when community-id
[:dispatch
[:communities/check-permissions-to-join-community community-id
updated-selected-permission-addresses :based-on-client-selection]])]}))
(rf/reg-event-fx :communities/toggle-selected-permission-address
toggle-selected-permission-address)
(defn toggle-share-all-addresses
[{:keys [db]} [community-id]]
(let [share-all-addresses? (get-in db [:communities community-id :share-all-addresses?])
next-share-all-addresses? (not share-all-addresses?)
accounts (utils/sorted-non-watch-only-accounts db)
addresses (set (map :address accounts))]
{:db (update-in db
[:communities community-id]
assoc
:share-all-addresses? next-share-all-addresses?
:selected-permission-addresses addresses)
:fx [(when (and community-id next-share-all-addresses?)
[:dispatch
[:communities/check-permissions-to-join-community community-id
addresses :based-on-client-selection]])]}))
(rf/reg-event-fx :communities/toggle-share-all-addresses
toggle-share-all-addresses)
(rf/reg-event-fx :communities/reset-selected-permission-addresses
(fn [{:keys [db]} [community-id]]
(when community-id
{:db (update-in db
[:communities community-id]
assoc
:selected-permission-addresses
(get-in db [:communities community-id :previous-permission-addresses])
:share-all-addresses?
(get-in db [:communities community-id :previous-share-all-addresses?]))
:fx [[:dispatch [:communities/check-permissions-to-join-community community-id]]]})))
(rf/reg-event-fx :communities/get-community-channel-share-data
(fn [_ [chat-id on-success]]
(let [{:keys [community-id channel-id]} (data-store.chats/decode-chat-id chat-id)]
@ -286,10 +193,6 @@
:url %}])]
{:fx [[:dispatch [:communities/get-community-channel-share-data chat-id on-success]]]})))
(rf/reg-event-fx :communities/set-airdrop-address
(fn [{:keys [db]} [address community-id]]
{:db (assoc-in db [:communities community-id :airdrop-address] address)}))
(defn community-fetched
[{:keys [db]} [community-id community]]
(when community
@ -425,16 +328,17 @@
[:dispatch [:chat/navigate-to-chat chat-id]])]})))
(defn get-revealed-accounts
[{:keys [db]} [community-id]]
[{:keys [db]} [community-id on-success]]
(let [{:keys [joined fetching-revealed-accounts]
:as community} (get-in db [:communities community-id])]
(when (and community joined (not fetching-revealed-accounts))
:as community} (get-in db [:communities community-id])
pending? (get-in db [:communities/my-pending-requests-to-join community-id])]
(when (and community (or pending? joined) (not fetching-revealed-accounts))
{:db (assoc-in db [:communities community-id :fetching-revealed-accounts] true)
:json-rpc/call
[{:method "wakuext_getRevealedAccounts"
:params [community-id (get-in db [:profile/profile :public-key])]
:js-response true
:on-success [:communities/get-revealed-accounts-success community-id]
:on-success [:communities/get-revealed-accounts-success community-id on-success]
:on-error (fn [err]
(log/error {:message "failed to fetch revealed accounts"
:community-id community-id
@ -448,19 +352,22 @@
[:catn
[:cofx :schema.re-frame/cofx]
[:args
[:schema [:catn [:community-id [:? :string]]]]]]
[:schema
[:catn
[:community-id [:? :string]]
[:on-success [:? :schema.re-frame/event]]]]]]
[:maybe
[:map
[:db map?]
[:json-rpc/call :schema.common/rpc-call]]]])
(rf/reg-event-fx :communities/get-revealed-accounts-success
(fn [{:keys [db]} [community-id revealed-accounts-js]]
(fn [{:keys [db]} [community-id on-success revealed-accounts-js]]
(when-let [community (get-in db [:communities community-id])]
(let [revealed-accounts
(reduce
(fn [acc {:keys [address] :as revealed-account}]
(assoc acc address (dissoc revealed-account :address)))
(assoc acc address revealed-account))
{}
(data-store.communities/<-revealed-accounts-rpc revealed-accounts-js))
@ -468,7 +375,9 @@
(-> community
(assoc :revealed-accounts revealed-accounts)
(dissoc :fetching-revealed-accounts))]
{:db (assoc-in db [:communities community-id] community-with-revealed-accounts)}))))
{:db (assoc-in db [:communities community-id] community-with-revealed-accounts)
:fx [(when (vector? on-success)
[:dispatch (conj on-success revealed-accounts)])]}))))
(rf/reg-event-fx :communities/get-revealed-accounts-failed
(fn [{:keys [db]} [community-id]]

View File

@ -7,99 +7,6 @@
(def community-id "community-id")
(deftest initialize-permission-addresses-test
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}}}}}
expected-db {:db (update-in (:db initial-db)
[:communities community-id]
assoc
:share-all-addresses? true
:previous-share-all-addresses? true
:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x1" "0x2"}
:airdrop-address "0x1")}]
(is (match? expected-db (events/initialize-permission-addresses initial-db [community-id])))))
(deftest toggle-selected-permission-address-test
(let [initial-db {:db {:communities {community-id {:selected-permission-addresses #{"0x1" "0x2"}}}}}]
(is (match? {:db {:communities {community-id {:selected-permission-addresses #{"0x1"}}}}}
(events/toggle-selected-permission-address initial-db ["0x2" community-id])))
(is (match? {:db {:communities {community-id {:selected-permission-addresses #{"0x1" "0x2" "0x3"}}}}}
(events/toggle-selected-permission-address initial-db ["0x3" community-id])))))
(deftest update-previous-permission-addresses-test
(let [wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}
"0x3" {:address "0x3"
:position 2}}}]
(let [initial-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x1" "0x2"
"0x3"}
:share-all-addresses? true
:previous-share-all-addresses? false
:airdrop-address "0x1"}}}}
expected-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x1" "0x2"
"0x3"}
:selected-permission-addresses #{"0x1" "0x2"
"0x3"}
:share-all-addresses? true
:previous-share-all-addresses? true
:airdrop-address "0x1"}}}}]
(is
(match? expected-db
(events/update-previous-permission-addresses initial-db [community-id]))))
(let [initial-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x2" "0x3"}
:airdrop-address "0x1"}}}}
expected-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x2" "0x3"}
:selected-permission-addresses #{"0x2" "0x3"}
:airdrop-address "0x2"}}}}]
(is
(match? expected-db
(events/update-previous-permission-addresses initial-db [community-id]))))))
(deftest toggle-share-all-addresses-test
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}}}
:communities {community-id {:share-all-addresses? true
:previous-share-all-addresses? true
:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x1" "0x2"}
:airdrop-address "0x1"}}}}
expected-db (update-in initial-db
[:db :communities community-id]
assoc
:previous-share-all-addresses? true
:share-all-addresses?
false)]
(is (match? expected-db (events/toggle-share-all-addresses initial-db [community-id]))))
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}}}
:communities {community-id {:share-all-addresses? false
:previous-share-all-addresses? false
:previous-permission-addresses #{"0x1"}
:selected-permission-addresses #{"0x1"}
:airdrop-address "0x1"}}}}
expected-db (update-in initial-db
[:db :communities community-id]
assoc
:selected-permission-addresses #{"0x1" "0x2"}
:previous-share-all-addresses? false
:share-all-addresses? true)]
(is (match? expected-db (events/toggle-share-all-addresses initial-db [community-id])))))
(deftest fetch-community
(testing "with community id"
(testing "update fetching indicator in db"
@ -243,12 +150,14 @@
(is (match?
nil
(events/get-revealed-accounts {:db {:communities {community-id community}}} [community-id]))))
(testing "given a already :fetching-revealed-accounts community"
(is (match?
nil
(events/get-revealed-accounts
{:db {:communities {community-id (assoc community :fetching-revealed-accounts true)}}}
[community-id]))))
(testing "given joined community"
(let [community (assoc community :joined true)
db {:communities {community-id community}
@ -258,7 +167,26 @@
(:db effects)))
(is (match? {:method "wakuext_getRevealedAccounts"
:params [community-id "profile-public-key"]}
(-> effects :json-rpc/call first (select-keys [:method :params]))))))))
(-> effects :json-rpc/call first (select-keys [:method :params]))))))
(testing "given there is a pending request"
(let [pub-key "profile-public-key"
community (assoc community :joined false)
db {:communities {community-id community}
:profile/profile {:public-key pub-key}
:communities/my-pending-requests-to-join {community-id [:anything]}}
on-success [:some-event-id]
actual (events/get-revealed-accounts {:db db} [community-id on-success])
expected {:db (assoc-in db
[:communities community-id :fetching-revealed-accounts]
true)
:json-rpc/call [{:method "wakuext_getRevealedAccounts"
:params [community-id pub-key]
:js-response true
:on-success [:communities/get-revealed-accounts-success
community-id on-success]
:on-error fn?}]}]
(is (match? expected actual))))))
(deftest handle-community
(let [community {:id community-id :clock 2}]
@ -267,24 +195,22 @@
(is (match? community-id
(-> effects :db :communities (get community-id) :id)))
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:chat.ui/spectate-community community-id]]
[[:dispatch [:chat.ui/spectate-community community-id]]
[:dispatch [:communities/check-permissions-to-join-community community-id]]]
(filter some? (:fx effects))))))
(testing "given a joined community"
(let [community (assoc community :joined true)
effects (events/handle-community {} [community])]
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:communities/check-permissions-to-join-community community-id]]
[:dispatch [:communities/get-revealed-accounts community-id]]]
[[:dispatch [:communities/check-permissions-to-join-community community-id]]]
(filter some? (:fx effects))))))
(testing "given a community with token-permissions-check"
(let [community (assoc community :token-permissions-check :fake-token-permissions-check)
effects (events/handle-community {} [community])]
(is (match?
[[:dispatch [:communities/initialize-permission-addresses community-id]]
[:dispatch [:chat.ui/spectate-community community-id]]]
[[:dispatch [:chat.ui/spectate-community community-id]]]
(filter some? (:fx effects))))))
(testing "given a community with lower clock"
(let [effects (events/handle-community {:db {:communities {community-id {:clock 3}}}} [community])]

View File

@ -4,8 +4,6 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/reg-event-fx :communities/check-permissions-to-join-community-success
(fn [{:keys [db]} [community-id based-on-client-selection? result]]
(let [token-permissions-check (cond-> result
@ -118,41 +116,19 @@
:category-id category-id
:collapse? collapse?})}]}))
(defn request-to-join-with-signatures-and-addresses
[{:keys [db]} [community-id signatures]]
(let [{:keys [airdrop-address selected-permission-addresses]} (get-in db [:communities community-id])]
{:fx [[:json-rpc/call
[{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id
:signatures signatures
:addressesToReveal selected-permission-addresses
:airdropAddress airdrop-address}]
:js-response true
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error community-id]}]]]}))
(rf/reg-event-fx :communities/request-to-join-with-signatures-and-addresses
request-to-join-with-signatures-and-addresses)
(defn sign-data-with-addresses
[_ [community-id password sign-params]]
{:fx [[:json-rpc/call
[{:method "wakuext_signData"
:params [(map #(assoc % :password password) sign-params)]
:on-success [:communities/request-to-join-with-signatures-and-addresses community-id]
:on-error [:communities/requested-to-join-error community-id]}]]]})
(rf/reg-event-fx :communities/sign-data-with-addresses sign-data-with-addresses)
(defn request-to-join-with-addresses
[{:keys [db]}
[{:keys [community-id password]}]]
(let [pub-key (get-in db [:profile/profile :public-key])
addresses-to-reveal (get-in db [:communities community-id :selected-permission-addresses])]
{:fx [[:json-rpc/call
[{:method "wakuext_generateJoiningCommunityRequestsForSigning"
:params [pub-key community-id addresses-to-reveal]
:on-success [:communities/sign-data-with-addresses community-id password]
:on-error [:communities/requested-to-join-error community-id]}]]]}))
addresses-to-reveal (get-in db [:communities/all-addresses-to-reveal community-id])
airdrop-address (get-in db [:communities/all-airdrop-addresses community-id])]
{:fx [[:effects.community/request-to-join
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal addresses-to-reveal
:airdrop-address airdrop-address
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error community-id]}]]}))
(rf/reg-event-fx :communities/request-to-join-with-addresses request-to-join-with-addresses)

View File

@ -120,7 +120,7 @@
[id color]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
#(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :show-request-to-join-screen-button
@ -168,7 +168,7 @@
:padding? true}]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
#(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :join-community-button

View File

@ -63,6 +63,10 @@
{:key :admin}
{:key :member}]})
(def description-top-descriptor
{:key :description-top-text
:type :text})
(def description-descriptor
{:key :description-text
:type :text})
@ -73,28 +77,32 @@
(defn view
[]
(let [state (reagent/atom {:actions :two-actions
:description :bottom
:description-text description
:error-message "Error message"
:button-one-label button-one
:button-two-label button-two
:button-one-props {:on-press (button-press 1)
:type :primary}
:button-two-props {:on-press (button-press 2)
:type :grey}
:blur? false
:role :owner
:scroll? false})]
(let [state (reagent/atom {:actions :two-actions
:description :bottom
:description-text description
:description-top-text "Eligible to join as"
:error-message "Error message"
:button-one-label button-one
:button-two-label button-two
:button-one-props {:on-press (button-press 1)
:type :primary}
:button-two-props {:on-press (button-press 2)
:type :grey}
:blur? false
:role :owner
:scroll? false})]
(fn []
[preview/preview-container
{:state state
:descriptor (merge descriptor
(case (:description @state)
:top role-descriptor
:bottom description-descriptor
:top-error error-descriptor
nil))
:descriptor (cond-> descriptor
(= (:description @state) :top)
(conj role-descriptor description-top-descriptor)
(= (:description @state) :bottom)
(conj description-descriptor)
(= (:description @state) :top-error)
(conj error-descriptor))
:blur? (:blur? @state)
:show-blur-background? true
:blur-dark-only? true

View File

@ -10,10 +10,12 @@
(defonce ^:private feature-flags-config
(reagent/atom
{::wallet.edit-default-keypair true
::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)
::wallet.network-filter (enabled-in-env? :FLAG_NETWORK_FILTER_ENABLED)
::profile.new-contact-ui (enabled-in-env? :FLAG_NEW_CONTACT_UI_ENABLED)}))
{::wallet.edit-default-keypair true
::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)
::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED)
::wallet.network-filter (enabled-in-env? :FLAG_NETWORK_FILTER_ENABLED)
::profile.new-contact-ui (enabled-in-env? :FLAG_NEW_CONTACT_UI_ENABLED)
::community.edit-account-selection (enabled-in-env? :FLAG_EDIT_ACCOUNT_SELECTION_ENABLED)}))
(defn feature-flags [] @feature-flags-config)

View File

@ -13,6 +13,8 @@
[status-im.contexts.chat.messenger.messages.view :as chat]
[status-im.contexts.chat.messenger.photo-selector.view :as photo-selector]
[status-im.contexts.communities.actions.accounts-selection.view :as communities.accounts-selection]
[status-im.contexts.communities.actions.addresses-for-permissions.view :as addresses-for-permissions]
[status-im.contexts.communities.actions.airdrop-addresses.view :as airdrop-addresses]
[status-im.contexts.communities.actions.request-to-join.view :as join-menu]
[status-im.contexts.communities.actions.share-community-channel.view :as share-community-channel]
[status-im.contexts.communities.discover.view :as communities.discover]
@ -122,9 +124,23 @@
:options options/transparent-screen-options
:component share-community-channel/view}
{:name :community-account-selection
;; Note: the sheet screen is used when selecting addresses to share when
;; joining a community. The non-sheet screen is used when editing shared
;; addresses after the join request was sent.
{:name :community-account-selection-sheet
:options {:sheet? true}
:component communities.accounts-selection/view}
{:name :community-account-selection
:options {:insets {:top? true}}
:component communities.accounts-selection/view}
{:name :addresses-for-permissions
:options {:insets {:top? true}}
:component addresses-for-permissions/view}
{:name :address-for-airdrop
:options {:insets {:top? true}}
:component airdrop-addresses/view}
{:name :lightbox
:options options/lightbox

View File

@ -350,57 +350,6 @@
(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]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [selected-permission-addresses]}] _]
selected-permission-addresses))
(re-frame/reg-sub
:communities/share-all-addresses?
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [share-all-addresses?]}] _]
share-all-addresses?))
(re-frame/reg-sub
:communities/unsaved-address-changes?
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [share-all-addresses? previous-share-all-addresses?
selected-permission-addresses previous-permission-addresses]}] _]
(or (not= share-all-addresses? previous-share-all-addresses?)
(not= selected-permission-addresses previous-permission-addresses))))
(re-frame/reg-sub
:communities/selected-permission-accounts
(fn [[_ community-id]]
[(re-frame/subscribe [:wallet/accounts-without-watched-accounts])
(re-frame/subscribe [:communities/selected-permission-addresses community-id])])
(fn [[accounts selected-permission-addresses]]
(filter #(contains? selected-permission-addresses (:address %)) accounts)))
(re-frame/reg-sub
:communities/airdrop-address
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [airdrop-address]}] _]
airdrop-address))
(re-frame/reg-sub
:communities/airdrop-account
(fn [[_ community-id]]
[(re-frame/subscribe [:wallet/accounts-with-customization-color])
(re-frame/subscribe [:communities/airdrop-address community-id])])
(fn [[accounts airdrop-address]]
(first (filter #(= (:address %) airdrop-address) accounts))))
(re-frame/reg-sub
:communities/token-images-by-symbol
(fn [[_ community-id]]

View File

@ -358,48 +358,6 @@
:img-src token-image-eth}]]}
(rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/airdrop-account
[sub-name]
(testing "returns airdrop account"
(swap! rf-db/app-db assoc-in [:communities community-id :airdrop-address] "0x1")
(swap! rf-db/app-db assoc
:wallet
{:accounts {"0x1" {:address "0x1"
:color :blue
:name "account1"}
"0x2" {:address "0x2"
:color :orange
:name "account2"}}})
(is (match? {:address "0x1"
:network-preferences-names #{}
:name "account1"
:color :blue
:customization-color :blue}
(rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/selected-permission-accounts
[sub-name]
(testing "returns selected permission accounts"
(swap! rf-db/app-db assoc-in
[:communities community-id :selected-permission-addresses]
#{"0x1" "0x3"})
(swap! rf-db/app-db assoc
:wallet
{:accounts {"0x1" {:address "0x1" :color :blue :name "account1"}
"0x2" {:address "0x2" :color :orange :name "account2"}
"0x3" {:address "0x3" :color :purple :name "account3"}}})
(is (match? [{:address "0x1"
:color :blue
:customization-color :blue
:network-preferences-names #{}
:name "account1"}
{:address "0x3"
:color :purple
:customization-color :purple
:network-preferences-names #{}
:name "account3"}]
(rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/community-color
[sub-name]
(testing "returns the community color"

View File

@ -0,0 +1,69 @@
(ns status-im.subs.community.account-selection
(:require
[re-frame.core :as re-frame]))
;; This sub is particularly useful in context tags in page-nav or drawer-top
;; components. It should be preferred instead of subscribing to the whole
;; community.
(re-frame/reg-sub :communities/for-context-tag
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [name images color]}]]
{:name name
:logo (get-in images [:thumbnail :uri])
:color color}))
(re-frame/reg-sub :communities/addresses-to-reveal
:<- [:communities/all-addresses-to-reveal]
(fn [addresses-by-id [_ community-id]]
(get addresses-by-id community-id)))
(re-frame/reg-sub :communities/airdrop-address
:<- [:communities/all-airdrop-addresses]
(fn [addresses-by-id [_ community-id]]
(get addresses-by-id community-id)))
(re-frame/reg-sub :communities/share-all-addresses?
:<- [:communities/selected-share-all-addresses]
(fn [flags-by-id [_ community-id]]
(get flags-by-id community-id)))
(re-frame/reg-sub :communities/can-edit-shared-addresses?
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])
(re-frame/subscribe [:communities/my-pending-request-to-join community-id])])
(fn [[{:keys [joined]} pending-requests]]
(boolean (or joined (seq pending-requests)))))
(re-frame/reg-sub :communities/permissions-check-for-selection
:<- [:communities/permissions-checks-for-selection]
(fn [permissions [_ id]]
(get permissions id)))
(re-frame/reg-sub :communities/highest-role-for-selection
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/permissions-check-for-selection community-id])])
(fn [[permissions-check] _]
(get-in permissions-check [:check :highestRole :type])))
(re-frame/reg-sub :communities/accounts-to-reveal
(fn [[_ community-id]]
[(re-frame/subscribe [:wallet/accounts-without-watched-accounts])
(re-frame/subscribe [:communities/addresses-to-reveal community-id])])
(fn [[accounts addresses] _]
(filter #(contains? addresses (:address %))
accounts)))
(re-frame/reg-sub :communities/airdrop-account
(fn [[_ community-id]]
[(re-frame/subscribe [:wallet/accounts-without-watched-accounts])
(re-frame/subscribe [:communities/airdrop-address community-id])])
(fn [[accounts airdrop-address] _]
(->> accounts
(filter #(= (:address %) airdrop-address))
first)))
(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)])))

View File

@ -0,0 +1,75 @@
(ns status-im.subs.community.account-selection-test
(:require
[cljs.test :refer [is testing]]
matcher-combinators.test
[re-frame.db :as rf-db]
status-im.subs.communities
[test-helpers.unit :as h]
[utils.re-frame :as rf]))
(def community-id "0x1")
(h/deftest-sub :communities/for-context-tag
[sub-name]
(reset! rf-db/app-db
{:communities
{community-id {:name "foo"
:images {:thumbnail {:uri "data:image/png;"}}
:color :orange}}})
(is (match? {:name "foo"
:logo "data:image/png;"
:color :orange}
(rf/sub [sub-name community-id]))))
(h/deftest-sub :communities/can-edit-shared-addresses?
[sub-name]
(testing "joined community and there are pending requests"
(reset! rf-db/app-db
{:communities {community-id {:id community-id :joined true}}
:communities/my-pending-request-to-join {community-id {:id :request-id-1}}})
(is (true? (rf/sub [sub-name community-id]))))
(testing "joined community and there are no pending requests"
(reset! rf-db/app-db
{:communities {community-id {:id community-id :joined true}}
:communities/my-pending-request-to-join {community-id {}}})
(is (true? (rf/sub [sub-name community-id]))))
(testing "not joined community and there are pending requests"
(reset! rf-db/app-db
{:communities {community-id {:id community-id :joined false}}
:communities/my-pending-request-to-join {community-id {:id :request-id-1}}})
(is (false? (rf/sub [sub-name community-id]))))
(testing "not joined community and there are no pending requests"
(reset! rf-db/app-db
{:communities {community-id {:id community-id :joined false}}
:communities/my-pending-request-to-join {community-id {}}})
(is (false? (rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/airdrop-account
[sub-name]
(let [airdrop-account {:address "0xA" :position 1}]
(reset! rf-db/app-db
{:communities/all-airdrop-addresses {community-id "0xA"}
:wallet {:accounts {"0xB" {:address "0xB" :position 0}
"0xA" airdrop-account}}})
(is (match? airdrop-account (rf/sub [sub-name community-id])))))
(h/deftest-sub :communities/accounts-to-reveal
[sub-name]
(reset! rf-db/app-db
{:communities/all-addresses-to-reveal {community-id #{"0xC" "0xB"}}
:wallet {:accounts {"0xB" {:address "0xB" :position 0}
"0xA" {:address "0xA" :position 1}
"0xC" {:address "0xC" :position 2}}}})
(is (match? [{:address "0xB" :position 0}
{:address "0xC" :position 2}]
(rf/sub [sub-name community-id]))))

View File

@ -6,6 +6,7 @@
status-im.subs.biometrics
status-im.subs.chats
status-im.subs.communities
status-im.subs.community.account-selection
status-im.subs.contact
status-im.subs.general
status-im.subs.messages
@ -150,6 +151,11 @@
(reg-root-key-sub :contract-communities :contract-communities)
(reg-root-key-sub :communities/permissioned-balances :communities/permissioned-balances)
(reg-root-key-sub :communities/permissions-check :communities/permissions-check)
(reg-root-key-sub :communities/all-addresses-to-reveal :communities/all-addresses-to-reveal)
(reg-root-key-sub :communities/all-airdrop-addresses :communities/all-airdrop-addresses)
(reg-root-key-sub :communities/selected-share-all-addresses :communities/selected-share-all-addresses)
(reg-root-key-sub :communities/permissions-checks-for-selection
:communities/permissions-checks-for-selection)
(reg-root-key-sub :communities/channel-permissions-check :communities/channel-permissions-check)
;;activity center

View File

@ -2279,6 +2279,19 @@
"sync-devices-complete-title": "Device sync complete!",
"sync-devices-complete-sub-title": "Your devices are now in sync",
"synced-with": "Synced with",
"confirm-and-leave": "Confirm and leave",
"membership-requirements-not-met": "Membership requirements not met",
"edit-shared-addresses": "Edit shared addresses",
"leave-community-farewell": "Well be sad to see you go but remember, you can come back at any time! All shared addresses will be unshared.",
"pending-join-request-farewell": "Well be sad to see you go but remember, you can request to join this community at any point. All shared addresses will be unshared.",
"all-changes-will-be-discarded": "All changes in shared addresses for permissions will be discarded.",
"cancel-request": "Cancel request",
"discard": "Discard",
"discard-changes?": "Discard changes?",
"confirm-and-cancel": "Confirm and cancel",
"you-will-be-a": "Youll be a",
"you-are-a": "Youre a",
"you-are-a-role": "Youre a {{role}}",
"you-eligible-to-join": "Youre eligible to join",
"you-eligible-to-join-as": "Youre eligible to join as {{role}}",
"eligible-to-join-as": "Eligible to join as",