(ns auto-ap.ssr.company-dropdown (:require [auto-ap.datomic :refer [conn pull-many]] [auto-ap.graphql.utils :refer [cleanse-query strip-special]] [auto-ap.logging :as alog] [auto-ap.solr :as solr] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.hx :as hx] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils :refer [html-response]] [bidi.bidi :as bidi] [clojure.data.json :as json] [clojure.string :as str] [datomic.api :as dc] [hiccup2.core :as hiccup] [iol-ion.query :refer [can-see-client?]])) (defn dropdown-search-results* [{:keys [options]}] [:ul (for [{:keys [id name group]} options] [:li [:div {:class "flex items-center pl-2 rounded hover:bg-green-100 dark:hover:bg-green-600"} (if group [:a {:href "#" :class "w-full py-2 ml-2 text-sm font-medium text-gray-900 rounded dark:text-gray-300" :hx-put (bidi/path-for ssr-routes/only-routes :active-client :request-method :put) :hx-target "#company-dropdown" :hx-headers (hx/json {"x-clients" (pr-str [:group group])}) "@click" (format "globalClientSelection={group: %s}" (hx/json group)) :hx-swap "outerHTML" :hx-trigger "click"} name] [:a {:href "#" :class "w-full py-2 ml-2 text-sm font-medium text-gray-900 rounded dark:text-gray-300" :hx-put (bidi/path-for ssr-routes/only-routes :active-client :request-method :put) :hx-target "#company-dropdown" :hx-headers (format "{\"x-clients\": \"[%d]\"}" id) "@click" (format "globalClientSelection={selected: [%d]}" id) :hx-swap "outerHTML" :hx-trigger "click"} name])]])]) (defn get-clients [identity query] (let [raw-query (not-empty (strip-special query)) cleansed-query (not-empty (cleanse-query query)) cleansed-search-query (str "name:(" cleansed-query ")") exec-search (fn [] (for [n (pull-many (dc/db conn) [:client/name :db/id] (for [{:keys [id name]} (solr/query solr/impl "clients" {"query" cleansed-search-query "fields" "id, name"}) :let [client-id (Long/parseLong id)] :when (can-see-client? identity client-id)] client-id))] {:id (:db/id n) :name (:client/name n)}))] (cond (str/starts-with? query "g:") [{:group (subs query 2) :name (str "All clients matching " (subs query 2))}] raw-query (let [exact-code-matches (for [n (pull-many (dc/db conn) [:client/name :db/id] (for [client-id (map first (dc/q '[:find ?e :in $ ?code :where [?e :client/code ?code]] (dc/db conn) query)) :when (can-see-client? identity client-id)] client-id))] {:id (:db/id n) :name (:client/name n)})] (or (seq exact-code-matches) (exec-search))) cleansed-query (exec-search)))) (defn dropdown-search-results [{:keys [identity] :as request}] (html-response (dropdown-search-results* {:options (get-clients identity (get (:query-params request) "search-text"))}))) (defn dropdown [{:keys [client-selection client identity clients]}] [:div#company-dropdown {:x-data (hx/json {}) :class "shrink-0"} [:script (hiccup/raw "localStorage.setItem(\"last-client-id\", \"" (:db/id client) "\")" "\n" "localStorage.setItem(\"last-selected-clients\", " (json/write-str (json/write-str client-selection)) #_(cond (:group client-selection) (:group client-selection) (:selected client-selection) (:selected client-selection) :else client-selection) ")")] [:div [:button#company-dropdown-button {:class "text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2.5 text-center inline-flex items-center whitespace-nowrap dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" "x-tooltip.on.click" "{content: ()=>$refs.tooltip.innerHTML, theme: 'light', onMount(i) { htmx.process(i.popper); }, allowHTML: true, interactive:true}" :type "button"} [:span {:class "truncate max-w-[10rem] sm:max-w-[14rem]"} (cond (= :mine client-selection) "My Companies" (= :all client-selection) "All Companies" (and client (= 1 (count clients))) (:client/name client) :else (str (count clients) " Companies"))] [:div.w-4.h-4.ml-2.shrink-0 svg/drop-down]] [:template#company-dropdown-list {:x-ref "tooltip"} [:div {:class "w-[300px]" "x-init" "$refs.company.focus()"} [:div {:class "p-3"} [:label {:for "input-group-search", :class "sr-only"} "Search"] [:div {:class "relative"} [:div {:class "absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none"} [:div.w-5.h-5.text-gray-500.dark:text-gray-400 svg/search]] [:input#company-search {:placeholder "Company name" :x-ref "company" :name "search-text" :class "block w-full p-2 pl-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" :autoFocus true :tab-index -1 :hx-trigger "keyup changed delay:500ms, search" :hx-get (bidi/path-for ssr-routes/only-routes :company-dropdown-search-results) :hx-target "#company-search-results" :hx-swap "innerHTML"}]] [:input#company-search-value {:type "hidden" :name "x-clients"}]] [:div.divide-y.divide-gray-100 [:div#company-search-results {:class "h-48 px-3 pb-3 overflow-y-auto text-sm text-gray-700 dark:text-gray-200"}] (when (= "admin" (:user/role identity)) [:div {:class "flex items-center pl-2 rounded hover:bg-green-100 dark:hover:bg-green-600"} [:button {:class "w-full py-2 ml-2 text-sm font-medium text-gray-900 rounded dark:text-gray-300" :hx-put (bidi/path-for ssr-routes/only-routes :active-client :request-method :put) :hx-target "#company-dropdown" "@click" "globalClientSelection=\"mine\"" :hx-headers "{\"x-clients\": \":mine\"}" :hx-swap "outerHTML" :hx-trigger "click"} "Mine"]]) [:div {:class "flex items-center pl-2 rounded hover:bg-green-100 dark:hover:bg-green-600"} [:button {:class "w-full py-2 ml-2 text-sm font-medium text-gray-900 rounded dark:text-gray-300" :hx-put (bidi/path-for ssr-routes/only-routes :active-client :request-method :put) :hx-target "#company-dropdown" "@click" "globalClientSelection=\"all\"" :hx-headers "{\"x-clients\": \":all\"}" :hx-swap "outerHTML" :hx-trigger "click"} "All"]]]]] [:script {:lang "text/javascript"} (hiccup/raw " function initCompanyDropdown() { var $dropdownTargetEl = document.getElementById('company-dropdown-list'); // set the element that trigger the dropdown menu on click var $dropdownTriggerEl = document.getElementById('company-dropdown-button'); var dropdownOptions = { placement: 'bottom', triggerType: 'click', offsetSkidding: 0, offsetDistance: 10, delay: 300, onHide: () => { }, onShow: () => { document.getElementById('company-search').focus() }, onToggle: () => { } }; var companyDrowdown = new Dropdown($dropdownTargetEl, $dropdownTriggerEl, dropdownOptions); } ")]]]) (defn active-client [{:keys [identity params] :as request}] (assoc (html-response (dropdown {:client-selection (:client-selection request) :clients (:clients request) :client (:client request) :identity identity})) :headers {"hx-trigger" "clientSelected"}))