Merge branch 'feature/reflow-app' into develop

This commit is contained in:
Simon Brooke 2018-08-29 13:55:57 +01:00
commit 872fc2b6a8
14 changed files with 178 additions and 249 deletions

View file

@ -362,7 +362,6 @@ th {
/* content of the current page in the Wiki - editable, provided by users. Within main-container */ /* content of the current page in the Wiki - editable, provided by users. Within main-container */
#content { #content {
border: thin solid silver;
width: 80%; width: 80%;
float: right; float: right;
padding-bottom: 5em; padding-bottom: 5em;
@ -396,7 +395,6 @@ th {
/* content of the current in the Wiki - editable, provided by users. Within main-container */ /* content of the current in the Wiki - editable, provided by users. Within main-container */
#content { #content {
border: thin solid silver;
width: 100%; width: 100%;
padding-bottom: 2em; padding-bottom: 2em;
} }

View file

@ -43,7 +43,7 @@ SELECT DISTINCT request.*,
addresses.address ||', '|| addresses.postcode ||', '|| visits.date AS visit_id_expanded, addresses.address ||', '|| addresses.postcode ||', '|| visits.date AS visit_id_expanded,
request.issue_id as issue_id_expanded, request.issue_id as issue_id_expanded,
request.method_id AS method_id_expanded, request.method_id AS method_id_expanded,
visits.date visits.date AS raised
FROM followuprequests as request, FROM followuprequests as request,
ln_experts_issues_canvassers as expertise, ln_experts_issues_canvassers as expertise,
canvassers as experts, canvassers as experts,
@ -58,7 +58,7 @@ and request.visit_id = visits.id
and visits.address_id = addresses.id and visits.address_id = addresses.id
and request.issue_id = expertise.issue_id and request.issue_id = expertise.issue_id
and expertise.canvasser_id = :expert and expertise.canvasser_id = :expert
ORDER BY visits.date desc ORDER BY raised
--:name get-last-visit-by-canvasser :? :1 --:name get-last-visit-by-canvasser :? :1
--:doc returns the most recent visit record of the canvasser with the specified `:id` --:doc returns the most recent visit record of the canvasser with the specified `:id`

View file

@ -5,6 +5,7 @@
<!-- head: if you want entire custom head content, override this block. --> <!-- head: if you want entire custom head content, override this block. -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="referrer" content="same-origin">
{% style "/css/yyy-common.css" %} {% style "/css/yyy-common.css" %}
{% style "/css/yyy-site.css" %} {% style "/css/yyy-site.css" %}
{% style "/css/spinner.css" %} {% style "/css/spinner.css" %}
@ -27,9 +28,13 @@
<menu id="nav-menu" class="nav"> <menu id="nav-menu" class="nav">
<li class=""><a href="{{servlet-context}}/home">Home</a></li> <li class=""><a href="{{servlet-context}}/home">Home</a></li>
<li class=""><a href="{{servlet-context}}/library">Library</a></li> <li class=""><a href="{{servlet-context}}/library">Library</a></li>
{% if user %}
<li class=""><a href="{{servlet-context}}/roles">Roles</a></li>
<li class=""><a href="{{servlet-context}}/logout">Logout</a></li>
{% else %}
<li class=""><a href="{{servlet-context}}/register">Register</a></li> <li class=""><a href="{{servlet-context}}/register">Register</a></li>
<li class="">{% if user %}<a href="{{servlet-context}}/logout">Logout</a> <li class=""><a href="{{servlet-context}}/login">Login</a></li>
{% else %}<a href="{{servlet-context}}/login">Login</a>{% endif %}</li> {% endif %}
<li class=""><a href="{{servlet-context}}/about">About</a></li> <li class=""><a href="{{servlet-context}}/about">About</a></li>
{% if user %} {% if user %}
<li id="user"><a href="{{servlet-context}}/profile">Logged in as {{user.username}}</a></li> <li id="user"><a href="{{servlet-context}}/profile">Logged in as {{user.username}}</a></li>

View file

@ -36,19 +36,16 @@ Add a new Followuprequest
<thead> <thead>
<tr> <tr>
<th> <th>
Id Elector
</th> </th>
<th> <th>
Elector_id Raised
</th> </th>
<th> <th>
Visit_id Issue
</th> </th>
<th> <th>
Issue_id Method
</th>
<th>
Method_id
</th> </th>
<th> <th>
&nbsp; &nbsp;
@ -56,13 +53,10 @@ Method_id
</tr> </tr>
<tr> <tr>
<th> <th>
<input id='id' type='text' name='id' value='{{ params.id }}'/>
</th>
<th>
<input id='elector_id' type='text' name='elector_id' value='{{ params.elector_id }}'/> <input id='elector_id' type='text' name='elector_id' value='{{ params.elector_id }}'/>
</th> </th>
<th> <th>
<input id='visit_id' type='text' name='visit_id' value='{{ params.visit_id }}'/> <input id='raised' type='text' name='raised' value='{{ params.raised }}'/>
</th> </th>
<th> <th>
<input id='issue_id' type='text' name='issue_id' value='{{ params.issue_id }}'/> <input id='issue_id' type='text' name='issue_id' value='{{ params.issue_id }}'/>
@ -79,17 +73,12 @@ Method_id
{% for record in records %} {% for record in records %}
<tr> <tr>
<td> <td>
{{ record.id }}
</td>
<td>
<a href='{{servlet-context}}/form-electors-Elector?id={{ record.elector_id }}'> <a href='{{servlet-context}}/form-electors-Elector?id={{ record.elector_id }}'>
{{ record.elector_id_expanded }} {{ record.elector_id_expanded }}
</a> </a>
</td> </td>
<td> <td>
<a href='{{servlet-context}}/form-visits-Visit?id={{ record.visit_id }}'> {{ record.raised}}
{{ record.visit_id_expanded }}
</a>
</td> </td>
<td> <td>
<a href='{{servlet-context}}/form-issues-Issue?id={{ record.issue_id }}'> <a href='{{servlet-context}}/form-issues-Issue?id={{ record.issue_id }}'>

View file

@ -140,7 +140,8 @@
params :visit_id (current-visit-id request))) params :visit_id (current-visit-id request)))
201) 201)
{:status 400 {:status 400
:body (json/write-str "create-intention requires params: `option_id` :body (json/write-str
"create-intention requires params: `option_id`
and either `locality` or both `address_id` and `elector_id`.")}) and either `locality` or both `address_id` and `elector_id`.")})
request))) request)))
@ -164,7 +165,28 @@
request))) request)))
(defn update-elector-signature!
"Set the `signature` in the params of this `request` as the signature for
the elector whose `id` is in the params of this `request`."
[request]
(let [params (massage-params request)]
(log/debug "Update elector signature with params: " params)
(valid-user-or-forbid
(with-params-or-error
(do-or-server-fail
(db/update-elector! db/*db* params)
201)
params
#{:id :signature})
request)))
(defroutes rest-routes (defroutes rest-routes
(GET "/rest/get-local-data" request (route/restricted (get-local-data request))) (GET "/rest/get-local-data"
(GET "/rest/create-intention" request (route/restricted (create-intention-and-visit! request))) request (route/restricted (get-local-data request)))
(GET "/rest/create-request" request (route/restricted (create-request-and-visit! request)))) (GET "/rest/create-intention"
request (route/restricted (create-intention-and-visit! request)))
(GET "/rest/create-request"
request (route/restricted (create-request-and-visit! request)))
(GET "/rest/update-elector-signature"
request (route/restricted (update-elector-signature! request))))

View file

@ -118,61 +118,57 @@
;; Routes ;; Routes
(secretary/set-config! :prefix "#") (secretary/set-config! :prefix "#")
(defn log-and-dispatch [arg]
(js/console.log (str "Dispatching " arg))
(rf/dispatch arg))
(secretary/defroute "/" [] (secretary/defroute "/" []
(log-and-dispatch [:set-active-page :map])) (ui/log-and-dispatch [:set-active-page :map]))
(secretary/defroute "/about" [] (secretary/defroute "/about" []
(log-and-dispatch [:set-active-page :about])) (ui/log-and-dispatch [:set-active-page :about]))
(secretary/defroute "/dwelling" [] (secretary/defroute "/dwelling" []
(log-and-dispatch [:set-active-page :dwelling])) (ui/log-and-dispatch [:set-active-page :dwelling]))
(secretary/defroute "/dwelling/:dwelling" {dwelling-id :dwelling} (secretary/defroute "/dwelling/:dwelling" {dwelling-id :dwelling}
(log-and-dispatch [:set-dwelling dwelling-id]) (ui/log-and-dispatch [:set-dwelling dwelling-id])
(log-and-dispatch [:set-active-page :dwelling])) (ui/log-and-dispatch [:set-active-page :dwelling]))
(secretary/defroute "/building/:address" {address-id :address} (secretary/defroute "/building/:address" {address-id :address}
(log-and-dispatch [:set-address address-id])) (ui/log-and-dispatch [:set-address address-id]))
(secretary/defroute "/elector" [] (secretary/defroute "/elector" []
(log-and-dispatch [:set-active-page :elector])) (ui/log-and-dispatch [:set-active-page :elector]))
(secretary/defroute "/elector/:elector" {elector-id :elector} (secretary/defroute "/elector/:elector/:consent" {elector-id :elector}
(log-and-dispatch [:set-elector-and-page {:elector-id elector-id :page :elector}])) (ui/log-and-dispatch [:set-elector-and-page {:elector-id elector-id :page :elector}]))
(secretary/defroute "/elector/:elector/:consent" {elector-id :elector consent :consent} (secretary/defroute "/elector/:elector/:consent" {elector-id :elector consent :consent}
(log-and-dispatch [:set-consent-and-page {:elector-id elector-id :consent (and true consent) :page :elector}])) (ui/log-and-dispatch [:set-active-page {:page :elector}]))
(secretary/defroute "/elector" [] (secretary/defroute "/elector" []
(log-and-dispatch [:set-active-page :elector])) (ui/log-and-dispatch [:set-active-page :elector]))
(secretary/defroute "/followup" [] (secretary/defroute "/followup" []
(log-and-dispatch [:set-active-page :followup])) (ui/log-and-dispatch [:set-active-page :followup]))
(secretary/defroute "/gdpr" [] (secretary/defroute "/gdpr" []
(log-and-dispatch [:set-active-page :gdpr])) (ui/log-and-dispatch [:set-active-page :gdpr]))
(secretary/defroute "/gdpr/:elector" {elector-id :elector} (secretary/defroute "/gdpr/:elector" {elector-id :elector}
(log-and-dispatch [:set-elector-and-page {:elector-id elector-id :page :gdpr}])) (ui/log-and-dispatch [:set-elector-and-page {:elector-id elector-id :page :gdpr}]))
(secretary/defroute "/issues" [] (secretary/defroute "/issues" []
(log-and-dispatch [:set-active-page :issues])) (ui/log-and-dispatch [:set-active-page :issues]))
(secretary/defroute "/issues/:elector" {elector-id :elector} (secretary/defroute "/issues/:elector" {elector-id :elector}
(log-and-dispatch [:set-elector-and-page {:elector-id elector-id :page :issues}])) (ui/log-and-dispatch [:set-elector-and-page {:elector-id elector-id :page :issues}]))
(secretary/defroute "/issue/:issue" {issue :issue} (secretary/defroute "/issue/:issue" {issue :issue}
(log-and-dispatch [:set-and-go-to-issue issue])) (ui/log-and-dispatch [:set-and-go-to-issue issue]))
(secretary/defroute "/map" [] (secretary/defroute "/map" []
(log-and-dispatch [:set-active-page :map])) (ui/log-and-dispatch [:set-active-page :map]))
(secretary/defroute "/set-intention/:elector/:intention" {elector-id :elector intention :intention} (secretary/defroute "/set-intention/:elector/:intention" {elector-id :elector intention :intention}
(log-and-dispatch [:set-intention {:elector-id elector-id :intention intention}])) (ui/log-and-dispatch [:set-intention {:elector-id elector-id :intention intention}]))
;; ------------------------- ;; -------------------------
;; History ;; History
@ -193,7 +189,7 @@
(defn init! [] (defn init! []
(rf/dispatch-sync [:initialize-db]) (rf/dispatch-sync [:initialize-db])
(rf/dispatch-sync [:get-current-location]) (rf/dispatch [:get-current-location])
(rf/dispatch [:fetch-locality]) (rf/dispatch [:fetch-locality])
(rf/dispatch [:fetch-options]) (rf/dispatch [:fetch-options])
(rf/dispatch [:fetch-issues]) (rf/dispatch [:fetch-issues])

View file

@ -7,7 +7,6 @@
[re-frame.core :refer [dispatch reg-event-db reg-event-fx subscribe]] [re-frame.core :refer [dispatch reg-event-db reg-event-fx subscribe]]
[ajax.core :refer [GET]] [ajax.core :refer [GET]]
[ajax.json :refer [json-request-format json-response-format]] [ajax.json :refer [json-request-format json-response-format]]
[youyesyet.canvasser-app.state :as db]
[youyesyet.locality :refer [locality]] [youyesyet.locality :refer [locality]]
)) ))
@ -39,19 +38,20 @@
(defn get-current-location [] (defn get-current-location []
"Get the current location from the device, setting it in the database and "Get the current location from the device, setting it in the database and
returning the locality." returning the locality."
(try (try
(if (.-geolocation js/navigator) (if (.-geolocation js/navigator)
(.getCurrentPosition (.getCurrentPosition
(.-geolocation js/navigator) (.-geolocation js/navigator)
(fn [position] (fn [position]
(js/console.log (str "Current location is: " (let [lat (.-latitude (.-coords position))
(.-latitude (.-coords position)) ", " lng (.-longitude (.-coords position))]
(.-longitude (.-coords position)))) (js/console.log (str "Current location is: " lat ", " lng))
(dispatch [:set-latitude (.-latitude (.-coords position))]) (dispatch [:set-latitude lat])
(dispatch [:set-longitude (.-longitude (.-coords position))]) (dispatch [:set-longitude lng])
(locality (.-latitude (.-coords position)) (.-longitude (.-coords position)))))) ;; (.panTo @(subscribe [:view]) (.latLng js/L lat lng))
(js/console.log "Geolocation not available") (locality lat lng))))
(js/console.log "Geolocation not available"))
(catch js/Object any (catch js/Object any
(js/console.log "Exception while trying to access location: " + any) (js/console.log "Exception while trying to access location: " + any)
0))) 0)))

View file

@ -140,34 +140,6 @@
db/default-db)) db/default-db))
;; (reg-event-fx
;; :feedback
;; (fn [x y]
;; (js/console.log (str "Feedback event called with x = " x "; y = " y))
;; (:db x)))
;; (reg-event-fx
;; :issues
;; (fn [x y]
;; (js/console.log (str "Issues event called with x = " x "; y = " y))
;; (:db x)))
;; (reg-event-fx
;; :options
;; (fn [x y]
;; (js/console.log (str "Options event called with x = " x "; y = " y))
;; (:db x)))
;; (reg-event-fx
;; :event
;; (fn [x y]
;; (js/console.log (str "Event event called with x = " x "; y = " y))
;; (:db x)))
(reg-event-fx (reg-event-fx
:fetch-locality :fetch-locality
(fn [{db :db} _] (fn [{db :db} _]
@ -204,36 +176,29 @@
(reg-event-fx (reg-event-fx
:process-locality :process-locality
(fn ;; TODO: why is this an `-fx`? Does it need to be?
[{db :db} [_ response]] (fn
(js/console.log (str "Updating locality data: " (count response) " addresses " )) [{db :db} [_ response]]
(refresh-map-pins) (js/console.log (str "Updating locality data: " (count response) " addresses " ))
{:dispatch-later [{:ms 60000 :dispatch [:fetch-locality]} (refresh-map-pins)
{:ms 1000 :dispatch [:get-current-location]}] {:db (assoc
:db (assoc (remove-from-feedback db :fetch-locality)
(remove-from-feedback db :fetch-locality) :addresses (js->clj response))}))
:addresses (js->clj response))}))
(reg-event-fx (reg-event-fx
:bad-locality :bad-locality
;; TODO: why is this an `-fx`? Does it need to be?
(fn (fn
[{db :db} [_ response]] [{db :db} [_ response]]
;; TODO: signal something has failed? It doesn't matter very much, unless it keeps failing. ;; TODO: signal something has failed? It doesn't matter very much, unless it keeps failing.
(js/console.log "Failed to fetch locality data") (js/console.log "Failed to fetch locality data")
;; loop to do it again ;; loop to do it again
(dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-locality]}]]) (dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-locality]}]])
(assoc {:db (assoc
(remove-from-feedback db :fetch-locality) (remove-from-feedback db :fetch-locality)
:error (cons :fetch-locality (:error db))))) :error (cons :fetch-locality (:error db)))}))
;; (reg-event-fx
;; :process-outqueue
;; (fn [{db :db} _]
;; (if
;; (empty? (:outqueue db))
(reg-event-fx (reg-event-fx
@ -262,12 +227,12 @@
(reg-event-db (reg-event-db
;; TODO: should try again
:bad-options :bad-options
(fn [db [_ response]] (fn [db [_ response]]
(js/console.log "Failed to fetch options") (js/console.log "Failed to fetch options")
(dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-options]}]])
(assoc (assoc
(remove-from-feedback db :fetch-options) db
:error (:response response)))) :error (:response response))))
@ -301,12 +266,12 @@
(reg-event-db (reg-event-db
;; TODO: should try again
:bad-issues :bad-issues
(fn [db [_ response]] (fn [db [_ response]]
(js/console.log "Failed to fetch issues") (js/console.log "Failed to fetch issues")
(dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-issues]}]])
(assoc (assoc
(remove-from-feedback db :fetch-issues) db
:error (:response response)))) :error (:response response))))
@ -347,7 +312,7 @@
:method_detail (-> db :method_detail) :method_detail (-> db :method_detail)
:action :create-request}) :action :create-request})
:send-request)) :send-request))
(assoc db :error "Please supply a telephone number to call")))) (assoc db :error "Please supply a telephone number/email address for elector"))))
(reg-event-db (reg-event-db
@ -380,15 +345,34 @@
:page :building)))))) :page :building))))))
(defn do-update-elector
[db elector]
(if-not
;; if the signature has changed
(= (:signature elector) (:signature (:elector db)))
(assoc
(add-to-outqueue
(clear-messages db)
(assoc elector
:action :update-elector-signature))
:elector elector)
(assoc db
:elector elector)))
(reg-event-db
:update-elector
(fn [db [_ elector]]
(js/console.log (str "Elector is " elector))
(do-update-elector db elector)))
(reg-event-db (reg-event-db
:set-consent-and-page :set-consent-and-page
(fn [db [_ args]] (fn [db [_ args]]
(let [page (:page args) (assoc
consent (:consent args) (do-update-elector db (:elector args))
elector-id (coerce-to-number (:elector-id args)) :page (:page args))))
elector (get-elector elector-id db)]
(js/console.log (str "Setting page to " page ", consent to " consent " for " (:name elector)))
(assoc (clear-messages db) :elector (assoc elector :consent true) :page page))))
(reg-event-db (reg-event-db

View file

@ -1,6 +1,7 @@
(ns ^{:doc "Canvasser app client state." (ns ^{:doc "Canvasser app client state."
:author "Simon Brooke"} :author "Simon Brooke"}
youyesyet.canvasser-app.state) youyesyet.canvasser-app.state
(:require [youyesyet.canvasser-app.gis :as gis]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; ;;;;
@ -28,129 +29,21 @@
;;; This is the constructor for the atom in which the state of the user interface is held. ;;; 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. ;;; The atom gets updated by 'events' registered in handler.cljs, q.v.
(def default-db
{
:addresses
[{:locality 548223905,
:address
"HAZELFIELD HOUSE, CASTLE DOUGLAS, DG7 1RF",
:phone nil,
:postcode "DG7 1RF",
:longitude -3.905045374625994,
:district_id 1,
:dwellings
[{:address_id_expanded
"HAZELFIELD HOUSE, CASTLE DOUGLAS, DG7 1RF, DG7 1RF",
:address_id 18,
:sub_address "",
:id 17,
:id_2 17,
:address_id_2 18,
:sub_address_2 "",
:electors
[{:email nil,
:dwelling_id_2 17,
:dwelling_id_expanded
"HAZELFIELD HOUSE, CASTLE DOUGLAS, DG7 1RF, DG7 1RF, ",
:intentions
[{:locality 548223905,
:visit_id_expanded
"HAZELFIELD HOUSE, CASTLE DOUGLAS, DG7 1RF, DG7 1RF, 2018-06-14 20:29:34.721522",
:option_id_expanded "Yes",
:option_id "Yes",
:option_id_2 "Yes",
:visit_id_2 1,
:elector_id_2 61,
:visit_id 1,
:elector_id 61,
:id 1,
:elector_id_expanded nil,
:id_2 1}],
:phone nil,
:phone_2 nil,
:gender_expanded "Female",
:name "Alice Sutherland",
:dwelling_id 17,
:id 61,
:gender "Female",
:gender_2 "Female",
:name_2 "Alice Sutherland",
:email_2 nil,
:id_2 61}
{:email nil,
:dwelling_id_2 17,
:dwelling_id_expanded
"HAZELFIELD HOUSE, CASTLE DOUGLAS, DG7 1RF, DG7 1RF, ",
:intentions [],
:phone nil,
:phone_2 nil,
:gender_expanded "Female",
:name "Charlie Sutherland",
:dwelling_id 17,
:id 62,
:gender "Female",
:gender_2 "Female",
:name_2 "Charlie Sutherland",
:email_2 nil,
:id_2 62}
{:email nil,
:dwelling_id_2 17,
:dwelling_id_expanded
"HAZELFIELD HOUSE, CASTLE DOUGLAS, DG7 1RF, DG7 1RF, ",
:intentions [],
:phone nil,
:phone_2 nil,
:gender_expanded "Male",
:name "Keith Sutherland",
:dwelling_id 17,
:id 64,
:gender "Male",
:gender_2 "Male",
:name_2 "Keith Sutherland",
:email_2 nil,
:id_2 64}
{:email nil,
:dwelling_id_2 17,
:dwelling_id_expanded
"HAZELFIELD HOUSE, CASTLE DOUGLAS, DG7 1RF, DG7 1RF, ",
:intentions [],
:phone nil,
:phone_2 nil,
:gender_expanded "Female",
:name "Lucy Sutherland",
:dwelling_id 17,
:id 63,
:gender "Female",
:gender_2 "Female",
:name_2 "Lucy Sutherland",
:email_2 nil,
:id_2 63}]}],
:id 18,
:latitude 54.8222716877376}]
;;; the currently selected address, if any. (def default-db
:address nil { ;;; any confirmation message to display
;;; electors at the currently selected dwelling :feedback '("Welcome to the canvasser app!")
:electors nil
;;; any error to display
:error nil
;;; the issue from among the issues which is currently selected.
;;; any confirmation message to display
:feedback '()
;;; the currently selected issue
:issue nil
;;; the issues selected for the issues page on this day.
:issues nil
;;; message of the day ;;; message of the day
:motd "This is a test version only. There is no real data." :motd "This is a test version only. There is no real data."
;;; the options from among which electors can select. ;;; the options from among which electors can select.
:options nil :outqueue '()
;;; the queue of items waiting to be transmitted. ;;; the view of the map we display
:outqueue () :view nil
;;; the currently displayed page within the app. ;;; the currently displayed page within the app.
:page :home :page :home
:view nil ;;; initial starting coords in the centre of Scotland.
:latitude 54.82 :latitude 56
:longitude -3.92 :longitude -4
:zoom 12}) :zoom 12})

View file

@ -28,6 +28,11 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn log-and-dispatch [arg]
(js/console.log (str "Dispatching " arg))
(rf/dispatch arg))
(defn back-link (defn back-link
"Generate a back link to the preceding page, or, if `target` is specified, "Generate a back link to the preceding page, or, if `target` is specified,
to a particular page." to a particular page."
@ -41,7 +46,7 @@
(defn big-link (defn big-link
[text & {:keys [target handler]}] [text & {:keys [target handler]}]
[:div.big-link-container {:key (gensym "big-link")} [:div.big-link-container {:key (gensym "big-link")}
[:a.big-link (merge [:a.big-link (merge {}
(if target {:href target}{}) (if target {:href target}{})
(if handler {:on-click handler}{})) (if handler {:on-click handler}{}))
text]]) text]])
@ -75,4 +80,5 @@
(nav-link "#/map" "Map" :map collapsed?) (nav-link "#/map" "Map" :map collapsed?)
(nav-link "#/dwelling" "Electors" :dwelling collapsed?) (nav-link "#/dwelling" "Electors" :dwelling collapsed?)
(nav-link "#/issues" "Issues" :issues collapsed?) (nav-link "#/issues" "Issues" :issues collapsed?)
(nav-link "#/about" "About" :about collapsed?)]])) (nav-link "#/about" "About" :about collapsed?)
(nav-link "/logout" "Logout" :logout collapsed?)]]))

View file

@ -41,7 +41,7 @@
[:div [:div
[:h1 (str "Flats at " (:address address))] [:h1 (str "Flats at " (:address address))]
[:div.container {:id "main-container"} [:div.container {:id "main-container"}
(ui/back-link) (ui/back-link "#map")
[:div {:id "dwelling-list"} [:div {:id "dwelling-list"}
(map (map
(fn (fn

View file

@ -80,11 +80,16 @@
(defn panel (defn panel
"Generate the electors panel." "Generate the electors panel."
[] []
(js/console.log "dwelling.panel")
(let [dwelling @(subscribe [:dwelling]) (let [dwelling @(subscribe [:dwelling])
address @(subscribe [:address]) address @(subscribe [:address])
sub-address (:sub-address dwelling) sub-address (:sub-address dwelling)
electors (sort-by :id (:electors dwelling)) electors (sort-by :id (:electors dwelling))
options @(subscribe [:options])] options @(subscribe [:options])
back (if
(> (count (:dwellings address)) 1)
"#building"
"#map")]
(if address (if address
[:div [:div
[:h1 (if sub-address [:h1 (if sub-address
@ -95,7 +100,7 @@
[:tbody [:tbody
(genders-row electors) (genders-row electors)
(names-row electors)]] (names-row electors)]]
(ui/back-link)]] (ui/back-link back)]]
(ui/error-panel "No address selected")))) (ui/error-panel "No address selected"))))

View file

@ -30,6 +30,27 @@
;; OK, the idea here is a GDPR consent form to be signed by the elector ;; OK, the idea here is a GDPR consent form to be signed by the elector
(def sig-pad
;; something the signature pad will be bound to
(atom nil))
(defn send-consent
"Extract the signature from the signature pad, encode it, add it to this
`elector`, and dispatch the `elector`; move on to the page `elector`."
[elector]
(dispatch
[:set-consent-and-page
{:elector-id (:id elector)
:page :elector
:elector (assoc
elector
:signature
(.toDataURL
@sig-pad
"image/svg+xml"))}])
nil)
(defn gdpr-render (defn gdpr-render
[] []
(let [elector @(subscribe [:elector])] (let [elector @(subscribe [:elector])]
@ -48,24 +69,23 @@
only against your electoral district, and not link it to you"]]]] only against your electoral district, and not link it to you"]]]]
[:tr [:tr
[:td [:td
[:canvas {:id "signature-pad"}]]]]]] [:canvas {:id "signature-pad" :on-mouse-out #(send-consent elector)}]]]]]]
(ui/back-link "#dwelling") (ui/back-link "#dwelling")
(ui/big-link "I consent" (ui/big-link "I consent"
:target (str "#elector/" (:id elector) "/true") :target (str "#elector")
:handler #(fn [] (dispatch [:set-consent-and-page {:elector-id (:id elector) :page :elector}]))) :handler #(send-consent elector))
;; TODO: need to save the signature
(ui/big-link "I DO NOT consent" (ui/big-link "I DO NOT consent"
:target (str "#elector/" (:id elector) "/true"))])) :target (str "#elector/" (:id elector) "/false"))]))
;; :handler #(fn [] (dispatch [:set-elector-and-page {:elector-id (:id elector) :page :elector}])))]))
(defn gdpr-did-mount (defn gdpr-did-mount
[] []
(js/SignaturePad. (.getElementById js/document "signature-pad"))) (reset! sig-pad (js/SignaturePad. (.getElementById js/document "signature-pad"))))
(defn panel (defn panel
"A reagent class for the GDPR consent form" "A reagent class for the GDPR consent form"
[] []
(js/console.log "gdpr.panel")
(reagent/create-class {:reagent-render gdpr-render (reagent/create-class {:reagent-render gdpr-render
:component-did-mount gdpr-did-mount})) :component-did-mount gdpr-did-mount}))

View file

@ -0,0 +1,11 @@
(ns youyesyet.canvasser-app.ui-utils-test
(:require [cljs.test :refer-macros [is are deftest testing use-fixtures]]
[reagent.core :as reagent :refer [atom]]
[youyesyet.canvasser-app.ui-utils :refer :all]))
(deftest big-link-tests
(testing "big-link"
(is (= [:div.big-link-container {:key (gensym "big-link")}
[:a.big-link {}
"Test"]]
(big-link "Test" nil nil)))))