a lot of progress on typeaheads, etc.
This commit is contained in:
@@ -4,4 +4,4 @@
|
||||
4) Permissions per location
|
||||
5) List of payments
|
||||
6) add payment
|
||||
7) add invoice
|
||||
7) add invoice - in progress
|
||||
|
||||
@@ -92,8 +92,6 @@
|
||||
:jar true
|
||||
:compiler {:main auto-ap.core
|
||||
:output-to "resources/public/js/compiled/app.js"
|
||||
:npm-deps {:react-autocomplete "1.8.1"}
|
||||
:install-deps true
|
||||
:optimizations :advanced
|
||||
:closure-defines {goog.DEBUG false}
|
||||
:pretty-print false}}
|
||||
|
||||
18
resources/public/css/font.min.css
vendored
Normal file
18
resources/public/css/font.min.css
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Open Sans Light'), local('OpenSans-Light'), url(/ttf/300.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(/ttf/400.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url(/ttf/700.ttf) format('truetype');
|
||||
}
|
||||
4
resources/public/css/fontawesome.min.css
vendored
Normal file
4
resources/public/css/fontawesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -4,11 +4,10 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Auto AP</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,700" rel="stylesheet">
|
||||
<!-- Bulma Version 0.6.0 -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.0/css/bulma.min.css" integrity="sha256-HEtF7HLJZSC3Le1HcsWbz1hDYFPZCqDhZa9QsCgVUdw=" crossorigin="anonymous" />
|
||||
<title>Integreat</title>
|
||||
<link rel="stylesheet" href="/css/fontawesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
|
||||
<link href="/css/font.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/bulma.min.css" integrity="sha256-HEtF7HLJZSC3Le1HcsWbz1hDYFPZCqDhZa9QsCgVUdw=" crossorigin="anonymous" />
|
||||
|
||||
<style>
|
||||
form.dz { border: 2px dashed lightgray;}
|
||||
|
||||
BIN
resources/public/ttf/300.ttf
Normal file
BIN
resources/public/ttf/300.ttf
Normal file
Binary file not shown.
BIN
resources/public/ttf/400.ttf
Normal file
BIN
resources/public/ttf/400.ttf
Normal file
Binary file not shown.
BIN
resources/public/ttf/700.ttf
Normal file
BIN
resources/public/ttf/700.ttf
Normal file
Binary file not shown.
@@ -126,15 +126,17 @@
|
||||
(assoc (base-graphql args) :select [:%count.*])))))
|
||||
|
||||
(defn import [parsed-invoices companies vendors]
|
||||
(insert-multi!
|
||||
(for [{:keys [total date invoice-number customer-identifier vendor-code] :as row} parsed-invoices]
|
||||
(do
|
||||
(dissoc (assoc row
|
||||
:company-id (:id (parse/best-match companies customer-identifier))
|
||||
:vendor-id (:id (first (filter #(= (:code %) vendor-code) vendors)))
|
||||
:imported false
|
||||
:potential-duplicate false)
|
||||
:vendor-code)))))
|
||||
(->> (insert-multi!
|
||||
(for [{:keys [total date invoice-number customer-identifier vendor-code] :as row} parsed-invoices]
|
||||
(do
|
||||
(dissoc (assoc row
|
||||
:company-id (:id (parse/best-match companies customer-identifier))
|
||||
:vendor-id (:id (first (filter #(= (:code %) vendor-code) vendors)))
|
||||
:imported false
|
||||
:potential-duplicate false)
|
||||
:vendor-code))))
|
||||
|
||||
(map db->clj)))
|
||||
|
||||
(defn apply-payment [invoice-id amount]
|
||||
(j/db-do-prepared (get-conn)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
[auto-ap.db.checks :as checks]
|
||||
[auto-ap.routes.checks :as rchecks]
|
||||
[auto-ap.graphql.users :as gq-users]
|
||||
[auto-ap.graphql.invoices :as gq-invoices]
|
||||
[auto-ap.db.reminders :as reminders]
|
||||
[auto-ap.db.invoices-checks :as invoices-checks]
|
||||
[auto-ap.db.utils :as utils]
|
||||
@@ -141,7 +142,14 @@
|
||||
:name {:type 'String}
|
||||
:role {:type 'String}
|
||||
:companies {:type '(list Int)}}}
|
||||
}
|
||||
|
||||
:add_invoice
|
||||
{:fields {:id {:type 'Int}
|
||||
:invoice_number {:type 'String}
|
||||
:date {:type 'String}
|
||||
:company_id {:type 'Int}
|
||||
:vendor_id {:type 'Int}
|
||||
:total {:type 'Float}}}}
|
||||
|
||||
:mutations
|
||||
{:print_checks {:type :check_result
|
||||
@@ -151,7 +159,11 @@
|
||||
:resolve :mutation/print-checks}
|
||||
:edit_user {:type :user
|
||||
:args {:edit_user {:type :edit_user}}
|
||||
:resolve :mutation/edit-user}}})
|
||||
:resolve :mutation/edit-user}
|
||||
|
||||
:add_invoice {:type :invoice
|
||||
:args {:invoice {:type :add_invoice}}
|
||||
:resolve :mutation/add-invoice}}})
|
||||
|
||||
|
||||
|
||||
@@ -281,10 +293,7 @@
|
||||
(:company_id args)
|
||||
(:bank_account_id args))))
|
||||
|
||||
(defn edit-user [context args value]
|
||||
(Thread/sleep 1000)
|
||||
(->graphql
|
||||
(gq-users/edit-user (:edit_user args))))
|
||||
|
||||
|
||||
(def schema
|
||||
(-> integreat-schema
|
||||
@@ -298,7 +307,8 @@
|
||||
:get-user get-user
|
||||
:get-user-companies get-user-companies
|
||||
:mutation/print-checks print-checks
|
||||
:mutation/edit-user edit-user
|
||||
:mutation/edit-user gq-users/edit-user
|
||||
:mutation/add-invoice gq-invoices/add-invoice
|
||||
:get-vendor get-vendor})
|
||||
schema/compile))
|
||||
|
||||
|
||||
17
src/clj/auto_ap/graphql/invoices.clj
Normal file
17
src/clj/auto_ap/graphql/invoices.clj
Normal file
@@ -0,0 +1,17 @@
|
||||
(ns auto-ap.graphql.invoices
|
||||
(:require [auto-ap.graphql.utils :refer [->graphql]]
|
||||
[auto-ap.db.invoices :as invoices]
|
||||
[auto-ap.time :refer [parse normal-date]]))
|
||||
|
||||
(defn add-invoice [context {{:keys [total invoice_number company_id vendor_id date] :as in} :invoice} value]
|
||||
|
||||
(-> (invoices/insert-multi! [{:invoice-number invoice_number
|
||||
:company-id company_id
|
||||
:vendor-id vendor_id
|
||||
:total total
|
||||
:outstanding-balance total
|
||||
:status "unpaid"
|
||||
:imported true
|
||||
:date (parse date normal-date)}])
|
||||
(first)
|
||||
(->graphql)))
|
||||
@@ -1,8 +1,9 @@
|
||||
(ns auto-ap.graphql.users
|
||||
(:require [auto-ap.db.users :as users]))
|
||||
|
||||
(defn edit-user [user]
|
||||
(users/update! user)
|
||||
(users/get-by-id (:id user)))
|
||||
(:require [auto-ap.db.users :as users]
|
||||
[auto-ap.graphql.utils :refer [->graphql]]))
|
||||
|
||||
(defn edit-user [context args value]
|
||||
(users/update! (:edit_user args))
|
||||
(->graphql
|
||||
(users/get-by-id (:edit_user args))))
|
||||
|
||||
|
||||
40
src/clj/auto_ap/graphql/utils.clj
Normal file
40
src/clj/auto_ap/graphql/utils.clj
Normal file
@@ -0,0 +1,40 @@
|
||||
(ns auto-ap.graphql.utils
|
||||
(:require [clojure.string :as str]
|
||||
[clojure.walk :as walk]))
|
||||
|
||||
|
||||
(defn snake->kebab [s]
|
||||
(str/replace s #"_" "-"))
|
||||
|
||||
(defn kebab [x]
|
||||
(keyword (snake->kebab (name x))))
|
||||
|
||||
(defn kebab->snake [s]
|
||||
(str/replace s #"-" "_"))
|
||||
|
||||
(defn snake [x]
|
||||
(keyword (kebab->snake (name x))))
|
||||
|
||||
(defn ->graphql [m]
|
||||
(walk/postwalk
|
||||
(fn [node]
|
||||
(cond
|
||||
|
||||
(keyword? node)
|
||||
(snake node)
|
||||
|
||||
:else
|
||||
node))
|
||||
m))
|
||||
|
||||
(defn <-graphql [m]
|
||||
(walk/postwalk
|
||||
(fn [node]
|
||||
(cond
|
||||
|
||||
(keyword? node)
|
||||
(kebab node)
|
||||
|
||||
:else
|
||||
node))
|
||||
m))
|
||||
@@ -79,11 +79,7 @@
|
||||
{:status 200
|
||||
:body (pr-str (invoices/get-pending (query-params "company")))
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
(POST "/" {:keys [edn-params]}
|
||||
(invoices/insert-multi! (:rows edn-params))
|
||||
{:status 200
|
||||
:body (pr-str (invoices/get-all))
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
|
||||
(POST "/approve" {:keys [query-params]}
|
||||
(invoices/approve)
|
||||
{:status 200
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
(ns auto-ap.time
|
||||
(:require [clj-time.core :as time]))
|
||||
(:require [clj-time.core :as time]
|
||||
[clj-time.format :as f]))
|
||||
|
||||
(defn local-now []
|
||||
(time/to-time-zone (time/now) (time/time-zone-for-id "America/Los_Angeles")))
|
||||
|
||||
(def normal-date "MM/dd/yyyy")
|
||||
|
||||
(defn parse [v format]
|
||||
(time/from-time-zone (f/parse (f/formatter format) v)
|
||||
(time/time-zone-for-id "America/Los_Angeles")))
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
(re-frame/reg-sub
|
||||
::modal-state
|
||||
(fn [db [_ id]]
|
||||
(println "ID" id)
|
||||
(get (:modal-state db) id)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
|
||||
63
src/cljs/auto_ap/views/components/typeahead.cljs
Normal file
63
src/cljs/auto_ap/views/components/typeahead.cljs
Normal file
@@ -0,0 +1,63 @@
|
||||
(ns auto-ap.views.components.typeahead
|
||||
(:require [reagent.core :as r]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(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
|
||||
(if @selected
|
||||
[:div.input
|
||||
[:div.control
|
||||
[:div.tags.has-addons
|
||||
[:span.tag @text]
|
||||
[:a.tag.is-delete {:on-click (fn [] (select [nil ""]))}]]]]
|
||||
|
||||
[:input.input {:type "text"
|
||||
:field [:vendor]
|
||||
:value @text
|
||||
:on-blur (fn [e]
|
||||
(cond @selected
|
||||
nil
|
||||
|
||||
(#{"" nil} @text)
|
||||
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])]])]))))
|
||||
@@ -9,6 +9,7 @@
|
||||
[auto-ap.views.pages.check :as check]
|
||||
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
||||
[auto-ap.views.components.modal :refer [modal action-modal]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead]]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.events :as events]))
|
||||
|
||||
@@ -190,7 +191,29 @@
|
||||
(re-frame/reg-event-fx
|
||||
::create-invoice
|
||||
(fn [{:keys [db]} _]
|
||||
{}))
|
||||
{:graphql
|
||||
{:token (-> db :user)
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "AddInvoice"}
|
||||
|
||||
:venia/queries [{:query/data [:add-invoice
|
||||
{:invoice @(re-frame/subscribe [::new-invoice])}
|
||||
[:id :total :outstanding-balance :date :invoice-number
|
||||
[:company [:id :name]]
|
||||
[:vendor [:id :name]]
|
||||
]]}]}
|
||||
:on-success [::invoice-created]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::invoice-created
|
||||
(fn [{:keys [db]} [_ result]]
|
||||
{:dispatch [::events/modal-completed ::new-invoice]
|
||||
:db (-> db
|
||||
(update-in [::invoice-page :invoices]
|
||||
(fn [is]
|
||||
(into [(:add-invoice result)]
|
||||
is)))
|
||||
(dissoc ::new-invoice))}))
|
||||
|
||||
(defn print-checks-modal []
|
||||
(let [{:keys [checked]} @(re-frame/subscribe [::invoice-page])
|
||||
@@ -240,55 +263,7 @@
|
||||
:max outstanding-balance
|
||||
: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 []
|
||||
(let [data @(re-frame/subscribe [::new-invoice])
|
||||
|
||||
Reference in New Issue
Block a user