From 7724a2514a3561a801bd07e4672fe60c99245b76 Mon Sep 17 00:00:00 2001
From: Simon Brooke <simon@journeyman.cc>
Date: Tue, 28 Aug 2018 14:27:44 +0100
Subject: [PATCH 1/3] Stuck with an on-click handler that isn't happening

---
 resources/templates/base.html                 |  1 +
 src/cljs/youyesyet/canvasser_app/core.cljs    | 40 +++++++++----------
 .../youyesyet/canvasser_app/handlers.cljs     | 29 ++++++++++----
 .../youyesyet/canvasser_app/ui_utils.cljs     |  8 +++-
 .../canvasser_app/views/building.cljs         |  2 +-
 .../canvasser_app/views/dwelling.cljs         |  9 ++++-
 .../youyesyet/canvasser_app/views/gdpr.cljs   | 28 ++++++++++---
 7 files changed, 78 insertions(+), 39 deletions(-)

diff --git a/resources/templates/base.html b/resources/templates/base.html
index c14f6de..3f9928e 100644
--- a/resources/templates/base.html
+++ b/resources/templates/base.html
@@ -5,6 +5,7 @@
     <!-- head: if you want entire custom head content, override this block. -->
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1"/>
+    <meta name="referrer" content="same-origin">
     {% style "/css/yyy-common.css" %}
     {% style "/css/yyy-site.css" %}
     {% style "/css/spinner.css" %}
diff --git a/src/cljs/youyesyet/canvasser_app/core.cljs b/src/cljs/youyesyet/canvasser_app/core.cljs
index 81b4e36..89493ac 100644
--- a/src/cljs/youyesyet/canvasser_app/core.cljs
+++ b/src/cljs/youyesyet/canvasser_app/core.cljs
@@ -118,61 +118,57 @@
 ;; Routes
 (secretary/set-config! :prefix "#")
 
-(defn log-and-dispatch [arg]
-  (js/console.log (str "Dispatching " arg))
-  (rf/dispatch arg))
-
 (secretary/defroute "/" []
-  (log-and-dispatch [:set-active-page :map]))
+  (ui/log-and-dispatch [:set-active-page :map]))
 
 (secretary/defroute "/about" []
-  (log-and-dispatch [:set-active-page :about]))
+  (ui/log-and-dispatch [:set-active-page :about]))
 
 (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}
-  (log-and-dispatch [:set-dwelling dwelling-id])
-  (log-and-dispatch [:set-active-page :dwelling]))
+  (ui/log-and-dispatch [:set-dwelling dwelling-id])
+  (ui/log-and-dispatch [:set-active-page :dwelling]))
 
 (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" []
-  (log-and-dispatch [:set-active-page :elector]))
+  (ui/log-and-dispatch [:set-active-page :elector]))
 
 (secretary/defroute "/elector/:elector" {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}
-  (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" []
-  (log-and-dispatch [:set-active-page :elector]))
+  (ui/log-and-dispatch [:set-active-page :elector]))
 
 (secretary/defroute "/followup" []
-  (log-and-dispatch [:set-active-page :followup]))
+  (ui/log-and-dispatch [:set-active-page :followup]))
 
 (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}
-  (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" []
-  (log-and-dispatch [:set-active-page :issues]))
+  (ui/log-and-dispatch [:set-active-page :issues]))
 
 (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}
-  (log-and-dispatch [:set-and-go-to-issue issue]))
+  (ui/log-and-dispatch [:set-and-go-to-issue issue]))
 
 (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}
-  (log-and-dispatch [:set-intention {:elector-id elector-id :intention intention}]))
+  (ui/log-and-dispatch [:set-intention {:elector-id elector-id :intention intention}]))
 
 ;; -------------------------
 ;; History
diff --git a/src/cljs/youyesyet/canvasser_app/handlers.cljs b/src/cljs/youyesyet/canvasser_app/handlers.cljs
index 833305f..3ab4419 100644
--- a/src/cljs/youyesyet/canvasser_app/handlers.cljs
+++ b/src/cljs/youyesyet/canvasser_app/handlers.cljs
@@ -209,8 +209,10 @@
    [{db :db} [_ response]]
    (js/console.log (str "Updating locality data: " (count response) " addresses " ))
    (refresh-map-pins)
-   {:dispatch-later [{:ms 60000 :dispatch [:fetch-locality]}
-                     {:ms 1000 :dispatch [:get-current-location]}]
+   {
+;;      :dispatch-later [{:ms 60000 :dispatch [:fetch-locality]}
+;;                      ;; {:ms 1000 :dispatch [:get-current-location]}
+;;                      ]
     :db (assoc
           (remove-from-feedback db :fetch-locality)
           :addresses (js->clj response))}))
@@ -380,15 +382,28 @@
             :page :building))))))
 
 
+(reg-event-db
+  :update-elector
+  (fn [db [_ args]]
+    (if (:signature (:elector db))
+      (do
+        (js/console.log "Updating elector signature")
+        (add-to-feedback
+          (add-to-outqueue
+            db
+            {:elector (:elector db)
+             :action :update-elector-signature})
+          :send-request))
+      (assoc db :error "Please supply a telephone number to call"))))
+
+
 (reg-event-db
   :set-consent-and-page
   (fn [db [_ args]]
     (let [page (:page args)
-          consent (:consent args)
-          elector-id (coerce-to-number (:elector-id 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))))
+          elector (:elector args)]
+      (dispatch [:update-elector {:elector elector}])
+      (assoc (clear-messages db) :elector elector :page page))))
 
 
 (reg-event-db
diff --git a/src/cljs/youyesyet/canvasser_app/ui_utils.cljs b/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
index 12ab66f..cd37ead 100644
--- a/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
+++ b/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
@@ -28,6 +28,11 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
+(defn log-and-dispatch [arg]
+  (js/console.log (str "Dispatching " arg))
+  (rf/dispatch arg))
+
+
 (defn back-link
   "Generate a back link to the preceding page, or, if `target` is specified,
   to a particular page."
@@ -40,8 +45,9 @@
 
 (defn big-link
   [text & {:keys [target handler]}]
+  (js/console.log (str "Big link with target '" target "'; handler '" handler "'"))
   [:div.big-link-container {:key (gensym "big-link")}
-   [:a.big-link (merge
+   [:a.big-link (merge {:href target :on-click handler}
                   (if target {:href target}{})
                   (if handler {:on-click handler}{}))
     text]])
diff --git a/src/cljs/youyesyet/canvasser_app/views/building.cljs b/src/cljs/youyesyet/canvasser_app/views/building.cljs
index d2cac79..3cc7446 100644
--- a/src/cljs/youyesyet/canvasser_app/views/building.cljs
+++ b/src/cljs/youyesyet/canvasser_app/views/building.cljs
@@ -41,7 +41,7 @@
     [:div
      [:h1 (str "Flats at " (:address address))]
      [:div.container {:id "main-container"}
-      (ui/back-link)
+      (ui/back-link "#map")
       [:div {:id "dwelling-list"}
        (map
          (fn
diff --git a/src/cljs/youyesyet/canvasser_app/views/dwelling.cljs b/src/cljs/youyesyet/canvasser_app/views/dwelling.cljs
index 73f28b3..88d5bee 100644
--- a/src/cljs/youyesyet/canvasser_app/views/dwelling.cljs
+++ b/src/cljs/youyesyet/canvasser_app/views/dwelling.cljs
@@ -80,11 +80,16 @@
 (defn panel
   "Generate the electors panel."
   []
+  (js/console.log "dwelling.panel")
   (let [dwelling @(subscribe [:dwelling])
         address @(subscribe [:address])
         sub-address (:sub-address dwelling)
         electors (sort-by :id (:electors dwelling))
-        options @(subscribe [:options])]
+        options @(subscribe [:options])
+        back (if
+               (> (count (:dwellings address)) 1)
+               "#building"
+               "#map")]
     (if address
       [:div
        [:h1 (if sub-address
@@ -95,7 +100,7 @@
          [:tbody
           (genders-row electors)
           (names-row electors)]]
-        (ui/back-link)]]
+        (ui/back-link back)]]
       (ui/error-panel "No address selected"))))
 
 
diff --git a/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs b/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
index 65e1e5a..9da0ad3 100644
--- a/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
+++ b/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
@@ -30,6 +30,11 @@
 
 ;; 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 gdpr-render
   []
   (let [elector @(subscribe [:elector])]
@@ -51,21 +56,32 @@
           [:canvas {:id "signature-pad"}]]]]]]
      (ui/back-link "#dwelling")
      (ui/big-link "I consent"
-                  :target (str "#elector/" (:id elector) "/true")
-                  :handler #(fn [] (dispatch [:set-consent-and-page {:elector-id (:id elector) :page :elector}])))
-     ;; TODO: need to save the signature
+                  ;; :target (str "#elector/" (:id elector) "/true/")
+                  :handler #(fn
+                              []
+                              (ui/log-and-dispatch
+                                [:set-consent-and-page
+                                 {:elector-id (:id elector)
+                                  :page :elector
+                                  :elector (merge
+                                             elector
+                                             :signature
+                                             (.toDataURL
+                                               sig-pad
+                                               "image/svg+xml")
+                                             )}])))
      (ui/big-link "I DO NOT consent"
-                  :target (str "#elector/" (:id elector) "/true"))]))
-                  ;; :handler #(fn [] (dispatch [:set-elector-and-page {:elector-id (:id elector) :page :elector}])))]))
+                  :target (str "#elector/" (:id elector) "/false"))]))
 
 
 (defn gdpr-did-mount
   []
-  (js/SignaturePad. (.getElementById js/document "signature-pad")))
+  (reset! sig-pad (js/SignaturePad. (.getElementById js/document "signature-pad"))))
 
 
 (defn panel
   "A reagent class for the GDPR consent form"
   []
+  (js/console.log "gdpr.panel")
   (reagent/create-class {:reagent-render gdpr-render
                          :component-did-mount gdpr-did-mount}))

From b7c745a0a4290f35cc82a772158a058bb53a0ae3 Mon Sep 17 00:00:00 2001
From: Simon Brooke <simon@journeyman.cc>
Date: Tue, 28 Aug 2018 18:44:26 +0100
Subject: [PATCH 2/3] Right, that's enough for today. I understand what's
 wrong.

---
 resources/templates/base.html                 |  8 +++--
 resources/templates/issue-expert/list.html    | 17 +++-------
 src/clj/youyesyet/routes/rest.clj             | 34 ++++++++++++++++---
 .../youyesyet/canvasser_app/handlers.cljs     | 20 ++++-------
 .../youyesyet/canvasser_app/ui_utils.cljs     | 10 +++---
 .../youyesyet/canvasser_app/views/gdpr.cljs   | 11 +++---
 .../canvasser_app/ui_utils_test.cljs          | 11 ++++++
 7 files changed, 68 insertions(+), 43 deletions(-)
 create mode 100644 test/cljs/youyesyet/canvasser_app/ui_utils_test.cljs

diff --git a/resources/templates/base.html b/resources/templates/base.html
index 3f9928e..ef97912 100644
--- a/resources/templates/base.html
+++ b/resources/templates/base.html
@@ -28,9 +28,13 @@
         <menu id="nav-menu" class="nav">
           <li class=""><a href="{{servlet-context}}/home">Home</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="">{% if user %}<a href="{{servlet-context}}/logout">Logout</a>
-            {% else %}<a href="{{servlet-context}}/login">Login</a>{% endif %}</li>
+          <li class=""><a href="{{servlet-context}}/login">Login</a></li>
+          {% endif %}
           <li class=""><a href="{{servlet-context}}/about">About</a></li>
           {% if user %}
           <li id="user"><a href="{{servlet-context}}/profile">Logged in as {{user.username}}</a></li>
diff --git a/resources/templates/issue-expert/list.html b/resources/templates/issue-expert/list.html
index 0cd0efc..5050fe0 100644
--- a/resources/templates/issue-expert/list.html
+++ b/resources/templates/issue-expert/list.html
@@ -36,19 +36,16 @@ Add a new Followuprequest
 <thead>
 <tr>
 <th>
-Id
+Elector
 </th>
 <th>
-Elector_id
+Visit
 </th>
 <th>
-Visit_id
+Issue
 </th>
 <th>
-Issue_id
-</th>
-<th>
-Method_id
+Method
 </th>
 <th>
 &nbsp;
@@ -56,9 +53,6 @@ Method_id
 </tr>
 <tr>
 <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 }}'/>
 </th>
 <th>
@@ -79,9 +73,6 @@ Method_id
 {% for record in records %}
 <tr>
 <td>
-{{ record.id }}
-</td>
-<td>
 <a href='{{servlet-context}}/form-electors-Elector?id={{ record.elector_id }}'>
 {{ record.elector_id_expanded }}
 </a>
diff --git a/src/clj/youyesyet/routes/rest.clj b/src/clj/youyesyet/routes/rest.clj
index 37abfc5..f3358f2 100644
--- a/src/clj/youyesyet/routes/rest.clj
+++ b/src/clj/youyesyet/routes/rest.clj
@@ -140,7 +140,8 @@
               params :visit_id (current-visit-id request)))
           201)
         {: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`.")})
       request)))
 
@@ -164,7 +165,32 @@
       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)]
+    (if (and (:elector_id request)(:signature request))
+        (valid-user-or-forbid
+      (with-params-or-error
+        (do-or-server-fail
+          (db/create-followuprequest! db/*db* params)
+          201)
+        params
+        #{:elector_id :signature})
+      request))
+    {:status 400
+     :body
+     (json/write-str
+       "update-elector-signature requires params `id` and `signature`.")}))
+
+
 (defroutes rest-routes
-  (GET "/rest/get-local-data" request (route/restricted (get-local-data 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/get-local-data"
+       request (route/restricted (get-local-data 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))))
diff --git a/src/cljs/youyesyet/canvasser_app/handlers.cljs b/src/cljs/youyesyet/canvasser_app/handlers.cljs
index 3ab4419..c8d3feb 100644
--- a/src/cljs/youyesyet/canvasser_app/handlers.cljs
+++ b/src/cljs/youyesyet/canvasser_app/handlers.cljs
@@ -384,26 +384,20 @@
 
 (reg-event-db
   :update-elector
-  (fn [db [_ args]]
-    (if (:signature (:elector db))
-      (do
-        (js/console.log "Updating elector signature")
-        (add-to-feedback
-          (add-to-outqueue
-            db
-            {:elector (:elector db)
-             :action :update-elector-signature})
-          :send-request))
-      (assoc db :error "Please supply a telephone number to call"))))
+  (fn [db [_ elector]]
+    (js/console.log (str "Elector is " elector))
+    db
+))
 
 
 (reg-event-db
   :set-consent-and-page
   (fn [db [_ args]]
     (let [page (:page args)
-          elector (:elector args)]
+          elector (:elector args)
+          new-db (assoc (clear-messages db) :elector elector :page page)]
       (dispatch [:update-elector {:elector elector}])
-      (assoc (clear-messages db) :elector elector :page page))))
+      new-db)))
 
 
 (reg-event-db
diff --git a/src/cljs/youyesyet/canvasser_app/ui_utils.cljs b/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
index cd37ead..452801a 100644
--- a/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
+++ b/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
@@ -45,15 +45,16 @@
 
 (defn big-link
   [text & {:keys [target handler]}]
-  (js/console.log (str "Big link with target '" target "'; handler '" handler "'"))
+  (js/console.log (str "Big link with target '" target "'; onclick handler '" handler "'"))
   [:div.big-link-container {:key (gensym "big-link")}
-   [:a.big-link (merge {:href target :on-click handler}
+   [:a.big-link (merge {:alt "Hello"}
                   (if target {:href target}{})
-                  (if handler {:on-click handler}{}))
+                  (if handler {:title handler}{}))
     text]])
 
 
 (defn nav-link [uri title page collapsed?]
+  (js/console.log (str "Adding nav-link with title '" title "'; target '" uri "'"))
   (let [selected-page @(rf/subscribe [:page])]
     [:li.nav-item
      {:class (when (= page selected-page) "active")
@@ -81,4 +82,5 @@
       (nav-link "#/map" "Map" :map collapsed?)
       (nav-link "#/dwelling" "Electors" :dwelling 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?)]]))
diff --git a/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs b/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
index 9da0ad3..6011ab6 100644
--- a/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
+++ b/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
@@ -56,20 +56,17 @@
           [:canvas {:id "signature-pad"}]]]]]]
      (ui/back-link "#dwelling")
      (ui/big-link "I consent"
-                  ;; :target (str "#elector/" (:id elector) "/true/")
-                  :handler #(fn
-                              []
-                              (ui/log-and-dispatch
+                  :handler #(dispatch
                                 [:set-consent-and-page
                                  {:elector-id (:id elector)
                                   :page :elector
-                                  :elector (merge
+                                  :elector (assoc
                                              elector
                                              :signature
                                              (.toDataURL
-                                               sig-pad
+                                               @sig-pad
                                                "image/svg+xml")
-                                             )}])))
+                                             )}]))
      (ui/big-link "I DO NOT consent"
                   :target (str "#elector/" (:id elector) "/false"))]))
 
diff --git a/test/cljs/youyesyet/canvasser_app/ui_utils_test.cljs b/test/cljs/youyesyet/canvasser_app/ui_utils_test.cljs
new file mode 100644
index 0000000..6221054
--- /dev/null
+++ b/test/cljs/youyesyet/canvasser_app/ui_utils_test.cljs
@@ -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)))))

From 439f5a254643b0425b7982d9d4df13940d5d6d6e Mon Sep 17 00:00:00 2001
From: Simon Brooke <simon@journeyman.cc>
Date: Wed, 29 Aug 2018 13:55:34 +0100
Subject: [PATCH 3/3] I'm almost satisfied; map not scrolling to device
 location on startup

---
 resources/public/css/yyy-common.css           |   2 -
 resources/sql/queries.sql                     |   4 +-
 resources/templates/issue-expert/list.html    |   8 +-
 src/clj/youyesyet/routes/rest.clj             |  12 +-
 src/cljs/youyesyet/canvasser_app/core.cljs    |   4 +-
 src/cljs/youyesyet/canvasser_app/gis.cljs     |  18 +--
 .../youyesyet/canvasser_app/handlers.cljs     |  97 +++++--------
 src/cljs/youyesyet/canvasser_app/state.cljs   | 131 ++----------------
 .../youyesyet/canvasser_app/ui_utils.cljs     |   6 +-
 .../youyesyet/canvasser_app/views/gdpr.cljs   |  31 +++--
 10 files changed, 89 insertions(+), 224 deletions(-)

diff --git a/resources/public/css/yyy-common.css b/resources/public/css/yyy-common.css
index b46e8cb..cbfb6b6 100644
--- a/resources/public/css/yyy-common.css
+++ b/resources/public/css/yyy-common.css
@@ -362,7 +362,6 @@ th {
 
   /* content of the current page in the Wiki - editable, provided by users. Within main-container */
   #content {
-    border: thin solid silver;
     width: 80%;
     float: right;
     padding-bottom: 5em;
@@ -396,7 +395,6 @@ th {
 
   /* content of the current in the Wiki - editable, provided by users. Within main-container */
   #content {
-    border: thin solid silver;
     width: 100%;
     padding-bottom: 2em;
   }
diff --git a/resources/sql/queries.sql b/resources/sql/queries.sql
index 822b2d6..779e572 100644
--- a/resources/sql/queries.sql
+++ b/resources/sql/queries.sql
@@ -43,7 +43,7 @@ SELECT DISTINCT request.*,
 	addresses.address ||', '|| addresses.postcode ||', '|| visits.date AS visit_id_expanded,
   request.issue_id as issue_id_expanded,
 	request.method_id AS method_id_expanded,
-  visits.date
+  visits.date AS raised
 FROM followuprequests as request,
   ln_experts_issues_canvassers as expertise,
   canvassers as experts,
@@ -58,7 +58,7 @@ and request.visit_id = visits.id
 and visits.address_id = addresses.id
 and request.issue_id = expertise.issue_id
 and expertise.canvasser_id = :expert
-ORDER BY visits.date desc
+ORDER BY raised
 
 --:name get-last-visit-by-canvasser :? :1
 --:doc returns the most recent visit record of the canvasser with the specified `:id`
diff --git a/resources/templates/issue-expert/list.html b/resources/templates/issue-expert/list.html
index 5050fe0..b6b31fb 100644
--- a/resources/templates/issue-expert/list.html
+++ b/resources/templates/issue-expert/list.html
@@ -39,7 +39,7 @@ Add a new Followuprequest
 Elector
 </th>
 <th>
-Visit
+Raised
 </th>
 <th>
 Issue
@@ -56,7 +56,7 @@ Method
 <input id='elector_id' type='text' name='elector_id' value='{{ params.elector_id }}'/>
 </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>
 <input id='issue_id' type='text' name='issue_id' value='{{ params.issue_id }}'/>
@@ -78,9 +78,7 @@ Method
 </a>
 </td>
 <td>
-<a href='{{servlet-context}}/form-visits-Visit?id={{ record.visit_id }}'>
-{{ record.visit_id_expanded }}
-</a>
+{{ record.raised}}
 </td>
 <td>
 <a href='{{servlet-context}}/form-issues-Issue?id={{ record.issue_id }}'>
diff --git a/src/clj/youyesyet/routes/rest.clj b/src/clj/youyesyet/routes/rest.clj
index f3358f2..6e948b0 100644
--- a/src/clj/youyesyet/routes/rest.clj
+++ b/src/clj/youyesyet/routes/rest.clj
@@ -170,19 +170,15 @@
   the elector whose `id` is in the params of this `request`."
   [request]
   (let [params (massage-params request)]
-    (if (and (:elector_id request)(:signature request))
+    (log/debug "Update elector signature with params: " params)
         (valid-user-or-forbid
       (with-params-or-error
         (do-or-server-fail
-          (db/create-followuprequest! db/*db* params)
+          (db/update-elector! db/*db* params)
           201)
         params
-        #{:elector_id :signature})
-      request))
-    {:status 400
-     :body
-     (json/write-str
-       "update-elector-signature requires params `id` and `signature`.")}))
+        #{:id :signature})
+      request)))
 
 
 (defroutes rest-routes
diff --git a/src/cljs/youyesyet/canvasser_app/core.cljs b/src/cljs/youyesyet/canvasser_app/core.cljs
index 89493ac..2dbbe2e 100644
--- a/src/cljs/youyesyet/canvasser_app/core.cljs
+++ b/src/cljs/youyesyet/canvasser_app/core.cljs
@@ -137,7 +137,7 @@
 (secretary/defroute "/elector" []
   (ui/log-and-dispatch [:set-active-page :elector]))
 
-(secretary/defroute "/elector/:elector" {elector-id :elector}
+(secretary/defroute "/elector/:elector/:consent" {elector-id :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}
@@ -189,7 +189,7 @@
 
 (defn init! []
   (rf/dispatch-sync [:initialize-db])
-  (rf/dispatch-sync [:get-current-location])
+  (rf/dispatch [:get-current-location])
   (rf/dispatch [:fetch-locality])
   (rf/dispatch [:fetch-options])
   (rf/dispatch [:fetch-issues])
diff --git a/src/cljs/youyesyet/canvasser_app/gis.cljs b/src/cljs/youyesyet/canvasser_app/gis.cljs
index c1db28b..2c47192 100644
--- a/src/cljs/youyesyet/canvasser_app/gis.cljs
+++ b/src/cljs/youyesyet/canvasser_app/gis.cljs
@@ -7,7 +7,6 @@
             [re-frame.core :refer [dispatch reg-event-db reg-event-fx subscribe]]
             [ajax.core :refer [GET]]
             [ajax.json :refer [json-request-format json-response-format]]
-            [youyesyet.canvasser-app.state :as db]
             [youyesyet.locality :refer [locality]]
             ))
 
@@ -39,19 +38,20 @@
 
 (defn get-current-location []
   "Get the current location from the device, setting it in the database and
-   returning the locality."
+  returning the locality."
   (try
     (if (.-geolocation js/navigator)
       (.getCurrentPosition
         (.-geolocation js/navigator)
         (fn [position]
-          (js/console.log (str "Current location is: "
-                               (.-latitude (.-coords position)) ", "
-                               (.-longitude (.-coords position))))
-          (dispatch [:set-latitude (.-latitude (.-coords position))])
-          (dispatch [:set-longitude (.-longitude (.-coords position))])
-          (locality (.-latitude (.-coords position)) (.-longitude (.-coords position))))))
-      (js/console.log "Geolocation not available")
+          (let [lat (.-latitude (.-coords position))
+                lng (.-longitude (.-coords position))]
+            (js/console.log (str "Current location is: " lat ", " lng))
+            (dispatch [:set-latitude lat])
+            (dispatch [:set-longitude lng])
+            ;; (.panTo @(subscribe [:view]) (.latLng js/L lat lng))
+            (locality lat lng))))
+      (js/console.log "Geolocation not available"))
     (catch js/Object any
       (js/console.log "Exception while trying to access location: " + any)
       0)))
diff --git a/src/cljs/youyesyet/canvasser_app/handlers.cljs b/src/cljs/youyesyet/canvasser_app/handlers.cljs
index c8d3feb..8c853d5 100644
--- a/src/cljs/youyesyet/canvasser_app/handlers.cljs
+++ b/src/cljs/youyesyet/canvasser_app/handlers.cljs
@@ -140,34 +140,6 @@
     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
  :fetch-locality
  (fn [{db :db} _]
@@ -204,38 +176,29 @@
 
 
 (reg-event-fx
- :process-locality
- (fn
-   [{db :db} [_ response]]
-   (js/console.log (str "Updating locality data: " (count response) " addresses " ))
-   (refresh-map-pins)
-   {
-;;      :dispatch-later [{:ms 60000 :dispatch [:fetch-locality]}
-;;                      ;; {:ms 1000 :dispatch [:get-current-location]}
-;;                      ]
-    :db (assoc
-          (remove-from-feedback db :fetch-locality)
-          :addresses (js->clj response))}))
+  :process-locality
+  ;; TODO: why is this an `-fx`? Does it need to be?
+  (fn
+    [{db :db} [_ response]]
+    (js/console.log (str "Updating locality data: " (count response) " addresses " ))
+    (refresh-map-pins)
+    {:db (assoc
+           (remove-from-feedback db :fetch-locality)
+           :addresses (js->clj response))}))
 
 
 (reg-event-fx
   :bad-locality
+  ;; TODO: why is this an `-fx`? Does it need to be?
   (fn
     [{db :db} [_ response]]
     ;; TODO: signal something has failed? It doesn't matter very much, unless it keeps failing.
     (js/console.log "Failed to fetch locality data")
     ;; loop to do it again
     (dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-locality]}]])
-    (assoc
+    {:db (assoc
       (remove-from-feedback db :fetch-locality)
-      :error (cons :fetch-locality (:error db)))))
-
-
-;; (reg-event-fx
-;;  :process-outqueue
-;;  (fn [{db :db} _]
-;;    (if
-;;      (empty? (:outqueue db))
+      :error (cons :fetch-locality (:error db)))}))
 
 
 (reg-event-fx
@@ -264,12 +227,12 @@
 
 
 (reg-event-db
- ;; TODO: should try again
   :bad-options
   (fn [db [_ response]]
     (js/console.log "Failed to fetch options")
+    (dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-options]}]])
     (assoc
-      (remove-from-feedback db :fetch-options)
+      db
       :error (:response response))))
 
 
@@ -303,12 +266,12 @@
 
 
 (reg-event-db
- ;; TODO: should try again
   :bad-issues
   (fn [db [_ response]]
     (js/console.log "Failed to fetch issues")
+    (dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-issues]}]])
     (assoc
-      (remove-from-feedback db :fetch-issues)
+      db
       :error (:response response))))
 
 
@@ -349,7 +312,7 @@
              :method_detail (-> db :method_detail)
              :action :create-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
@@ -382,22 +345,34 @@
             :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))
-    db
-))
+    (do-update-elector db elector)))
 
 
 (reg-event-db
   :set-consent-and-page
   (fn [db [_ args]]
-    (let [page (:page args)
-          elector (:elector args)
-          new-db (assoc (clear-messages db) :elector elector :page page)]
-      (dispatch [:update-elector {:elector elector}])
-      new-db)))
+    (assoc
+      (do-update-elector db (:elector args))
+      :page (:page args))))
 
 
 (reg-event-db
diff --git a/src/cljs/youyesyet/canvasser_app/state.cljs b/src/cljs/youyesyet/canvasser_app/state.cljs
index cb67e57..dcb7fae 100644
--- a/src/cljs/youyesyet/canvasser_app/state.cljs
+++ b/src/cljs/youyesyet/canvasser_app/state.cljs
@@ -1,6 +1,7 @@
 (ns ^{:doc "Canvasser app client state."
       :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.
 ;;; 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.
-    :address nil
-    ;;; electors at the currently selected dwelling
-    :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
+(def default-db
+  { ;;; any confirmation message to display
+    :feedback '("Welcome to the canvasser app!")
     ;;; 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 nil
-    ;;; the queue of items waiting to be transmitted.
-    :outqueue ()
+    :outqueue '()
+    ;;; the view of the map we display
+    :view nil
     ;;; the currently displayed page within the app.
     :page :home
-    :view nil
-    :latitude 54.82
-    :longitude -3.92
+    ;;; initial starting coords in the centre of Scotland.
+    :latitude 56
+    :longitude -4
     :zoom 12})
 
+
diff --git a/src/cljs/youyesyet/canvasser_app/ui_utils.cljs b/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
index 452801a..6609e35 100644
--- a/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
+++ b/src/cljs/youyesyet/canvasser_app/ui_utils.cljs
@@ -45,16 +45,14 @@
 
 (defn big-link
   [text & {:keys [target handler]}]
-  (js/console.log (str "Big link with target '" target "'; onclick handler '" handler "'"))
   [:div.big-link-container {:key (gensym "big-link")}
-   [:a.big-link (merge {:alt "Hello"}
+   [:a.big-link (merge {}
                   (if target {:href target}{})
-                  (if handler {:title handler}{}))
+                  (if handler {:on-click handler}{}))
     text]])
 
 
 (defn nav-link [uri title page collapsed?]
-  (js/console.log (str "Adding nav-link with title '" title "'; target '" uri "'"))
   (let [selected-page @(rf/subscribe [:page])]
     [:li.nav-item
      {:class (when (= page selected-page) "active")
diff --git a/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs b/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
index 6011ab6..4100a33 100644
--- a/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
+++ b/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs
@@ -35,6 +35,22 @@
   (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
   []
   (let [elector @(subscribe [:elector])]
@@ -53,20 +69,11 @@
                only against your electoral district, and not link it to you"]]]]
         [:tr
          [:td
-          [:canvas {:id "signature-pad"}]]]]]]
+          [:canvas {:id "signature-pad" :on-mouse-out #(send-consent elector)}]]]]]]
      (ui/back-link "#dwelling")
      (ui/big-link "I consent"
-                  :handler #(dispatch
-                                [:set-consent-and-page
-                                 {:elector-id (:id elector)
-                                  :page :elector
-                                  :elector (assoc
-                                             elector
-                                             :signature
-                                             (.toDataURL
-                                               @sig-pad
-                                               "image/svg+xml")
-                                             )}]))
+                  :target (str "#elector")
+                  :handler #(send-consent elector))
      (ui/big-link "I DO NOT consent"
                   :target (str "#elector/" (:id elector) "/false"))]))