mirror of
https://github.com/penpot/penpot.git
synced 2025-05-08 23:45:55 +02:00
🚧 Initial work on password form.
This commit is contained in:
parent
08bd135d55
commit
ae2d8330ca
4 changed files with 129 additions and 105 deletions
|
@ -8,6 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
|
[struct.core :as stt]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[uxbox.main.repo :as rp]
|
[uxbox.main.repo :as rp]
|
||||||
[uxbox.util.i18n :as i18n :refer (tr)]
|
[uxbox.util.i18n :as i18n :refer (tr)]
|
||||||
|
@ -58,20 +59,15 @@
|
||||||
|
|
||||||
;; --- Update Profile
|
;; --- Update Profile
|
||||||
|
|
||||||
(s/def ::fullname string?)
|
(stt/defs update-profile-spec
|
||||||
(s/def ::email us/email?)
|
{:fullname [stt/required stt/string]
|
||||||
(s/def ::username string?)
|
:email [stt/required stt/email]
|
||||||
(s/def ::language string?)
|
:username [stt/required stt/string]
|
||||||
|
:language [stt/required stt/string]})
|
||||||
(s/def ::update-profile
|
|
||||||
(s/keys :req-un [::fullname
|
|
||||||
::email
|
|
||||||
::language
|
|
||||||
::username]))
|
|
||||||
|
|
||||||
(defn update-profile
|
(defn update-profile
|
||||||
[data {:keys [on-success on-error]}]
|
[data {:keys [on-success on-error]}]
|
||||||
{:pre [(us/valid? ::update-profile data)
|
{:pre [(stt/valid? update-profile-spec data)
|
||||||
(fn? on-error)
|
(fn? on-error)
|
||||||
(fn? on-success)]}
|
(fn? on-success)]}
|
||||||
(reify
|
(reify
|
||||||
|
@ -85,7 +81,6 @@
|
||||||
(assoc :email (:email data))
|
(assoc :email (:email data))
|
||||||
(assoc :username (:username data))
|
(assoc :username (:username data))
|
||||||
(assoc-in [:metadata :language] (:language data)))]
|
(assoc-in [:metadata :language] (:language data)))]
|
||||||
(prn "update-profile" data)
|
|
||||||
(->> (rp/req :update/profile data)
|
(->> (rp/req :update/profile data)
|
||||||
(rx/map :payload)
|
(rx/map :payload)
|
||||||
(rx/do on-success)
|
(rx/do on-success)
|
||||||
|
|
|
@ -6,95 +6,102 @@
|
||||||
;; Copyright (c) 2016-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
;; Copyright (c) 2016-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||||
|
|
||||||
(ns uxbox.main.ui.settings.password
|
(ns uxbox.main.ui.settings.password
|
||||||
(:require [cljs.spec.alpha :as s :include-macros true]
|
(:require
|
||||||
[lentes.core :as l]
|
[cuerdas.core :as str]
|
||||||
[cuerdas.core :as str]
|
[lentes.core :as l]
|
||||||
[potok.core :as ptk]
|
[rumext.alpha :as mf]
|
||||||
[uxbox.main.store :as st]
|
[struct.core :as stt]
|
||||||
[uxbox.main.data.users :as udu]
|
[uxbox.builtins.icons :as i]
|
||||||
[uxbox.builtins.icons :as i]
|
[uxbox.main.data.users :as udu]
|
||||||
[uxbox.main.ui.messages :refer [messages-widget]]
|
[uxbox.main.store :as st]
|
||||||
[uxbox.main.ui.settings.header :refer [header]]
|
[uxbox.util.dom :as dom]
|
||||||
[uxbox.util.i18n :refer [tr]]
|
[uxbox.util.forms :as fm]
|
||||||
[uxbox.util.forms :as fm]
|
[uxbox.util.i18n :refer [tr]]
|
||||||
[uxbox.util.dom :as dom]
|
[uxbox.util.messages :as um]))
|
||||||
[uxbox.util.messages :as um]
|
|
||||||
[rumext.core :as mx :include-macros true]))
|
|
||||||
|
|
||||||
(def form-data (fm/focus-data :profile-password st/state))
|
(stt/defs password-form-spec
|
||||||
(def form-errors (fm/focus-errors :profile-password st/state))
|
{:password-1 [stt/required stt/string]
|
||||||
|
:password-2 [stt/required stt/string]
|
||||||
|
:password-old [stt/required stt/string]})
|
||||||
|
|
||||||
(def assoc-value (partial fm/assoc-value :profile-password))
|
(defn- on-submit
|
||||||
(def assoc-error (partial fm/assoc-error :profile-password))
|
[event form]
|
||||||
(def clear-form (partial fm/clear-form :profile-password))
|
(dom/prevent-default event)
|
||||||
|
(prn "on-submit" form)
|
||||||
|
#_(let [data (:clean-data form)
|
||||||
|
opts {:on-success #(prn "On Success" %)
|
||||||
|
:on-error #(on-error % form)}]
|
||||||
|
(st/emit! (udu/update-profile data opts))))
|
||||||
|
|
||||||
;; TODO: add better password validation
|
|
||||||
|
|
||||||
(s/def ::password-1 ::fm/non-empty-string)
|
|
||||||
(s/def ::password-2 ::fm/non-empty-string)
|
|
||||||
(s/def ::password-old ::fm/non-empty-string)
|
|
||||||
|
|
||||||
(s/def ::password-form
|
|
||||||
(s/keys :req-un [::password-1
|
|
||||||
::password-2
|
|
||||||
::password-old]))
|
|
||||||
|
|
||||||
(mx/defc password-form
|
;; #_(let [data (mx/deref form-data)
|
||||||
{:mixins [mx/reactive mx/static]}
|
;; errors (mx/react form-errors)
|
||||||
[]
|
;; valid? (fm/valid? ::password-form data)]
|
||||||
(let [data (mx/react form-data)
|
;; (letfn [(on-change [field event]
|
||||||
errors (mx/react form-errors)
|
;; (let [value (dom/event->value event)]
|
||||||
valid? (fm/valid? ::password-form data)]
|
;; (st/emit! (assoc-value field value))))
|
||||||
(letfn [(on-change [field event]
|
;; (on-success []
|
||||||
(let [value (dom/event->value event)]
|
;; (st/emit! (um/info (tr "settings.password.password-saved"))))
|
||||||
(st/emit! (assoc-value field value))))
|
;; (on-error [{:keys [code] :as payload}]
|
||||||
(on-success []
|
;; (case code
|
||||||
(st/emit! (um/info (tr "settings.password.password-saved"))))
|
;; :uxbox.services.users/old-password-not-match
|
||||||
(on-error [{:keys [code] :as payload}]
|
;; (st/emit! (assoc-error :password-old (tr "settings.password.wrong-old-password")))
|
||||||
(case code
|
|
||||||
:uxbox.services.users/old-password-not-match
|
|
||||||
(st/emit! (assoc-error :password-old (tr "settings.password.wrong-old-password")))
|
|
||||||
|
|
||||||
:else
|
;; :else
|
||||||
(throw (ex-info "unexpected" {:error payload}))))
|
;; (throw (ex-info "unexpected" {:error payload}))))
|
||||||
(on-submit [event]
|
;; (on-submit [event]
|
||||||
(st/emit! (udu/update-password data
|
;; (st/emit! (udu/update-password data
|
||||||
:on-success on-success
|
;; :on-success on-success
|
||||||
:on-error on-error)))]
|
;; :on-error on-error)))]
|
||||||
[:form.password-form
|
|
||||||
[:span.user-settings-label (tr "settings.password.change-password")]
|
|
||||||
[:input.input-text
|
|
||||||
{:type "password"
|
(mf/defc password-form
|
||||||
:class (fm/error-class errors :password-old)
|
[props]
|
||||||
:value (:password-old data "")
|
(let [{:keys [data] :as form} (fm/use-form {:initial {} :spec password-form-spec})]
|
||||||
:on-change (partial on-change :password-old)
|
(prn "password-form" form)
|
||||||
:placeholder (tr "settings.password.old-password")}]
|
[:form.password-form {:on-submit #(on-submit % form)}
|
||||||
(fm/input-error errors :password-old)
|
[:span.user-settings-label (tr "settings.password.change-password")]
|
||||||
[:input.input-text
|
[:input.input-text
|
||||||
{:type "password"
|
{:type "password"
|
||||||
:class (fm/error-class errors :password-1)
|
:name "password-old"
|
||||||
:value (:password-1 data "")
|
:class (fm/error-class form :password-old)
|
||||||
:on-change (partial on-change :password-1)
|
:value (:password-old data "")
|
||||||
:placeholder (tr "settings.password.new-password")}]
|
:on-blur (fm/on-input-blur form)
|
||||||
(fm/input-error errors :password-1)
|
:on-change (fm/on-input-change form)
|
||||||
[:input.input-text
|
:placeholder (tr "settings.password.old-password")}]
|
||||||
{:type "password"
|
[:& fm/error-input {:form form :field :password-old}]
|
||||||
:class (fm/error-class errors :password-2)
|
|
||||||
:value (:password-2 data "")
|
[:input.input-text
|
||||||
:on-change (partial on-change :password-2)
|
{:type "password"
|
||||||
:placeholder (tr "settings.password.confirm-password")}]
|
:name "password-1"
|
||||||
(fm/input-error errors :password-2)
|
:class (fm/error-class form :password-1)
|
||||||
[:input.btn-primary
|
:value (:password-1 data "")
|
||||||
{:type "button"
|
:on-blur (fm/on-input-blur form)
|
||||||
:class (when-not valid? "btn-disabled")
|
:on-change (fm/on-input-change form)
|
||||||
:disabled (not valid?)
|
:placeholder (tr "settings.password.new-password")}]
|
||||||
:on-click on-submit
|
[:& fm/error-input {:form form :field :password-1}]
|
||||||
:value (tr "settings.update-settings")}]])))
|
[:input.input-text
|
||||||
|
{:type "password"
|
||||||
|
:name "password-2"
|
||||||
|
:class (fm/error-class form :password-2)
|
||||||
|
:value (:password-2 data "")
|
||||||
|
:on-blur (fm/on-input-blur form)
|
||||||
|
:on-change (fm/on-input-change form)
|
||||||
|
:placeholder (tr "settings.password.confirm-password")}]
|
||||||
|
[:& fm/error-input {:form form :field :password-2}]
|
||||||
|
[:input.btn-primary
|
||||||
|
{:type "submit"
|
||||||
|
:class (when-not (:valid form) "btn-disabled")
|
||||||
|
:disabled (not (:valid form))
|
||||||
|
:value (tr "settings.update-settings")}]]))
|
||||||
|
|
||||||
;; --- Password Page
|
;; --- Password Page
|
||||||
|
|
||||||
(mx/defc password-page
|
(mf/defc password-page
|
||||||
[]
|
[props]
|
||||||
[:section.dashboard-content.user-settings
|
[:section.dashboard-content.user-settings
|
||||||
[:section.user-settings-content
|
[:section.user-settings-content
|
||||||
(password-form)]])
|
[:& password-form]]])
|
||||||
|
|
|
@ -41,10 +41,12 @@
|
||||||
(prn "on-error" error form)
|
(prn "on-error" error form)
|
||||||
(case (:code error)
|
(case (:code error)
|
||||||
:uxbox.services.users/email-already-exists
|
:uxbox.services.users/email-already-exists
|
||||||
(swap! form assoc-in [:errors :email] "errors.api.form.email-already-exists")
|
(swap! form assoc-in [:errors :email]
|
||||||
|
{:message "errors.api.form.email-already-exists"})
|
||||||
|
|
||||||
:uxbox.services.users/username-already-exists
|
:uxbox.services.users/username-already-exists
|
||||||
(swap! form assoc-in [:errors :username] "errors.api.form.username-already-exists")))
|
(swap! form assoc-in [:errors :username]
|
||||||
|
{:message "errors.api.form.username-already-exists"})))
|
||||||
|
|
||||||
(defn- initial-data
|
(defn- initial-data
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -44,9 +44,29 @@
|
||||||
([self f x y] (update-fn #(f % x y)))
|
([self f x y] (update-fn #(f % x y)))
|
||||||
([self f x y more] (update-fn #(apply f % x y more))))))
|
([self f x y more] (update-fn #(apply f % x y more))))))
|
||||||
|
|
||||||
(defn- simplify-errors
|
(defn- translate-error-type
|
||||||
|
[type]
|
||||||
|
(case type
|
||||||
|
::stt/string "errors.should-be-string"
|
||||||
|
::stt/number "errors.should-be-number"
|
||||||
|
::stt/number-str "errors.should-be-number"
|
||||||
|
::stt/integer "errors.should-be-integer"
|
||||||
|
::stt/integer-str "errors.should-be-integer"
|
||||||
|
::stt/required "errors.required"
|
||||||
|
::stt/email "errors.should-be-valid-email"
|
||||||
|
::stt/uuid "errors.should-be-uuid"
|
||||||
|
::stt/uuid-str "errors.should-be-valid-uuid"
|
||||||
|
"errors.undefined-error"))
|
||||||
|
|
||||||
|
(defn- translate-errors
|
||||||
[errors]
|
[errors]
|
||||||
(reduce-kv #(assoc %1 %2 (:message %3)) {} errors))
|
(reduce-kv (fn [acc key val]
|
||||||
|
(if (string? (:message val))
|
||||||
|
(assoc acc key val)
|
||||||
|
(->> (translate-error-type (:type val))
|
||||||
|
(assoc val :message)
|
||||||
|
(assoc acc key))))
|
||||||
|
{} errors))
|
||||||
|
|
||||||
(defn use-form
|
(defn use-form
|
||||||
[{:keys [initial spec] :as opts}]
|
[{:keys [initial spec] :as opts}]
|
||||||
|
@ -54,7 +74,7 @@
|
||||||
:errors {}
|
:errors {}
|
||||||
:touched {}})
|
:touched {}})
|
||||||
[errors' clean-data] (validate spec (:data state))
|
[errors' clean-data] (validate spec (:data state))
|
||||||
errors (merge (reduce-kv #(assoc %1 %2 (:message %3)) {} errors')
|
errors (merge (translate-errors errors')
|
||||||
(:errors state))]
|
(:errors state))]
|
||||||
(-> (assoc state
|
(-> (assoc state
|
||||||
:errors errors
|
:errors errors
|
||||||
|
@ -86,11 +106,16 @@
|
||||||
(mf/defc error-input
|
(mf/defc error-input
|
||||||
[{:keys [form field] :as props}]
|
[{:keys [form field] :as props}]
|
||||||
(let [touched? (get-in form [:touched field])
|
(let [touched? (get-in form [:touched field])
|
||||||
error? (get-in form [:errors field])]
|
error (get-in form [:errors field])]
|
||||||
(when (and touched? error?)
|
(when (and touched? error)
|
||||||
[:ul.form-errors
|
[:ul.form-errors
|
||||||
[:li {:key error?} (tr error?)]])))
|
[:li {:key (:type error)} (tr (:message error))]])))
|
||||||
|
|
||||||
|
(defn error-class
|
||||||
|
[form field]
|
||||||
|
(when (and (get-in form [:errors field])
|
||||||
|
(get-in form [:touched field]))
|
||||||
|
"invalid"))
|
||||||
|
|
||||||
;; --- Additional Validators
|
;; --- Additional Validators
|
||||||
|
|
||||||
|
@ -298,11 +323,6 @@
|
||||||
[:ul.form-errors
|
[:ul.form-errors
|
||||||
[:li {:key error} (tr error)]]))
|
[:li {:key error} (tr error)]]))
|
||||||
|
|
||||||
(defn error-class
|
|
||||||
[errors field]
|
|
||||||
(when (get errors field)
|
|
||||||
"invalid"))
|
|
||||||
|
|
||||||
(defn clear-mixin
|
(defn clear-mixin
|
||||||
[store type]
|
[store type]
|
||||||
{:will-unmount (fn [own]
|
{:will-unmount (fn [own]
|
||||||
|
|
Loading…
Add table
Reference in a new issue