created a typeahead. neat.
This commit is contained in:
@@ -92,6 +92,8 @@
|
|||||||
:jar true
|
:jar true
|
||||||
:compiler {:main auto-ap.core
|
:compiler {:main auto-ap.core
|
||||||
:output-to "resources/public/js/compiled/app.js"
|
:output-to "resources/public/js/compiled/app.js"
|
||||||
|
:npm-deps {:react-autocomplete "1.8.1"}
|
||||||
|
:install-deps true
|
||||||
:optimizations :advanced
|
:optimizations :advanced
|
||||||
:closure-defines {goog.DEBUG false}
|
:closure-defines {goog.DEBUG false}
|
||||||
:pretty-print false}}
|
:pretty-print false}}
|
||||||
|
|||||||
@@ -247,6 +247,53 @@
|
|||||||
background-color:#F5F5F5;
|
background-color:#F5F5F5;
|
||||||
}
|
}
|
||||||
.table { table-layout: fixed }
|
.table { table-layout: fixed }
|
||||||
|
|
||||||
|
.typeahead {
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeahead-menu {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
float: left;
|
||||||
|
min-width: 160px;
|
||||||
|
padding: 5px 0;
|
||||||
|
margin: 2px 0 0;
|
||||||
|
list-style: none;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||||
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||||
|
background-clip: padding-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeahead-suggestion {
|
||||||
|
display: block;
|
||||||
|
padding: 3px 20px;
|
||||||
|
clear: both;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
color: #333333;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.typeahead-suggestion:hover,
|
||||||
|
.typeahead-suggestion:focus,
|
||||||
|
.typeahead-menu:not(:hover) .typeahead-highlighted
|
||||||
|
{
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: 0;
|
||||||
|
background-color: #00d1b2;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
[auto-ap.subs :as subs]
|
[auto-ap.subs :as subs]
|
||||||
[auto-ap.routes :as routes]
|
[auto-ap.routes :as routes]
|
||||||
[auto-ap.effects :as effects]
|
[auto-ap.effects :as effects]
|
||||||
|
[auto-ap.utils :refer [by]]
|
||||||
[venia.core :as v]
|
[venia.core :as v]
|
||||||
[bidi.bidi :as bidi]
|
[bidi.bidi :as bidi]
|
||||||
[goog.crypt.base64 :as b64]
|
[goog.crypt.base64 :as b64]
|
||||||
@@ -35,9 +36,11 @@
|
|||||||
:user token)
|
:user token)
|
||||||
:graphql {:token token
|
:graphql {:token token
|
||||||
:query-obj {:venia/queries [[:company
|
:query-obj {:venia/queries [[:company
|
||||||
[:id :name [:bank-accounts [:id :number :check-number :name]]]]]}
|
[:id :name [:bank-accounts [:id :number :check-number :name]]]]
|
||||||
|
[:vendor
|
||||||
|
[:id :name]]]}
|
||||||
|
|
||||||
:on-success [::received-companies]}}))))
|
:on-success [::received-initial]}}))))
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
::toggle-menu
|
::toggle-menu
|
||||||
@@ -49,19 +52,19 @@
|
|||||||
(fn [{:keys [db]} [_ token user]]
|
(fn [{:keys [db]} [_ token user]]
|
||||||
{:graphql {:token token
|
{:graphql {:token token
|
||||||
:query-obj {:venia/queries [[:company
|
:query-obj {:venia/queries [[:company
|
||||||
[:id :name]]]}
|
[:id :name [:bank-accounts [:id :number :check-number :name]]]]
|
||||||
|
[:vendor
|
||||||
|
[:id :name]]]}
|
||||||
|
|
||||||
:on-success [::received-companies]}
|
:on-success [::received-initial]}
|
||||||
:db (assoc db :user (assoc user :token token))}))
|
:db (assoc db :user (assoc user :token token))}))
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
::received-companies
|
::received-initial
|
||||||
(fn [db [_ {companies :company}]]
|
(fn [db [_ {companies :company vendors :vendor :as x}]]
|
||||||
|
(-> db
|
||||||
(assoc db :companies (reduce (fn [companies company]
|
(assoc :companies (by :id companies) )
|
||||||
(assoc companies (:id company) company))
|
(assoc :vendors (by :id vendors) ))))
|
||||||
{}
|
|
||||||
companies))))
|
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
::swap-company
|
::swap-company
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
(ns auto-ap.views.pages.unpaid-invoices
|
(ns auto-ap.views.pages.unpaid-invoices
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[reagent.core :as r]
|
||||||
|
[clojure.string :as str]
|
||||||
[auto-ap.entities.companies :as company]
|
[auto-ap.entities.companies :as company]
|
||||||
[auto-ap.entities.vendors :as vendor]
|
[auto-ap.entities.vendors :as vendor]
|
||||||
[auto-ap.views.utils :refer [dispatch-event bind-field horizontal-field]]
|
[auto-ap.views.utils :refer [dispatch-event bind-field horizontal-field]]
|
||||||
@@ -238,9 +240,60 @@
|
|||||||
:max outstanding-balance
|
:max outstanding-balance
|
||||||
:step "0.01"}]]]]]])]]])))
|
:step "0.01"}]]]]]])]]])))
|
||||||
|
|
||||||
|
(defn typeahead [{:keys [matches on-change field value]}]
|
||||||
|
(let [text (r/atom (or (second (first (filter #(= (first %) value) matches))) ""))
|
||||||
|
highlighted (r/atom 0)
|
||||||
|
selected (r/atom (first (first (filter #(= (first %) value) matches))))
|
||||||
|
select (fn [[id t]]
|
||||||
|
(reset! selected id)
|
||||||
|
(reset! text t)
|
||||||
|
(println [id t])
|
||||||
|
(when on-change
|
||||||
|
(on-change id)))]
|
||||||
|
(fn [{:keys [matches on-change field value]}]
|
||||||
|
(let [valid-matches (take 5 (for [[[id t :as match] i] (map vector matches (range))
|
||||||
|
:when (str/includes? (.toLowerCase t) (.toLowerCase @text))]
|
||||||
|
match))]
|
||||||
|
[:div.typeahead
|
||||||
|
[:input.input {:type "text"
|
||||||
|
:field [:vendor]
|
||||||
|
:value @text
|
||||||
|
:on-blur (fn [e]
|
||||||
|
(cond @selected
|
||||||
|
nil
|
||||||
|
|
||||||
|
(seq valid-matches)
|
||||||
|
(do (select (first valid-matches))
|
||||||
|
true)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(do (select [nil ""])
|
||||||
|
true))
|
||||||
|
)
|
||||||
|
:on-key-up (fn [e]
|
||||||
|
(if (= 13 (.-keyCode e))
|
||||||
|
(do
|
||||||
|
(select (first valid-matches))
|
||||||
|
false)
|
||||||
|
true))
|
||||||
|
:on-change (fn [e]
|
||||||
|
(reset! highlighted (ffirst valid-matches))
|
||||||
|
(select [nil (.. e -target -value)]))}]
|
||||||
|
(when (and (seq @text)
|
||||||
|
(not @selected)
|
||||||
|
(seq valid-matches))
|
||||||
|
[:div.typeahead-menu
|
||||||
|
[:ul
|
||||||
|
(for [[id t :as match] valid-matches]
|
||||||
|
|
||||||
|
[:li.typeahead-suggestion {:class (if (= id @highlighted)
|
||||||
|
"typeahead-highlighted")
|
||||||
|
:on-mouse-down #(do (println "MATCH" match) (select match))} t])]])]))))
|
||||||
|
|
||||||
(defn new-invoice-modal []
|
(defn new-invoice-modal []
|
||||||
(let [data @(re-frame/subscribe [::new-invoice])
|
(let [data @(re-frame/subscribe [::new-invoice])
|
||||||
change-event [::events/change-form [::new-invoice]]]
|
change-event [::events/change-form [::new-invoice]]]
|
||||||
|
(println data)
|
||||||
[action-modal {:id ::new-invoice
|
[action-modal {:id ::new-invoice
|
||||||
:title "New Invoice"
|
:title "New Invoice"
|
||||||
:action-text "Create"
|
:action-text "Create"
|
||||||
@@ -248,10 +301,11 @@
|
|||||||
[horizontal-field
|
[horizontal-field
|
||||||
[:label.label "Vendor"]
|
[:label.label "Vendor"]
|
||||||
[bind-field
|
[bind-field
|
||||||
[:input.input {:type "text"
|
[typeahead {:matches (map (fn [x] [(:id x) (:name x)]) @(re-frame/subscribe [::subs/vendors]))
|
||||||
:field [:vendor]
|
:type "typeahead"
|
||||||
:event change-event
|
:field [:vendor-id]
|
||||||
:subscription data}]]]
|
:event change-event
|
||||||
|
:subscription data}]]]
|
||||||
[horizontal-field
|
[horizontal-field
|
||||||
[:label.label "Date"]
|
[:label.label "Date"]
|
||||||
[bind-field
|
[bind-field
|
||||||
@@ -263,10 +317,11 @@
|
|||||||
[horizontal-field
|
[horizontal-field
|
||||||
[:label.label "Company"]
|
[:label.label "Company"]
|
||||||
[bind-field
|
[bind-field
|
||||||
[:input.input {:type "text"
|
[typeahead {:matches (map (fn [x] [(:id x) (:name x)]) @(re-frame/subscribe [::subs/companies]))
|
||||||
:field [:company]
|
:type "typeahead"
|
||||||
:event change-event
|
:field [:company-id]
|
||||||
:subscription data}]]]
|
:event change-event
|
||||||
|
:subscription data}]]]
|
||||||
|
|
||||||
[horizontal-field
|
[horizontal-field
|
||||||
[:label.label "Invoice #"]
|
[:label.label "Invoice #"]
|
||||||
|
|||||||
@@ -68,11 +68,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" [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 [selected]
|
||||||
|
(re-frame/dispatch (conj (conj event field) selected)))
|
||||||
|
: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 :default [dom {:keys [field event subscription class spec] :as keys} & rest]
|
(defmethod do-bind :default [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)
|
||||||
_ (println field event dom rest)
|
|
||||||
keys (assoc keys
|
keys (assoc keys
|
||||||
:on-change (dispatch-value-change (conj event field))
|
:on-change (dispatch-value-change (conj event field))
|
||||||
:value (get-in subscription field)
|
:value (get-in subscription field)
|
||||||
|
|||||||
Reference in New Issue
Block a user