       (assoc :email "Email is empty")
 
       (when-let [email (:email person)]
-        (nil? (re-find email-regex email)))
+        (and (seq email)
+             (nil? (re-find email-regex email))))
       (assoc :email "Email is not valid")
 
       (nil? (:age person))
       (assoc :age "Age is not set"))))
 
+(defn validate-idea
+  "Build map of {key error} pairs, where each {error} relates to idea.{key}"
+  [idea]
+  (cond-> {}
+    ;; TODO: user has signed
+
+    (empty? (:title idea))
+    (assoc :title "Title cannot be blank.")
+
+    (when-let [title (:title idea)]
+      (and (seq title)
+           (some (comp #{title} :title) @db/ideas)))
+    (assoc :title "Title must be unique")
+
+    (empty? (:category idea))
+    (assoc :category "Category must be set.")))
+
 (defn validate-user!
   "Update errors atom, and return true if there were any errors."
   [doc]
   (let [errors (validate-user @doc)]
+    (swap! doc assoc :errors errors)
+    (empty? errors)))
+
+(defn validate-idea!
+  "Update errors atom, and return true if there were any errors."
+  [doc]
+  (let [errors (validate-idea @doc)]
+    (prn errors)
     (swap! doc assoc :errors errors)
     (empty? errors)))
 

     :on-change #(swap! idea-doc assoc-in [:category]
                        (-> % .-target .-value))}
    [:option
     {:value "" :disabled true :selected true}
     "Pick a category..."]
    (for [c @db/categories]
      [:option {:value c :key (symbol c)} c])]])

  [:div.row
   [:div.col
    [:input.form-control {:field type :id id :placeholder label}]]])

(defn error-field [key]
  [:div.row
   [:div.col-md-2]
   [:div.col-md-5
    [:div.alert.alert-danger
     {:field :alert :id (str ":errors." (name key))}]]])

;;; COMPONENTS

