Skip to content

Commit

Permalink
opening share link creates a new board
Browse files Browse the repository at this point in the history
  • Loading branch information
fterrier committed Feb 13, 2015
1 parent 555a4cc commit 65e4874
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 40 deletions.
2 changes: 1 addition & 1 deletion env/dev/src/cljs/tramboard_clj/script/main.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
:jsload-callback (fn []
(tram/main)))

(tram/hook-browser-navigation!)
(tram/init!)
(tram/main)
2 changes: 1 addition & 1 deletion env/prod/src/cljs/tramboard_clj/script/main.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

(enable-console-print!)

(tram/hook-browser-navigation!)
(tram/init!)
(tram/main)
17 changes: 13 additions & 4 deletions src/cljs/tramboard_clj/script/state.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"This namespace deals with state functions and manipulations. The complete state of the app is the
state of both split panes. Each pane's state is represented by a state structure contained in
a map with 2 named items, like this :
:split-states {:state-1 {:state-id :state-1 :state :home :params {} :visible true}
:state-2 {:state-id :state-2 :state :home :params {} :visible false}}
:order [:state-1 :state-2]}
:split-states {:state-1 {:state-id :state-1 :state :home :params {} :visible true}
:state-2 {:state-id :state-2 :state :home :params {} :visible false}}
:order [:state-1 :state-2]}
When referring to complete state, one means the whole structure above. When referring to state, one
means one of the 2 states inside the complete state.")

Expand All @@ -22,7 +22,7 @@
(let [split-states (:split-states complete-state)
state-1 (get split-states :state-1)
state-2 (get split-states :state-2)]
(and (:visible state-1) (:visible state-2))))
(and (:visible state-1) (:visible state-2))))

(defn go-home [state]
(assoc state :state :home :params {}))
Expand Down Expand Up @@ -56,6 +56,15 @@
:order [(:state-id state-to-toggle) (:state-id other-state)]))]
new-complete-state))

(defn reset-complete-state [complete-state]
"This shows state-1 and hides state-2"
(let [state-1 (get-state complete-state :state-1)
state-2 (get-state complete-state :state-2)
new-complete-state (reduce #(assoc-in %1 (%2 0) (%2 1)) complete-state
[[[:split-states :state-1] (go-home state-1)]
[[:split-states :state-2] (go-hide state-2)]])]
(assoc new-complete-state :order [:state-1 :state-2])))

(defn modify-complete-state [complete-state state fun]
"Applies fun to state inside complete-state and returns the new complete state."
(let [state-id (:state-id state)
Expand Down
8 changes: 4 additions & 4 deletions src/cljs/tramboard_clj/script/time.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@
"Unpure function that decides how this should be displayed depending on the current day"
(let [now (now)
datetime (from-long timestamp)
date-format (unparse date-formatter datetime)
hour-minute-format (unparse hour-minute-formatter datetime)
is-today (= date-format (unparse date-formatter now))
date-format (unparse date-formatter (to-default-time-zone datetime))
hour-minute-format (unparse hour-minute-formatter (to-default-time-zone datetime))
is-today (= date-format (unparse date-formatter (to-default-time-zone now)))
is-within-a-week (is-within datetime now (weeks 1))
is-yesterday (is-within datetime now (days 1))
display-time (str
(if is-today "today"
(if is-yesterday "yesterday"
(if is-within-a-week (str "last " (unparse only-day-formatter datetime))
(if is-within-a-week (str "last " (unparse only-day-formatter (to-default-time-zone datetime)))
(str " on " date-format))))
" at " hour-minute-format)]
display-time))
Expand Down
106 changes: 76 additions & 30 deletions src/cljs/tramboard_clj/script/tram.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,17 @@
[goog.history.EventType :as EventType]
[goog.crypt.base64 :as b64]
[tramboard-clj.script.time :refer [parse-from-date-time format-to-hour-minute display-time minutes-from]]
[tramboard-clj.script.state :refer [is-home is-edit is-split get-state go-home go-edit go-toggle-split modify-complete-state get-all-states]])
[tramboard-clj.script.state :refer [is-home is-edit is-split get-state go-home go-edit go-toggle-split modify-complete-state get-all-states reset-complete-state]])
(:import [goog.net XhrIo]
goog.History))

; some global constants here
(def refresh-rate 10000)

(secretary/set-config! :prefix "#")
(defroute "/link/:hash" [hash]
(js/console.log (str "got hash: " hash)))

; our initial app state
(defonce app-state
(atom {; views from local storage
(atom {:version 1
; views from local storage
:configured-views (array-map)
; navigation state
:complete-state {:split-states {:state-1 {:state-id :state-1 :state :home :params {} :visible true}
Expand Down Expand Up @@ -76,6 +73,24 @@
(defn get-stops-in-order [view]
(map #(get (:stops view) %) (:stops-order view)))

(defn- export-string-from-view [view]
(let [string-view (pr-str
(dissoc (update-in view [:stops]
; we remove :view-id :last-updated from the view and :known-destinations from each stop
(fn [stops] (into {} (map #(vector (key %)
(dissoc (val %) :known-destinations)) stops)))) :view-id :last-updated))]
(str/replace (b64/encodeString string-view) "=" "")))

(defn- pad [string num character]
"Pads a string with character until it has a num divisable size"
(let [length (count string)
too-big-by (mod length num)
base64-string (apply str string (repeat (if (= 0 too-big-by) 0 (- num too-big-by)) "="))]
base64-string))

(defn- view-from-export-string [string]
(reader/read-string (b64/decodeString (pad string 4 "="))))

(defn is-in-destinations [destinations arrival]
(let [keys [:to :number]
is-in-destination (contains? (into #{} (map #(select-keys % keys) destinations))
Expand Down Expand Up @@ -118,16 +133,47 @@
(dissoc configured-views view-id)
configured-views)))

(defn swap-add-view [app view]
(swap!
app (fn [app]
(let [configured-views (:configured-views app)
complete-state (:complete-state app)
view-id (:view-id view)
; TODO this is the same as in transact-add-stop, simplify
new-configured-views (assoc configured-views view-id view)
current-state (get-state complete-state :state-1)
; TODO this is the same as in transact-add-stop, simplify
new-complete-state (modify-complete-state (reset-complete-state complete-state) current-state #(go-edit % view-id))
new-app (assoc app
:configured-views new-configured-views
:complete-state new-complete-state)]
new-app))))

(defn- create-new-view [view]
(let [view-id (uuid)]
(update-updated-date (into {:view-id view-id} view))))

(secretary/set-config! :prefix "#")
(defroute share-link "/link/*" {hash :*}
(let [new-view (create-new-view (view-from-export-string hash))]
(println "Got link with a view to display" new-view)
(swap-add-view app-state new-view)
(.setToken (History.) "")))

(defn- get-share-link [view]
(str "http://staging.timeforcoffee.ch/" (share-link {:* (export-string-from-view view)})))

(defn transact-add-stop [app state stop]
(om/transact!
app (fn [app]
(let [configured-views (:configured-views app)
complete-state (:complete-state app)
current-state (get-state complete-state (:state-id state))
is-new-view (not (is-edit current-state))
view-id (if is-new-view (uuid) (:view-id (:params current-state)))
edit-view-id (:view-id (:params current-state))
current-view (if is-new-view (create-new-view nil) (get configured-views edit-view-id))
view-id (:view-id current-view)
new-complete-state (modify-complete-state complete-state current-state #(go-edit % view-id))
current-view (or (get configured-views view-id) {:view-id view-id})
new-view (add-stop-and-update-date current-view stop)
new-configured-views (assoc configured-views view-id new-view)]
(ga "send" "event" "stop" "add" {:dimension1 (:id stop)})
Expand Down Expand Up @@ -351,16 +397,6 @@
(dom/div #js {:className "stop-heading"}
(dom/h2 #js {:className "heading thin"} (str "Trams / buses / trains departing from " (str/join " / " (map #(:name %) (get-stops-in-order current-view)))))))))

(defn- export-view [view]
(pr-str
(dissoc (update-in view [:stops]
; we remove :view-id :last-updated from the view and :known-destinations from each stop
(fn [stops] (into {} (map #(vector (key %)
(dissoc (val %) :known-destinations)) stops)))) :view-id :last-updated)))

(defn- get-share-link [view]
(str "http://www.timeforcoffee.ch/#/link/" (str/replace (b64/encodeString (export-view view)) "=" "")))

(defn control-bar [{:keys [current-state current-view]} owner {:keys [on-activity-fn]}]
(reify
om/IWillMount
Expand Down Expand Up @@ -389,10 +425,17 @@
(when hide-ch (close! hide-ch))))
om/IDidUpdate
(did-update [_ _ prev-state]
(when (and (not (:share-input-visible prev-state))
(om/get-state owner :share-input-visible))
(let [share-input (om/get-node owner "shareInput")]
(.focus share-input))))
; we set the focus here on share input if necessary
(let [share-input-visible (om/get-state owner :share-input-visible)]
(when share-input-visible
(when (not (:share-input-visible prev-state))
(let [share-input (om/get-node owner "shareInput")]
(.focus share-input)))
; we recalculate the share string
(let [prev-share-input-value (:share-input-value prev-state)
new-share-input-value (get-share-link current-view)]
(when (not= prev-share-input-value new-share-input-value)
(om/set-state! owner :share-input-value new-share-input-value))))))
om/IRenderState
(render-state [this {:keys [share-input-value share-input-visible]}]
(let [excluded-destinations (remove nil? (flatten (map #(:excluded-destinations (val %)) (:stops current-view))))
Expand Down Expand Up @@ -866,13 +909,16 @@
(secretary/dispatch! (.-token event))))
(.setEnabled true)))

(defn init! []
(let [saved-state (or (try (reader/read-string (. js/localStorage (getItem "views"))) (catch :default e (println e) {})) {})]
(swap! app-state deep-merge saved-state)
(hook-browser-navigation!)))

(defn main []
(let [saved-state (or (try (reader/read-string (. js/localStorage (getItem "views"))) (catch :default e (println e) {})) {})
saved-app-state (swap! app-state deep-merge saved-state)]
(om/root split-stationboard saved-app-state
{:target (. js/document (getElementById "my-app"))
:tx-listen (fn [{:keys [path new-state]} _]
(. js/localStorage (setItem "views"
; here if we don't dissoc the page will reload in the current state
(pr-str new-state))))})))
(om/root split-stationboard app-state
{:target (. js/document (getElementById "my-app"))
:tx-listen (fn [{:keys [path new-state]} _]
(. js/localStorage (setItem "views"
; here if we don't dissoc the page will reload in the current state
(pr-str new-state))))}))

0 comments on commit 65e4874

Please sign in to comment.