From e42b2ed7bf1ad8100ff3abd7774cfad9d4cd9afd Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 11 Apr 2016 23:40:40 +0300 Subject: [PATCH] Overhaul of form data and errors handling. --- src/uxbox/data/forms.cljs | 40 +++++++++++++++++++++ src/uxbox/data/users.cljs | 37 +++++++++++++++---- src/uxbox/schema.cljs | 13 +++---- src/uxbox/ui/dashboard/colors.cljs | 2 +- src/uxbox/ui/dashboard/icons.cljs | 1 - src/uxbox/ui/form.cljs | 26 -------------- src/uxbox/ui/forms.cljs | 16 +++++++++ src/uxbox/ui/settings/password.cljs | 55 ++++++++++++++--------------- 8 files changed, 118 insertions(+), 72 deletions(-) create mode 100644 src/uxbox/data/forms.cljs delete mode 100644 src/uxbox/ui/form.cljs create mode 100644 src/uxbox/ui/forms.cljs diff --git a/src/uxbox/data/forms.cljs b/src/uxbox/data/forms.cljs new file mode 100644 index 000000000..78d527f1c --- /dev/null +++ b/src/uxbox/data/forms.cljs @@ -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 + +(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)) + + diff --git a/src/uxbox/data/users.cljs b/src/uxbox/data/users.cljs index 595751202..b3ca6f604 100644 --- a/src/uxbox/data/users.cljs +++ b/src/uxbox/data/users.cljs @@ -12,6 +12,7 @@ [uxbox.state :as st] [uxbox.schema :as sc] [uxbox.locales :refer (tr)] + [uxbox.data.forms :as forms] [uxbox.ui.messages :as uum])) ;; --- Profile Fetched @@ -59,17 +60,41 @@ [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 -(defrecord UpdatePassword [old-password password] +(defrecord UpdatePassword [data] rs/WatchEvent (-apply-watch [_ state s] (letfn [(on-error [err] - (uum/error (tr "errors.profile.update-password")) + (uum/error (tr "errors.profile.update-password") {:timeout 3000}) (rx/empty))] - (->> (rp/req :update/password {:old-password old-password :password password}) - (rx/catch on-error))))) + (let [params {:old-password (:old-password data) + :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 - [{:keys [old-password password]}] - (UpdatePassword. old-password password)) + [data] + (let [[errors data] (sc/validate data update-password-schema)] + (println errors) + (if errors + (forms/assign-errors :profile/password errors) + (UpdatePassword. data)))) diff --git a/src/uxbox/schema.cljs b/src/uxbox/schema.cljs index ab2195d53..ef8d6f3b2 100644 --- a/src/uxbox/schema.cljs +++ b/src/uxbox/schema.cljs @@ -80,12 +80,7 @@ (when-let [errors (first (validate schema data))] (throw (ex-info "Invalid data" errors)))) -;; (defn valid? -;; [validator data] -;; (let [result (validator data)] -;; (if result -;; result -;; (let [message (:default-message-format (meta validator)) -;; message (str/format message data)] -;; (throw (ex-info message {})))))) - +(defn valid? + [data schema] + (let [[errors data] (validate data schema)] + (not errors))) diff --git a/src/uxbox/ui/dashboard/colors.cljs b/src/uxbox/ui/dashboard/colors.cljs index 5cb798bcd..7cde68edd 100644 --- a/src/uxbox/ui/dashboard/colors.cljs +++ b/src/uxbox/ui/dashboard/colors.cljs @@ -17,7 +17,7 @@ [uxbox.library :as library] [uxbox.data.dashboard :as dd] [uxbox.ui.icons :as i] - [uxbox.ui.form :as form] + [uxbox.ui.forms :as form] [uxbox.ui.lightbox :as lightbox] [uxbox.ui.colorpicker :refer (colorpicker)] [uxbox.ui.mixins :as mx] diff --git a/src/uxbox/ui/dashboard/icons.cljs b/src/uxbox/ui/dashboard/icons.cljs index 8aec7ccc7..b397cef28 100644 --- a/src/uxbox/ui/dashboard/icons.cljs +++ b/src/uxbox/ui/dashboard/icons.cljs @@ -15,7 +15,6 @@ [uxbox.library :as library] [uxbox.data.dashboard :as dd] [uxbox.ui.icons :as i] - [uxbox.ui.form :as form] [uxbox.ui.shapes.core :as uusc] [uxbox.ui.lightbox :as lightbox] [uxbox.ui.mixins :as mx] diff --git a/src/uxbox/ui/form.cljs b/src/uxbox/ui/form.cljs deleted file mode 100644 index b517fe094..000000000 --- a/src/uxbox/ui/form.cljs +++ /dev/null @@ -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")) diff --git a/src/uxbox/ui/forms.cljs b/src/uxbox/ui/forms.cljs new file mode 100644 index 000000000..78ec63fc8 --- /dev/null +++ b/src/uxbox/ui/forms.cljs @@ -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")) diff --git a/src/uxbox/ui/settings/password.cljs b/src/uxbox/ui/settings/password.cljs index 625bddb7a..57b786eac 100644 --- a/src/uxbox/ui/settings/password.cljs +++ b/src/uxbox/ui/settings/password.cljs @@ -8,14 +8,17 @@ (ns uxbox.ui.settings.password (:require [sablono.core :as html :refer-macros [html]] [rum.core :as rum] + [lentes.core :as l] [cuerdas.core :as str] [uxbox.schema :as sc] + [uxbox.state :as st] [uxbox.locales :as t :refer (tr)] [uxbox.router :as r] [uxbox.rstore :as rs] [uxbox.data.users :as udu] + [uxbox.data.forms :as udf] [uxbox.ui.icons :as i] - [uxbox.ui.form :as form] + [uxbox.ui.forms :as forms] [uxbox.ui.messages :as uum] [uxbox.ui.mixins :as mx] [uxbox.ui.dashboard.header :refer (header)] @@ -23,58 +26,52 @@ ;; --- Password Form -(def password-form-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]]) +(def formdata + (-> (l/in [:forms :profile/password]) + (l/focus-atom st/state))) -(defn field-errors - [errors field] - (when-let [errors (get errors field)] - (html - [:ul - (for [error errors] - [:li {:key error} error])]))) +(def formerrors + (-> (l/in [:errors :profile/password]) + (l/focus-atom st/state))) + +(def assign-field-value + (partial udf/assign-field-value :profile/password)) (defn password-form-render [own] - (let [local (:rum/local own) - form (:form @local) - errors (:errors @local) - valid? true #_(nil? invalid-reason)] + (let [form (rum/react formdata) + errors (rum/react formerrors) + valid? (sc/valid? form udu/update-password-schema)] + (println valid?) (letfn [(on-field-change [field event] (let [value (dom/event->value event)] - (swap! local assoc-in [:form field] value))) + (rs/emit! (assign-field-value field value)))) (on-submit [event] - (when-let [data (form/validate! local password-form-schema)] - (let [params {:password (:password-1 form) - :old-password (:old-password form)}] - (rs/emit! (udu/update-password params)))))] + (rs/emit! (udu/update-password form)))] (html [:form.password-form [:span.user-settings-label "Change password"] [:input.input-text {:type "password" - :class (form/error-class local :old-password) + :class (forms/error-class errors :old-password) :value (:old-password form "") :on-change (partial on-field-change :old-password) :placeholder "Old password"}] - (form/input-error local :old-password) + (forms/input-error errors :old-password) [:input.input-text {:type "password" - :class (form/error-class local :password-1) + :class (forms/error-class errors :password-1) :value (:password-1 form "") :on-change (partial on-field-change :password-1) :placeholder "New password"}] - (form/input-error local :password-1) + (forms/input-error errors :password-1) [:input.input-text {:type "password" - :class (form/error-class local :password-2) + :class (forms/error-class errors :password-2) :value (:password-2 form "") :on-change (partial on-field-change :password-2) :placeholder "Confirm password"}] - (form/input-error local :password-2) + (forms/input-error errors :password-2) [:input.btn-primary {:type "button" :class (when-not valid? "btn-disabled") @@ -86,7 +83,7 @@ (mx/component {:render password-form-render :name "password-form" - :mixins [mx/static (mx/local)]})) + :mixins [mx/static (mx/local) rum/reactive]})) ;; --- Password Page