Added address validation

Former-commit-id: 5392b8d9a2
This commit is contained in:
Adrian Tiberius 2016-07-13 18:53:23 +03:00
parent 93023900f0
commit f67c252f0a
4 changed files with 73 additions and 31 deletions

View File

@ -69,7 +69,7 @@
(:label-font-large config) (:label-font-large config)
(:label-font-small config))) (:label-font-small config)))
:float-label? (if (s/blank? value) false true)}] :float-label? (if (s/blank? value) false true)}]
(log/debug "component-will-mount") ;(log/debug "component-will-mount")
(r/set-state component data))) (r/set-state component data)))
; Invoked once, only on the client (not on the server), immediately after the ; Invoked once, only on the client (not on the server), immediately after the
@ -79,7 +79,8 @@
; parent components. ; parent components.
(defn component-did-mount [component] (defn component-did-mount [component]
(let [props (r/props component)] (let [props (r/props component)]
(log/debug "component-did-mount:"))) ;(log/debug "component-did-mount:")
))
; Invoked when a component is receiving new props. This method is not called for ; Invoked when a component is receiving new props. This method is not called for
; the initial render. Use this as an opportunity to react to a prop transition ; the initial render. Use this as an opportunity to react to a prop transition
@ -87,7 +88,8 @@
; The old props can be accessed via this.props. Calling this.setState() within ; The old props can be accessed via this.props. Calling this.setState() within
; this function will not trigger an additional render. ; this function will not trigger an additional render.
(defn component-will-receive-props [component new-props] (defn component-will-receive-props [component new-props]
(log/debug "component-will-receive-props: new-props=" new-props)) ;(log/debug "component-will-receive-props: new-props=" new-props)
)
; Invoked before rendering when new props or state are being received. This method ; Invoked before rendering when new props or state are being received. This method
; is not called for the initial render or when forceUpdate is used. Use this as ; is not called for the initial render or when forceUpdate is used. Use this as
@ -97,20 +99,22 @@
; until the next state change. In addition, componentWillUpdate and ; until the next state change. In addition, componentWillUpdate and
; componentDidUpdate will not be called. ; componentDidUpdate will not be called.
(defn should-component-update [component next-props next-state] (defn should-component-update [component next-props next-state]
(log/debug "should-component-update: " next-props next-state) ;(log/debug "should-component-update: " next-props next-state)
true) true)
; Invoked immediately before rendering when new props or state are being received. ; Invoked immediately before rendering when new props or state are being received.
; This method is not called for the initial render. Use this as an opportunity ; This method is not called for the initial render. Use this as an opportunity
; to perform preparation before an update occurs. ; to perform preparation before an update occurs.
(defn component-will-update [component next-props next-state] (defn component-will-update [component next-props next-state]
(log/debug "component-will-update: " next-props next-state)) ;(log/debug "component-will-update: " next-props next-state)
)
; Invoked immediately after the component's updates are flushed to the DOM. ; Invoked immediately after the component's updates are flushed to the DOM.
; This method is not called for the initial render. Use this as an opportunity ; This method is not called for the initial render. Use this as an opportunity
; to operate on the DOM when the component has been updated. ; to operate on the DOM when the component has been updated.
(defn component-did-update [component prev-props prev-state] (defn component-did-update [component prev-props prev-state]
(log/debug "component-did-update: " prev-props prev-state)) ;(log/debug "component-did-update: " prev-props prev-state)
)
(defn on-focus [{:keys [component animation onFocus]}] (defn on-focus [{:keys [component animation onFocus]}]
(do (do
@ -147,7 +151,7 @@
focusLineColor (if error errorColor focusLineColor) focusLineColor (if error errorColor focusLineColor)
labelColor (if (and error (not float-label?)) errorColor labelColor) labelColor (if (and error (not float-label?)) errorColor labelColor)
label (if error (str label " *") label)] label (if error (str label " *") label)]
(log/debug "reagent-render: " data) ;(log/debug "reagent-render: " data)
[view (merge st/text-field-container wrapperStyle) [view (merge st/text-field-container wrapperStyle)
[animated-text {:style (st/label label-top label-font-size labelColor)} label] [animated-text {:style (st/label label-top label-font-size labelColor)} label]
[text-input {:style (merge st/text-input inputStyle) [text-input {:style (merge st/text-input inputStyle)
@ -187,5 +191,5 @@
:component-did-update component-did-update :component-did-update component-did-update
:display-name "text-field" :display-name "text-field"
:reagent-render reagent-render}] :reagent-render reagent-render}]
(log/debug "Creating text-field component: " data) ;(log/debug "Creating text-field component: " data)
(r/create-class component-data))) (r/create-class component-data)))

View File

@ -1,13 +1,21 @@
(ns status-im.contacts.validations (ns status-im.contacts.validations
(:require [cljs.spec :as s] (:require [cljs.spec :as s]
[cljsjs.web3]
[status-im.persistence.realm :as realm])) [status-im.persistence.realm :as realm]))
(defn is-address? [s]
(.isAddress js/Web3.prototype s))
(defn unique-identity? [identity] (defn unique-identity? [identity]
(println identity) (println identity)
(not (realm/exists? :contacts :whisper-identity identity))) (not (realm/exists? :contacts :whisper-identity identity)))
(defn valid-length? [identity] (defn valid-length? [identity]
(= 132 (count identity))) (let [length (count identity)]
(or
(= 130 length)
(= 132 length)
(is-address? identity))))
(s/def ::identity-length valid-length?) (s/def ::identity-length valid-length?)
(s/def ::unique-identity unique-identity?) (s/def ::unique-identity unique-identity?)

View File

@ -11,6 +11,7 @@
[status-im.components.text-field.view :refer [text-field]] [status-im.components.text-field.view :refer [text-field]]
[status-im.utils.identicon :refer [identicon]] [status-im.utils.identicon :refer [identicon]]
[status-im.components.toolbar :refer [toolbar]] [status-im.components.toolbar :refer [toolbar]]
[status-im.utils.utils :refer [log on-error http-post toast]]
[status-im.components.styles :refer [color-purple [status-im.components.styles :refer [color-purple
color-white color-white
icon-search icon-search
@ -43,12 +44,12 @@
:label (label :t/name) :label (label :t/name)
:onChangeText #(dispatch [:set-in [:new-contact :name] %])}]) :onChangeText #(dispatch [:set-in [:new-contact :name] %])}])
(defview contact-whisper-id-input [whisper-identity] (defview contact-whisper-id-input [whisper-identity error]
[] []
(let [error (if (str/blank? whisper-identity) "" nil) (let [error (if (str/blank? whisper-identity) "" error)
error (if (s/valid? ::v/whisper-identity whisper-identity) error (if (s/valid? ::v/whisper-identity whisper-identity)
error error
"Please enter a valid address or scan a QR code")] (label :t/enter-valid-address))]
[view button-input-container [view button-input-container
[text-field [text-field
{:error error {:error error
@ -56,26 +57,52 @@
:value whisper-identity :value whisper-identity
:wrapperStyle (merge button-input) :wrapperStyle (merge button-input)
:label (label :t/address) :label (label :t/address)
:onChangeText #(dispatch [:set-in [:new-contact :whisper-identity] %])}] :onChangeText #(do
(dispatch [:set-in [:new-contact :whisper-identity] %])
(dispatch [:set :new-contact-address-error nil]))}]
[scan-button {:showLabel (zero? (count whisper-identity)) [scan-button {:showLabel (zero? (count whisper-identity))
:handler #(dispatch [:scan-qr-code {:toolbar-title (label :t/new-contact)} :set-new-contact-from-qr])}]])) :handler #(dispatch [:scan-qr-code {:toolbar-title (label :t/new-contact)} :set-new-contact-from-qr])}]]))
(defn on-add-contact [whisper-identity new-contact]
(if (v/is-address? whisper-identity)
(http-post "get-contacts-by-address" {:addresses [whisper-identity]}
(fn [{:keys [contacts]}]
(if (> (count contacts) 0)
(let [contact (first contacts)
new-contact (merge
new-contact
{:address whisper-identity
:whisper-identity (:whisper-identity contact)})]
(dispatch [:add-new-contact new-contact]))
(dispatch [:set :new-contact-address-error (label :t/unknown-address)]))))
(dispatch [:add-new-contact new-contact])))
(defn toolbar-action [whisper-identity new-contact error]
(let [valid-contact? (and
(s/valid? ::v/contact new-contact)
(nil? error))]
{:image {:source {:uri (if valid-contact?
:icon_ok_blue
:icon_ok_disabled)}
:style icon-search}
:handler #(when valid-contact?
(let [contact (merge
{:photo-path (identicon whisper-identity)}
new-contact)]
(on-add-contact whisper-identity contact)))}))
(defview new-contact [] (defview new-contact []
[{:keys [name whisper-identity phone-number] :as new-contact} [:get :new-contact]] [{:keys [name whisper-identity phone-number] :as new-contact} [:get :new-contact]
(let [valid-contact? (s/valid? ::v/contact new-contact)] error [:get :new-contact-address-error]]
[view st/contact-form-container [view st/contact-form-container
[toolbar {:background-color :white [toolbar {:background-color :white
:nav-action {:image {:source {:uri :icon_back} :nav-action {:image {:source {:uri :icon_back}
:style icon-back} :style icon-back}
:handler #(dispatch [:navigate-back])} :handler #(dispatch [:navigate-back])}
:custom-content toolbar-title :custom-content toolbar-title
:action {:image {:source {:uri (if valid-contact? :action (toolbar-action whisper-identity new-contact error)}]
:icon_ok_blue [view st/form-container
:icon_ok_disabled)} [contact-name-input name]
:style icon-search} [contact-whisper-id-input whisper-identity error]]
:handler #(when valid-contact? (dispatch [:add-new-contact (merge {:photo-path (identicon whisper-identity)} new-contact)]))}}] [view st/address-explication-container
[view st/form-container [text {:style st/address-explication} (label :t/address-explication)]]])
[contact-name-input name]
[contact-whisper-id-input whisper-identity]]
[view st/address-explication-container
[text {:style st/address-explication} (label :t/address-explication)]]]))

View File

@ -125,6 +125,9 @@
:name "Name" :name "Name"
:whisper-identity "Whisper Identity" :whisper-identity "Whisper Identity"
:address-explication "Maybe here should be some text explaining what an address is and where to look for it" :address-explication "Maybe here should be some text explaining what an address is and where to look for it"
:enter-valid-address "Please enter a valid address or scan a QR code"
:unknown-address "Unknown address"
;login ;login
:recover-access "Recover access" :recover-access "Recover access"