revamping form.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
{:main auto-ap.core
|
{:main auto-ap.core
|
||||||
:output-to "resources/public/js/compiled/app.js"
|
:output-to "resources/public/js/compiled/app.js"
|
||||||
|
:parallel-build true
|
||||||
|
|
||||||
:optimizations :advanced
|
:optimizations :advanced
|
||||||
:closure-defines {goog.DEBUG false}
|
:closure-defines {goog.DEBUG false}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
(ns auto-ap.views.components.expense-accounts-field
|
(ns auto-ap.views.components.expense-accounts-field
|
||||||
(:require [auto-ap.forms :as forms]
|
(:require [auto-ap.forms :as forms]
|
||||||
[auto-ap.subs :as subs]
|
[auto-ap.subs :as subs]
|
||||||
[auto-ap.views.components.typeahead :refer [typeahead]]
|
[auto-ap.views.components.typeahead :refer [typeahead typeahead-entity]]
|
||||||
[auto-ap.views.utils :refer [bind-field dispatch-event ->$]]
|
[auto-ap.views.utils :refer [bind-field dispatch-event ->$]]
|
||||||
[goog.string :as gstring]
|
[goog.string :as gstring]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
@@ -13,7 +13,9 @@
|
|||||||
(not (get-in accounts [0 :account :id]))))
|
(not (get-in accounts [0 :account :id]))))
|
||||||
|
|
||||||
(defn default-account [accounts default-account amount]
|
(defn default-account [accounts default-account amount]
|
||||||
[{:id (str "new-" (random-uuid))
|
[{:id (doto (get-in accounts [0 :id]
|
||||||
|
(str "new-" (random-uuid)))
|
||||||
|
println)
|
||||||
:amount (Math/abs amount)
|
:amount (Math/abs amount)
|
||||||
:amount-percentage 100
|
:amount-percentage 100
|
||||||
:amount-mode "%"
|
:amount-mode "%"
|
||||||
@@ -24,7 +26,6 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn from-graphql [accounts total locations]
|
(defn from-graphql [accounts total locations]
|
||||||
(println accounts total locations)
|
|
||||||
(if (seq accounts)
|
(if (seq accounts)
|
||||||
(vec (map
|
(vec (map
|
||||||
(fn [a]
|
(fn [a]
|
||||||
@@ -133,20 +134,20 @@
|
|||||||
[:div.column.is-narrow
|
[:div.column.is-narrow
|
||||||
(when-not disabled
|
(when-not disabled
|
||||||
[:a.delete {:on-click (dispatch-event [::remove-expense-account event expense-accounts id])}])]]
|
[:a.delete {:on-click (dispatch-event [::remove-expense-account event expense-accounts id])}])]]
|
||||||
|
(println "TYPAHEAD" expense-accounts)
|
||||||
[:div.field
|
[:div.field
|
||||||
[:div.columns
|
[:div.columns
|
||||||
[:div.column
|
[:div.column
|
||||||
[:p.help "Account"]
|
[:p.help "Account"]
|
||||||
[:div.control.is-fullwidth
|
[:div.control.is-fullwidth
|
||||||
[bind-field
|
[bind-field
|
||||||
[typeahead {:matches (map (fn [x] [(:id x) (str (:numeric-code x) " - " (:name x))]) chooseable-expense-accounts)
|
[typeahead-entity {:matches chooseable-expense-accounts
|
||||||
:disabled disabled
|
:match->text (fn [x ] (str (:numeric-code x) " - " (:name x)))
|
||||||
:type "typeahead"
|
:disabled disabled
|
||||||
:field [index :account :id]
|
:type "typeahead-entity"
|
||||||
#_#_:text-field [index :account :name]
|
:field [index :account]
|
||||||
|
:event [::expense-account-changed event expense-accounts max-value]
|
||||||
:event [::expense-account-changed event expense-accounts max-value]
|
:subscription expense-accounts}]]]]
|
||||||
:subscription expense-accounts}]]]]
|
|
||||||
[:div.column.is-narrow
|
[:div.column.is-narrow
|
||||||
[:p.help "Location"]
|
[:p.help "Location"]
|
||||||
[:div.control
|
[:div.control
|
||||||
|
|||||||
@@ -110,7 +110,7 @@
|
|||||||
(defn appearing-side-bar [{:keys [visible?]} & children ]
|
(defn appearing-side-bar [{:keys [visible?]} & children ]
|
||||||
[appearing {:visible? visible? :enter-class "slide-in-right" :exit-class "slide-out-right" :timeout 500}
|
[appearing {:visible? visible? :enter-class "slide-in-right" :exit-class "slide-out-right" :timeout 500}
|
||||||
[:aside {:class "column is-4 aside menu" :style {:height "calc(100vh - 46px)" :overflow "auto"}}
|
[:aside {:class "column is-4 aside menu" :style {:height "calc(100vh - 46px)" :overflow "auto"}}
|
||||||
[:div.sub-main {} children ]]])
|
(into [:div.sub-main {} ] children )]])
|
||||||
|
|
||||||
(defn side-bar-layout [{:keys [side-bar main ap bottom right-side-bar]}]
|
(defn side-bar-layout [{:keys [side-bar main ap bottom right-side-bar]}]
|
||||||
(let [ap @(re-frame/subscribe [::subs/active-page])
|
(let [ap @(re-frame/subscribe [::subs/active-page])
|
||||||
|
|||||||
@@ -108,3 +108,113 @@
|
|||||||
|
|
||||||
:else
|
:else
|
||||||
nil)]))})))
|
nil)]))})))
|
||||||
|
|
||||||
|
(defn get-valid-entity-matches [matches not-found-description not-found-value text match->text]
|
||||||
|
(let [valid-matches (take 5 (for [[match i] (map vector matches (range))
|
||||||
|
:let [t (match->text match)]
|
||||||
|
:when (str/includes? (or (some-> t .toLowerCase) "") (or (some-> text .toLowerCase) ""))]
|
||||||
|
match))
|
||||||
|
valid-matches (if (and not-found-description text)
|
||||||
|
(concat valid-matches [[:not-found (not-found-description text) (not-found-value text)]])
|
||||||
|
valid-matches)]
|
||||||
|
valid-matches))
|
||||||
|
(defn typeahead-entity [{:keys [matches on-change field value class not-found-description
|
||||||
|
disabled not-found-value auto-focus]}]
|
||||||
|
(let [text (r/atom (or (second (first (filter #(= (first %) value) matches))) ""))
|
||||||
|
highlighted (r/atom nil)
|
||||||
|
]
|
||||||
|
(r/create-class
|
||||||
|
{:reagent-render (fn [{:keys [matches on-change disabled match->text field value class not-found-description]}]
|
||||||
|
(println "RENDERING ZZ" value)
|
||||||
|
(let [select (fn [entity]
|
||||||
|
(when on-change
|
||||||
|
(if (= :not-found entity)
|
||||||
|
(on-change nil)
|
||||||
|
(on-change entity))))
|
||||||
|
text-atom text
|
||||||
|
text (or (when value (match->text value)) @text)
|
||||||
|
valid-matches (get-valid-entity-matches matches not-found-description not-found-value text match->text)]
|
||||||
|
(println "TEXT" value (match->text value) text)
|
||||||
|
[:div.typeahead
|
||||||
|
(if disabled
|
||||||
|
|
||||||
|
^{:key (str "typeahead" text) } [:input.input {:disabled "disabled" :value text} ]
|
||||||
|
|
||||||
|
(if value
|
||||||
|
^{:key "typeahead"} [:div.input {:class class
|
||||||
|
:tab-index "0"
|
||||||
|
:on-key-up (fn [e]
|
||||||
|
(if (= 8 (.-keyCode e))
|
||||||
|
(do
|
||||||
|
(select nil)
|
||||||
|
(reset! text-atom nil)
|
||||||
|
true)
|
||||||
|
false))}
|
||||||
|
[:div.control
|
||||||
|
[:div.tags.has-addons
|
||||||
|
[:span.tag text]
|
||||||
|
[:a.tag.is-delete {:on-click (fn [] (select nil))}]]]]
|
||||||
|
^{:key "typeahead"} [:input.input {:type "text"
|
||||||
|
:class class
|
||||||
|
|
||||||
|
:value text
|
||||||
|
:auto-focus auto-focus
|
||||||
|
:on-blur (fn [e]
|
||||||
|
(cond value
|
||||||
|
nil
|
||||||
|
|
||||||
|
(#{"" nil} text)
|
||||||
|
nil
|
||||||
|
|
||||||
|
@highlighted
|
||||||
|
(do (select @highlighted)
|
||||||
|
|
||||||
|
true)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(do (select nil)
|
||||||
|
(reset! text-atom nil)
|
||||||
|
true)))
|
||||||
|
:on-key-down (fn [e]
|
||||||
|
(condp = (.-keyCode e)
|
||||||
|
; up
|
||||||
|
38 (do
|
||||||
|
(when-let [new-match (->> valid-matches
|
||||||
|
(take-while #(not= % @highlighted))
|
||||||
|
(last))]
|
||||||
|
(reset! highlighted new-match))
|
||||||
|
true)
|
||||||
|
;; dwon
|
||||||
|
40 (do
|
||||||
|
(when-let [new-match (->> valid-matches
|
||||||
|
(drop-while #(not= % @highlighted))
|
||||||
|
(drop 1)
|
||||||
|
(first))]
|
||||||
|
(reset! highlighted new-match))
|
||||||
|
true)
|
||||||
|
13 (do (.preventDefault e)
|
||||||
|
(when @highlighted
|
||||||
|
|
||||||
|
(select @highlighted)
|
||||||
|
false))
|
||||||
|
true))
|
||||||
|
:on-change (fn [e]
|
||||||
|
(let [new-matches (get-valid-entity-matches matches not-found-description not-found-value (.. e -target -value) match->text)]
|
||||||
|
(reset! highlighted (first new-matches)))
|
||||||
|
(reset! text-atom (.. e -target -value)))}]))
|
||||||
|
|
||||||
|
(cond
|
||||||
|
(and (seq text)
|
||||||
|
(not value)
|
||||||
|
(seq valid-matches))
|
||||||
|
(let [h @highlighted]
|
||||||
|
[:div.typeahead-menu
|
||||||
|
[:ul
|
||||||
|
(for [entity valid-matches]
|
||||||
|
(let [t (match->text entity)]
|
||||||
|
^{:key entity} [:li.typeahead-suggestion {:class (if (= entity h)
|
||||||
|
"typeahead-highlighted")
|
||||||
|
:on-mouse-down #(do (select entity))} t]))]])
|
||||||
|
|
||||||
|
:else
|
||||||
|
nil)]))})))
|
||||||
|
|||||||
@@ -65,6 +65,7 @@
|
|||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::saving
|
::saving
|
||||||
(fn [{:keys [db]} [_ edit-completed]]
|
(fn [{:keys [db]} [_ edit-completed]]
|
||||||
|
(println "saving..." edit-completed)
|
||||||
(when @(re-frame/subscribe [::can-submit])
|
(when @(re-frame/subscribe [::can-submit])
|
||||||
(let [{{:keys [id vendor-id account-id location]} :data :as data} @(re-frame/subscribe [::forms/form ::edit-transaction])]
|
(let [{{:keys [id vendor-id account-id location]} :data :as data} @(re-frame/subscribe [::forms/form ::edit-transaction])]
|
||||||
{:db (forms/loading db ::edit-transaction )
|
{:db (forms/loading db ::edit-transaction )
|
||||||
@@ -98,6 +99,7 @@
|
|||||||
::change-vendor
|
::change-vendor
|
||||||
[(forms/in-form ::edit-transaction)]
|
[(forms/in-form ::edit-transaction)]
|
||||||
(fn [{{:keys [data]} :db} [_ field value]]
|
(fn [{{:keys [data]} :db} [_ field value]]
|
||||||
|
(println "HIIII")
|
||||||
(if (and value (expense-accounts-field/can-replace-with-default? (:accounts data)))
|
(if (and value (expense-accounts-field/can-replace-with-default? (:accounts data)))
|
||||||
{:dispatch [::forms/change ::edit-transaction
|
{:dispatch [::forms/change ::edit-transaction
|
||||||
field value
|
field value
|
||||||
@@ -115,50 +117,72 @@
|
|||||||
|
|
||||||
;; VIEWS
|
;; VIEWS
|
||||||
|
|
||||||
|
|
||||||
|
(defn vertical-form [{:keys [can-submit id change-event ]}]
|
||||||
|
{:form (fn [{:keys [title] :as params} & children]
|
||||||
|
(let [{:keys [data active? error]} @(re-frame/subscribe [::forms/form id])]
|
||||||
|
|
||||||
|
(into ^{:key id} [:form { :on-submit (fn [e]
|
||||||
|
(when (.-stopPropagation e)
|
||||||
|
(.stopPropagation e)
|
||||||
|
(.preventDefault e))
|
||||||
|
(re-frame/dispatch-sync [::saving (:edit-completed params)]))}
|
||||||
|
[:h1.title.is-2 title]
|
||||||
|
|
||||||
|
]
|
||||||
|
children)))
|
||||||
|
:field (fn [label control]
|
||||||
|
(let [{:keys [data]} @(re-frame/subscribe [::forms/form id])]
|
||||||
|
[:div.field
|
||||||
|
(when label [:p.help label])
|
||||||
|
[:div.control [bind-field (assoc-in control [1 :subscription] data)]]]))
|
||||||
|
|
||||||
|
:error-notification (fn []
|
||||||
|
(when-let [error (:error @(re-frame/subscribe [::forms/form id]))]
|
||||||
|
^{:key error}
|
||||||
|
[:div.notification.is-warning.animated.fadeInUp error]))
|
||||||
|
:submit-button (fn [child]
|
||||||
|
(let [error (:error @(re-frame/subscribe [::forms/form id]))]
|
||||||
|
[:button.button.is-medium.is-primary.is-fullwidth {:disabled (if @(re-frame/subscribe [::can-submit])
|
||||||
|
""
|
||||||
|
"disabled")
|
||||||
|
:class (str @(re-frame/subscribe [::forms/loading-class id])
|
||||||
|
(when error " animated shake"))} child]))})
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::error
|
||||||
|
:<- [::forms/form ::edit-transaction]
|
||||||
|
(fn [{:keys [error]}]
|
||||||
|
error))
|
||||||
|
|
||||||
|
|
||||||
|
(def my-form (vertical-form {:can-submit [::can-submit]
|
||||||
|
:change-event [::forms/change ::edit-transaction]
|
||||||
|
:id ::edit-transaction}))
|
||||||
|
|
||||||
|
|
||||||
(defn form [{:keys [edit-completed]}]
|
(defn form [{:keys [edit-completed]}]
|
||||||
[forms/side-bar-form {:form ::edit-transaction }
|
[forms/side-bar-form {:form ::edit-transaction }
|
||||||
(let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::edit-transaction])
|
(let [locations #{"BR" "DT"} #_@(re-frame/subscribe [::subs/locations-for-client (:client-id data)])
|
||||||
locations @(re-frame/subscribe [::subs/locations-for-client (:client-id data)])
|
change-event [::forms/change ::edit-transaction]
|
||||||
change-event [::forms/change ::edit-transaction]]
|
{:keys [data] } @(re-frame/subscribe [::forms/form ::edit-transaction])
|
||||||
^{:key id}
|
{:keys [form field error-notification submit-button ]} my-form]
|
||||||
[:form { :on-submit (fn [e]
|
(println "DATA" data)
|
||||||
(when (.-stopPropagation e)
|
[form {:title "Hello" :edit-completed edit-completed}
|
||||||
(.stopPropagation e)
|
[field "Merchant"
|
||||||
(.preventDefault e))
|
[:input.input {:type "text"
|
||||||
(re-frame/dispatch-sync [::saving edit-completed]))}
|
:field [:yodlee-merchant :name]
|
||||||
[:h1.title.is-2 "Edit Transaction"]
|
:disabled "disabled"}]]
|
||||||
|
[field "Amount"
|
||||||
[:div.field
|
[:input.input {:type "text"
|
||||||
[:p.help "Merchant"]
|
:field [:amount]
|
||||||
[:div.control
|
:disabled "disabled"}]]
|
||||||
[bind-field
|
[field "Description"
|
||||||
[:input.input {:type "text"
|
[:input.input {:type "text"
|
||||||
:field [:yodlee-merchant :name]
|
:field [:description-original]
|
||||||
:disabled "disabled"
|
:disabled "disabled"}]]
|
||||||
:subscription data}]]]]
|
|
||||||
|
|
||||||
[:div.field
|
|
||||||
[:p.help "Amount"]
|
|
||||||
[:div.control
|
|
||||||
[bind-field
|
|
||||||
[:input.input {:type "text"
|
|
||||||
:field [:amount]
|
|
||||||
:disabled "disabled"
|
|
||||||
:subscription data}]]]]
|
|
||||||
|
|
||||||
[:div.field
|
|
||||||
[:p.help "Description"]
|
|
||||||
[:div.control
|
|
||||||
[bind-field
|
|
||||||
[:input.input {:type "text"
|
|
||||||
:field [:description-original]
|
|
||||||
:disabled "disabled"
|
|
||||||
:subscription data}]]]]
|
|
||||||
|
|
||||||
|
|
||||||
(if (and (seq (:potential-payment-matches data))
|
(if (and (seq (:potential-payment-matches data))
|
||||||
(not (:payment data)))
|
(not (:payment data)))
|
||||||
|
|
||||||
[:div.box
|
[:div.box
|
||||||
[:div.columns
|
[:div.columns
|
||||||
[:div.column
|
[:div.column
|
||||||
@@ -177,50 +201,21 @@
|
|||||||
"Match"]]]))]
|
"Match"]]]))]
|
||||||
]
|
]
|
||||||
[:div
|
[:div
|
||||||
[:div.field
|
[field "Vendor"
|
||||||
[:p.help "Vendor"]
|
[typeahead {:matches (map (fn [x] [(:id x) (:name x)]) @(re-frame/subscribe [::subs/vendors]))
|
||||||
[:div.control
|
:type "typeahead"
|
||||||
[bind-field
|
:auto-focus true
|
||||||
[typeahead {:matches (map (fn [x] [(:id x) (:name x)]) @(re-frame/subscribe [::subs/vendors]))
|
:field [:vendor-id]
|
||||||
:type "typeahead"
|
:disabled (boolean (:payment data))
|
||||||
:auto-focus true
|
:event [::change-vendor]}]]
|
||||||
:field [:vendor-id]
|
[field nil
|
||||||
:disabled (boolean (:payment data))
|
[expense-accounts-field
|
||||||
:event [::change-vendor]
|
{:type "expense-accounts"
|
||||||
:subscription data}]]]]
|
:field [:accounts]
|
||||||
|
:max (Math/abs (js/parseFloat (:amount data)))
|
||||||
|
:descriptor "credit account"
|
||||||
|
:disabled (boolean (:payment data))
|
||||||
[:div.field
|
:locations locations
|
||||||
[bind-field
|
:event change-event}]]
|
||||||
[expense-accounts-field
|
[error-notification]
|
||||||
{:type "expense-accounts"
|
[submit-button "Save"]])])])
|
||||||
:field [:accounts]
|
|
||||||
:max (Math/abs (js/parseFloat (:amount data)))
|
|
||||||
:descriptor "credit account"
|
|
||||||
:disabled (boolean (:payment data))
|
|
||||||
:locations locations
|
|
||||||
:event change-event
|
|
||||||
:subscription data}]]]
|
|
||||||
|
|
||||||
[:div.field
|
|
||||||
[:p.help]
|
|
||||||
[:div.control
|
|
||||||
[:label.checkbox
|
|
||||||
[bind-field
|
|
||||||
[:input.checkbox {:type "checkbox"
|
|
||||||
:field [:exclude-from-ledger]
|
|
||||||
:subscription data
|
|
||||||
:event change-event}
|
|
||||||
]]
|
|
||||||
" Exclude from ledger?"
|
|
||||||
]]]
|
|
||||||
|
|
||||||
(when error
|
|
||||||
^{:key error} [:div.notification.is-warning.animated.fadeInUp
|
|
||||||
error])
|
|
||||||
[:button.button.is-medium.is-primary.is-fullwidth {:disabled (if @(re-frame/subscribe [::can-submit])
|
|
||||||
""
|
|
||||||
"disabled")
|
|
||||||
:class (str @(re-frame/subscribe [::forms/loading-class ::edit-transaction])
|
|
||||||
(when error " animated shake"))} "Save"]])])])
|
|
||||||
|
|||||||
@@ -142,6 +142,22 @@
|
|||||||
keys (dissoc keys :field :subscription :event :spec)]
|
keys (dissoc keys :field :subscription :event :spec)]
|
||||||
(into [dom keys] (with-keys rest))))
|
(into [dom keys] (with-keys rest))))
|
||||||
|
|
||||||
|
|
||||||
|
(defmethod do-bind "typeahead-entity" [dom {:keys [field event text-event subscription class spec match->text] :as keys} & rest]
|
||||||
|
(let [field (if (keyword? field) [field] field)
|
||||||
|
event (if (keyword? event) [event] event)
|
||||||
|
keys (assoc keys
|
||||||
|
:on-change (fn [selected]
|
||||||
|
(re-frame/dispatch (conj (conj event field) selected))
|
||||||
|
#_(when text-field
|
||||||
|
(re-frame/dispatch (conj (conj (or text-event event) text-field) text-value))))
|
||||||
|
:value (get-in subscription field)
|
||||||
|
:class (str class
|
||||||
|
(when (and spec (not (s/valid? spec (get-in subscription field))))
|
||||||
|
" is-danger")))
|
||||||
|
keys (dissoc keys :field :subscription :event :spec)]
|
||||||
|
(into [dom keys] (with-keys rest))))
|
||||||
|
|
||||||
(defmethod do-bind "date" [dom {:keys [field event subscription class spec] :as keys} & rest]
|
(defmethod do-bind "date" [dom {:keys [field event subscription class spec] :as keys} & rest]
|
||||||
(let [field (if (keyword? field) [field] field)
|
(let [field (if (keyword? field) [field] field)
|
||||||
event (if (keyword? event) [event] event)
|
event (if (keyword? event) [event] event)
|
||||||
|
|||||||
Reference in New Issue
Block a user