(require '[reagent.core :as r] '[reagent.dom :as rdom] '[ajax.core :refer [POST]] '[clojure.string :as string]) (def state (r/atom {:view "sign-in-form" :message nil})) (defn clj->json [ds] (.stringify js/JSON (clj->js ds))) (defn parse-url-params [url] (let [url-obj (js/URL. url) params (.-searchParams url-obj)] (reduce (fn [acc key] (assoc acc key (.get params key))) {} (js/Array.from (.keys params))))) (def redirect-url (-> (.. js/window -location -href) (parse-url-params) (get "url"))) (defn http-post-sign-in-handler [response] (when-let [error-code (get-in response [:error :code])] (swap! state assoc-in [:message] {:txt (get-in response [:error :message]) :kind "error"}) (when (= error-code 22) ;; error code 22 - must reset password (js/setTimeout #(aset js/location "href" (str "/chpw" (when redirect-url (str "?url=" redirect-url)))) 1000))) (when-let [username (get-in response [:result :data :username])] (if redirect-url ;; redirect to url provided in ?url parameter (do (swap! state assoc :message {:txt (str username " signed in OK") :kind "success"}) (aset js/location "href" redirect-url)) ;; display list of services to choose from (swap! state assoc :message {:txt (str username " signed in OK") :kind "success"} :wss (get-in response [:result :data :wss]) :adminuis (get-in response [:result :data :adminuis]) :host (get-in response [:result :data :host]) :view "signed-in-ok")))) (defn on-sign-in-submit [e] (.preventDefault e) (let [username (.-value (js/document.getElementById "sin-username")) password (.-value (js/document.getElementById "sin-password"))] (when (not-empty (:message @state)) (swap! state assoc-in [:message] nil)) (POST "/rpc" {:body (clj->json {:jsonrpc "2.0" :id 0 :method "getCookie" :params {:options {:debug false} :data {:username username :password password}}}) :response-format :json :keywords? true :handler http-post-sign-in-handler}))) (defn sign-in-form [] [:<> [:h1 {:class "text-center my-2.5"} "Sign in to continue"] [:div {:class "flex items-center justify-center"} [:form {:class "p-5 bg-gray-100 rounded shadow shadow-gray-300 xl:w-2/12 lg:w-4/12 md:w-6/12 w-8/12"} [:input {:id "sin-username" :class "block p-2.5 w-full border border-solid border-gray-300 rounded-t focus:outline-0 hover:outline-0 focus:outline-0 hover:outline-0 focus:shadow-md" :required "" :placeholder "Username" :type "text"}] [:input {:id "sin-password" :class "block p-2.5 w-full border border-t-0 border-solid border-gray-300 rounded-b focus:outline-0 hover:outline-0 focus:shadow-md" :required "", :placeholder "Password" :type "password"}] [:button {:class "p-2.5 my-2.5 w-full text-lg text-white bg-blue-500 hover:bg-blue-600 rounded", :type "submit" :on-click on-sign-in-submit} "Sign in"] ;; [:label ;; {:class "block font-bold text-gray-600"} ;; [:input {:class "pl-5 mr-2" :type "checkbox"}] ;; "Remember me"] ]]]) (defn list-of-services [] (when (and (:wss @state) (:adminuis @state) (:host @state)) (let [wss (:wss @state) adminuis (:adminuis @state) host (:host @state)] [:div {:class "flex items-center justify-center"} [:ul {:class "space-y-4 text-gray-500 list-disc list-inside dark:text-gray-600"} [:li [:span {:class "font-semibold"} "Admin Services:"] [:ul {:class "ps-5 mt-2 space-y-1 list-disc list-inside"} (for [adminui adminuis] [:li [:a {:href (str "https://" adminui "." host)} (string/capitalize adminui)]])]] [:li [:span {:class "font-semibold"} "Websites:"] [:ul {:class "ps-5 mt-2 space-y-1 list-disc list-inside"} (for [ws wss] [:li [:a {:href (str "https://" ws "." host)} (string/upper-case ws)]])]]]]))) (defn error-message [msg] [:p {:class "my-2.5 p-2.5 bg-red-200 border border-solid border-red-300 text-center text-red-900 rounded"} msg]) (defn success-message [msg] [:p {:class "my-2.5 p-2.5 bg-green-200 border border-solid border-green-300 text-center text-green-900 rounded"} msg]) (defn message [] [:div {:class "flex items-center justify-center"} [:div {:class "xl:w-2/12 lg:w-4/12 md:w-6/12 w-8/12"} (when-let [message (:message @state)] (cond (= (:kind message) "error") [error-message (:txt message)] (= (:kind message) "success") [success-message (:txt message)]))]]) (defn my-component [] [:div (cond (= (:view @state) "sign-in-form") [:<> [sign-in-form] [message]] (= (:view @state) "signed-in-ok") [:<> [message] [list-of-services]])]) (rdom/render [my-component] (.getElementById js/document "app"))