Browse Source

Add buttons to copy summary of reponses

- Moves edit button to dropdown
- Adds options to copy to clipboard:
    - The list of absentees,
    - The complete list of responses
- Adds support stuff to make this work
Maarten van den Berg 7 years ago
parent
commit
85e4697725

+ 3 - 0
Gemfile

@@ -43,6 +43,9 @@ gem 'haml'
43 43
 gem 'rabl'
44 44
 gem 'oj'
45 45
 
46
+# Clipping
47
+gem 'clipboard-rails'
48
+
46 49
 # Use Fontawesome icons
47 50
 gem 'font-awesome-sass'
48 51
 

+ 2 - 0
Gemfile.lock

@@ -54,6 +54,7 @@ GEM
54 54
       will_paginate
55 55
     builder (3.2.3)
56 56
     byebug (9.0.6)
57
+    clipboard-rails (1.7.1)
57 58
     coffee-rails (4.2.1)
58 59
       coffee-script (>= 2.2.0)
59 60
       railties (>= 4.0.0, < 5.2.x)
@@ -205,6 +206,7 @@ DEPENDENCIES
205 206
   bootstrap-sass (~> 3.3.6)
206 207
   bootstrap-will_paginate
207 208
   byebug
209
+  clipboard-rails
208 210
   coffee-rails (~> 4.2)
209 211
   faker
210 212
   font-awesome-sass

+ 26 - 0
app/assets/javascripts/activities.coffee

@@ -0,0 +1,26 @@
1
+$(document).on 'turbolinks:load', ->
2
+  clipboard = new Clipboard('.copy-reactions', {
3
+    'text': clipreactions
4
+  })
5
+
6
+@clipreactions = (trigger) ->
7
+  id = trigger.dataset['activity']
8
+  dopresent = (typeof trigger.dataset['present'] != 'undefined')
9
+  doabsent  = (typeof trigger.dataset['absent']  != 'undefined')
10
+  donoresp  = (typeof trigger.dataset['unknown'] != 'undefined')
11
+  req = $.ajax({
12
+    async: false,
13
+    method: 'GET',
14
+    url: '/api/activities/' + id + '/response_summary'
15
+  })
16
+  resp = req.responseJSON.response_summary
17
+
18
+  res = []
19
+  if dopresent
20
+    res.push(resp['present']['message'])
21
+  if doabsent
22
+    res.push(resp['absent']['message'])
23
+  if donoresp
24
+    res.push(resp['unknown']['message'])
25
+
26
+  res.join('\n')

+ 1 - 0
app/assets/javascripts/application.js

@@ -16,5 +16,6 @@
16 16
 //= require bootstrap-sprockets
17 17
 //= require editable/bootstrap-editable
18 18
 //= require editable/rails
19
+//= require clipboard
19 20
 //= require_tree .
20 21
 //= require_self

+ 65 - 2
app/controllers/api/activities_controller.rb

@@ -1,6 +1,6 @@
1 1
 class Api::ActivitiesController < ApiController
2
-  before_action :set_activity, only: [:show]
3
-  before_action :require_membership!, only: [:show]
2
+  before_action :set_activity, only: [:show, :response_summary]
3
+  before_action :require_membership!, only: [:show, :reponse_summary]
4 4
   before_action :api_require_admin!, only: [:index]
5 5
 
6 6
   # GET /api/activities
@@ -14,6 +14,69 @@ class Api::ActivitiesController < ApiController
14 14
   def show
15 15
   end
16 16
 
17
+  # GET /api/activities/1/response_summary
18
+  # GET /api/activities/1/response_summary.json
19
+  def response_summary
20
+    as = @activity
21
+      .participants
22
+      .joins(:person)
23
+      .order('people.first_name ASC')
24
+
25
+    present = as
26
+      .where(attending: true)
27
+
28
+    unknown = as
29
+      .where(attending: nil)
30
+
31
+    absent = as
32
+      .where(attending: false)
33
+
34
+    presentnames = present
35
+      .map{|p| p.person.first_name }
36
+
37
+    unknownnames = unknown
38
+      .map{|p| p.person.first_name }
39
+
40
+    absentnames = absent
41
+      .map{|p| p.person.first_name }
42
+
43
+    if presentnames
44
+      present_mess = I18n.t('activities.participant.these_present', count: present.count, names: presentnames.join(', '))
45
+    else
46
+      present_mess = I18n.t('activities.participant.none_present')
47
+    end
48
+
49
+    if unknownnames
50
+      unknown_mess = I18n.t('activities.participant.these_unknown', count: unknown.count, names: unknownnames.join(', '))
51
+    else
52
+      unknown_mess = I18n.t('activities.participant.none_unknown')
53
+    end
54
+
55
+    if absentnames
56
+      absent_mess = I18n.t('activities.participant.these_absent', count: absent.count, names: absentnames.join(', '))
57
+    else
58
+      absent_mess = I18n.t('activities.participant.none_absent')
59
+    end
60
+
61
+    @summary = {
62
+      present: {
63
+        count: present.count,
64
+        names: presentnames,
65
+        message: present_mess
66
+      },
67
+      unknown: {
68
+        count: unknown.count,
69
+        names: unknownnames,
70
+        message: unknown_mess
71
+      },
72
+      absent: {
73
+        count: absent.count,
74
+        names: absentnames,
75
+        message: absent_mess
76
+      }
77
+    }
78
+  end
79
+
17 80
   private
18 81
     # Use callbacks to share common setup or constraints between actions.
19 82
     def set_activity

+ 18 - 3
app/views/activities/show.html.haml

@@ -3,10 +3,25 @@
3 3
   .col-md-9
4 4
     .panel.panel-default
5 5
       .panel-heading
6
+        .btn-group.pull-right
7
+          %button.btn.btn-default.dropdown-toggle.btn-xs{data: {toggle: 'dropdown'}, 'aria-haspopup': true, 'aria-expanded': false}
8
+            %i.fa.fa-cogs
9
+            %span.caret
10
+          %ul.dropdown-menu
11
+            %li
12
+              %a.copy-reactions{data: {activity: @activity.id, absent: true}}
13
+                %i.fa.fa-files-o
14
+                = t 'activities.participant.copy_absent'
15
+              %a.copy-reactions{data: {activity: @activity.id, present: true, absent: true, unknown: true}}
16
+                %i.fa.fa-files-o
17
+                = t 'activities.participant.copy_responses'
18
+            - if all_buttons
19
+              %li.divider{role: 'separator'}
20
+              %li
21
+                = link_to edit_group_activity_path(@group, @activity) do
22
+                  %i.fa.fa-pencil
23
+                  = t :edit
6 24
         = @activity.name
7
-        - if all_buttons
8
-          = link_to edit_group_activity_path(@group, @activity), class: 'pull-right' do
9
-            %i.fa.fa-pencil
10 25
 
11 26
 
12 27
       %table.table

+ 5 - 0
app/views/api/activities/response_summary.rabl

@@ -0,0 +1,5 @@
1
+object false
2
+
3
+node :response_summary do
4
+  @summary
5
+end

+ 9 - 0
config/locales/activities/en.yml

@@ -28,6 +28,15 @@ en:
28 28
       add_notes: "Add notes"
29 29
       yourresponse: "Your response"
30 30
 
31
+      copy_responses: "Copy responses"
32
+      copy_absent: "Copy absentees"
33
+      these_present: "The following %{count} participants are attending: %{names}."
34
+      none_present: "Nobody is attending."
35
+      these_unknown: "The following %{count} participants have not responded: %{names}."
36
+      none_unknown: "Everyone has responded."
37
+      these_absent: "The following %{count} participants are absent: %{names}."
38
+      none_absent: "Nobody is absent."
39
+
31 40
     organizers:
32 41
       one: "Organizer"
33 42
       other: "Organizers"

+ 9 - 0
config/locales/activities/nl.yml

@@ -28,6 +28,15 @@ nl:
28 28
       add_notes: "Opmerkingen toevoegen"
29 29
       yourresponse: "Jouw antwoord"
30 30
 
31
+      copy_responses: "Kopieer overzicht"
32
+      copy_absent: "Kopieer afwezigen"
33
+      these_present: "%{count} mensen zijn aangemeld: %{names}."
34
+      none_present: "Niemand heeft zich aangemeld."
35
+      these_unknown: "%{count} mensen hebben niet gereageerd: %{names}."
36
+      none_unknown: "Iedereen heeft gereageerd."
37
+      these_absent: "%{count} mensen zijn afgemeld: %{names}."
38
+      none_absent: "Niemand heeft zich afgemeld."
39
+
31 40
     organizers:
32 41
       one: "Organisator"
33 42
       other: "Organisatoren"

+ 3 - 0
config/routes.rb

@@ -57,7 +57,10 @@ Rails.application.routes.draw do
57 57
     end
58 58
 
59 59
     resources :groups, only: [:index, :show]
60
+
60 61
     resources :activities, only: [:index, :show]
62
+    get 'activities/:id/response_summary', to: 'activities#response_summary'
63
+
61 64
     resources :people, only: [:index, :show]
62 65
   end
63 66
 end