From 878a1cc28563abe8685fdab5c80109b02c749349 Mon Sep 17 00:00:00 2001 From: Brian Sztamfater Date: Tue, 3 Oct 2023 15:51:11 -0300 Subject: [PATCH] feat: implement saved contact address list item component (#17400) Signed-off-by: Brian Sztamfater --- src/quo2/components/icons/svg.cljs | 19 +++- .../saved_contact_address/component_spec.cljs | 53 +++++++++++ .../saved_contact_address/style.cljs | 62 +++++++++++++ .../saved_contact_address/view.cljs | 93 +++++++++++++++++++ src/quo2/core.cljs | 2 + src/quo2/core_spec.cljs | 1 + .../list_items/saved_contact_address.cljs | 45 +++++++++ src/status_im2/contexts/quo_preview/main.cljs | 3 + translations/en.json | 3 +- 9 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 src/quo2/components/list_items/saved_contact_address/component_spec.cljs create mode 100644 src/quo2/components/list_items/saved_contact_address/style.cljs create mode 100644 src/quo2/components/list_items/saved_contact_address/view.cljs create mode 100644 src/status_im2/contexts/quo_preview/list_items/saved_contact_address.cljs diff --git a/src/quo2/components/icons/svg.cljs b/src/quo2/components/icons/svg.cljs index b62e1c4cc7..129f83d61c 100644 --- a/src/quo2/components/icons/svg.cljs +++ b/src/quo2/components/icons/svg.cljs @@ -101,12 +101,29 @@ :stroke color-2 :stroke-width 1.1}]]) +(defn- contact-12 + [{:keys [color color-2] + :or {color colors/neutral-100 + color-2 colors/white} + :as props}] + [container props + [svg/circle + {:cx 6 + :cy 6 + :r 6 + :fill color}] + [svg/path + {:d + "M2.79504 9.01494C2.89473 8.85584 3.00297 8.70977 3.11963 8.5761C3.90594 7.67512 4.97212 7.45024 5.99992 7.45024C7.02772 7.45024 8.0939 7.67512 8.88021 8.5761C8.99688 8.70978 9.10512 8.85585 9.2048 9.01495C8.9501 9.28561 8.66149 9.52401 8.34577 9.72335C8.25403 9.55824 8.15512 9.41818 8.05145 9.29939C7.56503 8.74204 6.88121 8.55024 5.99992 8.55024C5.11862 8.55024 4.43481 8.74204 3.94839 9.29939C3.84472 9.41818 3.74582 9.55824 3.65408 9.72334C3.33835 9.524 3.04975 9.2856 2.79504 9.01494ZM5.99992 3.5502C5.47525 3.5502 5.04992 3.97552 5.04992 4.5002C5.04992 5.02487 5.47525 5.4502 5.99992 5.4502C6.52459 5.4502 6.94992 5.02487 6.94992 4.5002C6.94992 3.97552 6.52459 3.5502 5.99992 3.5502ZM3.94992 4.5002C3.94992 3.36801 4.86773 2.4502 5.99992 2.4502C7.1321 2.4502 8.04992 3.36801 8.04992 4.5002C8.04992 5.63238 7.1321 6.5502 5.99992 6.5502C4.86773 6.5502 3.94992 5.63238 3.94992 4.5002Z" + :fill color-2}]]) + (def ^:private icons {:i/clear-20 clear-20 :i/dropdown-20 dropdown-20 :i/pullup-20 pullup-20 :i/dropdown-12 dropdown-12 - :i/pullup-12 pullup-12}) + :i/pullup-12 pullup-12 + :i/contact-12 contact-12}) (defn- append-to-keyword [k & xs] diff --git a/src/quo2/components/list_items/saved_contact_address/component_spec.cljs b/src/quo2/components/list_items/saved_contact_address/component_spec.cljs new file mode 100644 index 0000000000..2cdb406916 --- /dev/null +++ b/src/quo2/components/list_items/saved_contact_address/component_spec.cljs @@ -0,0 +1,53 @@ +(ns quo2.components.list-items.saved-contact-address.component-spec + (:require [test-helpers.component :as h] + [quo2.components.list-items.saved-contact-address.view :as saved-contact-address] + [quo2.foundations.colors :as colors])) + +(def account + {:name "New House" + :address "0x21a...49e" + :emoji "🍔" + :customization-color :purple}) + +(h/describe "List items: saved contact address" + (h/test "default render" + (h/render [saved-contact-address/view]) + (h/is-truthy (h/query-by-label-text :container))) + + (h/test "renders account detail when passing one account" + (h/render [saved-contact-address/view {:accounts (repeat 1 account)}]) + (h/is-truthy (h/query-by-label-text :account-container))) + + (h/test "renders account count when passing multiple accounts" + (h/render [saved-contact-address/view {:accounts (repeat 2 account)}]) + (h/is-truthy (h/query-by-label-text :accounts-count))) + + (h/test "on-press-in changes state to :pressed" + (h/render [saved-contact-address/view {:accounts (repeat 1 account)}]) + (h/fire-event :on-press-in (h/get-by-label-text :container)) + (h/wait-for #(h/has-style (h/query-by-label-text :container) + {:backgroundColor (colors/custom-color :blue 50 5)}))) + + (h/test "on-press-out changes state to :active if active-state? is true (default value)" + (h/render [saved-contact-address/view {:accounts (repeat 1 account)}]) + (h/fire-event :on-press-in (h/get-by-label-text :container)) + (h/fire-event :on-press-out (h/get-by-label-text :container)) + (h/wait-for #(h/has-style (h/query-by-label-text :container) + {:backgroundColor (colors/custom-color :blue 50 10)}))) + + (h/test "on-press-out changes state to :default if active-state? is false" + (h/render [saved-contact-address/view + {:accounts (repeat 1 account) + :active-state? false}]) + (h/fire-event :on-press-in (h/get-by-label-text :container)) + (h/fire-event :on-press-out (h/get-by-label-text :container)) + (h/wait-for #(h/has-style (h/query-by-label-text :container) + {:backgroundColor :transparent}))) + + (h/test "on-press calls on-press" + (let [on-press (h/mock-fn)] + (h/render [saved-contact-address/view + {:on-press on-press + :accounts (repeat 1 account)}]) + (h/fire-event :on-press (h/get-by-label-text :container)) + (h/was-called on-press)))) diff --git a/src/quo2/components/list_items/saved_contact_address/style.cljs b/src/quo2/components/list_items/saved_contact_address/style.cljs new file mode 100644 index 0000000000..ec09b8197c --- /dev/null +++ b/src/quo2/components/list_items/saved_contact_address/style.cljs @@ -0,0 +1,62 @@ +(ns quo2.components.list-items.saved-contact-address.style + (:require [quo2.foundations.colors :as colors])) + +(defn- background-color + [{:keys [state customization-color]}] + (cond (or (= state :pressed) (= state :selected)) + (colors/custom-color customization-color 50 5) + (= state :active) + (colors/custom-color customization-color 50 10) + :else :transparent)) + +(defn container + [props] + {:height 56 + :border-radius 12 + :background-color (background-color props) + :flex-direction :row + :align-items :center + :padding-horizontal 12 + :padding-vertical 6 + :justify-content :space-between}) + +(def left-container + {:flex-direction :row + :align-items :center}) + +(defn dot-divider + [theme] + {:width 2 + :height 2 + :border-radius 2 + :margin-horizontal 4 + :background-color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}) + +(def saved-contact-container + {:margin-left 8}) + +(def account-container + {:flex-direction :row + :align-items :center}) + +(def account-title-container + {:flex-direction :row + :height 22 + :align-items :center}) + +(defn account-name + [theme] + {:margin-left 4 + :color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}) + +(defn accounts-count + [theme] + {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}) + +(defn account-address + [theme] + {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}) + +(def contact-icon-container + {:margin-left 4 + :margin-top 1.5}) diff --git a/src/quo2/components/list_items/saved_contact_address/view.cljs b/src/quo2/components/list_items/saved_contact_address/view.cljs new file mode 100644 index 0000000000..c9a951753b --- /dev/null +++ b/src/quo2/components/list_items/saved_contact_address/view.cljs @@ -0,0 +1,93 @@ +(ns quo2.components.list-items.saved-contact-address.view + (:require [quo2.components.avatars.user-avatar.view :as user-avatar] + [quo2.components.avatars.account-avatar.view :as account-avatar] + [quo2.components.markdown.text :as text] + [quo2.foundations.colors :as colors] + [quo2.theme :as quo.theme] + [react-native.core :as rn] + [quo2.components.list-items.saved-contact-address.style :as style] + [reagent.core :as reagent] + [quo2.components.icon :as icon] + [utils.i18n :as i18n])) + +(defn- account + [{:keys [emoji name address customization-color theme]}] + [rn/view + {:accessibility-label :account-container + :style style/account-container} + [account-avatar/view + {:emoji emoji + :size 16 + :customization-color customization-color}] + [text/text + {:size :paragraph-2 + :weight :monospace + :style (style/account-name theme)} + name] + [rn/view {:style (style/dot-divider theme)}] + [text/text + {:size :paragraph-2 + :weight :monospace + :style (style/account-address theme)} + address]]) + +(defn- internal-view + [] + (let [state (reagent/atom :default) + active? (atom false) + timer (atom nil) + on-press-in (fn [] + (when-not (= @state :selected) + (reset! timer (js/setTimeout #(reset! state :pressed) 100))))] + (fn [{:keys [contact-props accounts active-state? customization-color on-press theme] + :or {customization-color :blue + accounts [] + active-state? true}}] + (let [accounts-count (count accounts) + account-props (when (= accounts-count 1) + (first accounts)) + on-press-out (fn [] + (let [new-state (if (or (not active-state?) @active?) :default :active)] + (when @timer (js/clearTimeout @timer)) + (reset! timer nil) + (reset! active? (= new-state :active)) + (reset! state new-state)))] + [rn/pressable + {:style (style/container + {:state @state :customization-color customization-color}) + :on-press-in on-press-in + :on-press-out on-press-out + :on-press #(when on-press + (on-press)) + :accessibility-label :container} + [rn/view {:style style/left-container} + [user-avatar/user-avatar (assoc contact-props :size :small)] + [rn/view {:style style/saved-contact-container} + [rn/view + {:style style/account-title-container} + [text/text + {:weight :semi-bold + :size :paragraph-1} + (:full-name contact-props)] + [icon/icon :i/contact + {:container-style style/contact-icon-container + :accessibility-label :contact-icon + :size 12 + :color (colors/theme-colors colors/primary-50 colors/primary-60 theme) + :color-2 colors/white}]] + (if account-props + [account (assoc account-props :theme theme)] + [text/text + {:accessibility-label :accounts-count + :size :paragraph-2 + :style (style/accounts-count theme)} + (i18n/label :t/accounts-count {:count accounts-count})])]] + (when (> accounts-count 1) + [icon/icon :i/chevron-right + {:accessibility-label :check-icon + :size 20 + :color (colors/theme-colors colors/neutral-50 + colors/neutral-40 + theme)}])])))) + +(def view (quo.theme/with-theme internal-view)) diff --git a/src/quo2/core.cljs b/src/quo2/core.cljs index 75e7e514e9..24d497bf06 100644 --- a/src/quo2/core.cljs +++ b/src/quo2/core.cljs @@ -73,6 +73,7 @@ quo2.components.list-items.menu-item quo2.components.list-items.preview-list.view quo2.components.list-items.saved-address.view + quo2.components.list-items.saved-contact-address.view quo2.components.list-items.token-value.view quo2.components.list-items.user-list quo2.components.loaders.skeleton-list.view @@ -269,6 +270,7 @@ (def user-list quo2.components.list-items.user-list/user-list) (def community-list-item quo2.components.list-items.community.view/view) (def saved-address quo2.components.list-items.saved-address.view/view) +(def saved-contact-address quo2.components.list-items.saved-contact-address.view/view) (def token-value quo2.components.list-items.token-value.view/view) ;;;; Loaders diff --git a/src/quo2/core_spec.cljs b/src/quo2/core_spec.cljs index a59a420d0d..884e43d5a2 100644 --- a/src/quo2/core_spec.cljs +++ b/src/quo2/core_spec.cljs @@ -43,6 +43,7 @@ [quo2.components.list-items.community.component-spec] [quo2.components.list-items.dapp.component-spec] [quo2.components.list-items.saved-address.component-spec] + [quo2.components.list-items.saved-contact-address.component-spec] [quo2.components.list-items.token-value.component-spec] [quo2.components.loaders.skeleton-list.component-spec] [quo2.components.markdown.text-component-spec] diff --git a/src/status_im2/contexts/quo_preview/list_items/saved_contact_address.cljs b/src/status_im2/contexts/quo_preview/list_items/saved_contact_address.cljs new file mode 100644 index 0000000000..ac0b97a9d7 --- /dev/null +++ b/src/status_im2/contexts/quo_preview/list_items/saved_contact_address.cljs @@ -0,0 +1,45 @@ +(ns status-im2.contexts.quo-preview.list-items.saved-contact-address + (:require [quo2.core :as quo] + [reagent.core :as reagent] + [status-im2.contexts.quo-preview.preview :as preview] + [status-im2.common.resources :as resources])) + +(def descriptor + [{:key :accounts-number :type :number} + {:key :account-emoji :type :text} + {:key :account-name :type :text} + {:key :full-name :type :text} + {:key :show-alert-on-press? :type :boolean} + {:key :active-state? :type :boolean} + (preview/customization-color-option {:key :account-color}) + (preview/customization-color-option)]) + +(defn view + [] + (let [state (reagent/atom {:customization-color :blue + :accounts-number 1 + :account-name "New House" + :account-address "0x21a...49e" + :account-emoji "🍔" + :account-color :blue + :active-state? true + :full-name "Mark Villacampa" + :show-alert-on-press? false})] + (fn [] + (let [account-props {:name (:account-name @state) + :address (:account-address @state) + :emoji (:account-emoji @state) + :customization-color (:account-color @state)} + contact-props {:full-name (:full-name @state) + :profile-picture (resources/get-mock-image + :user-picture-male4) + :customization-color :purple}] + [preview/preview-container + {:state state + :descriptor descriptor} + [quo/saved-contact-address + (merge @state + {:accounts (repeat (:accounts-number @state) account-props) + :contact-props contact-props} + (when (:show-alert-on-press? @state) + {:on-press #(js/alert "Pressed!")}))]])))) diff --git a/src/status_im2/contexts/quo_preview/main.cljs b/src/status_im2/contexts/quo_preview/main.cljs index b177948b1f..ac42c95881 100644 --- a/src/status_im2/contexts/quo_preview/main.cljs +++ b/src/status_im2/contexts/quo_preview/main.cljs @@ -89,6 +89,7 @@ [status-im2.contexts.quo-preview.list-items.dapp :as dapp] [status-im2.contexts.quo-preview.list-items.preview-lists :as preview-lists] [status-im2.contexts.quo-preview.list-items.saved-address :as saved-address] + [status-im2.contexts.quo-preview.list-items.saved-contact-address :as saved-contact-address] [status-im2.contexts.quo-preview.list-items.token-value :as token-value] [status-im2.contexts.quo-preview.list-items.user-list :as user-list] [status-im2.contexts.quo-preview.list-items.community-list :as @@ -316,6 +317,8 @@ :component preview-lists/view} {:name :saved-address :component saved-address/view} + {:name :saved-contact-address + :component saved-contact-address/view} {:name :token-value :component token-value/view} {:name :user-list diff --git a/translations/en.json b/translations/en.json index 4aa80522f6..3101a631dc 100644 --- a/translations/en.json +++ b/translations/en.json @@ -2328,5 +2328,6 @@ "no-saved-addresses": "No saved addresses", "you-like-to-type-43-characters": "You like to type 43 characters?", "no-other-accounts": "No other accounts", - "here-is-a-cat-in-a-box-instead": "Here’s a cat in a box instead" + "here-is-a-cat-in-a-box-instead": "Here’s a cat in a box instead", + "accounts-count": "{{count}} accounts" }