From 2e81c7b6647fbd26749e312931af32b66fd0632f Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 21 Jul 2017 14:18:22 +0100 Subject: [PATCH] #41 Updated client to cope with dwelling changs --- resources/sql/queries.sql | 51 ++++++++-- src/cljs/youyesyet/canvasser_app/core.cljs | 11 ++- .../youyesyet/canvasser_app/handlers.cljs | 24 ++++- src/cljs/youyesyet/canvasser_app/state.cljs | 96 ++++++++++--------- .../canvasser_app/subscriptions.cljs | 5 + .../canvasser_app/views/building.cljs | 21 +++- .../canvasser_app/views/electors.cljs | 16 ++-- .../youyesyet/canvasser_app/views/issues.cljs | 2 +- .../youyesyet/canvasser_app/views/map.cljs | 11 ++- 9 files changed, 165 insertions(+), 72 deletions(-) diff --git a/resources/sql/queries.sql b/resources/sql/queries.sql index 5309965..e2170b8 100644 --- a/resources/sql/queries.sql +++ b/resources/sql/queries.sql @@ -83,14 +83,14 @@ WHERE id = :id -- :name create-canvasser! :! :n -- :doc creates a new canvasser record INSERT INTO canvassers -(username, fullname, elector_id, address_id, phone, email, authority_id, authorised) -VALUES (:username, :fullname, :elector_id, :address_id, :phone, :email, :authority_id, :authorised) +(username, fullname, elector_id, dwelling_id, phone, email, authority_id, authorised) +VALUES (:username, :fullname, :elector_id, :dwelling_id, :phone, :email, :authority_id, :authorised) RETURNING id -- :name update-canvasser! :! :n -- :doc update an existing canvasser record UPDATE canvassers -SET username = :username, fullname = :fullname, elector_id = :elector_id, address_id = :address_id, phone = :phone, email = :email, authority_id = :authority_id, authorised = :authorised +SET username = :username, fullname = :fullname, elector_id = :elector_id, dwelling_id = :dwelling_id, phone = :phone, email = :email, authority_id = :authority_id, authorised = :authorised WHERE id = :id -- :name get-canvasser :? :1 @@ -138,17 +138,52 @@ DELETE FROM districts WHERE id = :id +-- :name get-dwelling :? :1 +-- :doc retrieve a dwelling given the id. +SELECT * FROM dwellings +WHERE id = :id + +-- :name delete-dwelling! :! :n +-- :doc delete a dwelling given the id +DELETE FROM dwellings +WHERE id = :id + +-- :name create-dwelling! :! :n +-- :doc creates a new dwelling record +INSERT INTO dwellings +(id, address_id, sub_address) +VALUES (:id, :address_id, :sub_address) +RETURNING id + +-- :name update-dwelling! :! :n +-- :doc update an existing dwelling record +UPDATE dwellings +SET address_id = :address_id, + sub_address = :sub_address +WHERE id = :id + +-- :name get-dwelling :? :1 +-- :doc retrieve a dwelling given the id. +SELECT * FROM dwellings +WHERE id = :id + +-- :name delete-dwelling! :! :n +-- :doc delete a dwelling given the id +DELETE FROM dwellings +WHERE id = :id + + -- :name create-elector! :! :n -- :doc creates a new elector record INSERT INTO electors -(name, address_id, phone, email) -VALUES (:name, :address_id, :phone, :email) +(name, dwelling_id, phone, email) +VALUES (:name, :dwelling_id, :phone, :email) RETURNING id -- :name update-elector! :! :n -- :doc update an existing elector record UPDATE electors -SET name = :name, address_id = :address_id, phone = :phone, email = :email +SET name = :name, dwelling_id = :dwelling_id, phone = :phone, email = :email WHERE id = :id -- :name get-elector :? :1 @@ -254,8 +289,8 @@ WHERE id = :id -- :name create-visit! :! :n -- :doc creates a new visit record INSERT INTO visits -(address_id, canvasser_id) -VALUES (:address_id, :canvasser_id) +(dwelling_id, canvasser_id) +VALUES (:dwelling_id, :canvasser_id) RETURNING id -- visits is audit data; we don't update it. diff --git a/src/cljs/youyesyet/canvasser_app/core.cljs b/src/cljs/youyesyet/canvasser_app/core.cljs index 971261e..e492a35 100644 --- a/src/cljs/youyesyet/canvasser_app/core.cljs +++ b/src/cljs/youyesyet/canvasser_app/core.cljs @@ -14,6 +14,7 @@ [youyesyet.canvasser-app.subscriptions] [youyesyet.canvasser-app.ui-utils :as ui] [youyesyet.canvasser-app.views.about :as about] + [youyesyet.canvasser-app.views.building :as building] [youyesyet.canvasser-app.views.electors :as electors] [youyesyet.canvasser-app.views.followup :as followup] [youyesyet.canvasser-app.views.issue :as issue] @@ -50,6 +51,9 @@ (defn about-page [] (about/panel)) +(defn building-page [] + (building/panel)) + (defn electors-page [] (electors/panel)) @@ -67,6 +71,7 @@ (def pages {:about #'about-page + :building #'building-page :electors #'electors-page :followup #'followup-page :issues #'issues-page @@ -105,10 +110,10 @@ (secretary/defroute "/about" [] (rf/dispatch [:set-active-page :about])) -(secretary/defroute "/electors" [] - (rf/dispatch [:set-active-page :electors])) +(secretary/defroute "/electors/:dwelling" {dwelling-id :dwelling} + (rf/dispatch [:set-dwelling dwelling-id])) -(secretary/defroute "/electors/:address" {address-id :address} +(secretary/defroute "/building/:address" {address-id :address} (rf/dispatch [:set-address address-id])) (secretary/defroute "/followup" [] diff --git a/src/cljs/youyesyet/canvasser_app/handlers.cljs b/src/cljs/youyesyet/canvasser_app/handlers.cljs index e94d1b2..813ec99 100644 --- a/src/cljs/youyesyet/canvasser_app/handlers.cljs +++ b/src/cljs/youyesyet/canvasser_app/handlers.cljs @@ -112,7 +112,29 @@ (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)))) + (if + (= (count (:dwellings address)) 1) + (assoc (clear-messages db) + :address address + :dwelling (first (:dwellings address)) + :page :electors) + (assoc (clear-messages db) + :address address + :dwelling nil + :page :building))))) + + +(reg-event-db + :set-dwelling + (fn [db [_ dwelling-id]] + (let [id (read-string dwelling-id) + dwelling (first + (remove + nil? + (map + #(if (= id (:id %)) %) + (mapcat :dwellings (:addresses db)))))] + (assoc (clear-messages db) :dwelling dwelling :page :electors)))) (reg-event-db diff --git a/src/cljs/youyesyet/canvasser_app/state.cljs b/src/cljs/youyesyet/canvasser_app/state.cljs index 711413e..c967f7c 100644 --- a/src/cljs/youyesyet/canvasser_app/state.cljs +++ b/src/cljs/youyesyet/canvasser_app/state.cljs @@ -33,49 +33,53 @@ (def default-db {;;; 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 - }) + :address {:id 1 :address "13 Imaginary Terrace, IM1 3TE" :latitude 55.8253043 :longitude -4.2569057 + :dwellings [{:id 1 + :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 + :dwellings [{:id 1 + :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 + :dwellings [{:id 2 + :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 + :dwellings [{:id 3 :sub-address "Flat 1" + :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 :sub-address "Flat 2" + :electors [{:id 1 :name "David Dewar" :gender :male :intention :no}]}]}] + ;;; electors at the currently selected dwelling + :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}) diff --git a/src/cljs/youyesyet/canvasser_app/subscriptions.cljs b/src/cljs/youyesyet/canvasser_app/subscriptions.cljs index c3d18e5..3f87dee 100644 --- a/src/cljs/youyesyet/canvasser_app/subscriptions.cljs +++ b/src/cljs/youyesyet/canvasser_app/subscriptions.cljs @@ -46,6 +46,11 @@ (fn [db _] (:changes db))) +(reg-sub + :dwelling + (fn [db _] + (:dwelling db))) + (reg-sub :elector (fn [db _] diff --git a/src/cljs/youyesyet/canvasser_app/views/building.cljs b/src/cljs/youyesyet/canvasser_app/views/building.cljs index 40e5d0e..5e9e935 100644 --- a/src/cljs/youyesyet/canvasser_app/views/building.cljs +++ b/src/cljs/youyesyet/canvasser_app/views/building.cljs @@ -1,7 +1,8 @@ (ns ^{:doc "Canvasser app households in building panel." :author "Simon Brooke"} youyesyet.canvasser-app.views.building - (:require [re-frame.core :refer [reg-sub]])) + (:require [re-frame.core :refer [reg-sub subscribe]] + [youyesyet.canvasser-app.ui-utils :as ui])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; @@ -30,10 +31,22 @@ ;;; 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 building view. - +;;; I propose to follow this pattern. This file will provide the building view. (defn panel "Generate the building panel." [] - []) + (let [address @(subscribe [:address]) + dwellings (:dwellings address)] + [:div + [:h1 (str "Flats at " (:address address))] + [:div.container {:id "main-container"} + (ui/back-link) + [:div {:id "dwelling-list"} + (map + (fn + [dwelling] + (ui/big-link + (:sub-address dwelling) + (str "#/electors/" (:id dwelling))) ) + (:dwellings address))]]])) diff --git a/src/cljs/youyesyet/canvasser_app/views/electors.cljs b/src/cljs/youyesyet/canvasser_app/views/electors.cljs index aee2d4d..482d21a 100644 --- a/src/cljs/youyesyet/canvasser_app/views/electors.cljs +++ b/src/cljs/youyesyet/canvasser_app/views/electors.cljs @@ -32,7 +32,7 @@ ;;; 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 electors view. +;;; I propose to follow this pattern. This file will provide the electors view. ;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#electors-view @@ -107,14 +107,16 @@ (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])] + (let [dwelling @(subscribe [:dwelling]) + address @(subscribe [:address]) + sub-address (:sub-address dwelling) + electors (sort-by :id (:electors dwelling)) + options @(subscribe [:options])] (if address [:div - [:h1 (:address address)] + [:h1 (if sub-address + (str sub-address ", " (:address address)) + (:address address))] [:div.container {:id "main-container"} [:table [:tbody diff --git a/src/cljs/youyesyet/canvasser_app/views/issues.cljs b/src/cljs/youyesyet/canvasser_app/views/issues.cljs index 8aa1744..8b2ca47 100644 --- a/src/cljs/youyesyet/canvasser_app/views/issues.cljs +++ b/src/cljs/youyesyet/canvasser_app/views/issues.cljs @@ -31,7 +31,7 @@ ;;; 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 issues view. +;;; I propose to follow this pattern. This file will provide the issues view. ;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#issues-view diff --git a/src/cljs/youyesyet/canvasser_app/views/map.cljs b/src/cljs/youyesyet/canvasser_app/views/map.cljs index 6df73dd..a0a7097 100644 --- a/src/cljs/youyesyet/canvasser_app/views/map.cljs +++ b/src/cljs/youyesyet/canvasser_app/views/map.cljs @@ -57,7 +57,14 @@ (defn pin-image "select the name of a suitable pin image for this address" [address] - (let [intentions (set (remove nil? (map #(:intention %) (:electors address))))] + (let [intentions + (set + (remove + nil? + (map + #(:intention %) + (map :electors + (:dwellings address)))))] (case (count intentions) 0 "unknown-pin" 1 (str (name (first intentions)) "-pin") @@ -70,7 +77,7 @@ so back links work." [id] (js/console.log (str "Click handler for address #" id)) - (set! window.location.href (str "#electors/" id))) + (set! window.location.href (str "#building/" id))) ;; This way is probably more idiomatic React, but history doesn't work: ;; (defn map-pin-click-handler ;; [id]