diff --git a/src/quo/components/list_items/saved_address/view.cljs b/src/quo/components/list_items/saved_address/view.cljs index 34c2c967dff..9f2b93bd856 100644 --- a/src/quo/components/list_items/saved_address/view.cljs +++ b/src/quo/components/list_items/saved_address/view.cljs @@ -1,5 +1,6 @@ (ns quo.components.list-items.saved-address.view (:require + [clojure.string :as string] [quo.components.avatars.wallet-user-avatar.view :as wallet-user-avatar] [quo.components.icon :as icon] [quo.components.list-items.saved-address.style :as style] @@ -9,32 +10,51 @@ [react-native.core :as rn] [utils.address :as address])) +(def ^:private chains-map + {:eth :ethereum + :arb :arbitrum + :opt :optimism}) + (defn- left-container - [{:keys [blur? name ens address customization-color]}] + [{:keys [blur? ens address customization-color chain-color-map] address-name :name}] (let [theme (quo.theme/use-theme)] [rn/view {:style style/left-container} [wallet-user-avatar/wallet-user-avatar {:size :size-32 - :full-name name + :full-name address-name :customization-color customization-color}] [rn/view {:style style/account-container} [text/text {:weight :semi-bold :size :paragraph-1 :style style/name-text} - name] + address-name] [text/text {:size :paragraph-2} [text/text {:size :paragraph-2 :weight :monospace :style (style/account-address blur? theme)} + (map (fn [[chain color]] + ^{:key chain} + [text/text + {:size :paragraph-2 + :weight :monospace + :style {:color color}} (str (name chain) ":")]) + chain-color-map) (or ens (address/get-shortened-key address))]]]])) (defn view - [{:keys [blur? user-props active-state? customization-color on-press on-options-press] + [{:keys [blur? user-props active-state? customization-color on-press on-options-press chains] :or {customization-color :blue blur? false}}] (let [theme (quo.theme/use-theme) + chains-vector (map keyword (string/split chains #":")) + chain-color-map (->> chains-vector + (map (fn [chain-short-keyword] + (let [chain-full-name (get chains-map chain-short-keyword)] + {chain-short-keyword (colors/resolve-color chain-full-name + theme)}))) + (into {})) [state set-state] (rn/use-state :default) active? (rn/use-ref-atom false) timer (rn/use-ref-atom nil) @@ -64,7 +84,8 @@ :name (:name user-props) :ens (:ens user-props) :address (:address user-props) - :customization-color (or (:customization-color user-props) :blue)}] + :customization-color (or (:customization-color user-props) :blue) + :chain-color-map (when chains chain-color-map)}] (when on-options-press [rn/pressable {:accessibility-label :options-button diff --git a/src/status_im/contexts/preview/quo/list_items/saved_address.cljs b/src/status_im/contexts/preview/quo/list_items/saved_address.cljs index defccacf0d8..a8a1395f1fe 100644 --- a/src/status_im/contexts/preview/quo/list_items/saved_address.cljs +++ b/src/status_im/contexts/preview/quo/list_items/saved_address.cljs @@ -8,7 +8,8 @@ [(preview/customization-color-option {:key :account-color}) {:key :blur? :type :boolean} {:key :title :type :text} - (preview/customization-color-option)]) + (preview/customization-color-option) + {:key :chains :type :text}]) (defn view [] @@ -17,7 +18,8 @@ :account-color :flamingo :title "Alisher Yakupov" :address "0x21a...49e" - :on-options-press #(js/alert "Options button pressed!")})] + :on-options-press #(js/alert "Options button pressed!") + :chains "eth:opt:arb:"})] (fn [] [preview/preview-container {:state state diff --git a/src/status_im/contexts/settings/wallet/saved_addresses/events.cljs b/src/status_im/contexts/settings/wallet/saved_addresses/events.cljs new file mode 100644 index 00000000000..099f493bdca --- /dev/null +++ b/src/status_im/contexts/settings/wallet/saved_addresses/events.cljs @@ -0,0 +1,20 @@ +(ns status-im.contexts.settings.wallet.saved-addresses.events + (:require [taoensso.timbre :as log] + [utils.re-frame :as rf])) + +(rf/reg-event-fx + :wallet/remove-account-success + (fn [_ [toast-message _]] + {:fx [[:dispatch [:wallet/get-saved-addresses]] + [:dispatch-later + {:ms 100 + :dispatch [:wallet/show-account-deleted-toast toast-message]}]]})) + +(rf/defn delete-saved-address + {:events [:wallet/delete-saved-address]} + [_ {:keys [address test? toast-message]}] + {:json-rpc/call + [{:method "wakuext_deleteSavedAddress" + :params [address test?] + :on-success [:wallet/remove-account-success toast-message] + :on-error #(log/error "Failed to delete saved address" %)}]}) diff --git a/src/status_im/contexts/settings/wallet/saved_addresses/style.cljs b/src/status_im/contexts/settings/wallet/saved_addresses/style.cljs index ba3c5fff917..1c03054ef3f 100644 --- a/src/status_im/contexts/settings/wallet/saved_addresses/style.cljs +++ b/src/status_im/contexts/settings/wallet/saved_addresses/style.cljs @@ -2,7 +2,8 @@ (def title-container {:padding-horizontal 20 - :margin-top 12}) + :margin-top 12 + :margin-bottom 16}) (defn page-wrapper [inset-top] diff --git a/src/status_im/contexts/settings/wallet/saved_addresses/view.cljs b/src/status_im/contexts/settings/wallet/saved_addresses/view.cljs index c5274fa0662..11194256eba 100644 --- a/src/status_im/contexts/settings/wallet/saved_addresses/view.cljs +++ b/src/status_im/contexts/settings/wallet/saved_addresses/view.cljs @@ -1,14 +1,18 @@ (ns status-im.contexts.settings.wallet.saved-addresses.view (:require [quo.core :as quo] + [quo.foundations.colors :as colors] [quo.theme :as quo.theme] [react-native.core :as rn] + [react-native.platform :as platform] [react-native.safe-area :as safe-area] + [status-im.common.not-implemented :as not-implemented] [status-im.common.resources :as resources] + [status-im.config :as config] [status-im.contexts.settings.wallet.saved-addresses.style :as style] [utils.i18n :as i18n] [utils.re-frame :as rf])) -(defn empty-state +(defn- empty-state [] (let [theme (quo.theme/use-theme)] [quo/empty-state @@ -17,12 +21,169 @@ :image (resources/get-themed-image :sweating-man theme) :container-style style/empty-container-style}])) -(defn view +(defn- option + [{:keys [icon label on-press danger? sub-label add-divider? accessibility-label right-icon] :as opt}] + (when opt + ^{:key label} + {:icon icon + :label label + :on-press on-press + :danger? danger? + :sub-label sub-label + :right-icon right-icon + :add-divider? add-divider? + :accessibility-label accessibility-label})) + +(defn- remove-account + [address account-name customization-color] + (rf/dispatch [:hide-bottom-sheet]) + (rf/dispatch + [:show-bottom-sheet + {:theme :dark + :content (fn [] + [:<> + [quo/drawer-top + {:title (i18n/label :t/remove-saved-address) + :customization-color customization-color}] + [quo/context-tag + {:type :default + :customization-color customization-color + :size 24 + :full-name account-name + :container-style {:padding-horizontal 20 + :margin-bottom 16}}] + [quo/text + {:style {:padding-horizontal 20 + :margin-bottom 8}} + (i18n/label :t/remove-saved-address-description {:name account-name})] + [quo/bottom-actions + {:actions :two-actions + :button-one-label (i18n/label :t/remove) + :button-one-props {:on-press (fn [] + (rf/dispatch [:wallet/delete-saved-address + {:address address + :toast-message + (i18n/label :t/saved-address-removed) + :test? false}])) + :type :danger} + :button-two-label (i18n/label :t/cancel) + :button-two-props {:on-press #(rf/dispatch [:hide-bottom-sheet]) + :type :grey}}]])}])) + +(defn- options + [account-name address customization-color] + [(when config/show-not-implemented-features? + {:icon :i/arrow-up + :label (i18n/label :t/send-to-user {:user account-name}) + :on-press not-implemented/alert + :accessibility-label :send-to-user}) + (when config/show-not-implemented-features? + {:icon :i/link + :right-icon :i/external + :label (i18n/label :t/view-address-on-website {:website "Etherscan"}) + :on-press not-implemented/alert + :accessibility-label :view-address-on-etherscan}) + (when config/show-not-implemented-features? + {:icon :i/link + :right-icon :i/external + :label (i18n/label :t/view-address-on-website {:website "Optimistic"}) + :on-press not-implemented/alert + :accessibility-label :view-address-on-optimistic}) + {:icon :i/share + :on-press #(rf/dispatch + [:open-share + {:options (if platform/ios? + {:activityItemSources [{:placeholderItem {:type :text + :content address} + :item {:default {:type :text + :content + address}} + :linkMetadata {:title address}}]} + {:title address + :subject address + :message address + :isNewTask true})}]) + :label (i18n/label :t/share-address) + :accessibility-label :share-saved-address} + {:icon :i/qr-code + :label (i18n/label :t/show-address-qr) + :on-press (fn [] + (rf/dispatch [:wallet/set-current-viewing-account address]) + (rf/dispatch [:open-modal :screen/wallet.share-address {:status :share}])) + :accessibility-label :show-address-qr-code} + (when config/show-not-implemented-features? + {:icon :i/edit + :label (i18n/label :t/edit-account) + :on-press #(rf/dispatch [:navigate-to :screen/wallet.edit-account]) + :accessibility-label :edit-saved-address}) + (when config/show-not-implemented-features? + {:icon :i/delete + :label (i18n/label :t/remove-address) + :on-press #(remove-account address account-name customization-color) + :danger? true + :accessibility-label :remove-saved-address + :add-divider? true})]) + +(defn- sample-options + [account-name address customization-color] + (keep option (options account-name address customization-color))) + +(defn- account-sheet + [address account-name customization-color] + [quo/action-drawer + [(sample-options account-name address customization-color)]]) + +(defn- on-press-saved-address + [{:keys [address account-name ens-name customization-color]}] + (rf/dispatch + [:show-bottom-sheet + {:theme :dark + :selected-item (fn [] + [quo/saved-address + {:active-state? false + :user-props {:name account-name + :address address + :ens ens-name + :customization-color customization-color}}]) + :content (fn [] + [account-sheet + address account-name customization-color])}])) + +(defn- saved-address + [{:keys [address colorId _chain-short-names _test? ens?] + account-name :name}] + [quo/saved-address + {:on-press #(on-press-saved-address + {:account-name account-name + :address address + :ens-name (when ens? address) + :customization-color (keyword colorId)}) + :user-props {:name account-name + :address address + :customization-color (keyword colorId)}}]) + +(defn- header + [{:keys [title]}] + [quo/divider-label + {:container-style {:border-top-color colors/white-opa-5}} + title]) + +(defn- footer + [] + [rn/view {:height 8}]) + +(defn- navigate-back + [] + (rf/dispatch [:navigate-back])) + +(defn- view [] (let [inset-top (safe-area/get-top) customization-color (rf/sub [:profile/customization-color]) - saved-addresses [] - navigate-back (rn/use-callback #(rf/dispatch [:navigate-back]))] + saved-addresses (rf/sub [:wallet/grouped-saved-addresses])] + (rn/use-effect + (fn [] + (rf/dispatch [:wallet/get-saved-addresses]))) [quo/overlay {:type :shell :container-style (style/page-wrapper inset-top)} @@ -38,5 +199,13 @@ :right :action :customization-color customization-color :icon :i/add}]] + [rn/section-list + {:key-fn :title + :sticky-section-headers-enabled false + :render-section-header-fn header + :render-section-footer-fn footer + :sections saved-addresses + :render-fn saved-address + :separator [rn/view {:style {:height 4}}]}] (when-not (seq saved-addresses) [empty-state])])) diff --git a/src/status_im/contexts/wallet/events.cljs b/src/status_im/contexts/wallet/events.cljs index 3ee4328c9cf..cf07c359559 100644 --- a/src/status_im/contexts/wallet/events.cljs +++ b/src/status_im/contexts/wallet/events.cljs @@ -27,10 +27,16 @@ :type :positive :text (i18n/label :t/account-created {:name (:name account)})}]]]}))) +(defn set-current-viewing-account + [{:keys [db]} [address]] + {:db (assoc-in db [:wallet :current-viewing-account-address] address)}) + +(rf/reg-event-fx :wallet/set-current-viewing-account set-current-viewing-account) + (rf/reg-event-fx :wallet/navigate-to-account - (fn [{:keys [db]} [address]] - {:db (assoc-in db [:wallet :current-viewing-account-address] address) - :fx [[:dispatch [:navigate-to :screen/wallet.accounts address]]]})) + (fn [_cofx [address]] + {:fx [[:dispatch [:wallet/set-current-viewing-account address]] + [:dispatch [:navigate-to :screen/wallet.accounts address]]]})) (rf/reg-event-fx :wallet/navigate-to-new-account (fn [{:keys [db]} [address]] diff --git a/src/status_im/contexts/wallet/save_address/events.cljs b/src/status_im/contexts/wallet/save_address/events.cljs index 4cdf02294d9..1ba681d6214 100644 --- a/src/status_im/contexts/wallet/save_address/events.cljs +++ b/src/status_im/contexts/wallet/save_address/events.cljs @@ -29,7 +29,7 @@ (rf/reg-event-fx :wallet/get-saved-addresses-success (fn [{:keys [db]} [saved-addresses]] - {:db (assoc-in db [:wallet :saved-addresses] saved-addresses)})) + {:db (assoc-in db [:wallet :saved-addresses] (group-by :address saved-addresses))})) (rf/reg-event-fx :wallet/get-saved-addresses-error diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index a897316b171..c7dec47736e 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -28,6 +28,7 @@ status-im.contexts.onboarding.events status-im.contexts.profile.events status-im.contexts.profile.settings.events + status-im.contexts.settings.wallet.saved-addresses.events status-im.contexts.shell.qr-reader.events status-im.contexts.shell.share.events status-im.contexts.syncing.events @@ -37,6 +38,7 @@ status-im.contexts.wallet.common.wizard.events status-im.contexts.wallet.effects status-im.contexts.wallet.events + status-im.contexts.wallet.save-address.events status-im.contexts.wallet.send.events status-im.contexts.wallet.signals status-im.contexts.wallet.swap.events diff --git a/src/status_im/subs/wallet/saved_addresses.cljs b/src/status_im/subs/wallet/saved_addresses.cljs index 8b48bf730d7..f6c1e6eb3bf 100644 --- a/src/status_im/subs/wallet/saved_addresses.cljs +++ b/src/status_im/subs/wallet/saved_addresses.cljs @@ -1,5 +1,6 @@ (ns status-im.subs.wallet.saved-addresses (:require + [clojure.string :as string] [re-frame.core :as rf])) (rf/reg-sub @@ -13,3 +14,16 @@ (fn [wallet [address]] (some #(= address (:address %)) (:saved-addresses wallet)))) + +(rf/reg-sub + :wallet/grouped-saved-addresses + :<- [:wallet/saved-addresses] + (fn [saved-addresses] + (->> saved-addresses + vals + flatten + (sort-by :name) + (group-by #(string/upper-case (first (:name %)))) + (map (fn [[k v]] + {:title k + :data v}))))) diff --git a/src/status_im/subs/wallet/saved_addresses_test.cljs b/src/status_im/subs/wallet/saved_addresses_test.cljs new file mode 100644 index 00000000000..3ed362f6834 --- /dev/null +++ b/src/status_im/subs/wallet/saved_addresses_test.cljs @@ -0,0 +1,25 @@ +(ns status-im.subs.wallet.saved-addresses-test + (:require [clojure.test :refer [is testing]] + [re-frame.db :as rf-db] + [test-helpers.unit :as h] + [utils.re-frame :as rf])) + +(def saved-addresses-data + [{:address "0x0" :colorId "blue" :chainShortNames "eth:" :isTest false :name "Alice's address"} + {:address "0x1" :colorId "purple" :chainShortNames "eth:" :isTest false :name "Bob's address"}]) + +(def grouped-saved-addresses-data + [{:title "A" + :data + [{:address "0x0" :colorId "blue" :chainShortNames "eth:" :isTest false :name "Alice's address"}]} + {:title "B" + :data + [{:address "0x1" :colorId "purple" :chainShortNames "eth:" :isTest false :name "Bob's address"}]}]) + +(h/deftest-sub :wallet/grouped-saved-addresses + [sub-name] + (testing "returns data with prod" + (swap! rf-db/app-db assoc-in [:wallet :saved-addresses] saved-addresses-data) + (is + (= grouped-saved-addresses-data + (rf/sub [sub-name]))))) diff --git a/status-go-version.json b/status-go-version.json index 6666b5ec421..bcbc0494273 100644 --- a/status-go-version.json +++ b/status-go-version.json @@ -3,7 +3,7 @@ "_comment": "Instead use: scripts/update-status-go.sh ", "owner": "status-im", "repo": "status-go", - "version": "v0.179.13", - "commit-sha1": "f3f48654f54aebbb4949129f930fef648d8da8f9", - "src-sha256": "09gcr6fgx6v4qdp83w0n2ynnlvwjqid477jgpqjk57l5wfrv2raq" + "version": "add-emoji-to-saved-addresses", + "commit-sha1": "5c1ae90fa682ffb236f35b71c4d2911455bea8ce", + "src-sha256": "12xfsxdyclz8mx4qm6lywcbzqkxmrspni44450cqsa5qspdhdrxq" } diff --git a/translations/en.json b/translations/en.json index 7d21a57d84d..4479808e9a9 100644 --- a/translations/en.json +++ b/translations/en.json @@ -2613,5 +2613,11 @@ "scanning-for-activity": "Scanning for activity...", "send-community-link": "Send community link", "at-least-one-network-must-be-activated": "At least 1 network must be activated", - "status-is-a-secure-messaging-app": "Status is a secure messaging app, crypto wallet and web3 browser built with the state of the art technology" + "status-is-a-secure-messaging-app": "Status is a secure messaging app, crypto wallet and web3 browser built with the state of the art technology", + "send-to-user": "Send to {{user}}", + "view-address-on-website": "View address on {{website}}", + "saved-address-removed": "Saved address removed", + "remove-address": "Remove address", + "remove-saved-address-description": "Transaction history relating to this address will no longer be labelled ‘{{name}}’.", + "remove-saved-address": "Remove saved address" }