   (fn [state [_ query]]
     (helpers/set-search-query state query)))
 
-(reg-event-db
+(reg-event-fx
   :search-history
-  (fn [state [_ [query group-id]]]
+  (fn [{state :db :as cofx} [_ [query group-id]]]
     (if query
-      ; TODO
-      (do (sync/chsk-send!
-            [:braid.server/search [query group-id]]
-            15000
-            (fn [reply]
-              (dispatch [:set-page-loading false])
-              (if (:thread-ids reply)
-                (dispatch [:set-search-results [query reply]])
-                (dispatch [:set-page-error true]))))
-          (helpers/set-page-error state false))
-      state)))
+      {:websocket-send
+       (list
+         [:braid.server/search [query group-id]]
+         15000
+         (fn [reply]
+           (dispatch [:set-page-loading false])
+           (if (:thread-ids reply)
+             (dispatch [:set-search-results [query reply]])
+             (dispatch [:set-page-error true]))))
+       :db (helpers/set-page-error state false)}
+      {})))
 
 (reg-event-db
   :add-threads
   (fn [state [_ threads]]
     (helpers/add-threads state threads)))
 
-(reg-event-db
+(reg-event-fx
   :load-recent-threads
-  (fn [state [_ {:keys [group-id on-error on-complete]}]]
-    ; TODO
-    (sync/chsk-send!
-      [:braid.server/load-recent-threads group-id]
-      5000
-      (fn [reply]
-        (if-let [threads (:braid/ok reply)]
-          (dispatch [:add-threads threads])
-          (cond
-            (= reply :chsk/timeout) (on-error "Timed out")
-            (:braid/error reply) (on-error (:braid/error reply))
-            :else (on-error "Something went wrong")))
-        (on-complete (some? (:braid/ok reply)))))
-    state))
-
-(reg-event-db
+  (fn [cofx [_ {:keys [group-id on-error on-complete]}]]
+    {:websocket-send
+     (list
+       [:braid.server/load-recent-threads group-id]
+       5000
+       (fn [reply]
+         (if-let [threads (:braid/ok reply)]
+           (dispatch [:add-threads threads])
+           (cond
+             (= reply :chsk/timeout) (on-error "Timed out")
+             (:braid/error reply) (on-error (:braid/error reply))
+             :else (on-error "Something went wrong")))
+         (on-complete (some? (:braid/ok reply)))))}))
+
+(reg-event-fx
   :load-threads
-  (fn [state [_ {:keys [thread-ids on-complete]}]]
-    ; TODO
-    (sync/chsk-send!
-      [:braid.server/load-threads thread-ids]
-      5000
-      (fn [reply]
-        (when-let [threads (:threads reply)]
-          (dispatch [:add-threads threads]))
-        (when on-complete
-          (on-complete))))
-    state))
+  (fn [cofx [_ {:keys [thread-ids on-complete]}]]
+    {:websocket-send
+     (list
+       [:braid.server/load-threads thread-ids]
+       5000
+       (fn [reply]
+         (when-let [threads (:threads reply)]
+           (dispatch [:add-threads threads]))
+         (when on-complete
+           (on-complete))))}))
 
 (reg-event-db
   :set-channel-results

  (fn [state [_ threads-count]]
    (helpers/set-pagination-remaining state threads-count)))

(reg-event-db
  :threads-for-tag
  (fn [state [_ {:keys [tag-id offset limit on-complete]
                 :or {offset 0 limit 25}}]]
    ; TODO
    (sync/chsk-send!
      [:braid.server/threads-for-tag {:tag-id tag-id :offset offset :limit limit}]
      2500
      (fn [reply]
        (when-let [results (:threads reply)]
          (if (zero? offset)
            ; initial load of threads
            (dispatch [:set-channel-results results])
            ; paging more results in
            (dispatch [:add-channel-results results]))
          (dispatch [:set-pagination-remaining (:remaining reply)])
          (when on-complete (on-complete)))))
    state))

(reg-event-db
  :mark-thread-read
  (fn [state [_ thread-id]]
    ; TODO
    (sync/chsk-send! [:braid.server/mark-thread-read thread-id])
    (helpers/update-thread-last-open-at state thread-id)))

(reg-event-db
  :focus-thread

            [braid.client.state.helpers :as helpers]
            [braid.client.quests.helpers :as quest-helpers]))

; TODO: handle callbacks declaratively too?
(reg-fx :websocket-send (fn [args] (apply sync/chsk-send! args)))

(reg-fx :redirect-to (fn [route] (router/go-to route)))

(defn name->open-tag-id
  "Lookup tag by name in the open group"
