From d69b1f2b81ad212981d6670acfc4a308620002fa Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Mon, 9 Apr 2018 14:25:47 -0700 Subject: [PATCH] a lot of de-duplicating. --- src/cljc/auto_ap/entities/vendors.cljc | 16 +- .../auto_ap/views/pages/admin/vendors.cljs | 301 ++++++++++-------- 2 files changed, 174 insertions(+), 143 deletions(-) diff --git a/src/cljc/auto_ap/entities/vendors.cljc b/src/cljc/auto_ap/entities/vendors.cljc index bb808542..d7e92654 100644 --- a/src/cljc/auto_ap/entities/vendors.cljc +++ b/src/cljc/auto_ap/entities/vendors.cljc @@ -1,20 +1,26 @@ (ns auto-ap.entities.vendors - (:require [clojure.spec.alpha :as s])) + (:require [clojure.spec.alpha :as s] + [clojure.string :as str])) (def email-regex #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$") (s/def ::id int) -(s/def ::name (s/nilable string?)) +(s/def ::identifier (s/nilable string?)) +(s/def ::required-identifier (s/and string? + #(not (str/blank? %)))) + +(s/def ::name ::required-identifier) + (s/def ::email (s/nilable (s/and string? (s/or :is-email #(re-matches email-regex %) :is-empty #(= % ""))))) (s/def ::phone (s/nilable string?)) (s/def ::data (s/nilable string?)) -(s/def ::invoice-reminder-schedule (s/nilable string?)) -(s/def ::primary-contact ::name) +(s/def ::invoice-reminder-schedule (s/nilable #{"Weekly" "Never" nil})) +(s/def ::primary-contact ::identifier) (s/def ::primary-email ::email) (s/def ::primary-phone ::phone) -(s/def ::secondary-contact ::name) +(s/def ::secondary-contact ::identifier) (s/def ::secondary-email ::email) (s/def ::secondary-phone ::phone) diff --git a/src/cljs/auto_ap/views/pages/admin/vendors.cljs b/src/cljs/auto_ap/views/pages/admin/vendors.cljs index 503e5569..122ce9b9 100644 --- a/src/cljs/auto_ap/views/pages/admin/vendors.cljs +++ b/src/cljs/auto_ap/views/pages/admin/vendors.cljs @@ -33,9 +33,54 @@ [:td (::entity/primary-email v)] [:td (::entity/invoice-reminder-schedule v)]])]])) +(defmulti do-bind (fn [_ {:keys [type]}] + + type)) + +(defn danger-for [[dom {:keys [field subscription class] :as keys} & rest]] + (let [keys (assoc keys :class (str class + (when (not (s/valid? field (field subscription))) + " is-danger"))) + keys (dissoc keys :field :subscription)] + (vec (concat [dom keys] rest)))) + + +(defmethod do-bind "radio" [dom {:keys [field subscription class value] :as keys} & rest] + (let [keys (assoc keys + :on-change (dispatch-value-change [::events/change [field]]) + :checked (= (field subscription) value) + :class (str class + (when (not (s/valid? field (field subscription))) + " is-danger"))) + keys (dissoc keys :field :subscription)] + (vec (concat [dom keys] rest)))) + + +(defmethod do-bind :default [dom {:keys [field subscription class] :as keys} & rest] + (let [keys (assoc keys + :on-change (dispatch-value-change [::events/change [field]]) + :value (field subscription) + :class (str class + (when (not (s/valid? field (field subscription))) + " is-danger"))) + keys (dissoc keys :field :subscription)] + (vec (concat [dom keys] rest)))) + +(defn bind-field [all] + (apply do-bind all)) + +(defn horizontal-field [label & controls] + [:div.field.is-horizontal + [:div.field-label + label + ] + (into + [:div.field-body + ] + (map (fn [c] [:div.field c]) controls))]) + (defn edit-dialog [] (let [editing-vendor (:vendor @(re-frame/subscribe [::subs/admin]))] - (println editing-vendor) [:div.modal.is-active [:div.modal-background {:on-click (fn [] (re-frame/dispatch [::events/edit nil]))}] @@ -47,160 +92,140 @@ (str "Add " (or (::entity/name editing-vendor) "")))] [:button.delete {:on-click (fn [] (re-frame/dispatch [::events/edit nil]))}]] [:section.modal-card-body - [:div.field.is-horizontal - [:div.field-label - [:label.label "Name"]] - [:div.field-body - [:div.field - [:div.control - [:input.input {:type "text" :value (::entity/name editing-vendor) - :class (str/join " " (when (not (s/valid? ::entity/name (::entity/name editing-vendor))) - "is-danger")) - :on-change (dispatch-value-change [::events/change [::entity/name]])}]]]]] - [:div.field.is-horizontal - [:div.field-label - [:label.label "Code"]] - [:div.field-body - [:div.field - [:div.control - [:input.input.is-expanded {:type "text" :value (::entity/code editing-vendor) - :on-change (dispatch-value-change [::events/change [::entity/code]])}] - [:p.help "The vendor code is used for invoice parsing. Only one vendor at a time can use a code"]]]] - ] + [horizontal-field + [:label.label "Name"] + [:div.control + [bind-field + [:input.input {:type "text" + :field ::entity/name + :subscription editing-vendor}]]]] + + [horizontal-field + [:label.label "Code"] + [:div.control + + [bind-field + [:input.input.is-expanded {:type "text" + :field ::entity/code + :subscription editing-vendor}]] + [:p.help "The vendor code is used for invoice parsing. Only one vendor at a time can use a code"]]] [:h2.subtitle "Address"] - [:div.field.is-horizontal - [:div.field-label] - [:div.field-body - [:div.field - [:div.control + [horizontal-field + nil + [:div.control [:p.help "Address"] - [:input.input.is-expanded {:type "text" - :placeholder "1700 Pennsylvania Ave" - :value (::entity/address1 editing-vendor) - :on-change (dispatch-value-change [::events/change [::entity/address1]])}]]]]] - [:div.field.is-horizontal - [:div.field-label] - [:div.field-body - [:div.field - [:div.control - - [:input.input.is-expanded {:type "text" - :placeholder "Suite 400" - :value (::entity/address2 editing-vendor) - :on-change (dispatch-value-change [::events/change [::entity/address2]])}]]]]] - [:div.field.is-horizontal - [:div.field-label] - [:div.field-body - [:div.field - [:p.help "City"] - [:div.control - [:input.input.is-expanded {:type "text" - :value (::entity/city editing-vendor) - :placeholder "Cupertino" - :on-change (dispatch-value-change [::events/change [::entity/city]])}]]] - [:div.field - [:div.control - - [:p.help "State"] - [:input.input {:type "email" - :value (::entity/state editing-vendor) - :placeholder "CA" - :on-change (dispatch-value-change [::events/change [::entity/state]])}] - ]] - - [:div.field - [:div.control - [:p.help "Zip"] - [:input.input {:type "phone" - :value (::entity/zip editing-vendor) - :placeholder "95014" - :on-change (dispatch-value-change [::events/change [::entity/zip]])}] - ]]]] + [bind-field + [:input.input.is-expanded {:type "text" + :placeholder "1700 Pennsylvania Ave" + :field ::entity/address1 + :subscription editing-vendor}]]]] + + [horizontal-field + nil + [:div.control + [bind-field + [:input.input.is-expanded {:type "text" + :placeholder "Suite 400" + :field ::entity/address2 + :subscription editing-vendor}]]]] + + [horizontal-field + nil + [:div.control + [:p.help "City"] + [bind-field + [:input.input.is-expanded {:type "text" + :placeholder "Cupertino" + :field ::entity/city + :subscription editing-vendor}]]] + [:div.control + [:p.help "State"] + [bind-field + [:input.input {:type "text" + :placeholder "CA" + :field ::entity/state + :subscription editing-vendor}]]] + [:div.control + [:p.help "Zip"] + [bind-field + [:input.input {:type "text" + :field ::entity/zip + :subscription editing-vendor + :placeholder "95014"}]]]] + [:h2.subtitle "Contact"] - + [horizontal-field + [:label.label "Primary"] + [:div.control.has-icons-left + [bind-field + [:input.input.is-expanded {:type "text" + :field ::entity/primary-contact + :subscription editing-vendor}]] + [:span.icon.is-small.is-left + [:i.fa.fa-user]]] - [:div.field.is-horizontal - [:div.field-label - [:label.label "Primary"]] - [:div.field-body - [:div.field - [:div.control.has-icons-left - [:input.input.is-expanded {:type "text" - :value (::entity/primary-contact editing-vendor) - :on-change (dispatch-value-change [::events/change [::entity/primary-contact]])}] - [:span.icon.is-small.is-left - [:i.fa.fa-user]]]] - [:div.field - [:div.control.has-icons-left + [:div.control.has-icons-left [:span.icon.is-small.is-left [:i.fa.fa-envelope]] - [:input.input {:type "email" - :value (::entity/primary-email editing-vendor) - :class (str/join " " [(when (::entity/primary-email (invalid-fields ::entity/vendor editing-vendor )) - "is-danger")]) - :on-change (dispatch-value-change [::events/change [::entity/primary-email]])}]]] + [bind-field + [:input.input {:type "email" + :field ::entity/primary-email + :subscription editing-vendor}]]] - [:div.field - [:div.control.has-icons-left - [:input.input {:type "phone" - :value (::entity/primary-phone editing-vendor) - :on-change (dispatch-value-change [::events/change [::entity/primary-phone]])}] + [:div.control.has-icons-left + [bind-field + [:input.input {:type "phone" + :field ::entity/primary-phone + :subscription editing-vendor}]] [:span.icon.is-small.is-left - [:i.fa.fa-phone]]]]]] - [:div.field.is-horizontal - [:div.field-label - [:label.label "Secondary"]] - [:div.field-body - [:div.field - [:div.control.has-icons-left - [:input.input.is-expanded {:type "text" - :value (::entity/secondary-contact editing-vendor) - :on-change (dispatch-value-change [::events/change [::entity/secondary-contact]])}] + [:i.fa.fa-phone]]]] + + [horizontal-field + [:label.label "Secondary"] + [:div.control.has-icons-left + [bind-field + [:input.input.is-expanded {:type "text" + :field ::entity/secondary-contact + :subscription editing-vendor}]] [:span.icon.is-small.is-left - [:i.fa.fa-user]]]] - [:div.field - [:div.control.has-icons-left + [:i.fa.fa-user]]] + [:div.control.has-icons-left [:span.icon.is-small.is-left [:i.fa.fa-envelope]] - [:input.input {:type "email" - :value (::entity/secondary-email editing-vendor) - :on-change (dispatch-value-change [::events/change [::entity/secondary-email]])}]]] - - [:div.field - [:div.control.has-icons-left - [:input.input {:type "phone" - :value (::entity/secondary-phone editing-vendor) - :on-change (dispatch-value-change [::events/change [::entity/secondary-phone]])}] + [bind-field + [:input.input {:type "email" + :field ::entity/secondary-email + :subscription editing-vendor}]]] + [:div.control.has-icons-left + [bind-field + [:input.input {:type "phone" + :field ::entity/secondary-phone + :subscription editing-vendor}]] [:span.icon.is-small.is-left - [:i.fa.fa-phone]]]]]] - - [:div.field.is-horizontal - [:div.field-label - [:label.label "Invoice Reminders"]] - [:div.field-body - [:div.field - [:div.control + [:i.fa.fa-phone]]]] + + [horizontal-field + [:label.label "Invoice Reminders"] + [:div.control [:label.radio - [:input {:type "radio" - :name "schedule" - :value "Weekly" - :checked (if (= "Weekly" (::entity/invoice-reminder-schedule editing-vendor)) - "checked" - "") - :on-change (dispatch-value-change [::events/change [::entity/invoice-reminder-schedule]])}] + [bind-field + [:input {:type "radio" + :name "schedule" + :value "Weekly" + :field ::entity/invoice-reminder-schedule + :subscription editing-vendor}]] " Send weekly"] [:label.radio - [:input {:type "radio" - :name "schedule" - :value "Never" - :checked (if (= "Never" (::entity/invoice-reminder-schedule editing-vendor)) - "checked" - "") - :on-change (dispatch-value-change [::events/change [::entity/invoice-reminder-schedule]])}] - " Never"]]]] - ] + [bind-field + [:input {:type "radio" + :name "schedule" + :value "Never" + :field ::entity/invoice-reminder-schedule + :subscription editing-vendor}]] + " Never"]]] + (when (:saving? editing-vendor) [:div.is-overlay {:style {"backgroundColor" "rgba(150,150,150, 0.5)"}}])]