Here is my current frontend code:

(ns ^:figwheel-hooks simple-server.core
  (:require [clojure.string :as str]
            [ajax.core :refer [GET POST]]
            [goog.dom :as gdom]
            [goog.events :as events]
            [reagent.core :as r :refer [atom]]
            [reagent.dom :as rdom]
            [reitit.core :as reitit]
            [cljs.core.async :refer [<! >! chan timeout]]
            [cljs-http.client :as http]))
(def site-url "http://localhost:9500")

;; guesser page stuff
(def guess-val      (r/atom 5))

(def guess-text "Guess the number I'm thinking of!")
(defonce app-state (r/atom {:text guess-text}))


(defn slider-on-change-handler [js-event]
  (reset! guess-val (-> js-event .-target .-value)))

(defn multiply [a b] (* a b))


;; login page functions
(defn form-sanitizer [input]
  (str/lower-case (str/trim input)))


;; other considerations
(defn get-app-element []
  (gdom/getElement "app"))

(defonce event-channel (chan 10)) 


;; Frontend event handler to update username and password
(defn update-credentials [field value]
  (swap! app-state assoc field value))


;; Frontend event handler to submit the login form
(defn submit-login []
  (let [{:keys [username password]} @app-state]
    (POST (str site-url "/api/login")
          {:params {:username (form-sanitizer username) :password password}
           :handler (fn [response]
                      (swap! app-state merge
                             {:user-authenticated true
                              :message "Login successful, start guessing!"}))
           :error-handler (fn []
                            (swap! app-state assoc :message "Login failed! Try again."))})))

;; Frontend event handler to submit guesses to the backend
(defn submit-guess []
  (let [guess (@app-state :guess)]
    (POST (str site-url "/api/guess")
          {:params {:guess guess}
           :handler (fn [response]
                      (swap! app-state assoc :message (str "Server says: " response)))
           :error-handler (fn []
                            (swap! app-state assoc :message "Error submitting guess."))})))

;; Login component
(defn login-form [] 
    [:div.login-form
               [:h1 "Login"]
               [:input {:type "text"
                        :placeholder "Username"
                        :on-change #(update-credentials :username (-> % .-target .-value))}]
               [:input {:type "password"
                        :placeholder "Password"
                        :on-change #(update-credentials :password (-> % .-target .-value))}]
               [:button {:on-click submit-login} "Login"]
               [:div.message (@app-state :message)]])




(defn guessing-game []
  [:div.guessing-game
   [:h3 "Guess the number I'm thinking of!"]
   [:input {:type "number"
            :value (@app-state :guess)
            :on-change #(swap! app-state assoc :guess (-> % .-target .-value))}]
   [:button {:on-click submit-guess} "Submit Guess"]
   [:div.message (@app-state :message)]])


(defn guess-page []
  [:div
   [:h1 "Guessing Game"]
   [:h3 (:text @app-state)]
   [:div {:class "slidecontainer"}
    [:input {:type  "range"
             :id    "MyRange1"
             :min   1
             :max   10
             :value 5
             :on-change slider-on-change-handler}]]
   [:h3 @guess-val]])

;; Conditional rendering based on authentication
(defn app-root []
  (if (@app-state :user-authenticated)
    [guessing-game]
    [login-form]))

(defn mount-app []
  (rdom/render [app-root] (.getElementById js/document "app")))

(defn ^:after-load on-reload []
  ;; Re-mount the app after code reloading occurs
  (mount-app))

;; Initial mounting of the app
(mount-app)


I would like the HTTP requests to work using channels, similar to the following code:

(ns ^:figwheel-hooks reagent-2024.core
  (:require-macros [cljs.core.async.macros :refer [go]])
  (:require
   [goog.dom :as gdom]
   [reagent.core :as reagent]
   [reagent.dom :as rdom]
   [cljs.core.async :refer [<! >! chan timeout]]
   [cljs-http.client :as http]))

;; This command will cause our printlns to also show up in the console's log,
;; which can sometimes be useful.
(enable-console-print!)

;;;;  AJAX, or asynchronous javascript XmlHttpRequest
;;;;  or making our SPA's "live".

;; First we need an endpoint: see app_server.clj
;; Now, a manual example
(def resp (atom nil))
(go
  (let [r (<! (http/get "http://localhost:9500/api/random"))]
    (reset! resp r)))


;; Let us declare our state globally:
(defonce the-counter (reagent/atom 0))

;; Now let us create a communication channel which our
;; UI can sent event to.

(defonce event-channel (chan 10))

(defn send-event! [e]
  (go (>! event-channel e)))

;; And imagine there is a global event handler
;; which knows how to route events around.
(declare dispatch-event!)

(defonce global-handler
  (go
    (while true
      (let [e (<! event-channel)]
        (dispatch-event! e)))))

;; Wrap this in a nice asynchronous function
(defn fetch-remote-data []
  (go
    (let [resp (<! (http/get "http://localhost:9500/api/random"))]
      ;; Ignore error handling for the moment
      (dispatch-event! {:type :reset :number (get-in resp [:body :lucky-number])}))))


;; Now let's write the dispatcher:
(defn dispatch-event! [e]
  (case (:type e)
    :fetch       (fetch-remote-data)
    :reset       (reset! the-counter (:number e))
    (println "Don't know how to handle event: " e)))

(defn simple-button []
    [:div
     [:center
      [:h1 "Simple button example"]
      [:input {:type :button
               :class :button
               :value "Push me!"
               :on-click #(dispatch-event! {:type :fetch})}]
      [:div#the-text @the-counter]]])

;; OK - now we need a way to abstract away the "what" of the
;; button push.  Remember core.async?

(defn get-app-element []
  (gdom/getElement "app"))

(defn mount [el]
  (rdom/render [simple-button] el))

(defn mount-app-element []
  (when-let [el (get-app-element)]
    (mount el)))

;; conditionally start your application based on the presence of an "app" element
;; this is particularly helpful for testing this ns without launching the app
(mount-app-element)

;; specify reload hook with ^:after-load metadata
(defn ^:after-load on-reload []
  (mount-app-element)
  ;; optionally touch your app-state to force rerendering depending on
  ;; your application
  ;; (swap! app-state update-in [:__figwheel_counter] inc)
)