0
Fork 0
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:
Andrey Antukh 2016-04-11 23:40:40 +03:00
parent e509daaeef
commit e42b2ed7bf
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
8 changed files with 118 additions and 72 deletions

40
src/uxbox/data/forms.cljs Normal file
View 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))

View file

@ -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))))

View file

@ -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 {}))))))

View file

@ -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]

View file

@ -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]

View file

@ -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
View 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"))

View file

@ -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