(ns auto-ap.views.components.layouts (:require [auto-ap.events :as events] [auto-ap.forms :as forms] [auto-ap.forms.builder :as form-builder] [auto-ap.routes :as routes] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.subs :as subs] [auto-ap.views.components.modal :as modal] [auto-ap.views.components.search :as search] [auto-ap.views.components.vendor-dialog :as vendor-dialog] [auto-ap.views.utils :refer [active-when appearing dispatch-event-with-propagation login-url]] [bidi.bidi :as bidi] [clojure.string :as str] [re-frame.core :as re-frame] [reagent.core :as r] [vimsical.re-frame.cofx.inject :as inject])) (defn navbar-drop-down [{:keys [ class]} _] (let [!child (r/atom nil)] (r/create-class {:reagent-render (fn [{:keys [header id]} child] (let [menu-active? @(re-frame/subscribe [::subs/menu-active? id])] [:div { :class (str "navbar-item has-dropdown " (when menu-active? "is-active " ) " " class) :ref (fn [n] (reset! !child n)) :tab-index 0 :onBlur (fn [_] (js/setTimeout (fn [] (println @!child) (println (.-activeElement js/document)) (when-not (.contains @!child (.-activeElement js/document)) (re-frame/dispatch [::events/toggle-menu id]))) 2))} [:a {:class "navbar-link login" :on-click (fn [e] (.preventDefault e) (.stopPropagation e) (re-frame/dispatch [::events/toggle-menu id]) true)} header] [appearing {:visible? menu-active? :enter-class "appear" :exit-class "disappear" :timeout 200} [:div {:class "navbar-dropdown"} [:div child]]]]))}))) (defn login-dropdown [] (let [user (re-frame/subscribe [::subs/user])] (if @user [navbar-drop-down {:header [:span [:span.icon [:i.fa.fa-user]] [:span (:user/name @user)]] :id ::account} [:div [:a {:class "navbar-item" :href (bidi/path-for auto-ap.ssr-routes/only-routes :company)} "My company"] [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::vendor-dialog/started {}])} "New Vendor"] [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::vendor-dialog/edit {}])} "Edit Vendor"] (when (= "admin" (:user/role @user)) [:a {:class "navbar-item" :href (bidi/path-for routes/routes :admin)} "Administration"]) [:hr {:class "navbar-divider"}] [:a.navbar-item {:on-click (fn [e] (.preventDefault e) (re-frame/dispatch [::events/logout]))} "Logout"]]] [:a.navbar-item {:href (login-url)} "Login"]))) (re-frame/reg-sub ::client-search (fn [db] (::client-search db))) (re-frame/reg-sub ::matching-clients :<- [::subs/clients] :<- [::forms/form ::client-search] (fn [[clients {{client-search :value} :data}]] (if (empty? client-search) clients (if-let [exact-match (first (filter (fn [client] (= (str/lower-case (:code client)) (str/lower-case client-search))) clients))] [exact-match] (filter (fn [client] (or (str/includes? (str/lower-case (:code client)) (str/lower-case client-search)) (str/includes? (str/lower-case (:name client)) (str/lower-case client-search)))) clients))))) (re-frame/reg-event-fx ::client-searched [(re-frame/inject-cofx ::inject/sub [::matching-clients])] (fn [{::keys [matching-clients]}] {:dispatch-n [[::events/swap-client (first matching-clients)] [::events/toggle-menu ::select-client]]})) (defn client-dropdown [] (let [client (re-frame/subscribe [::subs/client]) matching-clients @(re-frame/subscribe [::matching-clients])] [navbar-drop-down {:header (str "Company: " (if @client (:name @client) "All")) :id ::select-client} [:div [:a {:class "navbar-item" :on-click (fn [] (re-frame/dispatch [::events/toggle-menu ::select-client]) (re-frame/dispatch [::forms/form-closing ::client-search]) (re-frame/dispatch [::events/swap-client nil]))} "All" ] [:hr {:class "navbar-divider"}] [form-builder/builder {:id ::client-search :submit-event [::client-searched]} [form-builder/raw-field-v2 {:field :value} [:input.input.navbar-item {:placeholder "Company name" :auto-focus true}]]] (for [{:keys [name id] :as client} (take 8 matching-clients)] ^{:key id } [:a {:class "navbar-item" :on-click (fn [] (re-frame/dispatch [::events/toggle-menu ::select-client]) (re-frame/dispatch [::events/swap-client client])) } name])]])) (defn navbar [] (let [navbar-menu-shown? (r/atom false)] (fn [ap] (let [user (re-frame/subscribe [::subs/user]) clients (re-frame/subscribe [::subs/clients]) is-initial-loading @(re-frame/subscribe [::subs/is-initial-loading?])] [:nav {:class "navbar has-shadow is-fixed-top is-grey"} [:div {:class "container"} [:div {:class "navbar-brand"} [:a {:class "navbar-item", :href "../"} [:img {:src "/img/logo.png"}]] [:div {:class "navbar-burger burger", :data-target "navMenu" :on-click (fn [] (swap! navbar-menu-shown? #(not %)))} [:span] [:span] [:span]]] [:div.navbar-menu {:id "navMenu" :class (if @navbar-menu-shown? "is-active" "")} (when-not is-initial-loading [:div.navbar-start [:a.navbar-item {:class [(active-when ap = :index)] :href (bidi/path-for routes/routes :index)} "Home" ] [:a.navbar-item {:class [(active-when ap #{:unpaid-invoices :paid-invoices})] :href (bidi/path-for routes/routes :unpaid-invoices)} "Invoices" ] [:a.navbar-item {:class [(active-when ap = :payments)] :href (bidi/path-for routes/routes :payments)} "Payments" ] (when (= "admin" (:user/role @user)) [:a.navbar-item {:class [(active-when ap = :sales-orders)] :href (bidi/path-for routes/routes :sales-orders)} "POS" ]) [:a.navbar-item {:class [(active-when ap = :transactions)] :href (bidi/path-for routes/routes :transactions)} "Transactions" ] (when (not= "manager" (:user/role @user)) [:a.navbar-item {:class [(active-when ap = :ledger)] :href (bidi/path-for routes/routes :ledger)} "Ledger" ])]) (when-not is-initial-loading [:div.navbar-end (when (> (count @clients) 1) [client-dropdown]) ])] (when-not is-initial-loading [login-dropdown])] (when (= "admin" (:user/role @user)) [:div {:style {:position "fixed" :top "4px" :right "8px"}} [search/search-button ]])])))) (defn appearing-side-bar [{:keys [visible?]} ] [appearing {:visible? visible? :enter-class "slide-in-right" :exit-class "slide-out-right" :timeout 500} [:aside {:class "column is-4 aside menu" :style {:height "calc(100vh - 46px)" :overflow "auto"}} (into [:div.sub-main {} ] (r/children (r/current-component)))]]) (defn side-bar-layout [{:keys [side-bar main bottom right-side-bar]}] (let [ap @(re-frame/subscribe [::subs/active-page]) client @(re-frame/subscribe [::subs/client])] [:div [modal/global-modal] [navbar ap] [:div {:class "columns has-shadow", :style {:margin-bottom "0px" :height "calc(100vh - 46px)" } :id "mail-app" } [:aside {:class "column aside menu is-2 " } [:div.main.left-nav [:div side-bar ]]] [:div {:class "column messages hero " :style { :overflow "auto" }, :id "message-feed"} ^{:key (str "active-page-" (:name client))} [:div.inbox-messages (when-let [error @(re-frame/subscribe [::subs/page-failure])] [:div.notification.is-warning.animated.fadeInUp error]) main]] (when right-side-bar right-side-bar) ] [:div bottom] [:div#dz-hidden]])) (defn side-bar [{:keys [on-close]} children] [:div [:a.delete.is-pulled-right {:on-click on-close}] [:div children]]) (defn loading-layout [] [side-bar-layout {:main [:div.has-text-centered.hero.is-fullheight.is-vertically-centered.is-centered [:div.hero-body [:div.container [:div.column.is-4.is-offset-4.has-text-centered [:div.loader.is-loading.is-active.big.is-centered]]]]]}])