(ns auto-ap.ssr.search (:require [auto-ap.graphql.utils :refer [can-see-client?]] [auto-ap.solr :as solr] [auto-ap.ssr.utils :refer [html-response modal-response]] [auto-ap.time :as atime] [clojure.string :as str] [com.brunobonacci.mulog :as mu] [auto-ap.ssr.components :as com] [auto-ap.ssr.svg :as svg])) (defn try-cleanse-date [d] (try (or (some-> (atime/parse-utc d atime/normal-date) (atime/unparse atime/solr-date)) (some-> (atime/parse-utc d atime/iso-date) (atime/unparse atime/solr-date)) d) (catch Exception _ d))) (defn try-parse-number [n] (if (re-find #"^[\-]?\d+\.\d+$" n) (str (with-precision 2 (some-> n (Double/parseDouble) bigdec (.setScale 2 java.math.RoundingMode/HALF_UP) (double)))) n)) (defn q->solr-q [q] (let [matches (re-seq #"(?:\".*?\"|\S)+" q)] (str/join " AND " (->> matches (map (fn [m] (cond (= "payment" m) "type:payment" (= "invoice" m) "type:invoice" (= "transaction" m) "type:transaction" (= "journal-entry" m) "type:journal-entry" :else (str "_text_:\"" (try-parse-number (try-cleanse-date m)) "" \")))))))) (defn search-results [q id] (into [] (filter (fn [d] (can-see-client? id (first (:client_id d))))) (solr/query solr/impl "invoices" {"query" (q->solr-q q) "fields" "id, date, amount, type, description, number, client_code, client_id, vendor_name"}))) (defn search-results* [q id] (let [results (search-results q id)] [:div (if (seq results) [:div.flex.gap-8.flex-col (for [doc results] (com/card {} [:div.flex.flex-col.gap-4 [:div.flex.items-center.p-2.gap-4.bg-gray-50.dark:bg-gray-800 [:div.h-8.w-8.p-2 (cond (= "transaction" (:type doc)) svg/bank (= "invoice" (:type doc)) svg/accounting-invoice-mail (= "payment" (:type doc)) svg/payments (= "journal-entry" (:type doc)) svg/receipt :else nil)] (clojure.string/capitalize (:type doc)) (com/pill {:color :primary} "client: " (:client_code doc)) (com/pill {:color :secondary} "amount: $" (first (:amount doc))) (when-let [vendor-name (first (:vendor_name doc))] (com/pill {:color :yellow} "vendor: " vendor-name)) [:div (com/link {:href (str "/" (cond (= "invoice" (:type doc)) "invoices" (= "transaction" (:type doc)) "transactions" (= "journal-entry" (:type doc)) "ledger" :else "payments") "/?exact-match-id=" (:id doc)) :target "_blank"} [:div.h-8.w-8.p-2 svg/external-link])]] [:div.px-4.pb-2 [:span [:strong (atime/unparse (atime/parse (:date doc) atime/solr-date) atime/normal-date)] ": " (str (or (first (:description doc)) (first (:number doc))))]]]))] [:div.block "No results found."])])) (defn dialog-contents [request] (if-let [q (get (:form-params request) "q")] (html-response (search-results* q (:identity request))) (modal-response (com/modal {} (com/modal-card {:class "w-full h-full"} [:div.p-2 "Search"] [:div#search.overflow-auto.space-y-6.p-2.w-full (com/text-input {:id "search-input" :type "search" :placeholder "5/5/2034 Magheritas" :name "q" :hx-post "/search" :hx-trigger "keyup changed delay:300ms, search" :hx-target "#search-results" :hx-indicator "#search" :value (:q (:params request)) :autofocus true}) [:i.text-sm.text-gray-600.dark:text-gray-50 "Try dates, numbers, vendors. To filter to specific type, use 'invoice', 'transaction', 'journal-entry', 'payment'."] #_[:style ".htmx-request #search-results {display: none} .htmx-request .htmx-indicator { display: block !important; }"] [:div#search-results] [:div.loader.is-loading.big.htmx-indicator]] nil)))))