More standardization

This commit is contained in:
Bryce Covert
2020-08-05 00:29:21 -07:00
parent e1ffeda851
commit 0fd8d4a1c1
8 changed files with 299 additions and 285 deletions

View File

@@ -197,6 +197,11 @@ nav.navbar .navbar-item.is-active {
background-color: #F9F9F9;
border-right: 1px solid #DEDEDE;
}
.aside .subtitle {
padding-top: 2rem;
margin-bottom: 0.75rem;
}
.messages {
display:block;
background-color: #fff;

View File

@@ -1,36 +1,40 @@
(ns auto-ap.datomic.clients
(:require [datomic.api :as d]
[auto-ap.datomic :refer [uri]]))
[auto-ap.datomic :refer [uri]]
[clojure.tools.logging :as log]))
(defn cleanse [e]
(-> e
(update :client/location-matches
(fn [lms]
(map #(assoc % :location-match/match (first (:location-match/matches %))) lms)))
(update :client/bank-accounts
(fn [bas]
(map (fn [i ba]
(-> ba
(update :bank-account/type :db/ident )
(update :bank-account/sort-order (fn [so] (or so i)))))
(range) bas)))))
(defn get-all []
(->> (d/q '[:find (pull ?e [* {:client/address [*]}])
(->> (d/q '[:find (pull ?e [*
{:client/address [*]}
{:client/bank-accounts [* {:bank-account/type [*]}]}])
:where [?e :client/name]]
(d/db (d/connect uri)))
(map first)
(map (fn [c]
(update c :client/location-matches
(fn [lms]
(map #(assoc % :location-match/match (first (:location-match/matches %))) lms)))))
(map (fn [c]
(update c :client/bank-accounts
(fn [bas]
(map (fn [i ba]
(-> ba
(update :bank-account/type :db/ident )
(update :bank-account/sort-order (fn [so] (or so i)))))
(range) bas)))))
(map cleanse)
))
(defn get-by-id [id]
(->>
(d/query (-> {:query {:find ['(pull ?e [*])]
(d/query (-> {:query {:find ['(pull ?e [* {:client/bank-accounts [* {:bank-account/type [*]}]}])]
:in ['$ '?e]
:where [['?e]]}
:args [(d/db (d/connect uri)) id]}
))
(first)
(first)
(cleanse)
#_(map first)
#_(first)))

View File

@@ -67,7 +67,7 @@
new-id-set (set (map :db/id vs))
retract-ids (filter (complement new-id-set) ids)]
(cond-> []
true (into (map (fn [i] [:db/retractEntity i ]) retract-ids))
true (into (map (fn [i] [:db/retract e a i ]) retract-ids))
(seq vs) (conj {:db/id e
a vs})))})}]])
@@ -308,7 +308,8 @@
{:db/ident :invoice/automatically-paid-when-due
:db/doc "Whether this invoice should be marked as paid when it's due"
:db/valueType :db.type/boolean
:db/cardinality :db.cardinality/one}]]}}
:db/cardinality :db.cardinality/one}]]}
:auto-ap/fix-reset-rels {:txes-fn `reset-function}}
]
(println "Conforming database...")
(c/ensure-conforms conn norms-map)

View File

@@ -65,7 +65,8 @@
{
:location_match
{:fields {:location {:type 'String}
:match {:type 'String}}}
:match {:type 'String}
:id {:type :id}}}
:client
{:fields {:id {:type :id}
@@ -526,7 +527,8 @@
:invoice_payment_amount {:fields {:invoice_id {:type :id}
:amount {:type 'Float}}}
:edit_location_match {:fields {:location {:type 'String}
:match {:type 'String}}}
:match {:type 'String}
:id {:type :id}}}
:edit_forecasted_transaction {:fields {:identifier {:type 'String}
:id {:type :id}

View File

@@ -3,7 +3,8 @@
[datomic.api :as d]
[auto-ap.datomic :refer [uri remove-nils]]
[auto-ap.graphql.utils :refer [->graphql assert-admin can-see-client?]]
[clojure.string :as str]))
[clojure.string :as str]
[clojure.tools.logging :as log]))
(defn assert-client-code-is-unique [code]
(when (seq (d/query {:query {:find '[?id]
@@ -76,6 +77,7 @@
:forecasted-transaction/amount (:amount %)}
)
(:forecasted_transactions edit_client))]]
_ (log/info "upserting client" transactions)
result @(d/transact (d/connect uri) transactions)]
(-> result :tempids (get id) (or id) d-clients/get-by-id
(update :client/location-matches

View File

@@ -44,7 +44,7 @@
:graphql {:token token
:query-obj {:venia/queries [[:client
[:id :name :code :email :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits :locations [:location-matches [:location :match]] [:bank-accounts [:id :code :number :bank-name :bank-code :check-number :name :routing :type :sort-order :visible :yodlee-account-id :locations :include-in-reports] ]
[:id :name :code :email :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits :locations [:location-matches [:id :location :match]] [:bank-accounts [:id :code :number :bank-name :bank-code :check-number :name :routing :type :sort-order :visible :yodlee-account-id :locations :include-in-reports] ]
[:address [:street1 :street2 :city :state :zip]]
[:forecasted-transactions [:id :amount :identifier :day-of-month]]]]
[:vendor
@@ -75,7 +75,7 @@
(fn [{:keys [db]} [_ token user]]
{:graphql {:token token
:query-obj {:venia/queries [[:client
[:id :name :code :matches :locations :week-a-debits :week-a-credits :week-b-debits :week-b-credits [:location-matches [:location :match]]
[:id :name :code :matches :locations :week-a-debits :week-a-credits :week-b-debits :week-b-credits [:location-matches [:id :location :match]]
[:address [:street1 :street2 :city :state :zip]]
[:bank-accounts [:id :code :number :bank-name :bank-code :check-number :name :routing :type :sort-order :visible :yodlee-account-id :locations :include-in-reports] ]
[:forecasted-transactions [:id :amount :identifier :day-of-month]]]]

View File

@@ -4,7 +4,7 @@
[auto-ap.subs :as subs]
[auto-ap.views.components.address :refer [address-field]]
[auto-ap.views.components.layouts :refer [side-bar]]
[auto-ap.views.utils :refer [dispatch-event horizontal-field nf]]
[auto-ap.views.utils :refer [dispatch-event horizontal-field nf multi-field]]
[cljs-time.coerce :as coerce]
[cljs-time.core :as t]
[clojure.spec.alpha :as s]
@@ -12,9 +12,11 @@
(re-frame/reg-sub
::can-submit
:<- [::forms/form ::form]
(fn [{:keys [data status]} _]
(s/valid? ::entity/client data)))
:<- [::new-client-request]
(fn [r _]
true
#_(s/valid? ::entity/client r)))
(re-frame/reg-sub
::new-client-request
@@ -24,8 +26,8 @@
:name (:name new-client-data)
:code (:code new-client-data) ;; TODO add validation can't change
:email (:email new-client-data)
:locations (:locations new-client-data)
:matches (vec (:matches new-client-data))
:locations (mapv :location (:locations new-client-data))
:matches (mapv :match (:matches new-client-data))
:location-matches (:location-matches new-client-data)
:week-a-credits (:week-a-credits new-client-data)
:week-a-debits (:week-a-debits new-client-data)
@@ -51,7 +53,7 @@
:id id
:sort-order sort-order
:visible visible
:locations (vec locations)
:locations (mapv :location locations)
:yodlee-account-id (when yodlee-account-id
(js/parseInt yodlee-account-id))
:code (if new?
@@ -65,9 +67,19 @@
(re-frame/reg-event-fx
::editing
(fn [{:keys [db]} [_ client-id]]
(println (get (:clients db) client-id))
{:db (-> db
(forms/stop-form ::form)
(forms/start-form ::form (get (:clients db) client-id)))}))
(forms/start-form ::form (-> (get (:clients db) client-id)
(update :locations #(mapv (fn [l] {:location l}) %))
(update :matches #(mapv (fn [l] {:match l}) %))
(update :bank-accounts
(fn [bas]
(mapv (fn [ba]
(update ba :locations (fn [ls]
(map (fn [l] {:location l})
ls))))
bas))))))}))
(re-frame/reg-event-fx
::save-new-client
@@ -77,25 +89,22 @@
(let [new-client-req @(re-frame/subscribe [::new-client-request])
user @(re-frame/subscribe [::subs/token])]
(if (s/valid? ::entity/client new-client-req)
{:db (-> new-client-form
(assoc :status :loading)
(assoc :error nil))
:graphql
{:token user
:query-obj {:venia/operation {:operation/type :mutation
:operation/name "EditClient"}
:venia/queries [{:query/data [:edit-client
{:edit-client new-client-req}
[:id :name :code :email :locations :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits
[:location-matches [:location :match]]
[:address [:street1 :street2 :city :state :zip]]
[:forecasted-transactions [:id :amount :identifier :day-of-month]]
[:bank-accounts [:id :number :check-number :name :code :bank-code :bank-name :routing :type :visible :yodlee-account-id :sort-order :locations]]]]}]}
:on-success [::save-complete]
:on-error [::forms/save-error ::new-client]}}
{:db new-client-form}))))
{:db (-> new-client-form
(assoc :status :loading)
(assoc :error nil))
:graphql
{:token user
:query-obj {:venia/operation {:operation/type :mutation
:operation/name "EditClient"}
:venia/queries [{:query/data [:edit-client
{:edit-client new-client-req}
[:id :name :code :email :locations :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits
[:location-matches [:location :match :id]]
[:address [:street1 :street2 :city :state :zip]]
[:forecasted-transactions [:id :amount :identifier :day-of-month]]
[:bank-accounts [:id :number :check-number :name :code :bank-code :bank-name :routing :type :visible :yodlee-account-id :sort-order :locations]]]]}]}
:on-success [::save-complete]
:on-error [::forms/save-error ::form]}})))
(re-frame/reg-event-db
::save-complete
(fn [db [_ client]]
@@ -104,48 +113,6 @@
(assoc-in [:clients (:id (:edit-client client))] (update (:edit-client client) :bank-accounts (fn [bas] (->> bas (sort-by :sort-order) vec)))))))
(re-frame/reg-event-db
::add-new-location
[(forms/in-form ::form) (re-frame/path [:data])]
(fn [client _]
(-> client
(update :locations conj (:location client))
(dissoc :location))))
(re-frame/reg-event-db
::add-location-to-bank-account
[(forms/in-form ::form) (re-frame/path [:data])]
(fn [client [_ which-account]]
(println client which-account)
(-> client
(update-in [:bank-accounts which-account :locations] #(conj (or % #{}) (get-in client [:bank-accounts which-account :location-select])))
(update-in [:bank-accounts which-account] dissoc :location-select))))
(re-frame/reg-event-db
::add-new-match
[(forms/in-form ::form) (re-frame/path [:data])]
(fn [client _]
(-> client
(update :matches conj (:match client))
(update :matches set)
(dissoc :match))))
(re-frame/reg-event-db
::remove-match
[(forms/in-form ::form) (re-frame/path [:data])]
(fn [client [_ which]]
(-> client
(update :matches set)
(update :matches disj which))))
(re-frame/reg-event-db
::add-new-location-match
[(forms/in-form ::form) (re-frame/path [:data])]
(fn [client _]
(-> client
(update :location-matches conj (:location-match client))
(dissoc :location-match))))
(re-frame/reg-event-db
::add-forecasted-transaction
[(forms/in-form ::form) (re-frame/path [:data])]
@@ -168,17 +135,6 @@
[]
%)))))
(re-frame/reg-event-db
::remove-location-match
[(forms/in-form ::form) (re-frame/path [:data])]
(fn [client [_ i]]
(-> client
(update :location-matches (fn [lm]
(->> lm
(map vector (range))
(filter (fn [[index item]]
(not= index i)))
(map second)))))))
(re-frame/reg-event-db
::add-new-bank-account
@@ -203,10 +159,7 @@
[(forms/in-form ::form) (re-frame/path [:data :bank-accounts])]
(fn [bank-accounts [_ index]]
(vec (concat (take index bank-accounts)
(drop (inc index) bank-accounts)))
#_(update db :bank-accounts
(fn [bas]
(filter #(not= (:code %) code) bas)))))
(drop (inc index) bank-accounts)))))
(re-frame/reg-event-db
::sort-swapped
@@ -362,23 +315,19 @@
[:label.label "Locations"]
[:div.control
[:p.help "If this account is location-specific, add the valid locations"]
[:div.field.has-addons
[:p.control
[:div.select
[raw-field
[:select {:type "select"
:style {:width "7em"}
:field [:bank-accounts sort-order :location-select]
:allow-nil? true
:spec (set (get-in new-client [:locations]))}
(map (fn [l] ^{:key l} [:option {:value l} l]) (get-in new-client [:locations]))]]]]
[:p.control {:on-click (dispatch-event [::add-location-to-bank-account sort-order]) } [:a.button "Add"]]]]
(if-let [locations (seq (get-in new-client [:bank-accounts sort-order :locations]))]
[:ul
(for [location locations]
^{:key location} [:li location ])]
[:i "This account applies to all locations"])]
[raw-field
[multi-field {:type "multi-field"
:field [:bank-accounts sort-order :locations]
:template [[:select.select {:type "select"
:style {:width "7em"}
:allow-nil? true
:field [:location]
:spec (set (map :location (get-in new-client [:locations])))}
[:<>
[:option ""]
[:<> (map (fn [l] ^{:key (:location l)}
[:option {:value (:location l)} (:location l)])
(get-in new-client [:locations]))]]]]}]]]]
[:div.field
[:label.checkbox
[raw-field
@@ -394,168 +343,138 @@
(defn new-client-form []
(let [{new-client :data } @(re-frame/subscribe [::forms/form ::form])
{:keys [form field raw-field error-notification submit-button ]} client-form
{:keys [form-inline field raw-field error-notification submit-button ]} client-form
next-week-a (if (is-week-a? (t/now))
"This week"
"Next week")
next-week-b (if (is-week-a? (t/now))
"Next week"
"This week")]
(println "ID" (:id new-client))
[side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])}
[form {:title "Add client"}
[field "Name"
[:input.input {:type "text"
:field [:name]
:spec ::entity/name
}]]
^{:key (:id new-client)}
[:div ;; div is important for actually unmounting for now
(form-inline {:title "Add client"}
[:<>
(field "Name"
[:input.input {:type "text"
:field [:name]
:spec ::entity/name
}])
[:div.field
[:p.help "Client code"
]
(if (:id new-client)
[:div.control
(:code new-client)]
[:div.control
[raw-field
[:input.input {:type "code"
:field :code
:spec ::entity/code}]]])]
[:div.field
[:p.help "Client code"
]
(if (:id new-client)
[:div.control
(:code new-client)]
[:div.control
(raw-field
[:input.input {:type "code"
:field :code
:spec ::entity/code}])])]
[field "Email"
[:input.input {:type "email"
:field :email
:spec ::entity/email}]]
(field "Email"
[:input.input {:type "email"
:field :email
:spec ::entity/email}])
[:div.field
[:p.help "Matches"]
[:div.control
[:div.field.has-addons
[:p.control
[raw-field
[:input.input {:type "text"
:field :match}]]]
[:p.control [:button.button.is-primary {:on-click (dispatch-event [::add-new-match])} "Add"]]]]
[:ul
(for [match (:matches new-client)]
^{:key match} [:li match [:a {:on-click (dispatch-event [::remove-match match])} [:span.icon [:span.fa.fa-times]]]])]]
[:h2.subtitle.is-5 "Name matches"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :matches
:template [[:input.input {:field [:match]
:placeholder "Harry's burger joint"
:style { :width "15em"}}]]}])]
[:div.field
[:p.help "Locations"]
[:div.control
[:div.field.has-addons
[:p.control
[raw-field
[:input.input {:type "text"
:field :location}]]]
[:p.control [:button.button.is-primary {:on-click (dispatch-event [::add-new-location])} "Add"]]]
[:ul
(for [location (:locations new-client)]
^{:key location} [:li location ])]]]
[:h2.subtitle "Locations"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :locations
:allow-change? false
:template [[:input.input {:field [:location]
:maxlength 2
:style { :width "4em"}}]]}])]
[:div.field
[:p.help "Location matches"]
[:div.control
[:div.field.has-addons
[:p.control
[raw-field
[:input.input {:type "text"
:placeholder "San Jose"
:field [:location-match :match]}]]]
[:p.control
[raw-field
[:input.input {:type "text"
:placeholder "DT"
:field [:location-match :location]}]]]
[:p.control [:button.button.is-primary {:on-click (dispatch-event [::add-new-location-match])} "Add"]]]
[:ul
(for [[index {:keys [location match]}] (map vector (range) (:location-matches new-client))]
^{:key index} [:li match "->" location [:a {:on-click (dispatch-event [::remove-location-match index])} [:span.icon
[:span.fa.fa-times]]]])]]]
[:h2.subtitle "Location Matches"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :location-matches
:template [[:input.input {:field [:match]
:placeholder "Downtown"
:style { :width "15em"}}]
[:input.input {:field [:location]
:placeholder "DT"
:maxlength 2
:style { :width "4em"}}]]}])]
[:div {:style {:padding-bottom "0.75em" :padding-top "0.75em"}}
[:h2.subtitle "Address"]
[address-field {:field [:address]
:event [::forms/change ::form]
:subscription new-client}]]
[:div {:style {:padding-bottom "0.75em" :padding-top "0.75em"}}
[:h2.subtitle "Address"]
[address-field {:field [:address]
:event [::forms/change ::form]
:subscription new-client}]]
[:h2.subtitle "Bank accounts"]
(for [bank-account (sort-by :sort-order (:bank-accounts new-client))]
^{:key (:sort-order bank-account)}
[bank-account-card new-client bank-account (= 0 (:sort-order bank-account)) (= (:sort-order bank-account) (dec (count (:bank-accounts new-client))))])
[:h2.subtitle "Bank accounts"]
(for [bank-account (sort-by :sort-order (:bank-accounts new-client))]
^{:key (:sort-order bank-account)}
[bank-account-card new-client bank-account (= 0 (:sort-order bank-account)) (= (:sort-order bank-account) (dec (count (:bank-accounts new-client))))])
[:div.columns
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :credit])} "Add Credit Account"]]
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :check])} "Add Checking Account"]]
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :cash])} "Add Cash Account"]]]
[:div.columns
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :credit])} "Add Credit Account"]]
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :check])} "Add Checking Account"]]
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :cash])} "Add Cash Account"]]]
[:h2.subtitle "Cash flow"]
[:label.label (str "Week A (" next-week-a ")")]
[field "Regular Credits"
[:input.input {:type "number"
:placeholder "500.00"
:field [:week-a-credits]
:step "0.01"}]]
[field "Regular Debits"
[:input.input {:type "number"
:placeholder "150.00"
:field [:week-a-debits]
:step "0.01"}]]
[:label.label (str "Week B (" next-week-b ")")]
[field "Regular Credits"
[:input.input {:type "number"
:placeholder "1000.00"
:field [:week-b-credits]
:step "0.01"}]]
[field "Regular Debits"
[:input.input {:type "number"
:placeholder "250.00"
:field [:week-b-debits]
:step "0.01"}]]
[:div.field
[:label.label "Forecasted transactions"]
[:div.control
[horizontal-field
nil
[:h2.subtitle "Cash flow"]
[:label.label (str "Week A (" next-week-a ")")]
[field "Regular Credits"
[:input.input {:type "number"
:placeholder "500.00"
:field [:week-a-credits]
:step "0.01"}]]
[field "Regular Debits"
[:input.input {:type "number"
:placeholder "150.00"
:field [:week-a-debits]
:step "0.01"}]]
[:label.label (str "Week B (" next-week-b ")")]
[field "Regular Credits"
[:input.input {:type "number"
:placeholder "1000.00"
:field [:week-b-credits]
:step "0.01"}]]
[field "Regular Debits"
[:input.input {:type "number"
:placeholder "250.00"
:field [:week-b-debits]
:step "0.01"}]]
[:div.field
[:label.label "Forecasted transactions"]
[:p.control
[:p.help "Identifier"]
[raw-field
[:input.input {:type "text"
:placeholder "Identifier"
:field [:new-forecasted-transaction :identifier]}]]]
[:p.control
[:p.help "Day of month"]
[raw-field
[:input.input {:type "number"
:placeholder "Day of month"
:step "1"
:field [:new-forecasted-transaction :day-of-month]}]]]
[:p.control
[:p.help "Amount"]
[raw-field
[:input.input {:type "number"
:placeholder "250.00"
:field [:new-forecasted-transaction :amount]
:step "0.01"}]]]
[:a.button {:on-click (dispatch-event [::add-forecasted-transaction])} "Add"]]]
[:ul
(for [forecasted-transaction (:forecasted-transactions new-client)]
^{:key (or (:id forecasted-transaction)
(:temp-id forecasted-transaction))}
[:li (:identifier forecasted-transaction) ": " (nf (:amount forecasted-transaction)) " on day " (:day-of-month forecasted-transaction) " of the month"
[:a {:on-click (dispatch-event [::remove-forecasted-transaction (or (:id forecasted-transaction)
(:temp-id forecasted-transaction))])} [:span.icon [:span.fa.fa-times]]]])]]
[error-notification]
[submit-button "Save"]]]))
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :forecasted-transactions
:template [[:input.input {:type "text"
:placeholder "Identifier"
:field [ :identifier]}]
[:input.input {:type "number"
:placeholder "Day of month"
:step "1"
:field [:day-of-month]}]
[:input.input {:type "number"
:placeholder "250.00"
:field [:amount]
:step "0.01"}]]}])]]
(error-notification)
(submit-button "Save")])]]))

View File

@@ -12,7 +12,8 @@
[goog.i18n.NumberFormat.Format]
[cljs-time.core :as t]
[clojure.string :as str]
[goog.crypt.base64 :as base64])
[goog.crypt.base64 :as base64]
[reagent.core :as r])
(:import
(goog.i18n NumberFormat)
(goog.i18n.NumberFormat Format)))
@@ -100,6 +101,85 @@
(defn with-keys [children]
(map-indexed (fn [i c] ^{:key i} c) children))
(def css-transition-group
(reagent/adapt-react-class js/ReactTransitionGroup.CSSTransition))
(defn appearing [{:keys [visible? enter-class exit-class timeout]} & children ]
(let [final-state (reagent/atom visible?)]
(fn [{:keys [visible?]} & children]
[css-transition-group {:in visible? :class-names {:exit exit-class :enter enter-class} :timeout timeout :onEnter (fn [] (reset! final-state true )) :onExited (fn [] (reset! final-state false))}
(if (or @final-state visible?)
(first children)
[:span])])))
(defn multi-field [{:keys [override-key override-value-key change-event default-key data value template on-change allow-change?]} ]
(let [value-repr (r/atom (mapv
(fn [x]
(assoc x :key (random-uuid) :new? false))
value))]
(fn [{:keys [override-key override-value-key change-event default-key data value template on-change allow-change?]} ]
(let [value @value-repr
already-has-new-row? (= [:key :new?] (keys (last value)))
value (if already-has-new-row?
value
(conj value {:key (random-uuid)
:new? true}))]
[:div
(for [[i override] (map vector (range) value)
:let [is-disabled? (if (= false allow-change?)
(not (boolean (:new? override)))
nil)]]
^{:key (:key override)}
[:div.level
[:div.level-left
[:div.level-item
(if (:new? override)
[:div.icon.is-medium {:class (if (not= i (dec (count value)))
"has-text-info")}
[:i.fa.fa-plus]]
[:div.icon.is-medium])]
[:<> (for [[idx template] (map vector (range ) template)]
^{:key idx}
[:div.level-item
[update template 1 assoc
:value (get-in override (get-in template [1 :field]))
:disabled is-disabled?
:on-change (fn [e]
(reset! value-repr
(into []
(filter (fn [r]
(not= [:key :new?] (keys r)))
(assoc-in value (into [i] (get-in template [1 :field])) (.. e -target -value ) ))))
(on-change (mapv
(fn [v]
(dissoc v :new? :key))
@value-repr)))]])
]
[:div.level-item
[:a.button
{:disabled is-disabled?
:on-click (fn []
(when-not is-disabled?
(reset! value-repr (into []
(filter (fn [{:keys [key ] :as v}]
(not= key (:key override)))
value)))
(on-change (mapv
(fn [v]
(dissoc v :new? :key))
@value-repr))))}
[:span.icon [:span.icon-remove]]]]
]])]))))
(defmethod do-bind "select" [dom {:keys [field allow-nil? subscription event class value spec] :as keys} & rest]
(let [field (if (keyword? field) [field] field)
event (if (keyword? event) [event] event)
@@ -158,6 +238,20 @@
keys (dissoc keys :field :subscription :event :spec)]
(into [dom keys] (with-keys rest))))
(defmethod do-bind "multi-field" [dom {:keys [field event subscription class spec] :as keys} & rest]
(let [field (if (keyword? field) [field] field)
event (if (keyword? event) [event] event)
keys (assoc keys
:on-change (fn [value]
(println value)
(re-frame/dispatch (conj (conj event field) 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 "typeahead-entity" [dom {:keys [field event text-event subscription class spec match->text] :as keys} & rest]
(let [field (if (keyword? field) [field] field)
@@ -309,24 +403,11 @@
[:div.field-body]
(with-keys (map (fn [x] [:div.field x]) controls)))])
(def css-transition-group
(reagent/adapt-react-class js/ReactTransitionGroup.CSSTransition))
(def date-picker
(do
(reagent/adapt-react-class (aget js/DatePicker "default"))))
(defn appearing [{:keys [visible? enter-class exit-class timeout]} & children ]
(let [final-state (reagent/atom visible?)]
(fn [{:keys [visible?]} & children]
[css-transition-group {:in visible? :class-names {:exit exit-class :enter enter-class} :timeout timeout :onEnter (fn [] (reset! final-state true )) :onExited (fn [] (reset! final-state false))}
(if (or @final-state visible?)
(first children)
[:span])])))
(defn local-now []
(t/to-default-time-zone (t/now)))