From b021b1e20a8307367972ae3552590d9de73b5d60 Mon Sep 17 00:00:00 2001 From: Shivek Khurana Date: Tue, 2 Jul 2024 18:48:48 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=9B=EF=B8=8F=20Account=20switcher=20UI?= =?UTF-8?q?=20for=20Wallet=20Connect=20sessions=20(#20573)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🎛️ Account switcher UI for Wallet Connect sessions * 😢 Remove repl workflow * 🔀 Merge current-proposal request and account * ❌ Remove redundant test * 🐛 Lint fix --------- Co-authored-by: Lungu Cristian --- .../wallet/wallet_connect/events.cljs | 68 +++++++------ .../session_proposal/style.cljs | 7 ++ .../wallet_connect/session_proposal/view.cljs | 99 +++++++++++++------ src/status_im/subs/wallet/wallet_connect.cljs | 7 +- .../subs/wallet/wallet_connect_test.cljs | 22 ++++- 5 files changed, 142 insertions(+), 61 deletions(-) diff --git a/src/status_im/contexts/wallet/wallet_connect/events.cljs b/src/status_im/contexts/wallet/wallet_connect/events.cljs index 2c7fdc1dd6..eff08d1ca1 100644 --- a/src/status_im/contexts/wallet/wallet_connect/events.cljs +++ b/src/status_im/contexts/wallet/wallet_connect/events.cljs @@ -53,10 +53,22 @@ (rf/reg-event-fx :wallet-connect/on-session-proposal (fn [{:keys [db]} [proposal]] - (log/info "Received Wallet Connect session proposal: " {:id (:id proposal)}) - {:db (assoc db :wallet-connect/current-proposal proposal) - :fx [[:dispatch - [:open-modal :screen/wallet.wallet-connect-session-proposal]]]})) + (let [accounts (get-in db [:wallet :accounts]) + without-watched (remove :watch-only? (vals accounts))] + (log/info "Received Wallet Connect session proposal: " {:id (:id proposal)}) + {:db (assoc db + ;; NOTE: for now using the first account, but should be using the account selected + ;; by the user on the connection screen. The default would depend on where the + ;; connection started from: + ;; - global scanner -> first account in list + ;; - wallet account dapps -> account that is selected + :wallet-connect/current-proposal + {:request proposal + :address (-> without-watched + first + :address)}) + :fx [[:dispatch + [:open-modal :screen/wallet.wallet-connect-session-proposal]]]}))) (rf/reg-event-fx :wallet-connect/on-session-request @@ -69,6 +81,11 @@ (fn [{:keys [db]}] {:db (dissoc db :wallet-connect/current-proposal)})) +(rf/reg-event-fx + :wallet-connect/set-current-proposal-address + (fn [{:keys [db]} [address]] + {:db (assoc-in db [:wallet-connect/current-proposal :address] address)})) + (rf/reg-event-fx :wallet-connect/reset-current-request (fn [{:keys [db]}] @@ -119,39 +136,34 @@ (rf/reg-event-fx :wallet-connect/approve-session (fn [{:keys [db]}] - (let [web3-wallet (get db :wallet-connect/web3-wallet) - current-proposal (get db :wallet-connect/current-proposal) - accounts (get-in db [:wallet :accounts]) - supported-chain-ids (->> db - chain/chain-ids - (map wallet-connect-core/chain-id->eip155) - vec) - ;; NOTE: for now using the first account, but should be using the account selected by the - ;; user on the connection screen. The default would depend on where the connection started - ;; from: - ;; - global scanner -> first account in list - ;; - wallet account dapps -> account that is selected - address (-> accounts keys first) - accounts (-> (partial wallet-connect-core/format-eip155-address address) - (map supported-chain-ids)) - supported-namespaces (clj->js {:eip155 - {:chains supported-chain-ids - :methods constants/wallet-connect-supported-methods - :events constants/wallet-connect-supported-events - :accounts accounts}})] + (let [web3-wallet (get db :wallet-connect/web3-wallet) + current-proposal-request (get-in db [:wallet-connect/current-proposal :request]) + supported-chain-ids (->> db + chain/chain-ids + (map wallet-connect-core/chain-id->eip155) + vec) + current-address (get-in db [:wallet-connect/current-proposal :address]) + accounts (-> (partial wallet-connect-core/format-eip155-address current-address) + (map supported-chain-ids)) + supported-namespaces (clj->js {:eip155 + {:chains supported-chain-ids + :methods constants/wallet-connect-supported-methods + :events constants/wallet-connect-supported-events + :accounts accounts}})] {:fx [[:effects.wallet-connect/approve-session {:web3-wallet web3-wallet - :proposal current-proposal + :proposal current-proposal-request :supported-namespaces supported-namespaces :on-success (fn [] (log/info "Wallet Connect session approved") - (let [metadata (-> current-proposal :params :proposer :metadata)] + (let [metadata + (-> current-proposal-request :params :proposer :metadata)] (rf/dispatch [:wallet-connect/reset-current-session-proposal]) (rf/dispatch [:wallet-connect/persist-session - {:id (:id current-proposal) + {:id (:id current-proposal-request) :dapp-name (:name metadata) :dapp-url (:url metadata) - :session-info current-proposal}]))) + :session-info current-proposal-request}]))) :on-fail (fn [error] (log/error "Wallet Connect session approval failed" {:error error diff --git a/src/status_im/contexts/wallet/wallet_connect/session_proposal/style.cljs b/src/status_im/contexts/wallet/wallet_connect/session_proposal/style.cljs index 488c180398..b8438fb73d 100644 --- a/src/status_im/contexts/wallet/wallet_connect/session_proposal/style.cljs +++ b/src/status_im/contexts/wallet/wallet_connect/session_proposal/style.cljs @@ -24,3 +24,10 @@ (def approval-li-spacer {:width 8}) + +(def account-switcher-title + {:padding-horizontal 20}) + +(def account-switcher-list + {:margin-top 8 + :padding-horizontal 8}) diff --git a/src/status_im/contexts/wallet/wallet_connect/session_proposal/view.cljs b/src/status_im/contexts/wallet/wallet_connect/session_proposal/view.cljs index 770037f503..2ae147219e 100644 --- a/src/status_im/contexts/wallet/wallet_connect/session_proposal/view.cljs +++ b/src/status_im/contexts/wallet/wallet_connect/session_proposal/view.cljs @@ -51,36 +51,79 @@ {:source (quo.resources/get-network :optimism)} {:source (quo.resources/get-network :arbitrum)}]) +(defn- set-current-proposal-address + [acc] + (fn [] + (rf/dispatch [:wallet-connect/set-current-proposal-address (:address acc)]) + (rf/dispatch [:hide-bottom-sheet]))) + +(defn- accounts-list + [] + (let [accounts (rf/sub [:wallet/accounts-without-watched-accounts]) + selected-address (rf/sub [:wallet-connect/current-proposal-address])] + [rn/view {:style style/account-switcher-list} + (for [account accounts] + ^{:key (-> account :address str)} + [quo/account-item + {:type :default + :state (if (and selected-address + (= (account :address) + selected-address)) + :selected + :default) + :account-props account + :on-press (set-current-proposal-address account)}])])) + +(defn- account-switcher-sheet + [] + [:<> + [rn/view {:style style/account-switcher-title} + [quo/text + {:size :heading-2 + :weight :semi-bold + :accessibility-label "select-account-title"} + (i18n/label :t/select-account)]] + [accounts-list]]) + +(defn- show-account-switcher-bottom-sheet + [] + (rf/dispatch + [:show-bottom-sheet + {:content account-switcher-sheet}])) + (defn- connection-category [] - (let [{:keys [name emoji customization-color]} (first (rf/sub - [:wallet/accounts-without-watched-accounts])) - data-item-common-props {:blur? false - :description :default - :card? false - :label :preview - :status :default - :size :default} - account-data-item-props (assoc data-item-common-props - :right-content {:type :accounts - :size :size-32 - :data [{:emoji emoji - :customization-color - customization-color}]} - :on-press #(js/alert "Not yet implemented") - :title (i18n/label :t/account-title) - :subtitle name - :icon-right? true - :right-icon :i/chevron-right - :icon-color colors/neutral-10) - networks-data-item-props (assoc data-item-common-props - :right-content {:type :network - :data - (get-placeholder-networks)} - :title (i18n/label :t/networks) - ;; TODO. The quo component for data-item - ;; does not support showing networks yet - :subtitle "Networks placeholder")] + (let [address (rf/sub [:wallet-connect/current-proposal-address]) + {:keys + [name + customization-color + emoji]} (rf/sub [:wallet-connect/account-details-by-address address]) + data-item-common-props {:blur? false + :description :default + :card? false + :label :preview + :status :default + :size :default} + account-data-item-props (assoc data-item-common-props + :right-content {:type :accounts + :size :size-32 + :data [{:emoji emoji + :customization-color + customization-color}]} + :on-press show-account-switcher-bottom-sheet + :title (i18n/label :t/account-title) + :subtitle name + :icon-right? true + :right-icon :i/chevron-right + :icon-color colors/neutral-10) + networks-data-item-props (assoc data-item-common-props + :right-content {:type :network + :data + (get-placeholder-networks)} + :title (i18n/label :t/networks) + ;; TODO. The quo component for data-item + ;; does not support showing networks yet + :subtitle "Networks placeholder")] [quo/category {:blur? false :list-type :data-item diff --git a/src/status_im/subs/wallet/wallet_connect.cljs b/src/status_im/subs/wallet/wallet_connect.cljs index a7609c5b84..d452036344 100644 --- a/src/status_im/subs/wallet/wallet_connect.cljs +++ b/src/status_im/subs/wallet/wallet_connect.cljs @@ -111,10 +111,15 @@ :wallet-connect/session-proposer :<- [:wallet-connect/current-proposal] (fn [proposal] - (-> proposal :params :proposer))) + (-> proposal :request :params :proposer))) (rf/reg-sub :wallet-connect/session-proposer-name :<- [:wallet-connect/session-proposer] (fn [proposer] (-> proposer :metadata :name))) + +(rf/reg-sub + :wallet-connect/current-proposal-address + (fn [db] + (get-in db [:wallet-connect/current-proposal :address]))) diff --git a/src/status_im/subs/wallet/wallet_connect_test.cljs b/src/status_im/subs/wallet/wallet_connect_test.cljs index 097335ed4c..634ea20e7f 100644 --- a/src/status_im/subs/wallet/wallet_connect_test.cljs +++ b/src/status_im/subs/wallet/wallet_connect_test.cljs @@ -45,8 +45,8 @@ [sub-name] (testing "Return the session proposer public key and metadata" (swap! rf-db/app-db - assoc - :wallet-connect/current-proposal + assoc-in + [:wallet-connect/current-proposal :request] sample-session) (let [proposer (rf/sub [sub-name])] @@ -60,9 +60,23 @@ [sub-name] (testing "Return only the name of the session proposer" (swap! rf-db/app-db - assoc - :wallet-connect/current-proposal + assoc-in + [:wallet-connect/current-proposal :request] sample-session) (is (= (-> sample-session :params :proposer :metadata :name) (rf/sub [sub-name]))))) + +(h/deftest-sub :wallet-connect/current-proposal-address + [sub-name] + (testing "Return the current proposal account address" + (let [address "0x1234567890abcdef"] + + (swap! rf-db/app-db assoc-in [:wallet-connect/current-proposal :address] address) + + (is (= address (rf/sub [sub-name])))) + + (testing "Return nil when there is no current proposal account" + (swap! rf-db/app-db assoc-in [:wallet-connect/current-proposal :address] nil) + + (is (nil? (rf/sub [sub-name]))))))