(ns auto-ap.forms (:require [re-frame.core :as re-frame] [auto-ap.views.utils :refer [dispatch-event bind-field]])) (re-frame/reg-sub ::form (fn [db [_ x]] (-> db ::forms x))) (re-frame/reg-sub ::is-loading? (fn [db [_ x]] (if (#{"loading" :loading} (get-in db [::forms x :status]) ) true false))) (re-frame/reg-sub ::loading-class (fn [db [_ x]] (if (#{"loading" :loading} (get-in db [::forms x :status]) ) "is-loading" ""))) (defn start-form [db form data] (assoc-in db [::forms form] {:error nil :active? true :id (random-uuid) :status nil :data data})) (defn saved-form [db form data] (update-in db [::forms form] assoc :error nil :status nil :data data)) (defn stop-form [db form] (update db ::forms dissoc form)) (re-frame/reg-event-db ::form-closing (fn [db [_ f]] (-> db (stop-form f)))) (defn in-form [form-name] (re-frame/path [::forms form-name])) (re-frame/reg-event-db ::change (fn [db [_ form & path-pairs]] (println "CHANGING" path-pairs) (reduce (fn [db [path value]] (assoc-in db (into [::forms form :data] path) value)) db (partition 2 path-pairs)))) (defn change-handler [form customize-fn] (fn [db [_ & path-pairs]] (reduce (fn [db [path value]] (let [updated (assoc-in db (into [::forms form :data] path) value)] (reduce (fn [updated [path value ]] (assoc-in updated (into [::forms form :data] path) value)) updated (partition 2 (customize-fn (get-in updated [::forms form :data]) path value))))) db (partition 2 path-pairs)))) (re-frame/reg-event-db ::save-error (fn [db [_ form result]] (-> db (assoc-in [::forms form :status] :error) (assoc-in [::forms form :error] (or (:message (first result)) result))))) (defn ^:deprecated side-bar-form [{:keys [form]} children] [:div [:a.delete.is-pulled-right {:on-click (dispatch-event [::form-closing form])}] [:div children]]) (defn loading [db id] (-> db (assoc-in [::forms id :status] :loading) (assoc-in [::forms id :error] nil))) (defn triggers-loading [form] (re-frame/enrich (fn [db event] (loading db form)))) (defn triggers-stop [form] (re-frame/enrich (fn [db event] (stop-form db form)))) (defn triggers-stop-loading [form] (re-frame/enrich (fn [db event] (assoc-in db [::forms form :status] nil)))) (defn save-succeeded [db id] (-> db (assoc-in [::forms id :status] nil) (assoc-in [::forms id :error] nil))) (defn vertical-form [{:keys [can-submit id change-event submit-event ]}] {:form (fn [{:keys [title] :as params} & children] (let [{:keys [data active? error]} @(re-frame/subscribe [::form id]) can-submit @(re-frame/subscribe can-submit)] (into ^{:key id} [:form { :on-submit (fn [e] (when (.-stopPropagation e) (.stopPropagation e) (.preventDefault e)) (when can-submit (re-frame/dispatch-sync (vec (conj submit-event params)))))} [:h1.title.is-2 title]] children))) :raw-field (fn [control] (let [{:keys [data]} @(re-frame/subscribe [::form id])] [bind-field (-> control (assoc-in [1 :subscription] data) (assoc-in [1 :event] change-event))])) :field (fn [label control] (let [{:keys [data]} @(re-frame/subscribe [::form id])] [:div.field (when label [:p.help label]) [:div.control [bind-field (-> control (assoc-in [1 :subscription] data) (assoc-in [1 :event] change-event))]]])) :error-notification (fn [] (when-let [error (:error @(re-frame/subscribe [::form id]))] ^{:key error} [:div.notification.is-warning.animated.fadeInUp error])) :submit-button (fn [child] (let [error (:error @(re-frame/subscribe [::form id]))] [:button.button.is-medium.is-primary.is-fullwidth {:disabled (if @(re-frame/subscribe can-submit) "" "disabled") :class (str @(re-frame/subscribe [::loading-class id]) (when error " animated shake"))} child]))})