🚧 More work on better forms and data validation.

This commit is contained in:
Andrey Antukh 2019-09-02 20:49:48 +02:00
parent 04a5038ff4
commit 689cc5f3e7
21 changed files with 641 additions and 618 deletions

View file

@ -7,10 +7,10 @@
(ns uxbox.main.ui.auth
(:require [uxbox.main.ui.auth.login :as login]
[uxbox.main.ui.auth.register :as register]
[uxbox.main.ui.auth.recovery-request :as recovery-request]
[uxbox.main.ui.auth.recovery :as recovery]))
#_[uxbox.main.ui.auth.recovery-request :as recovery-request]
#_[uxbox.main.ui.auth.recovery :as recovery]))
(def login-page login/login-page)
(def register-page register/register-page)
(def recovery-page recovery/recovery-page)
(def recovery-request-page recovery-request/recovery-request-page)
;; (def recovery-page recovery/recovery-page)
;; (def recovery-request-page recovery-request/recovery-request-page)

View file

@ -8,7 +8,7 @@
(ns uxbox.main.ui.auth.login
(:require
[rumext.alpha :as mf]
[struct.core :as s]
[struct.alpha :as s]
[uxbox.builtins.icons :as i]
[uxbox.config :as cfg]
[uxbox.main.data.auth :as da]
@ -19,9 +19,9 @@
[uxbox.util.i18n :refer [tr]]
[uxbox.util.router :as rt]))
(s/defs login-form-spec
{:username [fm/required fm/string]
:password [fm/required fm/string]})
(s/defs ::login-form
(s/dict :username (s/&& ::s/string ::fm/not-empty-string)
:password (s/&& ::s/string ::fm/not-empty-string)))
(defn- on-submit
[event form]
@ -42,7 +42,7 @@
(mf/defc login-form
[]
(let [{:keys [data] :as form} (fm/use-form {:initial {} :spec login-form-spec})]
(let [{:keys [data] :as form} (fm/use-form ::login-form {})]
[:form {:on-submit #(on-submit % form)}
[:div.login-content
(when cfg/isdemo
@ -84,6 +84,6 @@
[]
[:div.login
[:div.login-body
(messages-widget)
[:& messages-widget]
[:a i/logo]
[:& login-form]]])

View file

@ -21,62 +21,62 @@
[uxbox.util.i18n :refer (tr)]
[uxbox.util.router :as rt]))
(def form-data (fm/focus-data :recovery st/state))
(def form-errors (fm/focus-errors :recovery st/state))
;; (def form-data (fm/focus-data :recovery st/state))
;; (def form-errors (fm/focus-errors :recovery st/state))
(def assoc-value (partial fm/assoc-value :recovery))
(def assoc-errors (partial fm/assoc-errors :recovery))
(def clear-form (partial fm/clear-form :recovery))
;; (def assoc-value (partial fm/assoc-value :recovery))
;; (def assoc-errors (partial fm/assoc-errors :recovery))
;; (def clear-form (partial fm/clear-form :recovery))
;; --- Recovery Form
;; ;; --- Recovery Form
(s/def ::password ::fm/non-empty-string)
(s/def ::recovery-form
(s/keys :req-un [::password]))
;; (s/def ::password ::fm/non-empty-string)
;; (s/def ::recovery-form
;; (s/keys :req-un [::password]))
(mx/defc recovery-form
{:mixins [mx/static mx/reactive]}
[token]
(let [data (merge (mx/react form-data) {:token token})
valid? (fm/valid? ::recovery-form data)]
(letfn [(on-change [field event]
(let [value (dom/event->value event)]
(st/emit! (assoc-value field value))))
(on-submit [event]
(dom/prevent-default event)
(st/emit! (uda/recovery data)
(clear-form)))]
[:form {:on-submit on-submit}
[:div.login-content
[:input.input-text
{:name "password"
:value (:password data "")
:on-change (partial on-change :password)
:placeholder (tr "recover.password.placeholder")
:type "password"}]
[:input.btn-primary
{:name "login"
:class (when-not valid? "btn-disabled")
:disabled (not valid?)
:value (tr "recover.recover-password")
:type "submit"}]
[:div.login-links
[:a {:on-click #(st/emit! (rt/navigate :auth/login))} (tr "recover.go-back")]]]])))
;; (mx/defc recovery-form
;; {:mixins [mx/static mx/reactive]}
;; [token]
;; (let [data (merge (mx/react form-data) {:token token})
;; valid? (fm/valid? ::recovery-form data)]
;; (letfn [(on-change [field event]
;; (let [value (dom/event->value event)]
;; (st/emit! (assoc-value field value))))
;; (on-submit [event]
;; (dom/prevent-default event)
;; (st/emit! (uda/recovery data)
;; (clear-form)))]
;; [:form {:on-submit on-submit}
;; [:div.login-content
;; [:input.input-text
;; {:name "password"
;; :value (:password data "")
;; :on-change (partial on-change :password)
;; :placeholder (tr "recover.password.placeholder")
;; :type "password"}]
;; [:input.btn-primary
;; {:name "login"
;; :class (when-not valid? "btn-disabled")
;; :disabled (not valid?)
;; :value (tr "recover.recover-password")
;; :type "submit"}]
;; [:div.login-links
;; [:a {:on-click #(st/emit! (rt/navigate :auth/login))} (tr "recover.go-back")]]]])))
;; --- Recovery Page
;; ;; --- Recovery Page
(defn- recovery-page-init
[own]
(let [[token] (::mx/args own)]
(st/emit! (uda/validate-recovery-token token))
own))
;; (defn- recovery-page-init
;; [own]
;; (let [[token] (::mx/args own)]
;; (st/emit! (uda/validate-recovery-token token))
;; own))
(mx/defc recovery-page
{:mixins [mx/static (fm/clear-mixin st/store :recovery)]
:init recovery-page-init}
[token]
[:div.login
[:div.login-body
(messages-widget)
[:a i/logo]
(recovery-form token)]])
;; (mx/defc recovery-page
;; {:mixins [mx/static (fm/clear-mixin st/store :recovery)]
;; :init recovery-page-init}
;; [token]
;; [:div.login
;; [:div.login-body
;; (messages-widget)
;; [:a i/logo]
;; (recovery-form token)]])

View file

@ -20,52 +20,52 @@
[rumext.core :as mx :include-macros true]
[uxbox.util.router :as rt]))
(def form-data (fm/focus-data :recovery-request st/state))
(def form-errors (fm/focus-errors :recovery-request st/state))
;; (def form-data (fm/focus-data :recovery-request st/state))
;; (def form-errors (fm/focus-errors :recovery-request st/state))
(def assoc-value (partial fm/assoc-value :profile-password))
(def assoc-errors (partial fm/assoc-errors :profile-password))
(def clear-form (partial fm/clear-form :profile-password))
;; (def assoc-value (partial fm/assoc-value :profile-password))
;; (def assoc-errors (partial fm/assoc-errors :profile-password))
;; (def clear-form (partial fm/clear-form :profile-password))
(s/def ::username ::fm/non-empty-string)
(s/def ::recovery-request-form (s/keys :req-un [::username]))
;; (s/def ::username ::fm/non-empty-string)
;; (s/def ::recovery-request-form (s/keys :req-un [::username]))
(mx/defc recovery-request-form
{:mixins [mx/static mx/reactive]}
[]
(let [data (mx/react form-data)
valid? (fm/valid? ::recovery-request-form data)]
(letfn [(on-change [event]
(let [value (dom/event->value event)]
(st/emit! (assoc-value :username value))))
(on-submit [event]
(dom/prevent-default event)
(st/emit! (uda/recovery-request data)
(clear-form)))]
[:form {:on-submit on-submit}
[:div.login-content
[:input.input-text
{:name "username"
:value (:username data "")
:on-change on-change
:placeholder (tr "recovery-request.username-or-email.placeholder")
:type "text"}]
[:input.btn-primary
{:name "login"
:class (when-not valid? "btn-disabled")
:disabled (not valid?)
:value (tr "recovery-request.recover-password")
:type "submit"}]
[:div.login-links
[:a {:on-click #(st/emit! (rt/navigate :auth/login))} (tr "recovery-request.go-back")]]]])))
;; (mx/defc recovery-request-form
;; {:mixins [mx/static mx/reactive]}
;; []
;; (let [data (mx/react form-data)
;; valid? (fm/valid? ::recovery-request-form data)]
;; (letfn [(on-change [event]
;; (let [value (dom/event->value event)]
;; (st/emit! (assoc-value :username value))))
;; (on-submit [event]
;; (dom/prevent-default event)
;; (st/emit! (uda/recovery-request data)
;; (clear-form)))]
;; [:form {:on-submit on-submit}
;; [:div.login-content
;; [:input.input-text
;; {:name "username"
;; :value (:username data "")
;; :on-change on-change
;; :placeholder (tr "recovery-request.username-or-email.placeholder")
;; :type "text"}]
;; [:input.btn-primary
;; {:name "login"
;; :class (when-not valid? "btn-disabled")
;; :disabled (not valid?)
;; :value (tr "recovery-request.recover-password")
;; :type "submit"}]
;; [:div.login-links
;; [:a {:on-click #(st/emit! (rt/navigate :auth/login))} (tr "recovery-request.go-back")]]]])))
;; --- Recovery Request Page
;; ;; --- Recovery Request Page
(mx/defc recovery-request-page
{:mixins [mx/static (fm/clear-mixin st/store :recovery-request)]}
[]
[:div.login
[:div.login-body
(messages-widget)
[:a i/logo]
(recovery-request-form)]])
;; (mx/defc recovery-request-page
;; {:mixins [mx/static (fm/clear-mixin st/store :recovery-request)]}
;; []
;; [:div.login
;; [:div.login-body
;; (messages-widget)
;; [:a i/logo]
;; (recovery-request-form)]])

View file

@ -6,118 +6,131 @@
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.auth.register
(:require [cljs.spec.alpha :as s :include-macros true]
[lentes.core :as l]
[cuerdas.core :as str]
[uxbox.builtins.icons :as i]
[uxbox.main.store :as st]
[uxbox.main.data.auth :as uda]
[uxbox.main.ui.messages :refer [messages-widget]]
[uxbox.main.ui.navigation :as nav]
[uxbox.util.i18n :refer (tr)]
[uxbox.util.dom :as dom]
[uxbox.util.forms :as fm]
[rumext.core :as mx :include-macros true]
[uxbox.util.router :as rt]))
(:require
[cuerdas.core :as str]
[lentes.core :as l]
[rumext.alpha :as mf]
[struct.alpha :as s]
[uxbox.builtins.icons :as i]
[uxbox.main.data.auth :as uda]
[uxbox.main.store :as st]
[uxbox.main.ui.messages :refer [messages-widget]]
[uxbox.main.ui.navigation :as nav]
[uxbox.util.dom :as dom]
[uxbox.util.forms :as fm]
[uxbox.util.i18n :refer [tr]]
[uxbox.util.router :as rt]))
(def form-data (fm/focus-data :register st/state))
(def form-errors (fm/focus-errors :register st/state))
(s/defs ::register-form
(s/dict :username (s/&& ::s/string ::fm/not-empty-string)
:fullname (s/&& ::s/string ::fm/not-empty-string)
:password (s/&& ::s/string ::fm/not-empty-string)
:email ::s/email))
(def assoc-value (partial fm/assoc-value :register))
(def assoc-error (partial fm/assoc-error :register))
(def clear-form (partial fm/clear-form :register))
(defn- on-error
[error form]
(case (:code error)
:uxbox.services.users/registration-disabled
(st/emit! (tr "errors.api.form.registration-disabled"))
;; TODO: add better password validation
:uxbox.services.users/email-already-exists
(swap! form assoc-in [:errors :email]
{:type ::api
:message "errors.api.form.email-already-exists"})
(s/def ::username ::fm/non-empty-string)
(s/def ::fullname ::fm/non-empty-string)
(s/def ::password ::fm/non-empty-string)
(s/def ::email ::fm/email)
:uxbox.services.users/username-already-exists
(swap! form assoc-in [:errors :username]
{:type ::api
:message "errors.api.form.username-already-exists"})))
(s/def ::register-form
(s/keys :req-un [::username
::fullname
::email
::password]))
(defn- on-submit
[event form]
(dom/prevent-default event)
(let [data (:clean-data form)
on-error #(on-error % form)]
(st/emit! (uda/register data on-error))))
(mx/defc register-form
{:mixins [mx/static mx/reactive
(fm/clear-mixin st/store :register)]}
[]
(let [data (mx/react form-data)
errors (mx/react form-errors)
valid? (fm/valid? ::register-form data)]
(letfn [(on-change [field event]
(let [value (dom/event->value event)]
(st/emit! (assoc-value field value))))
(on-error [{:keys [type code] :as payload}]
(case code
:uxbox.services.users/registration-disabled
(st/emit! (tr "errors.api.form.registration-disabled"))
:uxbox.services.users/email-already-exists
(st/emit! (assoc-error :email (tr "errors.api.form.email-already-exists")))
:uxbox.services.users/username-already-exists
(st/emit! (assoc-error :username (tr "errors.api.form.username-already-exists")))))
(on-submit [event]
(dom/prevent-default event)
(st/emit! (uda/register data on-error)))]
[:form {:on-submit on-submit}
[:div.login-content
[:input.input-text
{:name "fullname"
:tab-index "2"
:value (:fullname data "")
:on-change (partial on-change :fullname)
:placeholder (tr "register.fullname.placeholder")
:type "text"}]
(fm/input-error errors :fullname)
(mf/defc register-form
[props]
(let [{:keys [data] :as form} (fm/use-form ::register-form {})]
(prn "register-form" form)
[:form {:on-submit #(on-submit % form)}
[:div.login-content
[:input.input-text
{:name "fullname"
:tab-index "1"
:value (:fullname data "")
:class (fm/error-class form :fullname)
:on-blur (fm/on-input-blur form :fullname)
:on-change (fm/on-input-change form :fullname)
:placeholder (tr "register.fullname.placeholder")
:type "text"}]
[:input.input-text
{:name "username"
:tab-index "3"
:value (:username data "")
:on-change (partial on-change :username)
:placeholder (tr "register.username.placeholder")
:type "text"}]
(fm/input-error errors :username)
[:& fm/field-error {:form form
:type #{::api}
:field :fullname}]
[:input.input-text
{:name "email"
:tab-index "4"
:ref "email"
:value (:email data "")
:on-change (partial on-change :email)
:placeholder (tr "register.email.placeholder")
:type "text"}]
(fm/input-error errors :email)
[:input.input-text
{:type "text"
:name "username"
:tab-index "2"
:class (fm/error-class form :username)
:on-blur (fm/on-input-blur form :username)
:on-change (fm/on-input-change form :username)
:value (:username data "")
:placeholder (tr "settings.profile.your-username")}]
[:input.input-text
{:name "password"
:tab-index "5"
:ref "password"
:value (:password data "")
:on-change (partial on-change :password)
:placeholder (tr "register.password.placeholder")
:type "password"}]
(fm/input-error errors :password)
[:& fm/field-error {:form form
:type #{::api}
:field :username}]
[:input.btn-primary
{:name "login"
:tab-index "6"
:class (when-not valid? "btn-disabled")
:disabled (not valid?)
:value (tr "register.get-started")
:type "submit"}]
[:div.login-links
[:a {:on-click #(st/emit! (rt/navigate :auth/login))} (tr "register.already-have-account")]]]])))
[:input.input-text
{:type "email"
:name "email"
:tab-index "3"
:class (fm/error-class form :email)
:on-blur (fm/on-input-blur form :email)
:on-change (fm/on-input-change form :email)
:value (:email data "")
:placeholder (tr "settings.profile.your-email")}]
[:& fm/field-error {:form form
:type #{::api}
:field :email}]
[:input.input-text
{:name "password"
:tab-index "4"
:value (:password data "")
:class (fm/error-class form :password)
:on-blur (fm/on-input-blur form :password)
:on-change (fm/on-input-change form :password)
:placeholder (tr "register.password.placeholder")
:type "password"}]
[:& fm/field-error {:form form
:type #{::api}
:field :email}]
[:input.btn-primary
{:type "submit"
:tab-index "5"
:class (when-not (:valid form) "btn-disabled")
:disabled (not (:valid form))
:value (tr "register.get-started")}]
[:div.login-links
[:a {:on-click #(st/emit! (rt/nav :auth/login))}
(tr "register.already-have-account")]]]]))
;; --- Register Page
(mx/defc register-page
{:mixins [mx/static]}
[own]
(mf/defc register-page
[props]
[:div.login
[:div.login-body
(messages-widget)
[:a i/logo]
(register-form)]])
[:& register-form]]])

View file

@ -25,7 +25,7 @@
[{:keys [route] :as props}]
(let [[section type id] (parse-route route)]
[:main.dashboard-main
(messages-widget)
[:& messages-widget]
[:& header {:section section}]
(case section
:dashboard/icons

View file

@ -40,7 +40,6 @@
(-> (l/key :projects)
(l/derive st/state)))
;; --- Helpers
(defn sort-projects-by

View file

@ -7,7 +7,7 @@
(ns uxbox.main.ui.dashboard.projects-forms
(:require
[cljs.spec.alpha :as s]
[struct.alpha :as s]
[rumext.alpha :as mf]
[uxbox.builtins.icons :as i]
[uxbox.main.data.projects :as udp]
@ -17,10 +17,10 @@
[uxbox.util.forms :as fm]
[uxbox.util.i18n :as t :refer [tr]]))
(def project-form-spec
{:name [fm/required fm/string]
:width [fm/required fm/number-str]
:height [fm/required fm/number-str]})
(s/defs ::project-form
(s/dict :name (s/&& ::s/string ::fm/not-empty-string)
:width ::s/number-str
:height ::s/number-str))
(def defaults
{:name ""
@ -44,13 +44,14 @@
(mf/defc create-project-form
[props]
(let [{:keys [data errors] :as form} (fm/use-form {:initial defaults :spec project-form-spec})]
(let [{:keys [data] :as form} (fm/use-form ::project-form defaults)]
[:form {:on-submit #(on-submit % form)}
[:input.input-text
{:placeholder "New project name"
:type "text"
:name "name"
:value (:name data)
:class (fm/error-class form :name)
:on-blur (fm/on-input-blur form :name)
:on-change (fm/on-input-change form :name)
:auto-focus true}]
@ -63,6 +64,7 @@
:type "number"
:min 0
:max 5000
:class (fm/error-class form :width)
:on-blur (fm/on-input-blur form :width)
:on-change (fm/on-input-change form :width)
:value (:width data)}]]
@ -75,6 +77,7 @@
:name "height"
:min 0
:max 5000
:class (fm/error-class form :height)
:on-blur (fm/on-input-blur form :height)
:on-change (fm/on-input-change form :height)
:value (:height data)}]]]

View file

@ -1,16 +1,17 @@
(ns uxbox.main.ui.messages
(:require [lentes.core :as l]
[uxbox.main.store :as st]
[uxbox.util.messages :as uum]
[rumext.core :as mx :include-macros true]))
(:require
[lentes.core :as l]
[rumext.alpha :as mf]
[uxbox.main.store :as st]
[uxbox.util.messages :as um]))
(def ^:private message-ref
(def ^:private message-iref
(-> (l/key :message)
(l/derive st/state)))
(mx/defc messages-widget
{:mixins [mx/static mx/reactive]}
(mf/defc messages-widget
[]
(let [message (mx/react message-ref)
on-close #(st/emit! (uum/hide))]
(uum/messages-widget (assoc message :on-close on-close))))
(let [message (mf/deref message-iref)
on-close #(st/emit! (um/hide))]
[:& um/messages-widget {:message message
:on-close on-close}]))

View file

@ -22,7 +22,7 @@
[{:keys [route] :as props}]
(let [section (get-in route [:data :name])]
[:main.dashboard-main
(messages-widget)
[:& messages-widget]
[:& header {:section section}]
(case section
:settings/profile (mf/element profile/profile-page)

View file

@ -8,7 +8,7 @@
(ns uxbox.main.ui.settings.password
(:require
[rumext.alpha :as mf]
[struct.core :as s]
[struct.alpha :as s]
[uxbox.builtins.icons :as i]
[uxbox.main.data.users :as udu]
[uxbox.main.store :as st]
@ -36,14 +36,14 @@
:on-error on-error}]
(st/emit! (udu/update-password data opts)))))
(s/defs password-form-spec
{:password-1 [s/required s/string]
:password-2 [s/required s/string [s/identical-to :password-1]]
:password-old [s/required s/string]})
(s/defs ::password-form
(s/dict :password-1 (s/&& ::s/string ::fm/not-empty-string)
:password-2 (s/&& ::s/string ::fm/not-empty-string)
:password-old (s/&& ::s/string ::fm/not-empty-string)))
(mf/defc password-form
[props]
(let [{:keys [data] :as form} (fm/use-form {:initial {} :spec password-form-spec})]
(let [{:keys [data] :as form} (fm/use-form ::password-form {})]
[:form.password-form {:on-submit #(on-submit % form)}
[:span.user-settings-label (tr "settings.password.change-password")]
[:input.input-text

View file

@ -10,7 +10,7 @@
[cuerdas.core :as str]
[lentes.core :as l]
[rumext.alpha :as mf]
[struct.core :as s]
[struct.alpha :as s]
[uxbox.builtins.icons :as i]
[uxbox.main.data.users :as udu]
[uxbox.main.store :as st]
@ -18,27 +18,28 @@
[uxbox.util.dom :as dom]
[uxbox.util.forms :as fm]
[uxbox.util.i18n :as i18n :refer [tr]]
[uxbox.util.interop :refer [iterable->seq]]))
[uxbox.util.interop :refer [iterable->seq]]
[uxbox.util.messages :as um]))
(defn profile->form
(defn- profile->form
[profile]
(let [language (get-in profile [:metadata :language])]
(-> (select-keys profile [:fullname :username :email])
(cond-> language (assoc :language language)))))
(def profile-ref
(def ^:private profile-ref
(-> (l/key :profile)
(l/derive st/state)))
(s/defs profile-form-spec
{:fullname [fm/required fm/string]
:username [fm/required fm/string]
:email [fm/required fm/email]
:language [fm/required fm/string]})
(s/defs ::profile-form
(s/dict :fullname (s/&& ::s/string ::fm/not-empty-string)
:username (s/&& ::s/string ::fm/not-empty-string)
:language (s/&& ::s/string ::fm/not-empty-string)
:email ::s/email))
(defn- on-error
[error form]
(prn "on-error" error form)
(case (:code error)
:uxbox.services.users/email-already-exists
(swap! form assoc-in [:errors :email]
@ -57,18 +58,20 @@
(defn- on-submit
[event form]
(prn "on-submit" form)
(dom/prevent-default event)
(let [data (:clean-data form)
opts {:on-success #(prn "On Success" %)
:on-error #(on-error % form)}]
on-success #(st/emit! (um/info (tr "settings.profile.profile-saved")))
on-error #(on-error % form)
opts {:on-success on-success
:on-error on-error}]
(st/emit! (udu/update-profile data opts))))
;; --- Profile Form
(mf/defc profile-form
[props]
(let [{:keys [data] :as form} (fm/use-form {:initial initial-data
:spec profile-form-spec})]
(prn "profile-form" form)
(let [{:keys [data] :as form} (fm/use-form ::profile-form initial-data)]
[:form.profile-form {:on-submit #(on-submit % form)}
[:span.user-settings-label (tr "settings.profile.section-basic-data")]
[:input.input-text

View file

@ -38,7 +38,7 @@
[:li {:on-click #(on-click % :settings/notifications)}
i/mail
[:span (tr "ds.user.notifications")]]
[:li {:on-click #(on-click % (da/logout))}
[:li {:on-click #(on-click % da/logout)}
i/exit
[:span (tr "ds.user.exit")]]]))

View file

@ -9,7 +9,6 @@
(:require
[beicon.core :as rx]
[lentes.core :as l]
[rumext.core :as mx]
[rumext.alpha :as mf]
[uxbox.main.constants :as c]
[uxbox.main.data.history :as udh]
@ -86,7 +85,7 @@
(mf/use-effect #(subscribe canvas page)
#js [(:id page)])
[:*
(messages-widget)
[:& messages-widget]
[:& header {:page page
:flags flags
:key (:id page)}]

View file

@ -2,12 +2,13 @@
;; 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) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
;; Copyright (c) 2015-2019 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2019 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.workspace.sidebar.sitemap-forms
(:require
[rumext.alpha :as mf]
[struct.alpha :as s]
[uxbox.builtins.icons :as i]
[uxbox.main.constants :as c]
[uxbox.main.data.pages :as udp]
@ -17,12 +18,12 @@
[uxbox.util.forms :as fm]
[uxbox.util.i18n :refer [tr]]))
(def page-form-spec
{:id [fm/uuid]
:project [fm/uuid]
:name [fm/required fm/string]
:width [fm/required fm/number-str]
:height [fm/required fm/number-str]})
(s/defs ::page-form
(s/dict :id (s/opt ::s/uuid)
:project ::s/uuid
:name (s/&& ::s/string ::fm/not-empty-string)
:width ::s/number-str
:height ::s/number-str))
(def defaults
{:name ""
@ -52,13 +53,13 @@
(mf/defc page-form
[{:keys [page] :as props}]
(let [{:keys [data errors] :as form} (fm/use-form {:initial #(initial-data page)
:spec page-form-spec})]
(let [{:keys [data] :as form} (fm/use-form ::page-form #(initial-data page))]
[:form {:on-submit #(on-submit % form)}
[:input.input-text
{:placeholder "Page name"
:type "text"
:name "name"
:class (fm/error-class form :name)
:on-blur (fm/on-input-blur form :name)
:on-change (fm/on-input-change form :name)
:value (:name data)
@ -72,6 +73,7 @@
:type "number"
:min 0
:max 5000
:class (fm/error-class form :width)
:on-blur (fm/on-input-blur form :width)
:on-change (fm/on-input-change form :width)
:value (:width data)}]]
@ -84,12 +86,14 @@
:type "number"
:min 0
:max 5000
:class (fm/error-class form :height)
:on-blur (fm/on-input-blur form :height)
:on-change (fm/on-input-change form :height)
:value (:height data)}]]]
[:input.btn-primary
{:value "Go go go!"
:type "submit"
:class (when-not (:valid form) "btn-disabled")
:disabled (not (:valid form))}]]))
(mf/defc page-form-dialog