Skip to content

Instantly share code, notes, and snippets.

@alexfaber2011
Created August 25, 2015 13:52
Show Gist options
  • Save alexfaber2011/f8937c483668a6d9e7f2 to your computer and use it in GitHub Desktop.
Save alexfaber2011/f8937c483668a6d9e7f2 to your computer and use it in GitHub Desktop.
taste of clojurescript and reagent
(ns informacast-csv.core
(:require [informacast-csv.informormacast-communicator :as communicator]
[informacast-csv.zip-worker :as zip-worker]
[reagent.core :as reagent]
[reagent.session :as session]
[reagent-forms.core :refer [bind-fields]]
[goog.history.EventType :as EventType]
[goog.events :as events]
[secretary.core :as secretary :refer-macros [defroute]])
(:import goog.History))
;; May want to remove in production
(enable-console-print!)
;; -------------------------
;; Navigation
(session/put! :enabled-pages #{:ip-address})
(defn enable-pages
[& page-ids]
(session/put! :enabled-pages (apply #(conj (session/get :enabled-pages) %) page-ids)))
(defn disable-pages
[& page-ids]
(session/put! :enabled-pages (apply #(disj (session/get :enabled-pages) %) page-ids)))
;; -------------------------
;; Components(
(def ip-doc (reagent/atom {}))
(def credentials-doc (reagent/atom {}))
(def import-doc (reagent/atom {}))
(def is-loading (reagent/atom false))
(defn toggle-loading-state [loading]
(reset! is-loading loading))
(defn submit-button []
[:button.btn.btn-primary {:disabled @is-loading :type "submit"} (if @is-loading "Loading..." "Submit")])
(def ip-form-template
[:form {:on-submit (fn [e]
(toggle-loading-state true)
(.preventDefault e)
(communicator/ping (:ip-address @ip-doc)
#(do
(enable-pages :credentials)
(secretary/dispatch! "#/credentials"))
#(do
(disable-pages :credentials :import)
(js/alert "Unable to find InformaCast server at specified URL"))
#(toggle-loading-state false)))}
[:div.form-group
[:label {:for :ip-address :style {:font-size "16pt"}} "IP ADDRESS:PORT"]
[:input.form-control.narrow {:field :text
:id :ip-address
:style {:text-align "center"}}]]
[submit-button]])
(defn ip-address-component []
(fn []
[:div
[:p.visible-md (when (not (clojure.string/blank? (:ip-address @ip-doc)))
(str "The route we will ping to see if your server is online is: " (communicator/interpolate-ip-address (:ip-address @ip-doc))))]
[bind-fields ip-form-template ip-doc]]))
(def credentials-form-template
[:form {:on-submit (fn [e]
(toggle-loading-state true)
(.preventDefault e)
(communicator/authenticate
(:username @credentials-doc)
(:password @credentials-doc)
#(do
(enable-pages :import)
(secretary/dispatch! "#/import"))
#(do
(disable-pages :import)
(js/alert %))
#(toggle-loading-state false)))}
[:div.form-group
[:label {:for :username :style {:font-size "16pt"}} "Credentials"]
[:input.form-control.narrow {:field :text
:id :username
:placeholder "user name"
:style {:text-align "center"}}]
[:input.form-control.narrow {:field :password
:placeholder "password"
:id :password
:style {:text-align "center"}}]]
[submit-button]])
(defn credentials-component []
(fn []
[:div
[bind-fields credentials-form-template credentials-doc]]))
(def import-form-template
[:form {:on-submit (fn [e]
(.preventDefault e)
(println "SUBMITTED"))}
[:div.form-group
[:label {:for :username :style {:font-size "16pt"}} "IMPORT YOUR .ZIP FILE"]
[:input.form-control.narrow {:type :file
:id :file-input
:style {:text-align "center"}
:on-change (fn [e]
(let [file (first (array-seq (.. e -target -files)))
file-reader (js/FileReader.)]
(set! (.-onload file-reader)
(fn [e]
(zip-worker/start-working (-> e .-target .-result))))
(.readAsArrayBuffer file-reader file))
(enable-pages :results))}]]
[:p "Process will begin immediately after selecting respective zip file"]])
(defn import-component []
(fn []
[:div
[bind-fields import-form-template import-doc]]))
(defn results-component []
[:div {:style {:max-height "500px" :overflow "scroll"}}
[:h1 "RESULTS"]
[:h3 "Successful Operations"]
(for [operation-description (communicator/get-successful-operations)]
[:h4 (str "Description: " operation-description)])
(when (not (empty? (communicator/get-unsuccessful-operations)))
[:div
[:h3 "Unsuccessful Operations"]
(for [operation-description (communicator/get-unsuccessful-operations)]
[:pre
[:h4 (str "Description" (:description operation-description))]
[:p "fieldName: " [:code (get operation-description :field-name)]]
[:p "fieldValue: " [:code (let [field-value (get operation-description :field-value)]
(if field-value
field-value
"null"))]]
[:p "messageType: " [:code (get operation-description :message-type)]]
[:p "message: " [:code (get operation-description :message)]]])])])
(defn not-found-component []
[:h1 {:class "cover-heading"} "PAGE NOT FOUND"])
;; -------------------------
;; Navigation
(def page-links [{:id :ip-address, :title "1 - IP Address", :url "#/", :component #'ip-address-component}
{:id :credentials, :title "2 - Credentials", :url "#/credentials", :component #'credentials-component}
{:id :import, :title "3 - Import", :url "#/import", :component #'import-component}
{:id :results, :title "4 - Results", :url "#/results", :component #'results-component}])
(defn set-current-page [page-id]
(if (= page-id :not-found)
(do
(session/put! :current-page #'not-found-component)
(session/put! :active-link nil))
(do
(session/put! :current-page (-> (filter #(= (:id %) page-id) page-links)
first
:component))
(session/put! :active-link page-id))))
(defn navigation []
[:div {:class "masthead clearfix"}
[:div {:class "inner"}
[:h3 {:class "masthead-brand"} "InformaCast Wizard"]
[:nav
[:ul {:class "nav masthead-nav"}
(doall (for [link page-links]
(let [link-enabled? (contains? (session/get :enabled-pages) (:id link))]
[:li {:class (when (= (:id link) (session/get :active-link)) "active")}
[:a {:href (if link-enabled? (:url link) "#")
:style {:cursor (if link-enabled? "pointer" "not-allowed") :color (when-not link-enabled? "#FBC6D3")}} (:title link)]])))]]]])
;; -------------------------
;; BASE
(defn page []
[:div.cover-container
[navigation]
[:div {:class "inner cover"}
[(session/get :current-page)]]])
(defn render-app []
(reagent/render [page]
(.getElementById js/document "app")))
;; -------------------------
;; History
(defn- hook-browser-navigation!
"Listens for html5 route changes and notifies secretary of the event"
[]
(doto (History.)
(events/listen EventType/NAVIGATE #(secretary/dispatch! (.-token %)))
(.setEnabled true)))
;; -------------------------
;; Routes
(secretary/set-config! :prefix "#")
(set-current-page :ip-address)
(defroute "/" [] (set-current-page :ip-address))
(defroute "/credentials" [] (set-current-page :credentials))
(defroute "/import" [] (set-current-page :import))
(defroute "/results" [] (set-current-page :results))
(defroute "*" [] (set-current-page :not-found))
(defn ^:export init
"Initializes the application by wiring our html5 routing with secretary and rendering our react application"
[]
(.initializeTouchEvents js/React true)
(hook-browser-navigation!)
(render-app))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment