parent
006824e0ed
commit
6be1adb40e
Binary file not shown.
After Width: | Height: | Size: 221 B |
Binary file not shown.
After Width: | Height: | Size: 348 B |
|
@ -0,0 +1,23 @@
|
|||
(ns status-im.common.validation.keypair
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.common.validation.general :as validators]
|
||||
[status-im.constants :as constants]
|
||||
utils.emojilib
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn keypair-too-short?
|
||||
[s]
|
||||
(< (-> s str string/trim count) constants/key-pair-name-min-length))
|
||||
|
||||
(defn keypair-too-long?
|
||||
[s]
|
||||
(> (-> s str string/trim count) constants/key-pair-name-max-length))
|
||||
|
||||
(defn validation-keypair-name
|
||||
[s]
|
||||
(cond
|
||||
(string/blank? s) nil
|
||||
(validators/has-emojis? s) (i18n/label :t/key-name-error-emoji)
|
||||
(validators/has-special-characters? s) (i18n/label :t/key-name-error-special-char)
|
||||
(keypair-too-short? s) (i18n/label :t/your-key-pair-name-is-too-short)
|
||||
(keypair-too-long? s) (i18n/label :t/your-key-pair-name-is-too-long)))
|
|
@ -0,0 +1,27 @@
|
|||
(ns status-im.common.validation.keypair-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest are]]
|
||||
[status-im.common.validation.keypair :as keypair-validator]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(deftest keypair-name-too-short-test
|
||||
(are [arg expected]
|
||||
(expected (keypair-validator/keypair-too-short? arg))
|
||||
"abc" true?
|
||||
"abcdef" false?))
|
||||
|
||||
(deftest keypair-name-too-long-test
|
||||
(are [arg expected]
|
||||
(expected (keypair-validator/keypair-too-long? arg))
|
||||
(apply str (repeat 25 "a")) true?
|
||||
"abcdef" false?))
|
||||
|
||||
(deftest validation-keypair-name-test
|
||||
(are [arg expected]
|
||||
(= (keypair-validator/validation-keypair-name arg) expected)
|
||||
nil nil
|
||||
"" nil
|
||||
"name !" (i18n/label :t/key-name-error-special-char)
|
||||
"Hello 😊" (i18n/label :t/key-name-error-emoji)
|
||||
"abc" (i18n/label :t/your-key-pair-name-is-too-short)
|
||||
(apply str (repeat 25 "a")) (i18n/label :t/your-key-pair-name-is-too-long)))
|
|
@ -77,6 +77,9 @@
|
|||
(def ^:const contact-request-message-state-declined 3)
|
||||
(def ^:const contact-request-message-max-length 280)
|
||||
|
||||
(def ^:const key-pair-name-max-length 20)
|
||||
(def ^:const key-pair-name-min-length 5)
|
||||
|
||||
(def request-to-join-pending-state 1)
|
||||
|
||||
(def reactions
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
(ns status-im.contexts.settings.wallet.events
|
||||
(:require
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/rename-keypair-success
|
||||
(fn [{:keys [db]} [key-uid name]]
|
||||
{:db (update-in db
|
||||
[:wallet :keypairs]
|
||||
(fn [keypairs]
|
||||
(map (fn [keypair]
|
||||
(if (= (keypair :key-uid) key-uid)
|
||||
(assoc keypair :name name)
|
||||
keypair))
|
||||
keypairs)))
|
||||
:fx [[:dispatch [:navigate-back]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:text (i18n/label :t/key-pair-name-updated)}]]]}))
|
||||
|
||||
(defn rename-keypair
|
||||
[_ [{:keys [key-uid keypair-name]}]]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "accounts_updateKeypairName"
|
||||
:params [key-uid keypair-name]
|
||||
:on-success [:wallet/rename-keypair-success key-uid keypair-name]
|
||||
:on-error #(log/info "failed to rename keypair " %)}]]]})
|
||||
|
||||
(rf/reg-event-fx :wallet/rename-keypair rename-keypair)
|
|
@ -0,0 +1,20 @@
|
|||
(ns status-im.contexts.settings.wallet.events-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is]]
|
||||
matcher-combinators.test
|
||||
[status-im.contexts.settings.wallet.events :as sut]))
|
||||
|
||||
(def key-uid "0xfef454bb492ee4677594f8e05921c84f336fa811deb99b8d922477cc87a38b98")
|
||||
|
||||
(deftest rename-keypair-test
|
||||
(let [new-keypair-name "key pair new"
|
||||
cofx {:db {}}
|
||||
expected {:fx [[:json-rpc/call
|
||||
[{:method "accounts_updateKeypairName"
|
||||
:params [key-uid new-keypair-name]
|
||||
:on-success [:wallet/rename-keypair-success key-uid new-keypair-name]
|
||||
:on-error fn?}]]]}]
|
||||
(is (match? expected
|
||||
(sut/rename-keypair cofx
|
||||
[{:key-uid key-uid
|
||||
:keypair-name new-keypair-name}])))))
|
|
@ -1,6 +1,19 @@
|
|||
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.actions.view
|
||||
(:require [quo.core :as quo]))
|
||||
(:require [quo.core :as quo]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn on-rename-request
|
||||
[data]
|
||||
(rf/dispatch [:open-modal :screen/settings.rename-keypair data]))
|
||||
|
||||
(defn view
|
||||
[props]
|
||||
[quo/drawer-top props])
|
||||
[props data]
|
||||
[:<>
|
||||
[quo/drawer-top props]
|
||||
[quo/action-drawer
|
||||
[(when (= (:type props) :keypair)
|
||||
[{:icon :i/edit
|
||||
:accessibility-label :rename-key-pair
|
||||
:label (i18n/label :t/rename-key-pair)
|
||||
:on-press #(on-rename-request data)}])]]])
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.rename.style)
|
||||
|
||||
(def header-container
|
||||
{:margin-bottom 8})
|
||||
|
||||
(def bottom-action
|
||||
{:margin-horizontal -20})
|
||||
|
||||
(def error-container
|
||||
{:margin-left 20
|
||||
:margin-vertical 8})
|
|
@ -0,0 +1,84 @@
|
|||
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.rename.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.common.validation.keypair :as keypair-validator]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.rename.style :as style]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn navigate-back [] (rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [name key-uid]} (rf/sub [:get-screen-params])
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
[unsaved-keypair-name set-unsaved-keypair-name] (rn/use-state name)
|
||||
[error-msg set-error-msg] (rn/use-state nil)
|
||||
[typing? set-typing?] (rn/use-state false)
|
||||
validate-keypair-name (rn/use-callback
|
||||
(debounce/debounce
|
||||
(fn [name]
|
||||
(set-error-msg
|
||||
(keypair-validator/validation-keypair-name
|
||||
name))
|
||||
(set-typing? false))
|
||||
300))
|
||||
on-change-text (rn/use-callback (fn [text]
|
||||
(set-typing? true)
|
||||
(set-unsaved-keypair-name
|
||||
text)
|
||||
(validate-keypair-name text)))
|
||||
on-clear (rn/use-callback (fn []
|
||||
(on-change-text "")))
|
||||
on-save (rn/use-callback #(rf/dispatch
|
||||
[:wallet/rename-keypair
|
||||
{:key-uid key-uid
|
||||
:keypair-name
|
||||
unsaved-keypair-name}])
|
||||
[unsaved-keypair-name key-uid])]
|
||||
[floating-button-page/view
|
||||
{:header [quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press navigate-back
|
||||
:accessibility-label :top-bar}]
|
||||
:footer [quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/save)
|
||||
:button-one-props {:disabled? (or typing?
|
||||
(string/blank? unsaved-keypair-name)
|
||||
(not (string/blank? error-msg)))
|
||||
:customization-color customization-color
|
||||
:on-press on-save}
|
||||
:container-style style/bottom-action}]}
|
||||
[quo/page-top
|
||||
{:container-style style/header-container
|
||||
:title (i18n/label :t/rename-key-pair)
|
||||
:description :context-tag
|
||||
:context-tag {:type :icon
|
||||
:size 24
|
||||
:context name
|
||||
:icon :i/seed-phrase}}]
|
||||
[quo/input
|
||||
{:container-style {:margin-horizontal 20}
|
||||
:placeholder (i18n/label :t/keypair-name-input-placeholder)
|
||||
:label (i18n/label :t/keypair-name)
|
||||
:default-value unsaved-keypair-name
|
||||
:char-limit constants/key-pair-name-max-length
|
||||
:max-length constants/key-pair-name-max-length
|
||||
:auto-focus true
|
||||
:clearable? (not (string/blank? unsaved-keypair-name))
|
||||
:on-clear on-clear
|
||||
:on-change-text on-change-text
|
||||
:error? (not (string/blank? error-msg))}]
|
||||
(when-not (string/blank? error-msg)
|
||||
[quo/info-message
|
||||
{:type :error
|
||||
:size :default
|
||||
:icon :i/info
|
||||
:container-style style/error-container}
|
||||
error-msg])]))
|
||||
|
|
@ -15,14 +15,15 @@
|
|||
|
||||
(defn on-options-press
|
||||
[{:keys [theme]
|
||||
:as props}]
|
||||
:as props} keypair]
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [actions/view props])
|
||||
{:content (fn [] [actions/view props keypair])
|
||||
:theme theme}]))
|
||||
|
||||
(defn- keypair
|
||||
[{keypair-type :type
|
||||
:keys [accounts name]}
|
||||
:keys [accounts name]
|
||||
:as item}
|
||||
_ _
|
||||
{:keys [profile-picture compressed-key customization-color]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
|
@ -42,7 +43,8 @@
|
|||
:profile-picture profile-picture)
|
||||
(not default-keypair?)
|
||||
(assoc :type :keypair
|
||||
:icon-avatar :i/seed))))
|
||||
:icon-avatar :i/seed))
|
||||
item))
|
||||
[customization-color default-keypair? name
|
||||
profile-picture shortened-key theme])]
|
||||
[quo/keypair
|
||||
|
|
|
@ -6,16 +6,14 @@
|
|||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.common.not-implemented :as not-implemented]
|
||||
[status-im.common.validation.general :as validators]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.add-account.create-account.key-pair-name.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def ^:private key-pair-name-max-length 15)
|
||||
(def ^:private key-pair-name-min-length 5)
|
||||
|
||||
(def error-messages
|
||||
{:too-long (i18n/label :t/key-name-error-length)
|
||||
:too-short (i18n/label :t/key-name-error-too-short {:count key-pair-name-min-length})
|
||||
:too-short (i18n/label :t/key-name-error-too-short {:count constants/key-pair-name-min-length})
|
||||
:emoji (i18n/label :t/key-name-error-emoji)
|
||||
:special-char (i18n/label :t/key-name-error-special-char)})
|
||||
|
||||
|
@ -33,10 +31,10 @@
|
|||
(fn [value]
|
||||
(set-key-pair-name value)
|
||||
(cond
|
||||
(> (count value) key-pair-name-max-length)
|
||||
(> (count value) constants/key-pair-name-max-length)
|
||||
(set-error :too-long)
|
||||
|
||||
(< 0 (count value) key-pair-name-min-length)
|
||||
(< 0 (count value) constants/key-pair-name-min-length)
|
||||
(set-error :too-short)
|
||||
|
||||
(validators/has-emojis? value)
|
||||
|
@ -81,7 +79,7 @@
|
|||
{:container-style style/input
|
||||
:placeholder (i18n/label :t/keypair-name-input-placeholder)
|
||||
:label (i18n/label :t/keypair-name)
|
||||
:char-limit key-pair-name-max-length
|
||||
:char-limit constants/key-pair-name-max-length
|
||||
:auto-focus true
|
||||
:on-change-text on-change-text
|
||||
:error error}]
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
[clojure.string :as string]
|
||||
[react-native.platform :as platform]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.settings.wallet.events]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[status-im.contexts.wallet.data-store :as data-store]
|
||||
[status-im.contexts.wallet.db :as db]
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
[status-im.contexts.profile.settings.screens.password.change-password.view :as change-password]
|
||||
[status-im.contexts.profile.settings.screens.password.view :as settings-password]
|
||||
[status-im.contexts.profile.settings.view :as settings]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.rename.view :as keypair-rename]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.view :as keypairs-and-accounts]
|
||||
[status-im.contexts.settings.wallet.saved-addresses.view :as saved-addresses-settings]
|
||||
[status-im.contexts.settings.wallet.wallet-options.view :as wallet-options]
|
||||
|
@ -503,6 +504,10 @@
|
|||
:options options/transparent-modal-screen-options
|
||||
:component wallet-options/view}
|
||||
|
||||
{:name :screen/settings.rename-keypair
|
||||
:options (assoc options/dark-screen :sheet? true)
|
||||
:component keypair-rename/view}
|
||||
|
||||
{:name :screen/settings.saved-addresses
|
||||
:options options/transparent-modal-screen-options
|
||||
:component saved-addresses-settings/view}
|
||||
|
|
|
@ -183,9 +183,10 @@
|
|||
:<- [:wallet/keypairs]
|
||||
(fn [keypairs [_ format-options]]
|
||||
(->> keypairs
|
||||
(map (fn [{:keys [accounts name type]}]
|
||||
(map (fn [{:keys [accounts name type key-uid]}]
|
||||
{:type (keyword type)
|
||||
:name name
|
||||
:key-uid key-uid
|
||||
:accounts (format-settings-keypair-accounts accounts format-options)})))))
|
||||
|
||||
(rf/reg-sub
|
||||
|
|
|
@ -1255,6 +1255,7 @@
|
|||
"remove-network": "Remove network",
|
||||
"remove-token": "Remove token",
|
||||
"removed": "removed",
|
||||
"rename-key-pair": "Rename key pair",
|
||||
"repeat-pin": "Repeat new 6-digit passcode",
|
||||
"repeat-puk": "Repeat new 12-digit PUK",
|
||||
"report-bug-email-template": "1. Issue Description\n{{description}}\n\n\n2. Steps to reproduce\n{{steps}}\n\n\n3. Attach screenshots that can demo the problem, please\n",
|
||||
|
@ -2570,6 +2571,7 @@
|
|||
"keypair-name": "Key pair name",
|
||||
"keypair-name-description": "Name key pair for your own personal reference",
|
||||
"keypair-name-input-placeholder": "Collectibles account, Old vault....",
|
||||
"key-pair-name-updated": "Key pair name updated",
|
||||
"goerli-testnet-toggle-confirmation": "Are you sure you want to toggle Goerli? This will log you out and you will have to login again.",
|
||||
"bridged-to": "Bridged to {{network}}",
|
||||
"slide-to-bridge": "Slide to bridge",
|
||||
|
@ -2590,6 +2592,8 @@
|
|||
"other": "{{count}} addresses"
|
||||
},
|
||||
"max": "Max: {{number}}",
|
||||
"your-key-pair-name-is-too-long": "Your key pair name is too long",
|
||||
"your-key-pair-name-is-too-short": "Your key pair name is too short",
|
||||
"key-name-error-length": "Key name too long",
|
||||
"key-name-error-emoji": "Emojis are not allowed",
|
||||
"key-name-error-special-char": "Special characters are not allowed",
|
||||
|
|
Loading…
Reference in New Issue