I'm trying to remake a guessing game engine - changing it from Clojure to ClojureScript. Here is the original .clj file for backend behaviour (note that this does not handle the actual game logic, that's in a separate file).

(ns reagent-2024.app-server
  (:require
   [clojure.pprint]
   [clojure.string :as str]
   [compojure.coercions   :refer [as-int]]
   [compojure.core        :refer [ANY defroutes GET POST]] 
   [compojure.route           :as route]
   [ring.adapter.jetty    :refer [run-jetty]]
   [ring.middleware.defaults  :as middleware]
   [ring.middleware.cookies   :as cookies]
   [ring.middleware.multipart-params :as multi]
   [ring.mock.request         :as mock]
   [ring.util.response        :as ring
    :refer [not-found redirect response status]]
   [simple-server.simple-game :as game]
   [byte-transforms           :as transforms]
   [hiccup.page            :refer [html5 include-js include-css]]))

(defn index-html []
  (html5
   [:head
    [:meta {:charset "UTF-8"}]
    [:meta {:name "viewport"
            :content "width=device-width, initial-scale=1"}]
    (include-css "/css/style.css")]
   [:body
    [:h2 "Text being served by the app-server Ring handler."]
    [:div {:id "app"}]
    (include-js "/cljs-out/dev-main.js")]))


;; (defn random-api []
;;   (println "I've been called!")
;;   {:status 200
;;    :body (pr-str {:lucky-number (rand-int 1000)
;;                   :a-set #{1 "foo" :baz [::a ::b]}})
;;    :headers {"Content-Type" "application/edn"}})


(defn set-session-cookie [response username]
  (ring/set-cookie response "token" (transforms/hash username :crc32) {:max-age 3600})) ; Set cookie with a maximum age of 1 hour

(defn get-session-cookie [request]
  (get-in request [:cookies "token" :value]))


(defn new-game-handler [request]
  (when (game/new-game! (get-session-cookie request))
    (response (str "OK - start guessing at /guess/?guess=N"))))


(defn form-sanitizer [input]
  (str/lower-case (str/trim input)))


(defn valid-login? [token password] ;; placeholder login logic...
  (or (and (= token "foo") (= password "bar"))
      (and (= token "admin") (= password "123"))
      (and (= token "user") (= password "pass"))
      (and (= token "egg") (= password "man"))
      (and (= token "test") (= password "test"))))

;; tried to combine these functions but the login page is very fragile
(defn login-page-handler []
  (response (slurp "resources/public/login.html")))
;; (defn guess-page-handler []
;;   (response (slurp "res/guess.html")))




(defn login-handler [request]
  (let [params (:form-params request)
        username (form-sanitizer (get params "username"))
        password (get params "password")]
    (if (valid-login? username password)
      (-> (redirect "/new-game")
          (set-session-cookie username))
      ;; (redirect (str "/new-game/" token))
      (response "Invalid login. Try again."))))

(defn guess-handler [guess user-hash]
  (condp = (game/guess-answer guess user-hash)
    nil       (-> (response  "You need to supply a guess with /guess?guess=N")
                  (status 400))
    :game-win  (response  (str "Congratulations! You win!"))
    :game-over (response  "Too bad! You ran out of tries!")
    :too-low   (response  (str "Too low! "  (game/get-remaining-tries user-hash) " tries remaining!"))
    :too-high  (response  (str "Too high! " (game/get-remaining-tries user-hash) " tries remaining!"))))


(defroutes site-routes 
 
  (GET  "/login"             []                          (login-page-handler))
  (POST "/login"             request                     (login-handler request))

  (GET  "/new-game"          request                     (new-game-handler request))
  ;; (GET  "/guess:token"    [token]                     (guess-page-handler token))
  (GET  "/guess"             [guess :<< as-int :as request]  (guess-handler guess (get-session-cookie request)))
  (ANY  "*"                  []                          (not-found (str "Sorry, no such URI on this server!\n\n
                                                                         Navigate to /new-game to start the guessing game.\n
                                                                         If you're in the middle of a game, go to /guess/?guess=N instead."))))

(defn add-content-type-htmltext-header [handler]
  (fn [request]
    (let [response (handler request)]
      (-> response
          (ring/header "Content-Type" "text/html")))))


(defn redirect-to-login-middleware
  "If a login cookie (at present, can be anything) is not found, redirects user to the login page."
  [handler]
  (fn [request]
    (let [token (get-session-cookie request)]
      (clojure.pprint/pprint request)
      (if (nil? token)
        (-> (handler (assoc request :uri "/login"))  ; Redirect to /login
            (ring/header "Content-Type" "text/html"))
        (handler request)))))


(def handler
  (-> site-routes
      (redirect-to-login-middleware)
      (middleware/wrap-defaults middleware/api-defaults)
      (add-content-type-htmltext-header)
      (multi/wrap-multipart-params)
      (cookies/wrap-cookies)))

(comment
  (handler (mock/request :get "/new-game"))
  (handler (mock/request :get "/guess?guess=3"))
  (handler (mock/request :get "/dunno")))

;; #_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
;; (defonce server
;;   (future (run-jetty #'handler {:port 3000 :join? false})))


Here is the current state of the ClojureScript side.

(ns ^:figwheel-hooks simple-server.core
  (:require [clojure.string :as str]
            [ajax.core :refer [GET]]
            [goog.dom :as gdom]
            [goog.events :as events]
            [goog.history.EventType :as HistoryEventType]
            [reagent.core :as r :refer [atom]]
            [reagent.dom :as rdom]
            [reitit.core :as reitit])
  (:import goog.History))


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

(def guess-text "Guess the number I'm thinking of!")

(defonce app-state (atom {:text guess-text}))

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

(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]])

(defn mount [el]
  (rdom/render [guess-page] 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
(mount-app-element)

;; specify reload hook with ^:after-load metadata
(defn ^:after-load on-reload []
  (mount-app-element)
  ;; (swap! app-state update-in [:__figwheel_counter] inc)
)

Can you tell me exactly what I need to put where?