mirror of
https://github.com/penpot/penpot.git
synced 2025-02-20 22:06:07 -05:00
Overhaul of form data and errors handling.
This commit is contained in:
parent
e509daaeef
commit
e42b2ed7bf
8 changed files with 118 additions and 72 deletions
40
src/uxbox/data/forms.cljs
Normal file
40
src/uxbox/data/forms.cljs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.data.forms
|
||||||
|
(:require [beicon.core :as rx]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[uxbox.repo :as rp]
|
||||||
|
[uxbox.rstore :as rs]
|
||||||
|
[uxbox.state :as st]
|
||||||
|
[uxbox.schema :as sc]
|
||||||
|
[uxbox.locales :refer (tr)]
|
||||||
|
[uxbox.ui.messages :as uum]))
|
||||||
|
|
||||||
|
;; --- Assign Errors
|
||||||
|
|
||||||
|
(defrecord AssignErrors [type errors]
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(assoc-in state [:errors type] errors)))
|
||||||
|
|
||||||
|
(defn assign-errors
|
||||||
|
([type] (assign-errors type nil))
|
||||||
|
([type errors]
|
||||||
|
(FormErrors. type errors)))
|
||||||
|
|
||||||
|
;; --- Assign Field Value
|
||||||
|
|
||||||
|
(defrecord AssignFieldValue [type field value]
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(assoc-in state [:forms type field] value)))
|
||||||
|
|
||||||
|
(defn assign-field-value
|
||||||
|
[type field value]
|
||||||
|
(AssignFieldValue. type field value))
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
[uxbox.schema :as sc]
|
[uxbox.schema :as sc]
|
||||||
[uxbox.locales :refer (tr)]
|
[uxbox.locales :refer (tr)]
|
||||||
|
[uxbox.data.forms :as forms]
|
||||||
[uxbox.ui.messages :as uum]))
|
[uxbox.ui.messages :as uum]))
|
||||||
|
|
||||||
;; --- Profile Fetched
|
;; --- Profile Fetched
|
||||||
|
@ -59,17 +60,41 @@
|
||||||
[data]
|
[data]
|
||||||
(UpdateProfile. data))
|
(UpdateProfile. data))
|
||||||
|
|
||||||
|
;; --- Password Updated
|
||||||
|
|
||||||
|
(defrecord PasswordUpdated []
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(assoc-in state [:forms :profile/password] {}))
|
||||||
|
|
||||||
|
rs/EffectEvent
|
||||||
|
(-apply-effect [_ state]
|
||||||
|
(uum/info (tr "profile.password-saved"))))
|
||||||
|
|
||||||
;; --- Update Password
|
;; --- Update Password
|
||||||
|
|
||||||
(defrecord UpdatePassword [old-password password]
|
(defrecord UpdatePassword [data]
|
||||||
rs/WatchEvent
|
rs/WatchEvent
|
||||||
(-apply-watch [_ state s]
|
(-apply-watch [_ state s]
|
||||||
(letfn [(on-error [err]
|
(letfn [(on-error [err]
|
||||||
(uum/error (tr "errors.profile.update-password"))
|
(uum/error (tr "errors.profile.update-password") {:timeout 3000})
|
||||||
(rx/empty))]
|
(rx/empty))]
|
||||||
(->> (rp/req :update/password {:old-password old-password :password password})
|
(let [params {:old-password (:old-password data)
|
||||||
(rx/catch on-error)))))
|
:password (:password-1 data)}]
|
||||||
|
(->> (rp/req :update/password params)
|
||||||
|
(rx/map #(->PasswordUpdated))
|
||||||
|
(rx/catch on-error))))))
|
||||||
|
|
||||||
|
(def update-password-schema
|
||||||
|
[[:password-1 sc/required sc/string [sc/min-len 6]]
|
||||||
|
[:password-2 sc/required sc/string
|
||||||
|
[sc/identical-to :password-1 :message "errors.form.password-not-match"]]
|
||||||
|
[:old-password sc/required sc/string]])
|
||||||
|
|
||||||
(defn update-password
|
(defn update-password
|
||||||
[{:keys [old-password password]}]
|
[data]
|
||||||
(UpdatePassword. old-password password))
|
(let [[errors data] (sc/validate data update-password-schema)]
|
||||||
|
(println errors)
|
||||||
|
(if errors
|
||||||
|
(forms/assign-errors :profile/password errors)
|
||||||
|
(UpdatePassword. data))))
|
||||||
|
|
|
@ -80,12 +80,7 @@
|
||||||
(when-let [errors (first (validate schema data))]
|
(when-let [errors (first (validate schema data))]
|
||||||
(throw (ex-info "Invalid data" errors))))
|
(throw (ex-info "Invalid data" errors))))
|
||||||
|
|
||||||
;; (defn valid?
|
(defn valid?
|
||||||
;; [validator data]
|
[data schema]
|
||||||
;; (let [result (validator data)]
|
(let [[errors data] (validate data schema)]
|
||||||
;; (if result
|
(not errors)))
|
||||||
;; result
|
|
||||||
;; (let [message (:default-message-format (meta validator))
|
|
||||||
;; message (str/format message data)]
|
|
||||||
;; (throw (ex-info message {}))))))
|
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
[uxbox.library :as library]
|
[uxbox.library :as library]
|
||||||
[uxbox.data.dashboard :as dd]
|
[uxbox.data.dashboard :as dd]
|
||||||
[uxbox.ui.icons :as i]
|
[uxbox.ui.icons :as i]
|
||||||
[uxbox.ui.form :as form]
|
[uxbox.ui.forms :as form]
|
||||||
[uxbox.ui.lightbox :as lightbox]
|
[uxbox.ui.lightbox :as lightbox]
|
||||||
[uxbox.ui.colorpicker :refer (colorpicker)]
|
[uxbox.ui.colorpicker :refer (colorpicker)]
|
||||||
[uxbox.ui.mixins :as mx]
|
[uxbox.ui.mixins :as mx]
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
[uxbox.library :as library]
|
[uxbox.library :as library]
|
||||||
[uxbox.data.dashboard :as dd]
|
[uxbox.data.dashboard :as dd]
|
||||||
[uxbox.ui.icons :as i]
|
[uxbox.ui.icons :as i]
|
||||||
[uxbox.ui.form :as form]
|
|
||||||
[uxbox.ui.shapes.core :as uusc]
|
[uxbox.ui.shapes.core :as uusc]
|
||||||
[uxbox.ui.lightbox :as lightbox]
|
[uxbox.ui.lightbox :as lightbox]
|
||||||
[uxbox.ui.mixins :as mx]
|
[uxbox.ui.mixins :as mx]
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
(ns uxbox.ui.form
|
|
||||||
(:require [sablono.core :refer-macros [html]]
|
|
||||||
[uxbox.schema :as sc]))
|
|
||||||
|
|
||||||
(defn validate!
|
|
||||||
[local schema]
|
|
||||||
(let [[errors data] (sc/validate (:form @local) schema)]
|
|
||||||
(if errors
|
|
||||||
(do
|
|
||||||
(swap! local assoc :errors errors)
|
|
||||||
nil)
|
|
||||||
(do
|
|
||||||
(swap! local assoc :errors nil)
|
|
||||||
data))))
|
|
||||||
|
|
||||||
(defn input-error
|
|
||||||
[local name]
|
|
||||||
(when-let [errors (get-in @local [:errors name])]
|
|
||||||
[:ul.form-errors
|
|
||||||
(for [error errors]
|
|
||||||
[:li {:key error} error])]))
|
|
||||||
|
|
||||||
(defn error-class
|
|
||||||
[local name]
|
|
||||||
(when (get-in @local [:errors name])
|
|
||||||
"invalid"))
|
|
16
src/uxbox/ui/forms.cljs
Normal file
16
src/uxbox/ui/forms.cljs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
(ns uxbox.ui.forms
|
||||||
|
(:require [sablono.core :refer-macros [html]]
|
||||||
|
[uxbox.schema :as sc]))
|
||||||
|
|
||||||
|
(defn input-error
|
||||||
|
[errors field]
|
||||||
|
(when-let [errors (get errors field)]
|
||||||
|
(html
|
||||||
|
[:ul.form-errors
|
||||||
|
(for [error errors]
|
||||||
|
[:li {:key error} error])])))
|
||||||
|
|
||||||
|
(defn error-class
|
||||||
|
[errors field]
|
||||||
|
(when (get errors field)
|
||||||
|
"invalid"))
|
|
@ -8,14 +8,17 @@
|
||||||
(ns uxbox.ui.settings.password
|
(ns uxbox.ui.settings.password
|
||||||
(:require [sablono.core :as html :refer-macros [html]]
|
(:require [sablono.core :as html :refer-macros [html]]
|
||||||
[rum.core :as rum]
|
[rum.core :as rum]
|
||||||
|
[lentes.core :as l]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[uxbox.schema :as sc]
|
[uxbox.schema :as sc]
|
||||||
|
[uxbox.state :as st]
|
||||||
[uxbox.locales :as t :refer (tr)]
|
[uxbox.locales :as t :refer (tr)]
|
||||||
[uxbox.router :as r]
|
[uxbox.router :as r]
|
||||||
[uxbox.rstore :as rs]
|
[uxbox.rstore :as rs]
|
||||||
[uxbox.data.users :as udu]
|
[uxbox.data.users :as udu]
|
||||||
|
[uxbox.data.forms :as udf]
|
||||||
[uxbox.ui.icons :as i]
|
[uxbox.ui.icons :as i]
|
||||||
[uxbox.ui.form :as form]
|
[uxbox.ui.forms :as forms]
|
||||||
[uxbox.ui.messages :as uum]
|
[uxbox.ui.messages :as uum]
|
||||||
[uxbox.ui.mixins :as mx]
|
[uxbox.ui.mixins :as mx]
|
||||||
[uxbox.ui.dashboard.header :refer (header)]
|
[uxbox.ui.dashboard.header :refer (header)]
|
||||||
|
@ -23,58 +26,52 @@
|
||||||
|
|
||||||
;; --- Password Form
|
;; --- Password Form
|
||||||
|
|
||||||
(def password-form-schema
|
(def formdata
|
||||||
[[:password-1 sc/required sc/string [sc/min-len 6]]
|
(-> (l/in [:forms :profile/password])
|
||||||
[:password-2 sc/required sc/string
|
(l/focus-atom st/state)))
|
||||||
[sc/identical-to :password-1 :message "errors.form.password-not-match"]]
|
|
||||||
[:old-password sc/required sc/string]])
|
|
||||||
|
|
||||||
(defn field-errors
|
(def formerrors
|
||||||
[errors field]
|
(-> (l/in [:errors :profile/password])
|
||||||
(when-let [errors (get errors field)]
|
(l/focus-atom st/state)))
|
||||||
(html
|
|
||||||
[:ul
|
(def assign-field-value
|
||||||
(for [error errors]
|
(partial udf/assign-field-value :profile/password))
|
||||||
[:li {:key error} error])])))
|
|
||||||
|
|
||||||
(defn password-form-render
|
(defn password-form-render
|
||||||
[own]
|
[own]
|
||||||
(let [local (:rum/local own)
|
(let [form (rum/react formdata)
|
||||||
form (:form @local)
|
errors (rum/react formerrors)
|
||||||
errors (:errors @local)
|
valid? (sc/valid? form udu/update-password-schema)]
|
||||||
valid? true #_(nil? invalid-reason)]
|
(println valid?)
|
||||||
(letfn [(on-field-change [field event]
|
(letfn [(on-field-change [field event]
|
||||||
(let [value (dom/event->value event)]
|
(let [value (dom/event->value event)]
|
||||||
(swap! local assoc-in [:form field] value)))
|
(rs/emit! (assign-field-value field value))))
|
||||||
(on-submit [event]
|
(on-submit [event]
|
||||||
(when-let [data (form/validate! local password-form-schema)]
|
(rs/emit! (udu/update-password form)))]
|
||||||
(let [params {:password (:password-1 form)
|
|
||||||
:old-password (:old-password form)}]
|
|
||||||
(rs/emit! (udu/update-password params)))))]
|
|
||||||
(html
|
(html
|
||||||
[:form.password-form
|
[:form.password-form
|
||||||
[:span.user-settings-label "Change password"]
|
[:span.user-settings-label "Change password"]
|
||||||
[:input.input-text
|
[:input.input-text
|
||||||
{:type "password"
|
{:type "password"
|
||||||
:class (form/error-class local :old-password)
|
:class (forms/error-class errors :old-password)
|
||||||
:value (:old-password form "")
|
:value (:old-password form "")
|
||||||
:on-change (partial on-field-change :old-password)
|
:on-change (partial on-field-change :old-password)
|
||||||
:placeholder "Old password"}]
|
:placeholder "Old password"}]
|
||||||
(form/input-error local :old-password)
|
(forms/input-error errors :old-password)
|
||||||
[:input.input-text
|
[:input.input-text
|
||||||
{:type "password"
|
{:type "password"
|
||||||
:class (form/error-class local :password-1)
|
:class (forms/error-class errors :password-1)
|
||||||
:value (:password-1 form "")
|
:value (:password-1 form "")
|
||||||
:on-change (partial on-field-change :password-1)
|
:on-change (partial on-field-change :password-1)
|
||||||
:placeholder "New password"}]
|
:placeholder "New password"}]
|
||||||
(form/input-error local :password-1)
|
(forms/input-error errors :password-1)
|
||||||
[:input.input-text
|
[:input.input-text
|
||||||
{:type "password"
|
{:type "password"
|
||||||
:class (form/error-class local :password-2)
|
:class (forms/error-class errors :password-2)
|
||||||
:value (:password-2 form "")
|
:value (:password-2 form "")
|
||||||
:on-change (partial on-field-change :password-2)
|
:on-change (partial on-field-change :password-2)
|
||||||
:placeholder "Confirm password"}]
|
:placeholder "Confirm password"}]
|
||||||
(form/input-error local :password-2)
|
(forms/input-error errors :password-2)
|
||||||
[:input.btn-primary
|
[:input.btn-primary
|
||||||
{:type "button"
|
{:type "button"
|
||||||
:class (when-not valid? "btn-disabled")
|
:class (when-not valid? "btn-disabled")
|
||||||
|
@ -86,7 +83,7 @@
|
||||||
(mx/component
|
(mx/component
|
||||||
{:render password-form-render
|
{:render password-form-render
|
||||||
:name "password-form"
|
:name "password-form"
|
||||||
:mixins [mx/static (mx/local)]}))
|
:mixins [mx/static (mx/local) rum/reactive]}))
|
||||||
|
|
||||||
;; --- Password Page
|
;; --- Password Page
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue