diff --git a/src/cljs/auto_ap/effects.cljs b/src/cljs/auto_ap/effects.cljs index 711247fc..2496e384 100644 --- a/src/cljs/auto_ap/effects.cljs +++ b/src/cljs/auto_ap/effects.cljs @@ -132,6 +132,7 @@ (swap! timeouts dissoc key)) time)))) + (re-frame/reg-fx :graphql (fn [{:keys [query on-success on-error token variables query-obj]}] diff --git a/src/cljs/auto_ap/views/pages/admin/clients.cljs b/src/cljs/auto_ap/views/pages/admin/clients.cljs index 10838371..1265d7ef 100644 --- a/src/cljs/auto_ap/views/pages/admin/clients.cljs +++ b/src/cljs/auto_ap/views/pages/admin/clients.cljs @@ -18,168 +18,140 @@ [auto-ap.routes :as routes] [bidi.bidi :as bidi])) +(re-frame/reg-sub + ::form + (fn [db [_ x]] + (-> db ::forms x))) + +;; TODO PREVENT DUPLICATES! (re-frame/reg-sub ::loading-class (fn [db [_ x]] - (if (get-in db [::loading x]) + (if (= (get-in db [::forms x :status]) "loading") "is-loading" ""))) -(re-frame/reg-event-fx +(defn start-form [db form data] + (assoc-in db [::forms form] {:error nil + :status nil + :data data})) +(defn stop-form [db form] + (update db ::forms dissoc form)) + +(re-frame/reg-event-db ::new - (fn [{:keys [db]} [_ client-id]] - {:db (-> db (assoc-in [:admin :adding-client?] true) - (assoc-in [:admin :new-client] {:new-account {:type :check}}))})) + (fn [db [_ client-id]] + (-> db + (assoc-in [:admin :adding-client?] true) + (start-form ::new-client (assoc {} :new-account {:type :check}))))) + + (re-frame/reg-event-fx ::edit-client-clicked (fn [{:keys [db]} [_ client-id]] {:db (-> db - (assoc-in [:admin :new-client] (assoc (get (:clients db) client-id) :new-account {:type :check})) + (start-form ::new-client (assoc (get (:clients db) client-id) :new-account {:type :check})) (assoc-in [:admin :adding-client? ] true))})) -(re-frame/reg-event-fx - ::save - (fn [{:keys [db]} _] - (let [edited-client (-> (:client @(re-frame/subscribe [::subs/admin])) - (dissoc :location))] - {:db (-> db - (assoc-in [::loading ::save-client] true) - (assoc-in [:admin :client :error] nil)) - :graphql - {:token (-> db :user) - :query-obj {:venia/operation {:operation/type :mutation - :operation/name "EditClient"} - :venia/queries [{:query/data [:edit-client - {:edit-client - (-> edited-client - (update :bank-accounts #(seq (into % (map (fn [ba] (dissoc ba :is-new?)) (:new-bank-accounts edited-client))))) - (dissoc :new-account) - (dissoc :new-bank-accounts) - )} - [:id :name :code :email [:address [:street1 :street2 :city :state :zip]] [:bank-accounts [:id :number :check-number :name :code :bank-code :bank-name :routing]]]]}]} - :on-success [::save-complete] - :on-error [::save-error]}}))) + (re-frame/reg-event-fx ::save-new-client - (fn [{:keys [db]} _] - (let [new-client (-> (:new-client @(re-frame/subscribe [::subs/admin])) - (dissoc :location))] - (if (s/valid? ::entity/client new-client) + [(re-frame/path [::forms ::new-client])] + (fn [{{new-client-data :data :as new-client-form} :db} _] + + (let [new-client-req {:id (:id new-client-data), + :name (:name new-client-data) + :code (:code new-client-data) ;; TODO add validation can't change + :email (:email new-client-data) + :locations (:locations new-client-data) + :address {:street1 (:street1 (:address new-client-data)) + :street2 (:street2 (:address new-client-data)), + :city (:city (:address new-client-data)) + :state (:state (:address new-client-data)) + :zip (:zip (:address new-client-data))} + :bank-accounts (map (fn [{:keys [number name check-number type id code bank-name routing bank-code]}] + {:number number + :name name + :check-number check-number + :type type + :id id + :code (str (:code new-client-data) "-" code) + :bank-name bank-name + :routing routing + :bank-code bank-code}) + (:bank-accounts new-client-data))} + user @(re-frame/subscribe [::subs/token])] + (if (s/valid? ::entity/client new-client-req) - {:db (-> db (assoc-in [::loading ::save-client] true) - (assoc-in [:admin :client :error] nil)) + {:db (-> new-client-form + (assoc :status :loading) + (assoc :error nil)) :graphql - {:token (-> db :user) + {:token user :query-obj {:venia/operation {:operation/type :mutation :operation/name "EditClient"} :venia/queries [{:query/data [:edit-client - {:edit-client - ;; TODO - hard code fields we want - (-> new-client - (update :bank-accounts #(seq (into % (map (fn [ba] (dissoc ba :is-new?)) (:new-bank-accounts new-client))))) - (dissoc :new-account) - (dissoc :new-bank-accounts)) - } - [:id :name :code :email [:address [:street1 :street2 :city :state :zip]] [:bank-accounts [:id :number :check-number :name :code :bank-code :bank-name :routing]]] - ]}]} + {:edit-client new-client-req} + [:id :name :code :email :locations [:address [:street1 :street2 :city :state :zip]] [:bank-accounts [:id :number :check-number :name :code :bank-code :bank-name :routing]]]]}]} :on-success [::save-complete] :on-error [::save-error]}} - {:db db})))) + {:db new-client-form})))) -(re-frame/reg-event-fx +(re-frame/reg-event-db ::save-complete - (fn [{:keys [db]} [_ client]] - - - {:dispatch [::events/modal-completed :auto-ap.views.pages.admin.clients/edit] - :db (-> db - (assoc-in [:admin :adding-client?] false) - (assoc-in [::loading ::save-client] nil) - (update :admin dissoc :new-client) - - - (assoc-in [:admin :client] nil) - (assoc-in [:clients (:id (:edit-client client))] (:edit-client client)))})) + (fn [db [_ client]] + (-> db + (stop-form ::new-client) + (assoc-in [:admin :adding-client?] false) + (assoc-in [:clients (:id (:edit-client client))] (:edit-client client))))) (re-frame/reg-event-db ::save-error + [(re-frame/path [::forms ::new-client])] (fn [db [_ result]] (-> db - (assoc-in [::loading ::save-client] false) - (assoc-in [:admin :client :error] (:message (first result)))))) - -(re-frame/reg-event-db - ::change - (fn [db [_ path value]] - - (assoc-in db (concat [:admin :client] path) - value))) + (assoc :status :error) + (assoc :error (:message (first result)))))) (re-frame/reg-event-db ::change-new + [(re-frame/path [::forms ::new-client :data])] (fn [db [_ path value]] - - (assoc-in db (concat [:admin :new-client] path) - value))) + (println db) + (assoc-in db path value))) -(re-frame/reg-event-fx - ::add-location - (fn [{:keys [db]} _] - (let [client (:client @(re-frame/subscribe [::subs/admin]))] - {:db (-> db - (update-in [:admin :client :locations] conj (:location client)) - (update-in [:admin :client] dissoc :location))}))) - -(re-frame/reg-event-fx +(re-frame/reg-event-db ::add-new-location - (fn [{:keys [db]} _] - (let [client (:new-client @(re-frame/subscribe [::subs/admin]))] - {:db (-> db - (update-in [:admin :new-client :locations] conj (:location client)) - (update-in [:admin :new-client] dissoc :location))}))) + [(re-frame/path [::forms ::new-client :data])] + (fn [client _] + (-> client + (update :locations conj (:location client)) + (dissoc :location)))) -(re-frame/reg-event-fx + +(re-frame/reg-event-db ::add-new-bank-account - (fn [{:keys [db]} _] - (let [client (:client @(re-frame/subscribe [::subs/admin])) - _ (prn (s/explain-data ::entity/bank-account (:new-account client))) - new-bank-account (:new-account client) - new-bank-account (-> new-bank-account - (update :code #(str (:code client) "-" %)) - (update :check-number #(if (seq %) (js/parseInt %) nil)) - (update :yodlee-account-id #(if (seq %) (js/parseInt %) nil)) - (assoc :is-new? true))] - {:db (-> db - (update-in [:admin :client :new-bank-accounts] (fn [bank-accounts] - (conj bank-accounts new-bank-account))) - (update-in [:admin :client :new-account] {:type :check}))}))) - -(re-frame/reg-event-fx - ::add-new-new-bank-account - (fn [{:keys [db]} _] - (let [client (:new-client @(re-frame/subscribe [::subs/admin])) - new-bank-account (:new-account client) - new-bank-account (-> new-bank-account - (update :code #(str (:code client) "-" %)) - (update :check-number #(if (seq %) (js/parseInt %) nil)) - (update :yodlee-account-id #(if (seq %) (js/parseInt %) nil)) - (assoc :is-new? true))] - {:db (-> db - (update-in [:admin :new-client :new-bank-accounts] (fn [bank-accounts] - (conj bank-accounts new-bank-account))) - (update-in [:admin :new-client] dissoc :new-account))}))) + [(re-frame/path [::forms ::new-client :data])] + (fn [{:keys [new-account] :as client} _] + (let [new-account (-> new-account + (update :check-number #(if (seq %) (js/parseInt %) nil)) + (update :yodlee-account-id #(if (seq %) (js/parseInt %) nil)))] + (println new-account) + (-> client + (update :bank-accounts conj new-account ) + (assoc :new-account {:type :check}))))) (re-frame/reg-event-db ::remove-new-bank-account - (fn [db [_ index]] - (update-in db [:admin :new-client :new-bank-accounts] + [(re-frame/path [::forms ::new-client :data])] + (fn [db [_ code]] + (update db :bank-accounts (fn [bas] - (vec (concat (take index bas) - (drop (inc index) bas))))))) + (filter #(not= (:code %) code) bas))))) (defn clients-table [] (let [clients (re-frame/subscribe [::subs/clients]) @@ -200,161 +172,7 @@ [:td (str/join ", " locations)] [:td email]])]])) -(defn clients-modal [] - (let [original-client-code (:code (:client @(re-frame/subscribe [::subs/admin])))] - (fn [] - (let [editing-client (:client @(re-frame/subscribe [::subs/admin]))] - [action-modal {:id ::edit - :title (str "Edit " (:name editing-client)) - :action-text "Save" - :save-event [::save]} - [horizontal-field - [:label.label "Name"] - [:div.control - [bind-field - [:input.input {:type "text" - :field :name - :spec ::entity/name - :event ::change - :subscription editing-client}]]]] - [horizontal-field - [:label.label "Client code"] - [:div.control - [bind-field - [:input.input {:type "code" - :field :code - :disabled (if (str/blank? original-client-code) - "" - "disabled") - :spec ::entity/code - :event ::change - :subscription editing-client}]]]] - - [horizontal-field - [:label.label "Email"] - [:div.control - [bind-field - [:input.input {:type "email" - :field :email - :spec ::entity/email - :event ::change - :subscription editing-client}]]]] - - [horizontal-field - [:label.label "Locations"] - [:div.control - [:div.field.has-addons - [:p.control - [bind-field - [:input.input {:type "text" - :field :location - :event ::change - :subscription editing-client}]]] - [:p.control [:button.button.is-primary {:on-click (dispatch-event [::add-location])} "Add"]]] - [:ul - (for [location (:locations editing-client)] - ^{:key location} [:li location ])]]] - [:h2.subtitle "Address"] - - - [address-field {:field [:address] - :event ::change - :subscription editing-client}] - [:h2.subtitle "Add account"] - [horizontal-field - [:label.label "Acct code"] - [:div.control - [:div.field.has-addons.is-extended - [:p.control [:a.button.is-static (:code editing-client) "-" ]] - [:p.control - [bind-field - [:input.input {:type "code" - :field [:new-account :code] - :spec ::entity/code - :event ::change - :subscription editing-client}]]]]]] - - [horizontal-field - [:label.label "Bank"] - [:div.control - - [bind-field - [:input.input {:placeholder "Bank Name" - :type "text" - :field [:new-account :bank-name] - :event ::change - :subscription editing-client}]]] - [:div.control - - [bind-field - [:input.input {:placeholder "Routing" - :type "text" - :field [:new-account :routing] - :event ::change - :subscription editing-client}]]] - [:div.control - - [bind-field - [:input.input {:placeholder "Code" - :type "text" - :field [:new-account :bank-code] - :event ::change - :subscription editing-client}]]]] - [horizontal-field - [:label.label "Account"] - [:div.control - [bind-field - [:input.input {:placeholder "Nickname" - :type "text" - :field [:new-account :name] - :event ::change - :subscription editing-client}]]] - [:div.control - [bind-field - [:input.input {:placeholder "Acct #" - :type "text" - :field [:new-account :number] - :event ::change - :subscription editing-client}]]] - [:div.control - [bind-field - [:input.input {:placeholder "Check #" - :type "text" - :field [:new-account :check-number] - :event ::change - :subscription editing-client}]]]] - [horizontal-field - [:label.label "Yodlee Account"] - [:div.control - [bind-field - [:input.input {:placeholder "Yodlee Account #" - :type "text" - :field [:new-account :yodlee-account-id] - :event ::change - :subscription editing-client}]]] - [:div.control - [:button.button.is-primary.is-pulled-right {:on-click (dispatch-event [::add-new-bank-account]) - :disabled (if (and (s/valid? ::entity/bank-account (:new-account editing-client)) - (not ((set (map :code (:bank-accounts editing-client))) - (str (:code editing-client) "-" (-> editing-client :new-account :code))))) - "" - "disabled")} "Add"]]] - - - - [:h2.subtitle "Bank Accounts"] - [horizontal-field - nil - [:div.control - [:ul - - (for [{:keys [code name number check-number id]} (:bank-accounts editing-client)] - ^{:key id} [:li code ": " name]) - (for [[index {:keys [name code number check-number]}] (map vector (range) (:new-bank-accounts editing-client))] - ^{:key index} [:li [:strong "* " code ": " name] [:button.button {:on-click (dispatch-event [::remove-new-bank-account index])} [:span.icon [:i.fa.fa-times]]]])]]] - - (when (:saving? editing-client) [:div.is-overlay {:style {"backgroundColor" "rgba(150,150,150, 0.5)"}}])])))) (defn admin-clients-content [] [:div @@ -364,14 +182,11 @@ [:h1.title "Clients"] [:div.is-pulled-right [:a.button.is-primary.is-large {:on-click (dispatch-event [::new])} "New client"]] - [clients-table] - (when editing-client - [clients-modal])])]) + [clients-table]])]) (defn new-client-form [] - (let [new-client (:new-client @(re-frame/subscribe [::subs/admin])) - error (:error (:client @(re-frame/subscribe [::subs/admin])))] + (let [{error :error new-client :data } @(re-frame/subscribe [::form ::new-client])] [:form [:section.section {:style {:padding-bottom "0.75em" :padding-top "0.75em"}} [:h1.title.is-2 "Add client"] @@ -519,7 +334,7 @@ (str (:code new-client) "-" (-> new-client :new-account :code))))) "" "disabled") - :on-click (dispatch-event [::add-new-new-bank-account])} "Add"]]]] + :on-click (dispatch-event [::add-new-bank-account])} "Add"]]]] [:section.section {:style {:padding-bottom "0.75em" :padding-top "0.75em"}} [:h2.subtitle "Bank Accounts"] @@ -529,7 +344,11 @@ [:ul (for [{:keys [code name number check-number id]} (:bank-accounts new-client)] - ^{:key id} [:li code ": " name]) + (if id + ^{:key code} + [:li code ": " name] + ^{:key code} + [:li [:strong "* " code ": " name] [:button.button {:on-click (dispatch-event [::remove-new-bank-account code])} [:span.icon [:i.fa.fa-times]]]])) (for [[index {:keys [name code number check-number]}] (map vector (range) (:new-bank-accounts new-client))] ^{:key index} [:li [:strong "* " code ": " name] [:button.button {:on-click (dispatch-event [::remove-new-bank-account index])} [:span.icon [:i.fa.fa-times]]]])]]]] @@ -545,7 +364,7 @@ "" "disabled") :on-click (dispatch-event [::save-new-client]) - :class (str @(re-frame/subscribe [::loading-class ::save-client]) (when error " animated shake"))} "Save"]])) + :class (str @(re-frame/subscribe [::loading-class ::new-client]) (when error " animated shake"))} "Save"]])) (defn admin-clients-page [] (let [{:keys [adding-client?]} @(re-frame/subscribe [::subs/admin])]