making main form better.
This commit is contained in:
@@ -10,7 +10,6 @@
|
|||||||
(s/def ::due (s/nilable ::shared/date))
|
(s/def ::due (s/nilable ::shared/date))
|
||||||
(s/def ::scheduled-payment (s/nilable ::shared/date))
|
(s/def ::scheduled-payment (s/nilable ::shared/date))
|
||||||
(s/def ::total ::shared/money)
|
(s/def ::total ::shared/money)
|
||||||
(s/def ::vendor-id ::shared/identifier)
|
|
||||||
|
|
||||||
(s/def ::invoice (s/keys :req-un [::client
|
(s/def ::invoice (s/keys :req-un [::client
|
||||||
::invoice-number
|
::invoice-number
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[clojure.string :as str]))
|
[clojure.string :as str]))
|
||||||
|
|
||||||
(def date-regex #"[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}")
|
(def date-regex #"[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}")
|
||||||
(def money-regex #"\-?[0-9]+(\.[0-9]{1,2})?$")
|
(def money-regex #"\-?[0-9]+(\.[0-9]{2})?$")
|
||||||
(def numeric-regex #"^[0-9]+$")
|
(def numeric-regex #"^[0-9]+$")
|
||||||
(def only-upper-case #"^[A-Z]+$")
|
(def only-upper-case #"^[A-Z]+$")
|
||||||
|
|
||||||
@@ -14,4 +14,5 @@
|
|||||||
|
|
||||||
(s/def ::money (s/or :string (s/and string?
|
(s/def ::money (s/or :string (s/and string?
|
||||||
#(re-matches money-regex %))
|
#(re-matches money-regex %))
|
||||||
:float float?))
|
:float float?
|
||||||
|
:int int?))
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
(defn builder [{:keys [can-submit data-sub change-event submit-event id fullwidth?] :as z}]
|
(defn builder [{:keys [can-submit data-sub change-event submit-event id fullwidth?] :as z}]
|
||||||
(let [data-sub (or data-sub [::forms/form id])
|
(let [data-sub (or data-sub [::forms/form id])
|
||||||
change-event (or change-event [::forms/change id])
|
change-event (or change-event [::forms/change id])
|
||||||
{:keys [data error]} @(re-frame/subscribe data-sub)
|
{:keys [data error] form-key :id} @(re-frame/subscribe data-sub)
|
||||||
status @(re-frame/subscribe [::status/single id])]
|
status @(re-frame/subscribe [::status/single id])]
|
||||||
(r/create-element Provider #js {:value #js {:can-submit @(re-frame/subscribe can-submit)
|
(r/create-element Provider #js {:value #js {:can-submit @(re-frame/subscribe can-submit)
|
||||||
:change-event change-event
|
:change-event change-event
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
:data data
|
:data data
|
||||||
:fullwidth? fullwidth?}}
|
:fullwidth? fullwidth?}}
|
||||||
(r/as-element
|
(r/as-element
|
||||||
|
^{:key form-key}
|
||||||
[:form {:on-submit (fn [e]
|
[:form {:on-submit (fn [e]
|
||||||
(when (.-stopPropagation e)
|
(when (.-stopPropagation e)
|
||||||
(.stopPropagation e)
|
(.stopPropagation e)
|
||||||
@@ -78,13 +79,19 @@
|
|||||||
(into [:div.control ] children)]))]))
|
(into [:div.control ] children)]))]))
|
||||||
|
|
||||||
(defn field []
|
(defn field []
|
||||||
(let [[label child] (r/children (r/current-component))]
|
(let [props (r/props (r/current-component))
|
||||||
|
[label child] (r/children (r/current-component))]
|
||||||
[:> Consumer {}
|
[:> Consumer {}
|
||||||
(fn [consume]
|
(fn [consume]
|
||||||
(r/as-element
|
(r/as-element
|
||||||
[:div.field
|
[:div.field
|
||||||
(when label (if (aget consume "fullwidth?") [:p.help label]
|
(when label
|
||||||
[:label.label label]))
|
(if (aget consume "fullwidth?")
|
||||||
|
[:p.help label]
|
||||||
|
[:label.label
|
||||||
|
(if (:required? props)
|
||||||
|
[:span label [:span.has-text-danger " *"]]
|
||||||
|
label)]))
|
||||||
[:div.control [raw-field {} child]]]))]))
|
[:div.control [raw-field {} child]]]))]))
|
||||||
|
|
||||||
(defn horizontal-control []
|
(defn horizontal-control []
|
||||||
@@ -111,7 +118,7 @@
|
|||||||
(into [:div {:style {:margin-bottom "5em"}}]
|
(into [:div {:style {:margin-bottom "5em"}}]
|
||||||
(r/children (r/current-component)))])
|
(r/children (r/current-component)))])
|
||||||
|
|
||||||
(defn submit-button []
|
(defn submit-button [{:keys [class]}]
|
||||||
(let [[child] (r/children (r/current-component))]
|
(let [[child] (r/children (r/current-component))]
|
||||||
[:> Consumer {}
|
[:> Consumer {}
|
||||||
(fn [consume]
|
(fn [consume]
|
||||||
@@ -121,7 +128,8 @@
|
|||||||
(r/as-element
|
(r/as-element
|
||||||
[:button.button.is-medium.is-primary {:disabled (or (status/disabled-for status)
|
[:button.button.is-medium.is-primary {:disabled (or (status/disabled-for status)
|
||||||
(not can-submit))
|
(not can-submit))
|
||||||
:class (cond-> (status/class-for status)
|
:class (cond-> (or class [])
|
||||||
|
(status/class-for status) (conj (status/class-for status))
|
||||||
fullwidth? (conj "is-fullwidth")) }
|
fullwidth? (conj "is-fullwidth")) }
|
||||||
child])))]))
|
child])))]))
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,6 @@
|
|||||||
updated-accounts (if-let [location (get-in updated-accounts [(first field) :account :location])]
|
updated-accounts (if-let [location (get-in updated-accounts [(first field) :account :location])]
|
||||||
(assoc-in updated-accounts [(first field) :location] location)
|
(assoc-in updated-accounts [(first field) :location] location)
|
||||||
updated-accounts)]
|
updated-accounts)]
|
||||||
(println updated-accounts)
|
|
||||||
{:dispatch (into event [updated-accounts])})))
|
{:dispatch (into event [updated-accounts])})))
|
||||||
|
|
||||||
|
|
||||||
@@ -163,7 +162,6 @@
|
|||||||
[:div.column.is-narrow
|
[:div.column.is-narrow
|
||||||
[:p.help "Location"]
|
[:p.help "Location"]
|
||||||
[:div.control
|
[:div.control
|
||||||
(println account)
|
|
||||||
(if-let [forced-location (:location account)]
|
(if-let [forced-location (:location account)]
|
||||||
[:div.select
|
[:div.select
|
||||||
[:select {:disabled "disabled" :style {:width "5em"} :value forced-location} [:option {:value forced-location} forced-location]]]
|
[:select {:disabled "disabled" :style {:width "5em"} :value forced-location} [:option {:value forced-location} forced-location]]]
|
||||||
|
|||||||
@@ -1,23 +1,71 @@
|
|||||||
(ns auto-ap.views.components.money-field
|
(ns auto-ap.views.components.money-field
|
||||||
(:require [reagent.core :as r]
|
(:require [reagent.core :as r]
|
||||||
[clojure.string :as str]))
|
[auto-ap.views.utils :refer [->short$]]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[react :as react]))
|
||||||
|
(def good-$ #"^\-?[0-9]+(\.[0-9][0-9])?$")
|
||||||
|
|
||||||
(defn money-field [{:keys [min max disabled on-change value]}]
|
(defn -money-field [{:keys [min max disabled on-change value class style]}]
|
||||||
(let [parsed-amount (r/atom {:parsed value
|
(let [[ parsed-amount set-parsed-amount] (react/useState {:parsed value
|
||||||
:raw (str value)})]
|
:raw (cond
|
||||||
(fn [{:keys [min max disabled on-change value]}]
|
(str/blank? value)
|
||||||
[:input.input {:type "number"
|
""
|
||||||
|
|
||||||
|
(js/Number.isNaN (js/parseFloat value))
|
||||||
|
""
|
||||||
|
|
||||||
|
:else
|
||||||
|
(->short$ (js/parseFloat value)))})]
|
||||||
|
(react/useEffect (fn []
|
||||||
|
;; allow the controlling field to change the raw representation
|
||||||
|
;; when the raw amount is a valid representation, so that 33.
|
||||||
|
;; doesn't get unset
|
||||||
|
(when (or
|
||||||
|
(and (:raw parsed-amount)
|
||||||
|
(re-find good-$ (:raw parsed-amount)))
|
||||||
|
(str/blank? (:raw parsed-amount)))
|
||||||
|
(set-parsed-amount
|
||||||
|
(assoc parsed-amount
|
||||||
|
:parsed value
|
||||||
|
:raw (cond
|
||||||
|
(str/blank? value)
|
||||||
|
""
|
||||||
|
|
||||||
|
(js/Number.isNaN (js/parseFloat value))
|
||||||
|
""
|
||||||
|
|
||||||
|
:else
|
||||||
|
(->short$ (js/parseFloat value))))))
|
||||||
|
nil))
|
||||||
|
[:div.control.has-icons-left
|
||||||
|
[:input.input {:type "text"
|
||||||
:disabled disabled
|
:disabled disabled
|
||||||
|
:class class
|
||||||
:on-change (fn [e]
|
:on-change (fn [e]
|
||||||
(let [raw (.. e -target -value)
|
(let [raw (.. e -target -value)
|
||||||
new-value (when (and raw (not (str/blank? raw)))
|
new-value (when (and raw
|
||||||
|
(not (str/blank? raw))
|
||||||
|
(re-find good-$ raw))
|
||||||
(js/parseFloat raw))]
|
(js/parseFloat raw))]
|
||||||
(swap! parsed-amount assoc
|
(set-parsed-amount {:raw raw
|
||||||
:raw raw
|
:parsed new-value})
|
||||||
:parsed new-value)
|
|
||||||
(when (not= value new-value)
|
(when (not= value new-value)
|
||||||
(on-change new-value))))
|
(on-change new-value))))
|
||||||
:value (:raw @parsed-amount)
|
:value (or (:raw parsed-amount)
|
||||||
|
"")
|
||||||
|
:on-blur (fn []
|
||||||
|
(when-not (re-find good-$ (:raw parsed-amount))
|
||||||
|
|
||||||
|
(set-parsed-amount {:raw ""
|
||||||
|
:parsed nil})
|
||||||
|
(on-change nil)))
|
||||||
:min min
|
:min min
|
||||||
:max max
|
:max max
|
||||||
:step "0.01"}])))
|
:step "0.01"
|
||||||
|
:style (or style
|
||||||
|
{:width "8em"})}]
|
||||||
|
[:span.icon.is-left
|
||||||
|
[:i.fa.fa-usd]]]))
|
||||||
|
|
||||||
|
(defn money-field []
|
||||||
|
[:f> -money-field (r/props (r/current-component))])
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
::search-completed
|
::search-completed
|
||||||
(fn [_ [_ set-items set-loading-status result]]
|
(fn [_ [_ set-items set-loading-status result]]
|
||||||
(set-loading-status nil)
|
(set-loading-status nil)
|
||||||
(set-items (:search-results result))
|
(set-items (into-array (:search-results result)))
|
||||||
{}))
|
{}))
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::search-failed
|
::search-failed
|
||||||
@@ -54,20 +54,27 @@
|
|||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::input-value-changed
|
::input-value-changed
|
||||||
(fn [_ [_ input-value search-query set-items set-loading-status]]
|
(fn [_ [_ input-value search-query set-items set-loading-status]]
|
||||||
(set-items [])
|
(set-items #js [])
|
||||||
(when (> (count input-value) 2)
|
(when (> (count input-value) 2)
|
||||||
(set-loading-status :loading)
|
(set-loading-status :loading)
|
||||||
{:dispatch-debounce {:event [::input-value-settled input-value search-query set-items set-loading-status]
|
{:dispatch-debounce {:event [::input-value-settled input-value search-query set-items set-loading-status]
|
||||||
:time 250
|
:time 250
|
||||||
:key ::input-value-settled}})))
|
:key ::input-value-settled}})))
|
||||||
|
|
||||||
(defn typeahead-v3-internal [{:keys [class entity->text entities on-input-change style ^js on-change disabled value name auto-focus] :or {disabled false} :as i}]
|
(defn typeahead-v3-internal [{:keys [class entity->text entities on-input-change style ^js on-change disabled value name auto-focus] :or {disabled false}
|
||||||
(let [[items set-items] (react/useState (or (clj->js entities)
|
prop-value :value
|
||||||
|
:as i}]
|
||||||
|
(let [[items set-items] (react/useState (or entities
|
||||||
[]))
|
[]))
|
||||||
[focused set-focus] (react/useState (boolean auto-focus))
|
[focused set-focus] (react/useState (boolean auto-focus))
|
||||||
[loading-status set-loading-status] (react/useState false)
|
[loading-status set-loading-status] (react/useState false)
|
||||||
|
[value set-value] (react/useState value)
|
||||||
|
|
||||||
|
;; resets internal representation of value when props change
|
||||||
|
_ (react/useEffect (fn []
|
||||||
|
(set-value prop-value)))
|
||||||
[getMenuProps getComboboxProps getInputProps getItemProps isOpen highlightedIndex selectItem selectedItem setInputValue]
|
[getMenuProps getComboboxProps getInputProps getItemProps isOpen highlightedIndex selectItem selectedItem setInputValue]
|
||||||
(as-> (useCombobox (clj->js {:items items
|
(as-> (useCombobox #js {:items (into-array items)
|
||||||
:defaultHighlightedIndex 0
|
:defaultHighlightedIndex 0
|
||||||
:defaultSelectedItem value
|
:defaultSelectedItem value
|
||||||
:itemToString (fn []
|
:itemToString (fn []
|
||||||
@@ -76,9 +83,11 @@
|
|||||||
:onInputValueChange (fn [input]
|
:onInputValueChange (fn [input]
|
||||||
(on-input-change input set-items set-loading-status))
|
(on-input-change input set-items set-loading-status))
|
||||||
:stateReducer state-reducer
|
:stateReducer state-reducer
|
||||||
|
:selectedItem value
|
||||||
:onSelectedItemChange (fn [z]
|
:onSelectedItemChange (fn [z]
|
||||||
|
(set-value (aget z "selectedItem"))
|
||||||
(when on-change
|
(when on-change
|
||||||
(on-change (js->clj (aget z "selectedItem") :keywordize-keys true))))})) $
|
(on-change (aget z "selectedItem"))))}) $
|
||||||
(map #(aget $ %) ["getMenuProps" "getComboboxProps" "getInputProps" "getItemProps" "isOpen" "highlightedIndex" "selectItem" "selectedItem" "setInputValue"]))]
|
(map #(aget $ %) ["getMenuProps" "getComboboxProps" "getInputProps" "getItemProps" "isOpen" "highlightedIndex" "selectItem" "selectedItem" "setInputValue"]))]
|
||||||
[:<>
|
[:<>
|
||||||
[:div.typeahead (assoc (js->clj (getComboboxProps))
|
[:div.typeahead (assoc (js->clj (getComboboxProps))
|
||||||
@@ -110,7 +119,7 @@
|
|||||||
[:div.level-item
|
[:div.level-item
|
||||||
[:div.control
|
[:div.control
|
||||||
[:div.tags.has-addons
|
[:div.tags.has-addons
|
||||||
[:span.tag (:name (js->clj selectedItem :keywordize-keys true))]
|
[:span.tag (:name selectedItem)]
|
||||||
(when name
|
(when name
|
||||||
[:input {:type "hidden" :name name :value (:id (js->clj selectedItem :keywordize-keys true))}])
|
[:input {:type "hidden" :name name :value (:id (js->clj selectedItem :keywordize-keys true))}])
|
||||||
(when-not disabled
|
(when-not disabled
|
||||||
@@ -166,11 +175,12 @@
|
|||||||
(fn [input set-items]
|
(fn [input set-items]
|
||||||
(if entities-by-id
|
(if entities-by-id
|
||||||
(do
|
(do
|
||||||
|
(set-items
|
||||||
|
(into-array
|
||||||
(->> (.search entity-index (or (aget input "inputValue") "") #js {:fuzzy 0.2} )
|
(->> (.search entity-index (or (aget input "inputValue") "") #js {:fuzzy 0.2} )
|
||||||
clj->js
|
(take 10)))))
|
||||||
(take 10)
|
|
||||||
(set-items)))
|
|
||||||
|
|
||||||
(set-items (map clj->js (take 10 (filter (fn [x] (str/includes? (or (some-> (entity->text x) str/lower-case) "")
|
(set-items (into-array
|
||||||
|
(take 10 (filter (fn [x] (str/includes? (or (some-> (entity->text x) str/lower-case) "")
|
||||||
(or (some-> (aget input "inputValue") str/lower-case) "")))
|
(or (some-> (aget input "inputValue") str/lower-case) "")))
|
||||||
entities)))))))]])
|
entities)))))))]])
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
:name name
|
:name name
|
||||||
:print-as print-as
|
:print-as print-as
|
||||||
:terms (or (str->int terms)
|
:terms (or (str->int terms)
|
||||||
0)
|
nil)
|
||||||
:default-account-id (:id default-account)
|
:default-account-id (:id default-account)
|
||||||
:address address
|
:address address
|
||||||
:primary-contact primary-contact
|
:primary-contact primary-contact
|
||||||
|
|||||||
@@ -1,34 +1,41 @@
|
|||||||
(ns auto-ap.views.pages.invoices.form
|
(ns auto-ap.views.pages.invoices.form
|
||||||
(:require [auto-ap.entities.invoice :as invoice]
|
(:require
|
||||||
|
[auto-ap.entities.invoice :as invoice]
|
||||||
[auto-ap.events :as events]
|
[auto-ap.events :as events]
|
||||||
[auto-ap.forms :as forms]
|
[auto-ap.forms :as forms]
|
||||||
|
[auto-ap.forms.builder :as form-builder]
|
||||||
[auto-ap.status :as status]
|
[auto-ap.status :as status]
|
||||||
[auto-ap.subs :as subs]
|
[auto-ap.subs :as subs]
|
||||||
[auto-ap.time-utils :refer [next-dom]]
|
[auto-ap.time-utils :refer [next-dom]]
|
||||||
[auto-ap.utils :refer [dollars=]]
|
[auto-ap.utils :refer [dollars=]]
|
||||||
[auto-ap.views.components.dropdown :refer [drop-down]]
|
|
||||||
[auto-ap.views.components.expense-accounts-field
|
[auto-ap.views.components.expense-accounts-field
|
||||||
:as
|
:as expense-accounts-field
|
||||||
expense-accounts-field
|
:refer [recalculate-amounts]]
|
||||||
:refer
|
|
||||||
[expense-accounts-field recalculate-amounts]]
|
|
||||||
[auto-ap.views.components.layouts :as layouts]
|
[auto-ap.views.components.layouts :as layouts]
|
||||||
|
[auto-ap.views.components.level :refer [left-stack]]
|
||||||
[auto-ap.views.components.modal :as modal]
|
[auto-ap.views.components.modal :as modal]
|
||||||
|
[auto-ap.views.components.expense-accounts-field :refer [expense-accounts-field]]
|
||||||
|
[auto-ap.views.components.dropdown :refer [drop-down]]
|
||||||
[auto-ap.views.components.money-field :refer [money-field]]
|
[auto-ap.views.components.money-field :refer [money-field]]
|
||||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||||
[auto-ap.views.components.typeahead.vendor :refer [search-backed-typeahead]]
|
[auto-ap.views.components.typeahead.vendor
|
||||||
|
:refer [search-backed-typeahead]]
|
||||||
[auto-ap.views.pages.invoices.common :refer [invoice-read]]
|
[auto-ap.views.pages.invoices.common :refer [invoice-read]]
|
||||||
[auto-ap.views.utils
|
[auto-ap.views.utils
|
||||||
:refer
|
:refer [date->str
|
||||||
[date->str date-picker dispatch-event standard str->date with-user]]
|
date-picker-friendly
|
||||||
|
dispatch-event
|
||||||
|
standard
|
||||||
|
str->date
|
||||||
|
with-user]]
|
||||||
[cljs-time.core :as c]
|
[cljs-time.core :as c]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[vimsical.re-frame.fx.track :as track]
|
[vimsical.re-frame.cofx.inject :as inject]
|
||||||
[vimsical.re-frame.cofx.inject :as inject]))
|
[vimsical.re-frame.fx.track :as track]))
|
||||||
|
|
||||||
;; SUBS
|
;; SUBS
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
@@ -134,7 +141,8 @@
|
|||||||
:vendor-preferences vendor-preferences
|
:vendor-preferences vendor-preferences
|
||||||
:scheduled-payment (:scheduled-payment edit-invoice)
|
:scheduled-payment (:scheduled-payment edit-invoice)
|
||||||
:invoice-number (:invoice-number edit-invoice)
|
:invoice-number (:invoice-number edit-invoice)
|
||||||
:total (:total edit-invoice)
|
:total (cond-> (:total edit-invoice)
|
||||||
|
(not (str/blank? (:total edit-invoice))) (js/parseFloat ))
|
||||||
:original edit-invoice
|
:original edit-invoice
|
||||||
:vendor (:vendor edit-invoice)
|
:vendor (:vendor edit-invoice)
|
||||||
:client (:client edit-invoice)
|
:client (:client edit-invoice)
|
||||||
@@ -320,8 +328,12 @@
|
|||||||
min-total (if (= (:total (:original data)) (:outstanding-balance (:original data)))
|
min-total (if (= (:total (:original data)) (:outstanding-balance (:original data)))
|
||||||
nil
|
nil
|
||||||
(- (:total (:original data)) (:outstanding-balance (:original data))))]
|
(- (:total (:original data)) (:outstanding-balance (:original data))))]
|
||||||
(with-meta
|
[form-builder/builder {:can-submit [::can-submit]
|
||||||
(form-inline (assoc params :title [:div "New Invoice "
|
:change-event [::changed]
|
||||||
|
:submit-event [::save-requested [::saving ]]
|
||||||
|
:id ::form}
|
||||||
|
|
||||||
|
[form-builder/section {:title [:div "New Invoice "
|
||||||
(cond
|
(cond
|
||||||
(#{:unpaid ":unpaid"} (:status data))
|
(#{:unpaid ":unpaid"} (:status data))
|
||||||
nil
|
nil
|
||||||
@@ -339,20 +351,20 @@
|
|||||||
[:div.tag.is-info.is-light "Paid"])
|
[:div.tag.is-info.is-light "Paid"])
|
||||||
|
|
||||||
:else
|
:else
|
||||||
nil)])
|
nil)]}
|
||||||
[:<>
|
|
||||||
(when-not active-client
|
(when-not active-client
|
||||||
(field [:span "Client"
|
[form-builder/field {:required? true}
|
||||||
[:span.has-text-danger " *"]]
|
"Client"
|
||||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||||
:entity->text :name
|
:entity->text :name
|
||||||
:type "typeahead-v3"
|
:type "typeahead-v3"
|
||||||
:auto-focus (if active-client false true)
|
:auto-focus (if active-client false true)
|
||||||
:field [:client]
|
:field [:client]
|
||||||
:disabled exists?
|
:disabled exists?
|
||||||
:spec ::invoice/client}]))
|
:spec ::invoice/client}]])
|
||||||
(field [:span "Vendor"
|
[form-builder/field {:required? true}
|
||||||
[:span.has-text-danger " *"]]
|
"Vendor"
|
||||||
[search-backed-typeahead {:disabled exists?
|
[search-backed-typeahead {:disabled exists?
|
||||||
:search-query (fn [i]
|
:search-query (fn [i]
|
||||||
[:search_vendor
|
[:search_vendor
|
||||||
@@ -360,87 +372,56 @@
|
|||||||
[:name :id]])
|
[:name :id]])
|
||||||
:type "typeahead-v3"
|
:type "typeahead-v3"
|
||||||
:auto-focus (if active-client true false)
|
:auto-focus (if active-client true false)
|
||||||
:field [:vendor]}])
|
:field [:vendor]}]]
|
||||||
|
[form-builder/field {:required? true}
|
||||||
(field [:span "Date"
|
"Date"
|
||||||
[:span.has-text-danger " *"]]
|
[date-picker-friendly {:type "date"
|
||||||
[date-picker {:class-name "input"
|
|
||||||
:class "input"
|
|
||||||
:format-week-number (fn [] "")
|
|
||||||
:previous-month-button-label ""
|
|
||||||
:placeholder "mm/dd/yyyy"
|
|
||||||
:disable-keyboard-navigation true
|
|
||||||
:next-month-button-label ""
|
|
||||||
:next-month-label ""
|
|
||||||
:type "date"
|
|
||||||
:field [:date]
|
:field [:date]
|
||||||
:spec ::invoice/date}])
|
:spec ::invoice/date}]]
|
||||||
|
|
||||||
(field "Due (optional)"
|
[form-builder/field
|
||||||
[date-picker {:class-name "input"
|
"Due (optional)"
|
||||||
:class "input"
|
[date-picker-friendly {:type "date"
|
||||||
:format-week-number (fn [] "")
|
|
||||||
:previous-month-button-label ""
|
|
||||||
:placeholder "mm/dd/yyyy"
|
|
||||||
:disable-keyboard-navigation true
|
|
||||||
:next-month-button-label ""
|
|
||||||
:next-month-label ""
|
|
||||||
:type "date"
|
|
||||||
:field [:due]
|
:field [:due]
|
||||||
:spec ::invoice/due}])
|
:spec ::invoice/due}]]
|
||||||
|
[form-builder/vertical-control
|
||||||
[:p.help "Scheduled payment (optional)"]
|
"Scheduled payment (optional)"
|
||||||
[:div.level
|
[left-stack
|
||||||
[:div.level-left
|
|
||||||
[:div.level-item
|
|
||||||
[:div.control
|
[:div.control
|
||||||
(raw-field
|
[form-builder/raw-field
|
||||||
[date-picker {:class-name "input"
|
[date-picker-friendly {:type "date"
|
||||||
:class "input"
|
|
||||||
:disabled (boolean (:schedule-when-due data))
|
|
||||||
:format-week-number (fn [] "")
|
|
||||||
:previous-month-button-label ""
|
|
||||||
:placeholder "mm/dd/yyyy"
|
|
||||||
:next-month-button-label ""
|
|
||||||
:next-month-label ""
|
|
||||||
:type "date"
|
|
||||||
:field [:scheduled-payment]
|
:field [:scheduled-payment]
|
||||||
:spec ::invoice/scheduled-payment}])]]
|
:spec ::invoice/scheduled-payment}]]]
|
||||||
[:div.level-item [:div.control
|
[:div.control
|
||||||
(raw-field
|
[form-builder/raw-field
|
||||||
|
|
||||||
[switch-field {:id "schedule-when-due"
|
[switch-field {:id "schedule-when-due"
|
||||||
:field [:schedule-when-due]
|
:field [:schedule-when-due]
|
||||||
:label "Same as due date"
|
:label "Same as due date"
|
||||||
:type "checkbox"}])]]]]
|
:type "checkbox"}]]]]]
|
||||||
|
[form-builder/field {:required? true}
|
||||||
(field [:span "Invoice #"
|
"Invoice #"
|
||||||
[:span.has-text-danger " *"]]
|
|
||||||
[:input.input {:type "text"
|
[:input.input {:type "text"
|
||||||
:field [:invoice-number]
|
:field [:invoice-number]
|
||||||
:spec ::invoice/invoice-number}])
|
:spec ::invoice/invoice-number}]]
|
||||||
|
[form-builder/field {:required? true}
|
||||||
|
"Total"
|
||||||
(field [:span "Total"
|
|
||||||
[:span.has-text-danger " *"]]
|
|
||||||
[money-field {:type "money"
|
[money-field {:type "money"
|
||||||
:field [:total]
|
:field [:total]
|
||||||
:disabled (if can-change-amount? "" "disabled")
|
:disabled (if can-change-amount? "" "disabled")
|
||||||
|
:style {:max-width "8em"}
|
||||||
:min min-total
|
:min min-total
|
||||||
:spec ::invoice/total
|
:spec ::invoice/total
|
||||||
:step "0.01"}])
|
:step "0.01"}]]]
|
||||||
|
[form-builder/raw-field
|
||||||
(with-meta
|
|
||||||
(field nil
|
|
||||||
[expense-accounts-field {:type "expense-accounts"
|
[expense-accounts-field {:type "expense-accounts"
|
||||||
:descriptor "expense account"
|
:descriptor "expense account"
|
||||||
:locations (:locations (:client data))
|
:locations (:locations (:client data))
|
||||||
:max (:total data)
|
:max (:total data)
|
||||||
:client (or (:client data) active-client)
|
:client (or (:client data) active-client)
|
||||||
:field [:expense-accounts]}])
|
:field [:expense-accounts]}]]
|
||||||
{:key (str (:id (:vendor data) "none") "-" (:id (:client data) "none") )})
|
[form-builder/error-notification]
|
||||||
|
[:div {:style {:margin-bottom "1em"}}]
|
||||||
(error-notification)
|
|
||||||
|
|
||||||
[:div.columns
|
[:div.columns
|
||||||
(when-not exists?
|
(when-not exists?
|
||||||
[:div.column
|
[:div.column
|
||||||
@@ -464,9 +445,8 @@
|
|||||||
^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::save-requested [::add-and-print id :check]])} "Print checks from " name]
|
^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::save-requested [::add-and-print id :check]])} "Print checks from " name]
|
||||||
^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::save-requested [::add-and-print id :debit]])} "Debit from " name]))))]]])
|
^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::save-requested [::add-and-print id :debit]])} "Debit from " name]))))]]])
|
||||||
[:div.column
|
[:div.column
|
||||||
|
[form-builder/submit-button {:class ["is-fullwidth"]}
|
||||||
(submit-button "Save")]]])
|
"Save"]]]])])
|
||||||
{:key id}))])
|
|
||||||
|
|
||||||
|
|
||||||
(defn form [_]
|
(defn form [_]
|
||||||
|
|||||||
@@ -38,6 +38,19 @@
|
|||||||
(defn ->% [x]
|
(defn ->% [x]
|
||||||
(nf% x))
|
(nf% x))
|
||||||
|
|
||||||
|
(defn ->short$ [x]
|
||||||
|
(cond
|
||||||
|
(nil? x)
|
||||||
|
nil
|
||||||
|
|
||||||
|
(int? x)
|
||||||
|
(str x)
|
||||||
|
|
||||||
|
(float? x)
|
||||||
|
(.toFixed x 2)
|
||||||
|
|
||||||
|
))
|
||||||
|
|
||||||
(defn active-when= [active-page candidate]
|
(defn active-when= [active-page candidate]
|
||||||
(when (= active-page candidate) " is-active"))
|
(when (= active-page candidate) " is-active"))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user