#5: Sorting out merge horror
This commit is contained in:
commit
3795f4e0fe
109 changed files with 3648 additions and 1436 deletions
|
|
@ -15,9 +15,6 @@
|
|||
Timestamp
|
||||
PreparedStatement]))
|
||||
|
||||
;; TODO: I am CERTANLY misunderstanding something here. We ought to be getting
|
||||
;; the database connection string and credentials fomr profiles.clj
|
||||
;; (def ^:dynamic *db* {:name "java:comp/env/jdbc/EmployeeDB"})
|
||||
(defstate ^:dynamic *db*
|
||||
:start (conman/connect! {:jdbc-url (env :database-url)
|
||||
:driver-class-name "org.postgresql.Driver"})
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@
|
|||
(assoc params
|
||||
:page template
|
||||
:csrf-token *anti-forgery-token*
|
||||
:servlet-context *app-context*)))
|
||||
:servlet-context *app-context*
|
||||
:version (System/getProperty "youyesyet.version"))))
|
||||
"text/html; charset=utf-8"))
|
||||
|
||||
(defn error-page
|
||||
|
|
|
|||
115
src/cljc/youyesyet/outqueue.cljc
Normal file
115
src/cljc/youyesyet/outqueue.cljc
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
(ns youyesyet.outqueue
|
||||
(:require
|
||||
#?(:clj [clojure.core]
|
||||
:cljs [reagent.core :refer [atom]])))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.outqueue: queue of messages waiting to be sent to the server.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; The items are (obviously) the actual items in the queue;
|
||||
;;; the queue is locked if an attempt is currently being made to transmit
|
||||
;;; an item.
|
||||
|
||||
(defn new-queue
|
||||
"Create a new queue"
|
||||
([]
|
||||
(new-queue '()))
|
||||
([items]
|
||||
(atom {:locked false
|
||||
:items (if
|
||||
(seq? items)
|
||||
(reverse items)
|
||||
(list items))})))
|
||||
|
||||
(defn add!
|
||||
"Add this item to the queue."
|
||||
[q item]
|
||||
(swap! q
|
||||
(fn [a]
|
||||
(assoc a :items
|
||||
(cons item (:items a))))))
|
||||
|
||||
(defn q?
|
||||
[x]
|
||||
(try
|
||||
(let [q (deref x)
|
||||
locked (:locked q)]
|
||||
(and
|
||||
(seq? (:items q))
|
||||
(or (true? locked) (false? locked))))
|
||||
(catch #?(:clj Exception :cljs js/Object) any
|
||||
#?(:clj (print (.getMessage any))
|
||||
:cljs (js/console.log (str any))))))
|
||||
|
||||
(defn peek
|
||||
"Look at the next item which could be removed from the queue."
|
||||
[q]
|
||||
(last (:items (deref q))))
|
||||
|
||||
(defn locked?
|
||||
[q]
|
||||
(:locked (deref q)))
|
||||
|
||||
(defn unlock!
|
||||
([q ]
|
||||
(unlock! q true))
|
||||
([q value]
|
||||
(swap! q (fn [a] (assoc a :locked (not (true? value)))))))
|
||||
|
||||
(defn lock!
|
||||
[q]
|
||||
(unlock! q false))
|
||||
|
||||
|
||||
(defn count
|
||||
"Return the count of items currently in the queue."
|
||||
[q]
|
||||
(count (deref q)))
|
||||
|
||||
(defn take!
|
||||
"Return the first item from the queue, rebind the queue to the remaining
|
||||
items. If the queue is empty return nil."
|
||||
[q]
|
||||
(swap! q (fn [a]
|
||||
(let [items (reverse (:items a))
|
||||
item (first items)
|
||||
new-queue (reverse (rest items))]
|
||||
(assoc (assoc a :items new-queue) :v item))))
|
||||
(:v (deref q)))
|
||||
|
||||
(defn maybe-process-next
|
||||
"Apply this process, assumed to be a function of one argument, to the next
|
||||
item in the queue, if the queue is not currently locked; return the value
|
||||
returned by process."
|
||||
[q process]
|
||||
(if (and (q? q)(not (locked? q)))
|
||||
(try
|
||||
(lock! q)
|
||||
(let [v (apply process (list (peek q)))]
|
||||
(take! q)
|
||||
v)
|
||||
(catch #?(:clj Exception :cljs js/Object) any
|
||||
#?(:clj (print (.getMessage any))
|
||||
:cljs (js/console.log (str any))))
|
||||
(finally (unlock! q)))
|
||||
))
|
||||
|
|
@ -1,57 +1,132 @@
|
|||
(ns youyesyet.core
|
||||
(:require [reagent.core :as r]
|
||||
[re-frame.core :as rf]
|
||||
[secretary.core :as secretary]
|
||||
(:require cljsjs.react-leaflet
|
||||
[ajax.core :refer [GET POST]]
|
||||
[goog.events :as events]
|
||||
[goog.history.EventType :as HistoryEventType]
|
||||
[markdown.core :refer [md->html]]
|
||||
[ajax.core :refer [GET POST]]
|
||||
[reagent.core :as r]
|
||||
[re-frame.core :as rf]
|
||||
[secretary.core :as secretary]
|
||||
[youyesyet.ajax :refer [load-interceptors!]]
|
||||
[youyesyet.handlers]
|
||||
[youyesyet.subscriptions]
|
||||
[youyesyet.ui-utils :as ui]
|
||||
[youyesyet.views.about :as about]
|
||||
[youyesyet.views.home :as home]
|
||||
[youyesyet.views.electors :as electors]
|
||||
[youyesyet.views.followup :as followup]
|
||||
[youyesyet.views.issue :as issue]
|
||||
[youyesyet.views.issues :as issues]
|
||||
[youyesyet.views.map :as maps])
|
||||
(:import goog.History))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.core: core of the app.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; So that we can do debug logging!
|
||||
(enable-console-print!)
|
||||
|
||||
(defn about-page []
|
||||
(about/panel))
|
||||
|
||||
(defn electors-page []
|
||||
(electors/panel))
|
||||
|
||||
(defn home-page []
|
||||
(home/panel))
|
||||
(defn followup-page []
|
||||
(followup/panel))
|
||||
|
||||
(defn issues-page []
|
||||
(issues/panel))
|
||||
|
||||
(defn issue-page []
|
||||
(issue/panel))
|
||||
|
||||
(defn map-page []
|
||||
(maps/panel))
|
||||
|
||||
(def pages
|
||||
{:home #'home-page
|
||||
{:about #'about-page
|
||||
:electors #'electors-page
|
||||
:followup #'followup-page
|
||||
:issues #'issues-page
|
||||
:issue #'issue-page
|
||||
:map #'map-page
|
||||
:about #'about-page})
|
||||
})
|
||||
|
||||
(defn page []
|
||||
[:div
|
||||
[:header
|
||||
[ui/navbar]
|
||||
[:h1 "You yes yet?"]]
|
||||
[(pages @(rf/subscribe [:page]))]])
|
||||
|
||||
(defn page
|
||||
"Render the single page of the app, taking the current panel from
|
||||
the :page key in the state map."
|
||||
[]
|
||||
(let [content (pages @(rf/subscribe [:page]))
|
||||
error @(rf/subscribe [:error])
|
||||
feedback @(rf/subscribe [:feedback])
|
||||
outqueue @(rf/subscribe [:outqueue])]
|
||||
[:div
|
||||
[:header
|
||||
[ui/navbar]]
|
||||
(if content [content]
|
||||
[:div.error (str "No content in page " :page)])
|
||||
[:footer
|
||||
[:div.error {:style [:display (if error "block" "none")]} (str error)]
|
||||
[:div.feedback {:style [:display (if feedback :block :none)]} (str feedback)]
|
||||
[:div.queue (if
|
||||
(nil? outqueue) ""
|
||||
(str (count outqueue) " items queued to send"))]]]))
|
||||
|
||||
;; -------------------------
|
||||
;; Routes
|
||||
(secretary/set-config! :prefix "#")
|
||||
|
||||
(secretary/defroute "/" []
|
||||
(rf/dispatch [:set-active-page :home]))
|
||||
(rf/dispatch [:set-active-page :map]))
|
||||
|
||||
(secretary/defroute "/about" []
|
||||
(rf/dispatch [:set-active-page :about]))
|
||||
|
||||
(secretary/defroute "/electors" []
|
||||
(rf/dispatch [:set-active-page :electors]))
|
||||
|
||||
(secretary/defroute "/electors/:address" {address-id :address}
|
||||
(rf/dispatch [:set-address address-id]))
|
||||
|
||||
(secretary/defroute "/followup" []
|
||||
(rf/dispatch [:set-active-page :followup]))
|
||||
|
||||
(secretary/defroute "/issues" []
|
||||
(rf/dispatch [:set-active-page :issues]))
|
||||
|
||||
(secretary/defroute "/issues/:elector" {elector-id :elector}
|
||||
(rf/dispatch [:set-elector-and-page {:elector-id elector-id :page :issues}]))
|
||||
|
||||
(secretary/defroute "/issue/:issue" {issue :issue}
|
||||
(rf/dispatch [:set-and-go-to-issue issue]))
|
||||
|
||||
(secretary/defroute "/map" []
|
||||
(rf/dispatch [:set-active-page :map]))
|
||||
|
||||
(secretary/defroute "/set-intention/:elector/:intention" {elector-id :elector intention :intention}
|
||||
(rf/dispatch [:set-intention {:elector-id elector-id :intention intention}]))
|
||||
|
||||
;; -------------------------
|
||||
;; History
|
||||
;; must be called after routes have been defined
|
||||
|
|
@ -65,9 +140,6 @@
|
|||
|
||||
;; -------------------------
|
||||
;; Initialize app
|
||||
(defn fetch-docs! []
|
||||
(GET (str js/context "/docs")
|
||||
{:handler #(rf/dispatch [:set-docs %])}))
|
||||
|
||||
(defn mount-components []
|
||||
(r/render [#'page] (.getElementById js/document "app")))
|
||||
|
|
@ -75,6 +147,5 @@
|
|||
(defn init! []
|
||||
(rf/dispatch-sync [:initialize-db])
|
||||
(load-interceptors!)
|
||||
(fetch-docs!)
|
||||
(hook-browser-navigation!)
|
||||
(mount-components))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,79 @@
|
|||
(ns youyesyet.db)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.db: the state of the app.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; This is the constructor for the atom in which the state of the user interface is held.
|
||||
;;; The atom gets updated by 'events' registered in handler.cljs, q.v.
|
||||
;;;
|
||||
;;; not wonderfully happy with 'db' as a name for this namespace; will probably change to
|
||||
;;; 'client-state'.
|
||||
|
||||
(def default-db
|
||||
{:page :home})
|
||||
{;;; the currently selected address, if any.
|
||||
:address {:id 1 :address "13 Imaginary Terrace, IM1 3TE" :latitude 55.8253043 :longitude -4.2569057
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]}
|
||||
;;; a list of the addresses in the current location at which there
|
||||
;;; are electors registered.
|
||||
:addresses [{:id 1 :address "13 Imaginary Terrace, IM1 3TE" :latitude 55.8253043 :longitude -4.2570944
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]}
|
||||
{:id 2 :address "15 Imaginary Terrace, IM1 3TE" :latitude 55.8252354 :longitude -4.2572778
|
||||
:electors [{:id 1 :name "Beryl Brown" :gender :female}
|
||||
{:id 2 :name "Betty Black" :gender :female}]}
|
||||
{:id 3 :address "17 Imaginary Terrace, IM1 3TE" :latitude 55.825166 :longitude -4.257026
|
||||
:electors [{:id 1 :name "Catriona Crathie" :gender :female :intention :yes}
|
||||
{:id 2 :name "Colin Caruthers" :gender :male :intention :yes}
|
||||
{:id 3 :name "Calum Crathie" :intention :yes}]}
|
||||
{:id 4 :address "19 Imaginary Terrace, IM1 3TE" :latitude 55.82506950000001 :longitude -4.2570239
|
||||
:electors [{:id 1 :name "David Dewar" :gender :male :intention :no}]}]
|
||||
;;; electors at the currently selected address
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]
|
||||
;;; any error to display
|
||||
:error nil
|
||||
;;; the issue from among the issues which is currently selected.
|
||||
;;; any confirmation message to display
|
||||
:feedback nil
|
||||
;;; the currently selected issue
|
||||
:issue "Currency"
|
||||
;;; the issues selected for the issues page on this day.
|
||||
:issues {"Currency" "Scotland could keep the Pound, or use the Euro. But we could also set up a new currency of our own. Yada yada yada"
|
||||
"Monarchy" "Scotland could keep the Queen. This is an issue to be decided after independence. Yada yada yada"
|
||||
"Defence" "Scotland will not have nuclear weapons, and will probably not choose to engage in far-off wars. But we could remain members of NATO"}
|
||||
;;; message of the day
|
||||
:motd "This is a test version only. There is no real data."
|
||||
;;; the options from among which electors can select.
|
||||
:options [{:id :yes :description "Yes"} {:id :no :description "No"}]
|
||||
;;; the queue of items waiting to be transmitted.
|
||||
:outqueue ()
|
||||
;;; the currently displayed page within the app.
|
||||
:page :home
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,18 +1,152 @@
|
|||
(ns youyesyet.handlers
|
||||
(:require [youyesyet.db :as db]
|
||||
[re-frame.core :refer [dispatch reg-event-db]]))
|
||||
(:require [cljs.reader :refer [read-string]]
|
||||
[re-frame.core :refer [dispatch reg-event-db]]
|
||||
[youyesyet.db :as db]
|
||||
))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.handlers: handlers for events.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn clear-messages
|
||||
"Return a state like this state except with the error and feedback messages
|
||||
set nil"
|
||||
[state]
|
||||
(merge state {:error nil :feedback nil}))
|
||||
|
||||
|
||||
(defn get-elector
|
||||
"Return the elector at this address (or the current address if not specified)
|
||||
with this id."
|
||||
([elector-id state]
|
||||
(get-elector elector-id state (:address state)))
|
||||
([elector-id state address]
|
||||
(first
|
||||
(remove
|
||||
nil?
|
||||
(map
|
||||
#(if (= elector-id (:id %)) %)
|
||||
(:electors address))))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:initialize-db
|
||||
(fn [_ _]
|
||||
db/default-db))
|
||||
|
||||
(reg-event-db
|
||||
:set-active-page
|
||||
(fn [db [_ page]]
|
||||
(assoc db :page page)))
|
||||
|
||||
(reg-event-db
|
||||
:set-docs
|
||||
(fn [db [_ docs]]
|
||||
(assoc db :docs docs)))
|
||||
:send-intention
|
||||
(fn [db [_ args]]
|
||||
(let [intention (:intention args)
|
||||
elector-id (:elector-id args)
|
||||
elector
|
||||
(first
|
||||
(remove nil?
|
||||
(map
|
||||
#(if (= elector-id (:id %)) %)
|
||||
(:electors (:address db)))))
|
||||
old-address (:address db)
|
||||
new-address (assoc old-address :electors (cons (assoc elector :intention intention) (remove #(= % elector) (:electors old-address))))]
|
||||
(cond
|
||||
(nil? elector)
|
||||
(assoc db :error "No elector found; not setting intention")
|
||||
(= intention (:intention elector)) (do (js/console.log "Elector's intention hasn't changed; not setting intention") db)
|
||||
true
|
||||
(do
|
||||
(js/console.log (str "Setting intention of elector " elector " to " intention))
|
||||
(merge
|
||||
(clear-messages db)
|
||||
{:addresses
|
||||
(cons new-address (remove old-address (:addresses db)))
|
||||
:address new-address
|
||||
:elector elector
|
||||
:outqueue (cons (assoc args :action :set-intention) (:outqueue db))}))))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:send-request
|
||||
(fn [db [_ _]]
|
||||
(if (and (:elector db) (:issue db) (:telephone db))
|
||||
(do
|
||||
(js/console.log "Sending request")
|
||||
(assoc db
|
||||
:feedback "Request has been queued"
|
||||
:outqueue (cons
|
||||
{:elector-id (:id (:elector db))
|
||||
:issue (:issue db)
|
||||
:action :add-request} (:outqueue db))))
|
||||
(assoc db :error "Please supply a telephone number to call"))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-active-page
|
||||
(fn [db [_ page]]
|
||||
(if page
|
||||
(assoc (clear-messages db) :page page))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-address
|
||||
(fn [db [_ address-id]]
|
||||
(let [id (read-string address-id)
|
||||
address (first (remove nil? (map #(if (= id (:id %)) %) (:addresses db))))]
|
||||
(assoc (clear-messages db) :address address :page :electors))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-and-go-to-issue
|
||||
(fn [db [_ issue]]
|
||||
(js/console.log (str "Setting page to :issue, issue to " issue))
|
||||
(assoc (assoc (clear-messages db) :issue issue) :page :issue)))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-elector-and-page
|
||||
(fn [db [_ args]]
|
||||
(let [page (:page args)
|
||||
elector-id (read-string (:elector-id args))
|
||||
elector (get-elector elector-id db)]
|
||||
(js/console.log (str "Setting page to " page ", elector to " elector))
|
||||
(assoc (clear-messages db) :elector elector :page page))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-elector
|
||||
(fn [db [_ elector-id]]
|
||||
(let [elector (get-elector (read-string elector-id) db)]
|
||||
(js/console.log (str "Setting elector to " elector))
|
||||
(assoc (clear-messages db) :elector elector))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-issue
|
||||
(fn [db [_ issue]]
|
||||
(js/console.log (str "Setting issue to " issue))
|
||||
(assoc (clear-messages db) :issue issue)))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-telephone
|
||||
(fn [db [_ telephone]]
|
||||
(js/console.log (str "Setting telephone to " telephone))
|
||||
(assoc (clear-messages db) :telephone telephone)))
|
||||
|
|
|
|||
|
|
@ -1,12 +1,86 @@
|
|||
(ns youyesyet.subscriptions
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.electors: subscriptions for everything in the app state.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(reg-sub
|
||||
:motd
|
||||
(fn [db _]
|
||||
(:motd db)))
|
||||
|
||||
(reg-sub
|
||||
:address
|
||||
(fn [db _]
|
||||
(:address db)))
|
||||
|
||||
(reg-sub
|
||||
:addresses
|
||||
(fn [db _]
|
||||
(:addresses db)))
|
||||
|
||||
(reg-sub
|
||||
:changes
|
||||
(fn [db _]
|
||||
(:changes db)))
|
||||
|
||||
(reg-sub
|
||||
:elector
|
||||
(fn [db _]
|
||||
(:elector db)))
|
||||
|
||||
(reg-sub
|
||||
:error
|
||||
(fn [db _]
|
||||
(:error db)))
|
||||
|
||||
(reg-sub
|
||||
:feedback
|
||||
(fn [db _]
|
||||
(:feedback db)))
|
||||
|
||||
(reg-sub
|
||||
:issue
|
||||
(fn [db _]
|
||||
(:issue db)))
|
||||
|
||||
(reg-sub
|
||||
:issues
|
||||
(fn [db _]
|
||||
(:issues db)))
|
||||
|
||||
(reg-sub
|
||||
:page
|
||||
(fn [db _]
|
||||
(:page db)))
|
||||
|
||||
(reg-sub
|
||||
:docs
|
||||
:options
|
||||
(fn [db _]
|
||||
(:docs db)))
|
||||
(:options db)))
|
||||
|
||||
(reg-sub
|
||||
:outqueue
|
||||
(fn [db _]
|
||||
(:outqueue db)))
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
|
||||
(defn big-link [text target]
|
||||
[:div.big-link-container
|
||||
[:div.big-link-container {:key target}
|
||||
[:a.big-link {:href target} text]])
|
||||
|
||||
|
||||
|
|
@ -45,6 +45,14 @@
|
|||
:on-click #(reset! collapsed? true)} title]]))
|
||||
|
||||
|
||||
(defn error-panel
|
||||
[message]
|
||||
[:div
|
||||
[:h1.error message]
|
||||
[:div.container {:id "main-container"}
|
||||
(back-link)]])
|
||||
|
||||
|
||||
(defn navbar []
|
||||
(r/with-let [collapsed? (r/atom true)]
|
||||
[:div {:id "nav"}
|
||||
|
|
@ -52,8 +60,7 @@
|
|||
:src "img/threelines.png"
|
||||
:on-click #(swap! collapsed? not)}]
|
||||
[:menu.nav {:id "nav-menu" :class (if @collapsed? "hidden" "shown")}
|
||||
(nav-link "#/" "Home" :home collapsed?)
|
||||
(nav-link "#/library" "Library" :library collapsed?)
|
||||
(nav-link "#/register" "Register" :register collapsed?)
|
||||
(nav-link "#/login" "Login" :login collapsed?)
|
||||
(nav-link "#/map" "Map" :map collapsed?)
|
||||
(nav-link "#/electors" "Electors" :electors collapsed?)
|
||||
(nav-link "#/issues" "Issues" :issues collapsed?)
|
||||
(nav-link "#/about" "About" :about collapsed?)]]))
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
(ns youyesyet.views.about
|
||||
(:require [re-frame.core :refer [reg-sub]]
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
[markdown.core :refer [md->html]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.electors: about/credits view for youyesyet.
|
||||
;;;; youyesyet.views.about: about/credits view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
|
|
@ -25,7 +26,6 @@
|
|||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
|
|
@ -33,22 +33,32 @@
|
|||
(defn panel
|
||||
"Generate the about panel."
|
||||
[]
|
||||
[:div.container {:id "main-container"}
|
||||
[:h2 "Pre-alpha/proof of concept"]
|
||||
[:p {:class "centre"}
|
||||
[:img {:src "img/ric-logo.png" :width "24" :height "24"}]
|
||||
" A project of the "
|
||||
[:a {:href "https://radical.scot/"} "Radical Independence Campaign"]]
|
||||
[:p {:class "centre"}
|
||||
[:img {:src "img/clojure-icon.gif" :alt "Clojure" :height "24" :width "24"}]
|
||||
" Powered by "
|
||||
[:a {:href "http://clojure.org"} "Clojure"]]
|
||||
[:p {:class "centre"}
|
||||
[:img {:src "img/github-logo-transparent.png" :alt "GitHub" :height "24" :width "24"}]
|
||||
" Find me/fork me on "
|
||||
[:a {:href "https://github.com/simon-brooke/youyesyet"} "GitHub"]]
|
||||
[:p {:class "centre"}
|
||||
[:img {:src "img/gnu.small.png" :alt "Free Software Foundation" :height "24" :width "24"}]
|
||||
" Licensed under the "
|
||||
[:a {:href "http://www.gnu.org/licenses/gpl-2.0.html"}
|
||||
"GNU General Public License v2.0"]]])
|
||||
(let [motd @(subscribe [:motd])]
|
||||
[:div
|
||||
[:h1 "You Yes Yet?"]
|
||||
[:div.container {:id "main-container"}
|
||||
[:h2 "Pre-alpha/proof of concept"]
|
||||
[:p.motd {:dangerouslySetInnerHTML
|
||||
{:__html (md->html motd)}}]
|
||||
[:p
|
||||
[:img {:src "img/credits/ric-logo.png" :width "24" :height "24"}]
|
||||
" A project of the "
|
||||
[:a {:href "https://radical.scot/"} "Radical Independence Campaign"]]
|
||||
[:p
|
||||
[:img {:src "img/credits/luminus-logo.png" :alt "Luminus" :height "24" :width "24"}]
|
||||
" Built with "
|
||||
[:a {:href "http://www.luminusweb.net/"} "Luminus Web"]]
|
||||
[:p
|
||||
[:img {:src "img/credits/clojure-icon.gif" :alt "Clojure" :height "24" :width "24"}]
|
||||
" Powered by "
|
||||
[:a {:href "http://clojure.org"} "Clojure"]]
|
||||
[:p
|
||||
[:img {:src "img/credits/github-logo-transparent.png" :alt "GitHub" :height "24" :width "24"}]
|
||||
" Find me/fork me on "
|
||||
[:a {:href "https://github.com/simon-brooke/youyesyet"} "GitHub"]]
|
||||
[:p
|
||||
[:img {:src "img/credits/gnu.small.png" :alt "Free Software Foundation" :height "24" :width "24"}]
|
||||
" Licensed under the "
|
||||
[:a {:href "http://www.gnu.org/licenses/gpl-2.0.html"}
|
||||
"GNU General Public License v2.0"]]
|
||||
(ui/back-link)]]))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
(ns youyesyet.views.electors
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
(:require [reagent.core :refer [atom]]
|
||||
[re-frame.core :refer [reg-sub subscribe dispatch]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
|
|
@ -32,7 +34,99 @@
|
|||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#electors-view
|
||||
|
||||
;;; The design for this panel is one column per elector within the address.
|
||||
;;; Each column contains
|
||||
;;; 1. a stick figure identifying gender (for recognition);
|
||||
;;; 2. the elector's name;
|
||||
;;; 3. one icon for each option on the ballot;
|
||||
;;; 4. an 'issues' icon.
|
||||
;;; The mechanics of how this panel is laid out don't matter.
|
||||
|
||||
(defn gender-cell
|
||||
[elector]
|
||||
(let [gender (:gender elector)
|
||||
image (if gender (name gender) "unknown")]
|
||||
[:td {:key (:id elector)} [:img {:src (str "img/gender/" image ".png") :alt image}]]))
|
||||
|
||||
|
||||
(defn genders-row
|
||||
[electors]
|
||||
[:tr
|
||||
(map
|
||||
#(gender-cell %) electors)])
|
||||
|
||||
|
||||
(defn name-cell
|
||||
[elector]
|
||||
[:td {:key (str "name-" (:id elector))} (:name elector)])
|
||||
|
||||
(defn names-row
|
||||
[electors]
|
||||
[:tr
|
||||
(map
|
||||
#(name-cell %) electors)])
|
||||
|
||||
|
||||
(defn options-row
|
||||
[electors option]
|
||||
(let [optid (:id option)
|
||||
optname (name optid)]
|
||||
[:tr {:key (str "options-" optname)}
|
||||
(map
|
||||
(fn [elector] (let [selected (= optid (:intention elector))
|
||||
image (if selected (str "img/option/" optname "-selected.png")
|
||||
(str "img/option/" optname "-unselected.png"))]
|
||||
[:td {:key (str "option-" optid "-" (:id elector))}
|
||||
[:img
|
||||
{:src image
|
||||
:alt optname
|
||||
:on-click #(dispatch
|
||||
[:send-intention {:elector-id (:id elector)
|
||||
:intention optid}])}]]))
|
||||
;; TODO: impose an ordering on electors - by name or by id
|
||||
electors)]))
|
||||
|
||||
|
||||
(defn issue-cell
|
||||
"Create an issue cell for a particular elector"
|
||||
[elector]
|
||||
[:td {:key (:id elector)}
|
||||
[:a {:href (str "#/issues/" (:id elector))}
|
||||
[:img {:src "img/issues.png" :alt "Issues"}]]])
|
||||
|
||||
|
||||
(defn issues-row
|
||||
[electors]
|
||||
[:tr
|
||||
(map
|
||||
#(issue-cell %)
|
||||
electors)])
|
||||
|
||||
(defn panel
|
||||
"Generate the electors panel."
|
||||
[]
|
||||
[])
|
||||
(let [address @(subscribe [:address])
|
||||
addresses @(subscribe [:addresses])
|
||||
electors (sort-by :id (:electors address))
|
||||
options @(subscribe [:options])
|
||||
changes @(subscribe [:changes])]
|
||||
(if address
|
||||
[:div
|
||||
[:h1 (:address address)]
|
||||
[:div.container {:id "main-container"}
|
||||
[:table
|
||||
[:tbody
|
||||
;; genders row
|
||||
(genders-row electors)
|
||||
;; names row
|
||||
(names-row electors)
|
||||
;; options rows
|
||||
(map
|
||||
#(options-row electors %)
|
||||
options)
|
||||
;; issues row
|
||||
(issues-row electors)]]
|
||||
(ui/back-link)]]
|
||||
(ui/error-panel "No address selected"))))
|
||||
|
||||
|
||||
|
|
|
|||
77
src/cljs/youyesyet/views/followup.cljs
Normal file
77
src/cljs/youyesyet/views/followup.cljs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
(ns youyesyet.views.followup
|
||||
(:require [re-frame.core :refer [reg-sub subscribe dispatch]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.followup-request: followup-request view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the followup-request view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#followup-request-form
|
||||
|
||||
(defn panel
|
||||
"Generate the followup-request panel."
|
||||
[]
|
||||
(let [issue @(subscribe [:issue])
|
||||
issues @(subscribe [:issues])
|
||||
elector @(subscribe [:elector])
|
||||
address @(subscribe [:address])]
|
||||
(js/console.log (str "Issue is " issue "; elector is " elector))
|
||||
(cond
|
||||
(nil? address)
|
||||
(ui/error-panel "No address selected")
|
||||
(nil? issues)
|
||||
(ui/error-panel "No issues loaded")
|
||||
true
|
||||
[:div
|
||||
[:h1 "Followup Request"]
|
||||
[:div.container {:id "main-container"}
|
||||
[:div {}
|
||||
[:p.widget
|
||||
[:label {:for "elector"} "Elector"]
|
||||
[:select {:id "elector" :name "elector" :defaultValue (:id elector)
|
||||
:on-change #(dispatch [:set-elector (.-value (.-target %))])}
|
||||
(map
|
||||
#(let []
|
||||
[:option {:value (:id %) :key (:id %)} (:name %)]) (:electors address))]]
|
||||
[:p.widget
|
||||
[:label {:for "issue"} "Issue"]
|
||||
;; #(reset! val (-> % .-target .-value))
|
||||
[:select {:id "issue" :name "issue" :defaultValue issue
|
||||
:on-change #(dispatch [:set-issue (.-value (.-target %))])}
|
||||
(map
|
||||
#(let []
|
||||
[:option {:key % :value %} %]) (keys issues))]]
|
||||
[:p.widget
|
||||
[:label {:for "telephone"} "Telephone number"]
|
||||
[:input {:type "text" :id "telephone" :name "telephone"
|
||||
:on-change #(dispatch [:set-telephone (.-value (.-target %))])}]]
|
||||
[:p.widget
|
||||
[:label {:for "send"} "To request a call"]
|
||||
[:button {:id "send" :on-click #(dispatch [:send-request])} "Send this!"]]]
|
||||
(ui/back-link)]])))
|
||||
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
(ns youyesyet.views.followup-request
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.followup-request: followup-request view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the followup-request view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#followup-request-form
|
||||
|
||||
(defn panel
|
||||
"Generate the followup-request panel."
|
||||
[]
|
||||
[])
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
(ns youyesyet.views.login
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.login: login view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the login view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#followup-requests-view
|
||||
|
||||
(defn panel
|
||||
"Generate the login panel."
|
||||
[]
|
||||
[])
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
(ns youyesyet.views.home
|
||||
(:require [re-frame.core :as rf]
|
||||
[markdown.core :refer [md->html]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.electors: home view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will provide the home view.
|
||||
|
||||
(defn panel
|
||||
"Generate the home panel."
|
||||
[]
|
||||
[:div.container {:id "main-container"}
|
||||
(ui/big-link "About" "#/about")
|
||||
(ui/big-link "Map" "#/map")
|
||||
[:div.jumbotron
|
||||
[:h1 "You Yes Yet?"]
|
||||
[:p "Time to start building your site!"]
|
||||
[:p [:a.btn.btn-primary.btn-lg {:href "http://luminusweb.net"} "Learn more »"]]]])
|
||||
(when-let [docs @(rf/subscribe [:docs])]
|
||||
[:div.row
|
||||
[:div.col-md-12
|
||||
[:div {:dangerouslySetInnerHTML
|
||||
{:__html (md->html docs)}}]]])
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
(ns youyesyet.views.followup-action
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
(ns youyesyet.views.issue
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
[markdown.core :refer [md->html]]
|
||||
[youyesyet.ui-utils :as ui]
|
||||
[youyesyet.views.issues :as issues]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.followup-action: followup-action view for youyesyet.
|
||||
;;;; youyesyet.views.issues: issues view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
|
|
@ -28,11 +31,19 @@
|
|||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the followup-action view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#followup-action-view
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the single issue view.
|
||||
|
||||
(defn panel
|
||||
"Generate the followup-action panel."
|
||||
"Generate the issue panel."
|
||||
[]
|
||||
[])
|
||||
(let [issue @(subscribe [:issue])
|
||||
issues @(subscribe [:issues])]
|
||||
[:div
|
||||
[:h1 issue]
|
||||
[:div.container {:id "main-container"}
|
||||
[:div {:id "issue"}
|
||||
[:div {:id "issue-text"
|
||||
:dangerouslySetInnerHTML
|
||||
{:__html (md->html (issues issue))}}]]
|
||||
(ui/big-link "Request call" "#/followup")
|
||||
(ui/back-link)]]))
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
(ns youyesyet.views.issues
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
|
|
@ -32,7 +33,16 @@
|
|||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#issues-view
|
||||
|
||||
;;; Simple list of the issues of the day.
|
||||
(defn panel
|
||||
"Generate the issues panel."
|
||||
[]
|
||||
[])
|
||||
(let [issues @(subscribe [:issues])]
|
||||
(if issues
|
||||
[:div
|
||||
[:h1 "Issues"]
|
||||
[:div.container {:id "main-container"}
|
||||
(ui/back-link)
|
||||
[:div {:id "issue-list"}
|
||||
(map (fn [k] (ui/big-link k (str "#/issue/" k))) (keys issues))]]]
|
||||
(ui/error-panel "No issues loaded"))))
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
(ns youyesyet.views.login
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.login: login view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the login view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#logging-in
|
||||
|
||||
(defn panel
|
||||
"Generate the login panel."
|
||||
[]
|
||||
[])
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
(ns youyesyet.views.map
|
||||
(:require [re-frame.core :refer [reg-sub]]
|
||||
(:require [re-frame.core :refer [reg-sub subscribe dispatch]]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#map-view
|
||||
|
||||
|
||||
;;; Cribbed heavily from
|
||||
;;; https://github.com/reagent-project/reagent-cookbook/tree/master/recipes/leaflet
|
||||
;;; but using OSM data because we can't afford commercial, so also cribbed from
|
||||
|
|
@ -41,6 +40,11 @@
|
|||
;;; Note that this is raw reagent stylee; it should be refactoed into re-frame stylee
|
||||
;;; when I understand it better.
|
||||
|
||||
;;; There should be one flag on the map for each address record currently in frame.
|
||||
;;; Clicking the flag sets that address as the current address in the app state,
|
||||
;;; and redirects to the electors view. How we handle blocks of flats needs further
|
||||
;;; thought.
|
||||
|
||||
;; which provider to use
|
||||
(def *map-provider* :osm)
|
||||
|
||||
|
|
@ -48,26 +52,75 @@
|
|||
(def osm-attrib "Map data © <a href='http://openstreetmap.org'>OpenStreetMap</a> contributors")
|
||||
|
||||
|
||||
(defn pin-image
|
||||
"select the name of a suitable pin image for this address"
|
||||
[address]
|
||||
(let [intentions (set (remove nil? (map #(:intention %) (:electors address))))]
|
||||
(case (count intentions)
|
||||
0 "unknown-pin"
|
||||
1 (str (name (first intentions)) "-pin")
|
||||
"mixed-pin")))
|
||||
|
||||
|
||||
(defn map-pin-click-handler
|
||||
"On clicking on the pin, navigate to the electors at the address.
|
||||
This way of doing it adds an antry in the browser location history,
|
||||
so back links work."
|
||||
[id]
|
||||
(js/console.log (str "Click handler for address #" id))
|
||||
(set! window.location.href (str "#electors/" id)))
|
||||
;; This way is probably more idiomatic React, but history doesn't work:
|
||||
;; (defn map-pin-click-handler
|
||||
;; [id]
|
||||
;; (dispatch [:set-address id]))
|
||||
|
||||
|
||||
(defn add-map-pin
|
||||
"Add a map-pin at this address in this map view"
|
||||
[address view]
|
||||
(let [lat (:latitude address)
|
||||
lng (:longitude address)
|
||||
pin (.icon js/L
|
||||
(clj->js
|
||||
{:iconUrl (str "img/map-pins/" (pin-image address) ".png")
|
||||
:shadowUrl "img/map-pins/shadow_pin.png"
|
||||
:iconSize [32 42]
|
||||
:shadowSize [57 24]
|
||||
:iconAnchor [16 41]
|
||||
:shadowAnchor [16 23]}))
|
||||
marker (.marker js/L
|
||||
(.latLng js/L lat lng)
|
||||
(clj->js {:icon pin
|
||||
:title (:address address)}))
|
||||
]
|
||||
(.on marker "click" (fn [_] (map-pin-click-handler (str (:id address)))))
|
||||
(.addTo marker view)))
|
||||
|
||||
|
||||
;; My gods mapbox is user-hostile!
|
||||
(defn map-did-mount-mapbox
|
||||
"Did-mount function loading map tile data from MapBox (proprietary)."
|
||||
"Did-mount function loading map tile data from MapBox (proprietary)."
|
||||
[]
|
||||
(let [map (.setView (.map js/L "map") #js [55.86 -4.25] 13)]
|
||||
(let [view (.setView (.map js/L "map" (clj->js {:zoomControl "false"})) #js [55.82 -4.25] 40)]
|
||||
;; NEED TO REPLACE FIXME with your mapID!
|
||||
(.addTo (.tileLayer js/L "http://{s}.tiles.mapbox.com/v3/FIXME/{z}/{x}/{y}.png"
|
||||
(clj->js {:attribution "Map data © [...]"
|
||||
:maxZoom 18}))
|
||||
map)))
|
||||
view)))
|
||||
|
||||
|
||||
(defn map-did-mount-osm
|
||||
"Did-mount function loading map tile data from Open Street Map (open)."
|
||||
"Did-mount function loading map tile data from Open Street Map."
|
||||
[]
|
||||
(let [map (.setView (.map js/L "map") #js [55.86 -4.25] 13)]
|
||||
(let [view (.setView (.map js/L "map" (clj->js {:zoomControl false})) #js [55.82 -4.25] 13)
|
||||
addresses @(subscribe [:addresses])]
|
||||
(js/console.log (str "Adding " (count addresses) " pins"))
|
||||
(doall (map #(add-map-pin % view) addresses))
|
||||
(.addTo (.tileLayer js/L osm-url
|
||||
(clj->js {:attribution osm-attrib
|
||||
:maxZoom 18}))
|
||||
map)))
|
||||
view)
|
||||
))
|
||||
|
||||
|
||||
(defn map-did-mount
|
||||
|
|
@ -91,4 +144,3 @@
|
|||
[]
|
||||
(reagent/create-class {:reagent-render map-render
|
||||
:component-did-mount map-did-mount}))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
(ns youyesyet.views.role-menu
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.role-menu: role-menu view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the role-menu view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#after-login
|
||||
|
||||
|
||||
(defn panel
|
||||
"Generate the role-menu panel."
|
||||
[]
|
||||
[])
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
(ns youyesyet.views.signup
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.signup: signup view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the signup view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#creating-an-account
|
||||
|
||||
(defn panel
|
||||
"Generate the signup panel."
|
||||
[]
|
||||
[])
|
||||
Loading…
Add table
Add a link
Reference in a new issue