From 08f17909f64e12e131890ef73fcf12fce830f938 Mon Sep 17 00:00:00 2001 From: alwxndr Date: Fri, 23 Sep 2016 16:22:35 +0300 Subject: [PATCH] Profile validations (#235) Former-commit-id: 80ec3eeef3c816b5ed24bf992fac4115523ca378 --- .re-natal | 3 +- package.json | 1 + src/status_im/accounts/handlers.cljs | 5 +- src/status_im/accounts/screen.cljs | 5 +- src/status_im/android/platform.cljs | 24 ++- src/status_im/chat/handlers.cljs | 14 +- src/status_im/chat/handlers/wallet_chat.cljs | 7 +- src/status_im/chat/screen.cljs | 3 +- src/status_im/chat/sign_up.cljs | 39 ++-- src/status_im/chat/utils.cljs | 5 +- src/status_im/commands/handlers/jail.cljs | 5 +- src/status_im/commands/handlers/loading.cljs | 7 +- .../components/chat_icon/screen.cljs | 3 +- src/status_im/components/styles.cljs | 1 + .../components/text_field/styles.cljs | 24 ++- src/status_im/components/text_field/view.cljs | 28 +-- src/status_im/constants.cljs | 5 +- src/status_im/contacts/styles.cljs | 4 +- src/status_im/db.cljs | 5 +- src/status_im/handlers.cljs | 7 +- src/status_im/ios/platform.cljs | 4 +- src/status_im/profile/screen.cljs | 199 ++++++++++-------- src/status_im/profile/styles.cljs | 33 ++- src/status_im/profile/validations.cljs | 22 ++ src/status_im/translations/en.cljs | 2 + 25 files changed, 260 insertions(+), 195 deletions(-) create mode 100644 src/status_im/profile/validations.cljs diff --git a/.re-natal b/.re-natal index fe8f3fd066..7a9c39e062 100644 --- a/.re-natal +++ b/.re-natal @@ -27,7 +27,8 @@ "react-native-image-resizer", "react-native-image-crop-picker", "react-native-webview-bridge", - "react-native-drawer-layout" + "react-native-drawer-layout", + "homoglyph-finder" ], "imageDirs": [ "images" diff --git a/package.json b/package.json index 6b421c0f49..dc9e3dbcf6 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "dns.js": "^1.0.1", "domain-browser": "^1.1.7", "events": "^1.1.1", + "homoglyph-finder": "^1.1.1", "https-browserify": "0.0.1", "identicon.js": "github:status-im/identicon.js", "os-browserify": "^0.1.2", diff --git a/src/status_im/accounts/handlers.cljs b/src/status_im/accounts/handlers.cljs index 14a4e69f8a..dbb72461fa 100644 --- a/src/status_im/accounts/handlers.cljs +++ b/src/status_im/accounts/handlers.cljs @@ -14,7 +14,8 @@ status-im.accounts.recover.handlers [clojure.string :as str] [status-im.utils.datetime :as time] - [status-im.utils.handlers :as u])) + [status-im.utils.handlers :as u] + [status-im.constants :refer [console-chat-id]])) (defn save-account [_ [_ account]] @@ -117,7 +118,7 @@ :content (label :t/keypair-generated)} :content-type content-type-command-request :outgoing false - :from "console" + :from console-chat-id :to "me"}]) db)) diff --git a/src/status_im/accounts/screen.cljs b/src/status_im/accounts/screen.cljs index f7d3481889..5e6737b27f 100644 --- a/src/status_im/accounts/screen.cljs +++ b/src/status_im/accounts/screen.cljs @@ -26,7 +26,8 @@ [status-im.utils.listview :as lw] [status-im.accounts.views.account :refer [account-view]] [status-im.i18n :refer [label]] - [status-im.accounts.styles :as st])) + [status-im.accounts.styles :as st] + [status-im.constants :refer [console-chat-id]])) (defn toolbar-title [] (let [style (merge toolbar-title-text {:color color-white})] @@ -46,7 +47,7 @@ (dispatch-sync [:reset-app]) ; add accounts screen to history ( maybe there is a better way ? ) (dispatch [:navigate-to-clean :accounts]) - (dispatch [:navigate-to :chat "console"])) + (dispatch [:navigate-to :chat console-chat-id])) (defview accounts [] [accounts [:get :accounts] diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 330e4e32fd..0fa98adab9 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -3,17 +3,19 @@ [status-im.utils.utils :as u])) (def component-styles - {:status-bar {:default {:height 0 - :bar-style "default" - :color styles/color-gray} - :main {:height 0 - :bar-style "default" - :color styles/color-gray} - :transparent {:height 20 - :bar-style "default" - :translucent? true - :color styles/color-transparent}} - :bottom-gradient {:height 3}}) + {:status-bar {:default {:height 0 + :bar-style "default" + :color styles/color-gray} + :main {:height 0 + :bar-style "default" + :color styles/color-gray} + :transparent {:height 20 + :bar-style "default" + :translucent? true + :color styles/color-transparent}} + :bottom-gradient {:height 3} + :input-label {:left 4} + :input-error-text {:margin-left 4}}) (def fonts {:default {:font-family "sans-serif"} diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 4610c191c6..74feb625ca 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -25,6 +25,7 @@ [status-im.utils.types :refer [json->clj]] [status-im.chat.handlers.commands :refer [command-prefix]] [status-im.chat.utils :refer [console? not-console?]] + [status-im.constants :refer [console-chat-id]] status-im.chat.handlers.animation status-im.chat.handlers.requests status-im.chat.handlers.unviewed-messages @@ -142,7 +143,7 @@ (str command-prefix text) text)] (dispatch [::stage-command-with-content command text'])) - (dispatch [::check-suggestions "console" text]))))) + (dispatch [::check-suggestions console-chat-id text]))))) (register-handler ::stage-command-with-content (u/side-effect! @@ -172,9 +173,8 @@ (defn init-console-chat [{:keys [chats] :as db} existing-account?] - (let [chat-id "console" - new-chat sign-up-service/console-chat] - (if (chats chat-id) + (let [new-chat sign-up-service/console-chat] + (if (chats console-chat-id) db (do (chats/create-chat new-chat) @@ -183,9 +183,9 @@ (sign-up-service/start-signup)) (-> db (assoc :new-chat new-chat) - (update :chats assoc chat-id new-chat) - (update :chats-ids conj chat-id) - (assoc :current-chat-id "console")))))) + (update :chats assoc console-chat-id new-chat) + (update :chats-ids conj console-chat-id) + (assoc :current-chat-id console-chat-id)))))) (register-handler :init-console-chat (fn [db _] diff --git a/src/status_im/chat/handlers/wallet_chat.cljs b/src/status_im/chat/handlers/wallet_chat.cljs index 284cade83a..40b964150a 100644 --- a/src/status_im/chat/handlers/wallet_chat.cljs +++ b/src/status_im/chat/handlers/wallet_chat.cljs @@ -1,10 +1,11 @@ (ns status-im.chat.handlers.wallet-chat (:require [re-frame.core :refer [after enrich path dispatch]] - [status-im.utils.handlers :refer [register-handler] :as u])) + [status-im.utils.handlers :refer [register-handler] :as u] + [status-im.constants :refer [wallet-chat-id]])) (register-handler :init-wallet-chat (u/side-effect! (fn [] - (dispatch [:add-chat "wallet" {:name "Wallet" - :dapp-url "http://127.0.0.1:3450"}])))) + (dispatch [:add-chat wallet-chat-id {:name "Wallet" + :dapp-url "http://127.0.0.1:3450"}])))) diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index 7f1fc61068..dcf27392e9 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -26,6 +26,7 @@ [status-im.chat.views.bottom-info :refer [bottom-info-view]] [status-im.i18n :refer [label label-pluralize]] [status-im.components.animation :as anim] + [status-im.constants :refer [console-chat-id]] [reagent.core :as r] [clojure.string :as str] [cljs-time.core :as t])) @@ -82,7 +83,7 @@ (<= last-online-date now-date)) (time/time-ago last-online-date) (label :t/active-unknown))) - (if (= chat-id "console") + (if (= chat-id console-chat-id) (label :t/active-online) (label :t/active-unknown)))) diff --git a/src/status_im/chat/sign_up.cljs b/src/status_im/chat/sign_up.cljs index 2fc41d1712..3416c8567c 100644 --- a/src/status_im/chat/sign_up.cljs +++ b/src/status_im/chat/sign_up.cljs @@ -6,7 +6,8 @@ [status-im.utils.sms-listener :refer [add-sms-listener remove-sms-listener]] [status-im.utils.phone-number :refer [format-phone-number]] - [status-im.constants :refer [text-content-type + [status-im.constants :refer [console-chat-id + text-content-type content-type-command content-type-command-request content-type-status]] @@ -15,7 +16,7 @@ (defn send-console-message [text] {:message-id (random/id) :from "me" - :to "console" + :to console-chat-id :content text :content-type text-content-type :outgoing true}) @@ -36,7 +37,7 @@ (or message (label :t/confirmation-code))) :content-type content-type-command-request :outgoing false - :from "console" + :from console-chat-id :to "me"}]))) (defn handle-sms [{body :body}] @@ -60,7 +61,7 @@ :content (label :t/contacts-syncronized) :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me"}]) (dispatch [:set-signed-up true])) @@ -74,7 +75,7 @@ :content (:message body) :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me"}]) (let [status (keyword (:status body))] (when (= :confirmed status) @@ -95,7 +96,7 @@ (label :t/phone-number-required)) :content-type content-type-command-request :outgoing false - :from "console" + :from console-chat-id :to "me"}]))) ;; -- Saving password ---------------------------------------- @@ -106,7 +107,7 @@ :content (label :t/password-saved) :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me" :new? false}]) (dispatch [:received-message @@ -114,7 +115,7 @@ :content (label :t/generate-passphrase) :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me" :new? false}]) (dispatch [:received-message @@ -122,7 +123,7 @@ :content (label :t/here-is-your-passphrase) :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me" :new? false}]) (dispatch [:received-message @@ -130,7 +131,7 @@ :content mnemonic :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me" :new? false}]) (dispatch [:received-message @@ -138,7 +139,7 @@ :content (label :t/written-down) :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me" :new? false}]) ;; TODO highlight '!phone' @@ -149,8 +150,8 @@ (def intro-status {:message-id "intro-status" :content (label :t/intro-status) - :from "console" - :chat-id "console" + :from console-chat-id + :chat-id console-chat-id :content-type content-type-status :outgoing false :to "me"}) @@ -162,7 +163,7 @@ :content (label :t/intro-message1) :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me"}]) (when-not logged-in? (dispatch [:received-message @@ -170,7 +171,7 @@ :content (label :t/intro-message2) :content-type text-content-type :outgoing false - :from "console" + :from console-chat-id :to "me"}]) (dispatch [:received-message @@ -180,12 +181,12 @@ (label :t/keypair-generated)) :content-type content-type-command-request :outgoing false - :from "console" + :from console-chat-id :to "me"}]))) (def console-chat - {:chat-id "console" - :name "console" + {:chat-id console-chat-id + :name console-chat-id ; todo remove/change dapp config fot console :dapp-url "http://localhost:8185/resources" :dapp-hash 858845357 @@ -193,6 +194,6 @@ :group-chat false :is-active true :timestamp (.getTime (js/Date.)) - :contacts [{:identity "console" + :contacts [{:identity console-chat-id :text-color "#FFFFFF" :background-color "#AB7967"}]}) diff --git a/src/status_im/chat/utils.cljs b/src/status_im/chat/utils.cljs index 6084c2e8b2..3cd56d9d85 100644 --- a/src/status_im/chat/utils.cljs +++ b/src/status_im/chat/utils.cljs @@ -1,7 +1,8 @@ -(ns status-im.chat.utils) +(ns status-im.chat.utils + (:require [status-im.constants :refer [console-chat-id]])) (defn console? [s] - (= "console" s)) + (= console-chat-id s)) (def not-console? (complement console?)) diff --git a/src/status_im/commands/handlers/jail.cljs b/src/status_im/commands/handlers/jail.cljs index 7799c8e926..2f82f3dda6 100644 --- a/src/status_im/commands/handlers/jail.cljs +++ b/src/status_im/commands/handlers/jail.cljs @@ -6,7 +6,8 @@ [status-im.utils.types :refer [json->clj]] [status-im.commands.utils :refer [generate-hiccup reg-handler]] [clojure.string :as s] - [status-im.components.react :as r])) + [status-im.components.react :as r] + [status-im.constants :refer [console-chat-id]])) (defn init-render-command! [_ [chat-id command message-id data]] @@ -37,7 +38,7 @@ parameters' (assoc parameters :command command')] (if transaction-hash (dispatch [:wait-for-transaction transaction-hash parameters']) - (let [events (if (= "console" chat-id) + (let [events (if (= console-chat-id chat-id) (merge regular-events console-events) regular-events) parameters'' (if-let [handler (events (keyword event))] diff --git a/src/status_im/commands/handlers/loading.cljs b/src/status_im/commands/handlers/loading.cljs index 4b97a7eb4f..28f1f0d6f8 100644 --- a/src/status_im/commands/handlers/loading.cljs +++ b/src/status_im/commands/handlers/loading.cljs @@ -7,7 +7,8 @@ [status-im.persistence.realm.core :as realm] [status-im.components.status :as status] [status-im.utils.types :refer [json->clj]] - [status-im.commands.utils :refer [reg-handler]])) + [status-im.commands.utils :refer [reg-handler]] + [status-im.constants :refer [console-chat-id wallet-chat-id]])) (def commands-js "commands.js") @@ -25,10 +26,10 @@ (when true ;-let [url (get-in db [:chats identity :dapp-url])] (cond - (= "console" identity) + (= console-chat-id identity) (dispatch [::validate-hash identity (slurp "resources/console.js")]) - (= "wallet" identity) + (= wallet-chat-id identity) (dispatch [::validate-hash identity (slurp "resources/wallet.js")]) :else diff --git a/src/status_im/components/chat_icon/screen.cljs b/src/status_im/components/chat_icon/screen.cljs index 1fe5a4555d..58ed8afe71 100644 --- a/src/status_im/components/chat_icon/screen.cljs +++ b/src/status_im/components/chat_icon/screen.cljs @@ -8,6 +8,7 @@ [status-im.components.icons.custom-icons :refer [oct-icon]] [status-im.components.chat-icon.styles :as st] [status-im.components.styles :refer [default-chat-color]] + [status-im.constants :refer [console-chat-id]] [clojure.string :as s])) (defn default-chat-icon [name styles] @@ -33,7 +34,7 @@ (defview chat-icon-view [chat-id group-chat name online styles] [photo-path [:chat-photo chat-id]] [view (:container styles) - (if-not (or (s/blank? photo-path) (= chat-id "console")) + (if-not (or (s/blank? photo-path) (= chat-id console-chat-id)) [chat-icon photo-path styles] [default-chat-icon name styles]) (when-not group-chat diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index 6eee35fa01..c2cfbad64b 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -15,6 +15,7 @@ (def color-light-gray "#EEF2F5") (def text1-color color-black) +(def text1-disabled-color "#555555") (def text2-color color-gray) (def text3-color color-blue) (def text4-color color-white) diff --git a/src/status_im/components/text_field/styles.cljs b/src/status_im/components/text_field/styles.cljs index 526b3cbe30..78e748236d 100644 --- a/src/status_im/components/text_field/styles.cljs +++ b/src/status_im/components/text_field/styles.cljs @@ -1,4 +1,5 @@ -(ns status-im.components.text-field.styles) +(ns status-im.components.text-field.styles + (:require [status-im.utils.platform :refer [platform-specific]])) (def text-field-container @@ -15,12 +16,13 @@ :text-align-vertical :top}) (defn label [top font-size color] - {:position :absolute - :top top - :left 0 - :color color - :font-size font-size - :background-color :transparent}) + (let [input-label-style (get-in platform-specific [:component-styles :input-label])] + (merge input-label-style + {:position :absolute + :top top + :color color + :font-size font-size + :background-color :transparent}))) (def label-float {}) @@ -36,6 +38,8 @@ :width width}) (defn error-text [color] - {:color color - :background-color :transparent - :font-size 12}) + (let [input-error-text-style (get-in platform-specific [:component-styles :input-error-text])] + (merge input-error-text-style + {:color color + :background-color :transparent + :font-size 12}))) diff --git a/src/status_im/components/text_field/view.cljs b/src/status_im/components/text_field/view.cljs index fe13a287de..4828f0172b 100644 --- a/src/status_im/components/text_field/view.cljs +++ b/src/status_im/components/text_field/view.cljs @@ -126,32 +126,32 @@ (when onFocus (onFocus)))) (defn on-input-blur [{:keys [component value animation onBlur]}] - (do - (log/debug "Input blurred") - (r/set-state component {:has-focus false - :float-label? (if (s/blank? value) false true)}) - (when (s/blank? value) - (field-animation animation)) - (when onBlur (onBlur)))) + (log/debug "Input blurred") + (r/set-state component {:has-focus false + :float-label? (if (s/blank? value) false true)}) + (when (s/blank? value) + (field-animation animation)) + (when onBlur (onBlur))) (defn get-width [event] (.-width (.-layout (.-nativeEvent event)))) (defn reagent-render [data children] - (let [component (r/current-component) + (let [component (r/current-component) {:keys [has-focus float-label? label-top label-font-size line-width + current-value max-line-width] :as state} (r/state component) {:keys [wrapper-style input-style line-color focus-line-color secure-text-entry label-color error-color error label value on-focus on-blur on-change-text on-change editable] :as props} (merge default-props (r/props component)) - line-color (if error error-color line-color) + line-color (if error error-color line-color) focus-line-color (if error error-color focus-line-color) - label-color (if (and error (not float-label?)) error-color label-color) - label (if error (str label " *") label)] + label-color (if (and error (not float-label?)) error-color label-color) + label (if error (str label " *") label)] [view (merge st/text-field-container wrapper-style) [animated-text {:style (st/label label-top label-font-size label-color)} label] [text-input {:style (merge st/text-input input-style) @@ -167,7 +167,7 @@ :to-line-width max-line-width} :onFocus on-focus}) :on-blur #(on-input-blur {:component component - :value value + :value (or current-value value) :animation {:top label-top :to-top (:label-bottom config) :font-size label-font-size @@ -175,7 +175,9 @@ :line-width line-width :to-line-width 0} :onBlur on-blur}) - :on-change-text #(on-change-text %) + :on-change-text (fn [text] + (r/set-state component {:current-value text}) + (on-change-text text)) :on-change #(on-change %) :default-value value}] [view {:style (st/underline-container line-color) diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index c1067da47a..65ed3a0b67 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -18,4 +18,7 @@ (def default-number-of-messages 20) -(def default-number-of-discovery-search-results 20) \ No newline at end of file +(def default-number-of-discovery-search-results 20) + +(def console-chat-id "console") +(def wallet-chat-id "wallet") \ No newline at end of file diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index 2aba7aafcb..9274b44037 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -159,8 +159,8 @@ :left 0}) (def form-container - {:marginLeft 16 - :margin-top 16}) + {:margin-left 16 + :margin-top 16}) (def address-explication-container {:flex 1 diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index cce344e978..3fd96c1138 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -1,7 +1,8 @@ (ns status-im.db (:require [schema.core :as s :include-macros true] [status-im.components.react :refer [animated]] - [status-im.components.animation :as anim])) + [status-im.components.animation :as anim] + [status-im.constants :refer [console-chat-id]])) ;; schema of app-db (def schema {:greeting s/Str}) @@ -31,7 +32,7 @@ :chats {} :chat {:command nil :last-message nil} - :current-chat-id "console" + :current-chat-id console-chat-id :contacts-ids #{} :selected-contacts #{} diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index f18e08dd73..4bd8cca0fe 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -22,7 +22,8 @@ status-im.accounts.handlers status-im.protocol.handlers status-im.transactions.handlers - [status-im.utils.types :as t])) + [status-im.utils.types :as t] + [status-im.constants :refer [console-chat-id]])) ;; -- Common -------------------------------------------------------------- @@ -49,7 +50,7 @@ (fn [db _] (assoc db :chats {} - :current-chat-id "console"))) + :current-chat-id console-chat-id))) (register-handler :initialize-account (u/side-effect! @@ -69,7 +70,7 @@ (dispatch [:initialize-db]) (dispatch [:load-accounts]) (dispatch [:init-console-chat]) - (dispatch [:load-commands! "console"])))) + (dispatch [:load-commands! console-chat-id])))) (register-handler :initialize-crypt (u/side-effect! diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index dabfb79eec..718e8eac74 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -18,7 +18,9 @@ :border-bottom-width 0.5} :chat {:new-message {:border-top-color styles/color-gray3 :border-top-width 0.5}} - :bottom-gradient {:height 1}}) + :bottom-gradient {:height 1} + :input-label {:left 0} + :input-error-text {:margin-left 0}}) (def fonts {:default {:font-family "SFUIDisplay-Regular"} diff --git a/src/status_im/profile/screen.cljs b/src/status_im/profile/screen.cljs index 33412d7575..05016108a7 100644 --- a/src/status_im/profile/screen.cljs +++ b/src/status_im/profile/screen.cljs @@ -1,7 +1,8 @@ (ns status-im.profile.screen (:require-macros [status-im.utils.views :refer [defview]]) - (:require [reagent.core :as r] - [re-frame.core :refer [subscribe dispatch]] + (:require [re-frame.core :refer [subscribe dispatch]] + [clojure.string :as str] + [cljs.spec :as s] [status-im.components.react :refer [view text text-input @@ -12,51 +13,51 @@ touchable-opacity show-image-picker]] [status-im.components.icons.custom-icons :refer [oct-icon]] - [status-im.components.chat-icon.screen :refer [profile-icon - my-profile-icon]] + [status-im.components.chat-icon.screen :refer [my-profile-icon]] [status-im.components.status-bar :refer [status-bar]] - [status-im.profile.styles :as st] - [status-im.utils.handlers :refer [get-hashtags]] - [status-im.profile.handlers :refer [message-user - update-profile]] + [status-im.components.text-field.view :refer [text-field]] [status-im.components.qr-code :refer [qr-code]] - [status-im.utils.phone-number :refer [format-phone-number - valid-mobile-number?]] - [status-im.utils.fs :refer [read-file]] - [status-im.utils.types :refer [clj->json]] + [status-im.utils.handlers :refer [get-hashtags]] + [status-im.utils.phone-number :refer [format-phone-number]] [status-im.utils.image-processing :refer [img->base64]] [status-im.utils.platform :refer [platform-specific]] - [status-im.i18n :refer [label]] - [clojure.string :as str])) + [status-im.profile.handlers :refer [message-user + update-profile]] + [status-im.profile.validations :as v] + [status-im.profile.styles :as st] + [status-im.i18n :refer [label]])) -(defview toolbar [{:keys [account profile-edit-data edit?]}] - [view - [touchable-highlight {:style st/back-btn-touchable - :on-press (fn [] - (dispatch [:set :profile-edit {:edit? false - :name nil - :email nil - :status nil - :photo-path nil}]) - (dispatch [:navigate-back]))} - [view st/back-btn-container - [icon :back st/back-btn-icon]]] - [touchable-highlight {:style st/actions-btn-touchable - :on-press (fn [] - (when edit? - (update-profile account profile-edit-data)) - (dispatch [:set-in [:profile-edit :edit?] (not edit?)]))} - [view st/actions-btn-container - (if edit? - [oct-icon {:name :check - :style st/ok-btn-icon}] - [icon :dots st/edit-btn-icon])]]]) +(defn toolbar [{:keys [account profile-edit-data edit?]}] + (let [profile-edit-data-valid? (s/valid? ::v/profile profile-edit-data)] + [view + [touchable-highlight {:style st/back-btn-touchable + :on-press (fn [] + (dispatch [:set :profile-edit {:edit? false + :name nil + :email nil + :status nil + :photo-path nil}]) + (dispatch [:navigate-back]))} + [view st/back-btn-container + [icon :back st/back-btn-icon]]] + [touchable-highlight {:style st/actions-btn-touchable + :on-press (fn [] + (if edit? + (when profile-edit-data-valid? + (update-profile account profile-edit-data) + (dispatch [:set-in [:profile-edit :edit?] false])) + (dispatch [:set-in [:profile-edit :edit?] true])))} + [view st/actions-btn-container + (if edit? + [oct-icon {:name :check + :style (st/ok-btn-icon profile-edit-data-valid?)}] + [icon :dots st/edit-btn-icon])]]])) -(defview status-image-view [{{address :address - username :name} :account - photo-path :photo-path - status :status - edit? :edit?}] +(defn status-image-view [{{address :address + username :name} :account + photo-path :photo-path + status :status + edit? :edit?}] [view st/status-block [view st/user-photo-container (if edit? @@ -78,24 +79,8 @@ [text-input {:style st/status-input :editable edit? :placeholder (label :t/profile-no-status) - :on-change-text #(dispatch [:set-in [:profile-edit :status] %])} - status]]) - - -(defview profile-property-view [{name :name - value :value - empty-value :empty-value - on-change-text :on-change-text - {edit-mode? :edit?} :profile-data}] - [view st/profile-property-view-container - [view st/profile-property-view-sub-container - [text {:style st/profile-property-view-label - :font :medium} - name] - [text-input {:style st/profile-property-view-value - :editable (and on-change-text edit-mode?) - :on-change-text on-change-text} - (or value (when-not edit-mode? empty-value))]]]) + :on-change-text #(dispatch [:set-in [:profile-edit :status] %]) + :value status}]]) (defview profile [] [{whisper-identity :whisper-identity @@ -136,18 +121,35 @@ [icon :more_vertical_blue st/more-btn-image]]]]] [scroll-view st/profile-properties-container - [profile-property-view {:name (label :t/username) - :value (if (not= username address) - username) - :empty-value (label :t/not-specified)}] - [profile-property-view {:name (label :t/phone-number) - :value (if-not (or (not phone) (str/blank? phone)) - (format-phone-number phone)) - :empty-value (label :t/not-specified)}] - [profile-property-view {:name (label :t/email) - :value (if-not (or (not email) (str/blank? email)) - email) - :empty-value (label :t/not-specified)}] + [text-field + {:editable false + :input-style st/profile-input-text + :wrapper-style st/profile-input-wrapper + :value (if (and (not= username address) + username + (not (str/blank? username))) + username + (label :t/not-specified)) + :label (label :t/username)}] + + [text-field + {:editable false + :input-style st/profile-input-text + :wrapper-style st/profile-input-wrapper + :value (if (and phone (not (str/blank? phone))) + (format-phone-number phone) + (label :t/not-specified)) + :label (label :t/phone-number)}] + + [text-field + {:editable false + :input-style st/profile-input-text + :wrapper-style st/profile-input-wrapper + :value (if (and email (not (str/blank? email))) + email + (label :t/not-specified)) + :label (label :t/email)}] + [view st/report-user-container [touchable-highlight {:on-press (fn [] ;; TODO not implemented @@ -164,6 +166,8 @@ status :status :as account} [:get-current-account] {edit? :edit? + new-name :name + new-email :email new-status :status new-photo-path :photo-path :as profile-edit-data} [:get :profile-edit]] @@ -179,23 +183,42 @@ :edit? edit?}] [scroll-view st/profile-properties-container - [profile-property-view {:name (label :t/username) - :value (if (not= username address) - username) - :empty-value (label :t/not-specified) - :on-change-text #(dispatch [:set-in [:profile-edit :name] %]) - :profile-data profile-edit-data}] - [profile-property-view {:name (label :t/phone-number) - :value (if-not (or (not phone) (str/blank? phone)) - (format-phone-number phone)) - :empty-value (label :t/not-specified) - :profile-data profile-edit-data}] - [profile-property-view {:name (label :t/email) - :value (if-not (or (not email) (str/blank? email)) - email) - :empty-value (label :t/not-specified) - :on-change-text #(dispatch [:set-in [:profile-edit :email] %]) - :profile-data profile-edit-data}] + [text-field + {:error (if-not (s/valid? ::v/name new-name) + (label :t/error-incorrect-name)) + :error-color "#7099e6" + :editable edit? + :input-style (if edit? + st/profile-input-text + st/profile-input-text-non-editable) + :wrapper-style st/profile-input-wrapper + :value (if (not= username address) + username) + :label (label :t/username) + :on-change-text #(dispatch [:set-in [:profile-edit :name] %])}] + + [text-field + {:editable false + :input-style st/profile-input-text-non-editable + :wrapper-style st/profile-input-wrapper + :value (if (and phone (not (str/blank? phone))) + (format-phone-number phone)) + :label (label :t/phone-number)}] + + [text-field + {:error (if-not (s/valid? ::v/email new-email) + (label :t/error-incorrect-email)) + :error-color "#7099e6" + :editable edit? + :input-style (if edit? + st/profile-input-text + st/profile-input-text-non-editable) + :wrapper-style st/profile-input-wrapper + :value (if (and email (not (str/blank? email))) + email) + :label (label :t/email) + :on-change-text #(dispatch [:set-in [:profile-edit :email] %])}] + [view st/qr-code-container ;; TODO: this public key should be replaced by address [qr-code {:value (str "ethereum:" public-key) diff --git a/src/status_im/profile/styles.cljs b/src/status_im/profile/styles.cljs index 1972032348..f40dd0ca2f 100644 --- a/src/status_im/profile/styles.cljs +++ b/src/status_im/profile/styles.cljs @@ -1,6 +1,7 @@ (ns status-im.profile.styles (:require [status-im.components.styles :refer [color-light-blue-transparent color-white + color-gray color-black color-blue color-blue-transparent @@ -8,6 +9,7 @@ online-color separator-color text1-color + text1-disabled-color text2-color]])) (def profile @@ -42,9 +44,9 @@ {:width 4 :height 16}) -(def ok-btn-icon +(defn ok-btn-icon [enabled?] {:font-size 22 - :color :black}) + :color (if enabled? color-black color-gray)}) (def user-photo-container {:margin-top 22}) @@ -113,32 +115,21 @@ (def profile-properties-container {:margin-top 20 + :margin-left 16 :align-items :stretch :flex-firection :column}) -(def profile-property-view-container - {:padding-left 16}) +(def profile-input-wrapper + {:margin-bottom 16}) -(def profile-property-view-sub-container - {:border-bottom-width 1 - :border-bottom-color separator-color - :padding-right 16}) +(def profile-input-text + {:color text1-color}) -(def profile-property-view-label - {:margin-top 18 - :font-size 14 - :color text2-color}) - -(def profile-property-view-value - {:margin-top 8 - :margin-bottom 8 - :padding 0 - :height 40 - :font-size 16 - :color text1-color}) +(def profile-input-text-non-editable + {:color text1-disabled-color}) (def report-user-container - {:margin-top 50 + {:margin-top 32 :margin-bottom 43 :align-items :center}) diff --git a/src/status_im/profile/validations.cljs b/src/status_im/profile/validations.cljs new file mode 100644 index 0000000000..74a8787303 --- /dev/null +++ b/src/status_im/profile/validations.cljs @@ -0,0 +1,22 @@ +(ns status-im.profile.validations + (:require [cljs.spec :as s] + [status-im.utils.phone-number :refer [valid-mobile-number?]] + [status-im.constants :refer [console-chat-id wallet-chat-id]] + [clojure.string :as str])) + +(def homoglyph-finder (js/require "homoglyph-finder")) + +(defn correct-name? [username] + (let [username (some-> username (str/trim))] + (and (not (.isMatches homoglyph-finder username console-chat-id)) + (not (.isMatches homoglyph-finder username wallet-chat-id))))) + +(defn correct-email? [email] + (let [pattern #"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"] + (or (str/blank? email) + (and (string? email) (re-matches pattern email))))) + +(s/def ::name correct-name?) +(s/def ::email correct-email?) + +(s/def ::profile (s/keys :req-un [::name ::email])) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index c0e80d76f8..7b08dd3623 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -56,6 +56,8 @@ :email "Email" :profile-no-status "No status" :add-to-contacts "Add to contacts" + :error-incorrect-name "Please, select another name" + :error-incorrect-email "Incorrect e-mail" ;;make_photo :image-source-title "Profile image"