From 54d9e5ebeb546b0d03903ce3d9a3e1e88cbd4f70 Mon Sep 17 00:00:00 2001 From: Ajay Sivan Date: Fri, 16 Feb 2024 17:41:22 +0530 Subject: [PATCH] Share all current and future addresses - UI (#18843) Fixes - 'Confirm changes' button unexpected enabled state - The Confirm button remains enabled even after deselecting all addresses when the user has watch-only wallet accounts. - Disable the Confirm button when the user deselects the accounts with the token required to join. - Use community color for address checkbox --- .../wallet/account_permissions/schema.cljs | 1 + .../wallet/account_permissions/view.cljs | 17 ++++--- .../addresses_for_permissions/view.cljs | 47 ++++++++++++++----- .../contexts/communities/events.cljs | 45 +++++++++++++----- .../contexts/communities/events_test.cljs | 40 ++++++++++++++++ src/status_im/contexts/communities/utils.cljs | 7 +++ .../quo/wallet/account_permissions.cljs | 39 ++++++++------- src/status_im/subs/communities.cljs | 16 +++++++ translations/en.json | 1 + 9 files changed, 164 insertions(+), 49 deletions(-) diff --git a/src/quo/components/wallet/account_permissions/schema.cljs b/src/quo/components/wallet/account_permissions/schema.cljs index d59e6c90d6..a0dd1d95b8 100644 --- a/src/quo/components/wallet/account_permissions/schema.cljs +++ b/src/quo/components/wallet/account_permissions/schema.cljs @@ -18,5 +18,6 @@ [:disabled? {:optional true} [:maybe :boolean]] [:on-change {:optional true} [:maybe fn?]] [:container-style {:optional true} [:maybe :map]] + [:customization-color {:optional true} [:maybe :schema.common/customization-color]] [:theme :schema.common/theme]]]] :any]) diff --git a/src/quo/components/wallet/account_permissions/view.cljs b/src/quo/components/wallet/account_permissions/view.cljs index bf77f21338..95c4b9deb4 100644 --- a/src/quo/components/wallet/account_permissions/view.cljs +++ b/src/quo/components/wallet/account_permissions/view.cljs @@ -42,9 +42,11 @@ (defn- view-internal [{:keys - [checked? disabled? on-change token-details keycard? theme container-style] + [checked? disabled? on-change token-details keycard? theme container-style customization-color] {:keys - [name address emoji customization-color]} :account}] + [name address emoji] + :as account} :account + :or {customization-color :blue}}] [rn/view {:style (merge (style/container theme) container-style) :accessibility-label :wallet-account-permissions} @@ -52,7 +54,7 @@ [account-avatar/view {:size 32 :emoji emoji - :customization-color customization-color}] + :customization-color (:customization-color account)}] [rn/view {:style style/account-details} [rn/view {:style style/name-and-keycard} [text/text @@ -67,10 +69,11 @@ {:address address :format :short}]] [selectors/view - {:type :checkbox - :checked? checked? - :disabled? disabled? - :on-change on-change}]] + {:type :checkbox + :checked? checked? + :customization-color customization-color + :disabled? disabled? + :on-change on-change}]] [token-details-section token-details]]) diff --git a/src/status_im/contexts/communities/actions/addresses_for_permissions/view.cljs b/src/status_im/contexts/communities/actions/addresses_for_permissions/view.cljs index 789a339b1b..38bbeb2d73 100644 --- a/src/status_im/contexts/communities/actions/addresses_for_permissions/view.cljs +++ b/src/status_im/contexts/communities/actions/addresses_for_permissions/view.cljs @@ -32,18 +32,21 @@ :token (:symbol balance))))) (defn- account-item - [{:keys [color address name emoji]} _ _ [selected-addresses community-id]] + [{:keys [color address name emoji]} _ _ + {:keys [selected-addresses community-id share-all-addresses? community-color]}] (let [balances (rf/sub [:communities/permissioned-balances-by-address community-id address])] [quo/account-permissions - {:account {:name name - :address address - :emoji emoji - :customization-color color} - :token-details (balances->components-props balances) - :checked? (contains? selected-addresses address) - :on-change #(rf/dispatch [:communities/toggle-selected-permission-address - address community-id]) - :container-style {:margin-bottom 8}}])) + {:account {:name name + :address address + :emoji emoji + :customization-color color} + :token-details (balances->components-props balances) + :checked? (contains? selected-addresses address) + :disabled? share-all-addresses? + :on-change #(rf/dispatch [:communities/toggle-selected-permission-address + address community-id]) + :container-style {:margin-bottom 8} + :customization-color community-color}])) (defn view [{:keys [scroll-enabled? on-scroll]}] @@ -54,6 +57,8 @@ {:keys [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]) highest-role-text (when highest-permission-role (i18n/label (communities.utils/role->translation-key highest-permission-role)))] @@ -68,10 +73,24 @@ :community-logo (get-in images [:thumbnail :uri]) :customization-color color}] + [quo/category + {:list-type :settings + :data [{:title (i18n/label :t/share-all-current-and-future-addresses) + :action :selector + :action-props {:on-change #(rf/dispatch + [:communities/toggle-share-all-addresses + id]) + :customization-color color + :checked? share-all-addresses?}}] + :container-style {:padding-bottom 16}}] + [gesture/flat-list {:render-fn account-item - :render-data [selected-addresses id] - :content-container-style {:padding 20} + :render-data {:selected-addresses selected-addresses + :community-id id + :share-all-addresses? share-all-addresses? + :community-color color} + :content-container-style {:padding-horizontal 20} :scroll-enabled scroll-enabled? :on-scroll on-scroll :key-fn :address @@ -109,7 +128,9 @@ [quo/button {:container-style {:flex 1} :customization-color color - :disabled? (empty? selected-addresses) + :disabled? (or (empty? selected-addresses) + (not highest-permission-role) + (not unsaved-address-changes?)) :on-press (fn [] (rf/dispatch [:communities/update-previous-permission-addresses id]) (rf/dispatch [:navigate-back]))} diff --git a/src/status_im/contexts/communities/events.cljs b/src/status_im/contexts/communities/events.cljs index 40ad49d70d..36777deee6 100644 --- a/src/status_im/contexts/communities/events.cljs +++ b/src/status_im/contexts/communities/events.cljs @@ -12,6 +12,7 @@ status-im.contexts.communities.actions.addresses-for-permissions.events status-im.contexts.communities.actions.community-options.events status-im.contexts.communities.actions.leave.events + [status-im.contexts.communities.utils :as utils] [status-im.navigation.events :as navigation] [taoensso.timbre :as log] [utils.i18n :as i18n] @@ -163,15 +164,16 @@ (defn initialize-permission-addresses [{:keys [db]} [community-id]] (when community-id - (let [accounts (get-in db [:wallet :accounts]) - sorted-accounts (sort-by :position (vals accounts)) - addresses (set (map :address sorted-accounts))] + (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 sorted-accounts)))}))) + :airdrop-address (:address (first accounts)))}))) (rf/reg-event-fx :communities/initialize-permission-addresses initialize-permission-addresses) @@ -179,17 +181,18 @@ (defn update-previous-permission-addresses [{:keys [db]} [community-id]] (when community-id - (let [accounts (get-in db [:wallet :accounts]) - sorted-accounts (sort-by :position (vals accounts)) + (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 %)) - sorted-accounts) - current-airdrop-address (get-in db [:communities community-id :airdrop-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) @@ -218,12 +221,32 @@ (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?]) + accounts (utils/sorted-non-watch-only-accounts db) + addresses (set (map :address accounts))] + {:db (update-in db + [:communities community-id] + (fn [community] + (-> community + (assoc :share-all-addresses? (not share-all-addresses?)) + (cond-> (not share-all-addresses?) + (assoc :selected-permission-addresses addresses)))))})) + +(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 (assoc-in db - [:communities community-id :selected-permission-addresses] - (get-in db [:communities community-id :previous-permission-addresses])) + {: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/share-community-channel-url-with-data diff --git a/src/status_im/contexts/communities/events_test.cljs b/src/status_im/contexts/communities/events_test.cljs index 510b6a122c..374d8763bb 100644 --- a/src/status_im/contexts/communities/events_test.cljs +++ b/src/status_im/contexts/communities/events_test.cljs @@ -16,6 +16,8 @@ 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")}] @@ -39,12 +41,16 @@ :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 @@ -61,6 +67,40 @@ (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"} + :selected-permission-addresses #{"0x1"} + :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" diff --git a/src/status_im/contexts/communities/utils.cljs b/src/status_im/contexts/communities/utils.cljs index 51bffa37a9..808dbc9279 100644 --- a/src/status_im/contexts/communities/utils.cljs +++ b/src/status_im/contexts/communities/utils.cljs @@ -11,3 +11,10 @@ constants/community-token-permission-become-admin :t/admin constants/community-token-permission-become-member :t/member fallback-to))) + +(defn sorted-non-watch-only-accounts + [db] + (->> (get-in db [:wallet :accounts]) + (vals) + (remove :watch-only?) + (sort-by :position))) diff --git a/src/status_im/contexts/preview/quo/wallet/account_permissions.cljs b/src/status_im/contexts/preview/quo/wallet/account_permissions.cljs index fde6ded763..ea276b05a3 100644 --- a/src/status_im/contexts/preview/quo/wallet/account_permissions.cljs +++ b/src/status_im/contexts/preview/quo/wallet/account_permissions.cljs @@ -24,7 +24,8 @@ {:key :empty-token-list} {:key :1-token} {:key :3-tokens} - {:key :5-tokens}]}]) + {:key :5-tokens}]} + (preview/customization-color-option {:key :customization-color})]) (def ^:private token-details {:no-tokens nil @@ -50,23 +51,25 @@ (defn view [] - (let [state (reagent/atom {:name "Trip to Vegas" - :address "0x2f0fbf0a93c5999e9b4410848403a02b38983eb2" - :emoji "😊" - :account-color :blue - :token-details :no-tokens - :keycard? true - :checked? true - :disabled? false})] + (let [state (reagent/atom {:name "Trip to Vegas" + :address "0x2f0fbf0a93c5999e9b4410848403a02b38983eb2" + :emoji "😊" + :account-color :blue + :token-details :no-tokens + :customization-color :blue + :keycard? true + :checked? true + :disabled? false})] (fn [] [preview/preview-container {:state state :descriptor descriptor} [quo/account-permissions - {:account {:name (:name @state) - :address (:address @state) - :emoji (:emoji @state) - :customization-color (:account-color @state)} - :token-details (token-details (:token-details @state)) - :keycard? (:keycard? @state) - :checked? (:checked? @state) - :disabled? (:disabled? @state) - :on-change (fn [checked?] (swap! state assoc :checked? checked?))}]]))) + {:account {:name (:name @state) + :address (:address @state) + :emoji (:emoji @state) + :customization-color (:account-color @state)} + :token-details (token-details (:token-details @state)) + :keycard? (:keycard? @state) + :checked? (:checked? @state) + :disabled? (:disabled? @state) + :customization-color (:customization-color @state) + :on-change (fn [checked?] (swap! state assoc :checked? checked?))}]]))) diff --git a/src/status_im/subs/communities.cljs b/src/status_im/subs/communities.cljs index cb8112dbc8..6cda8007d7 100644 --- a/src/status_im/subs/communities.cljs +++ b/src/status_im/subs/communities.cljs @@ -367,6 +367,22 @@ (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]] diff --git a/translations/en.json b/translations/en.json index 6c804bc358..f1acc4560e 100644 --- a/translations/en.json +++ b/translations/en.json @@ -180,6 +180,7 @@ "other": "{{count}} members" }, "community-rules": "Community rules", + "share-all-current-and-future-addresses": "Share all current and future addresses", "address-to-share": "Addresses to share", "addresses-for-permissions": "Addresses for permissions", "no-addresses-selected": "At least 1 address must be shared with community",