Browse Source

Buttons work! (And it's ugly)

Maarten van den Berg 8 years ago
parent
commit
c9183e5828

+ 73 - 0
app/assets/javascripts/buttonhandlers.js

@@ -0,0 +1,73 @@
1
+// Provides handlers for the buttons!
2
+
3
+$(setup_handlers);
4
+
5
+function setup_handlers()
6
+{
7
+  $('.btn-present').on("click", set_present);
8
+  $('.btn-absent').on("click", set_absent);
9
+}
10
+
11
+// Update all references on the page to this activity:
12
+// 1. The present/absent buttons
13
+// 2. The activity's row-color in any tables
14
+function activity_changed(activity_id, new_state)
15
+{
16
+    // Set the present buttons and absent buttons to their appropriate state
17
+
18
+}
19
+
20
+function set_present(e)
21
+{
22
+  var group, person, activity;
23
+  group = this.dataset["groupId"];
24
+  person = this.dataset["personId"];
25
+  activity = this.dataset["activityId"];
26
+  $.ajax(`/groups/${group}/activities/${activity}/presence`,
27
+    {
28
+      method: 'PUT',
29
+      data: {person_id: person, attending: true}
30
+    }
31
+  );
32
+
33
+  // Set row state to success
34
+  $(`tr[data-person-id=${person}][data-activity-id=${activity}]`)
35
+    .removeClass('danger warning')
36
+    .addClass('success');
37
+
38
+  // Update present buttons
39
+  $(`.btn-present[data-person-id=${person}][data-activity-id=${activity}]`)
40
+    .html(check_selected);
41
+  $(`.btn-absent[data-person-id=${person}][data-activity-id=${activity}]`)
42
+    .html(times_unselected);
43
+}
44
+
45
+function set_absent()
46
+{
47
+  var group, person, activity;
48
+  group = this.dataset["groupId"];
49
+  person = this.dataset["personId"];
50
+  activity = this.dataset["activityId"];
51
+  $.ajax(`/groups/${group}/activities/${activity}/presence`,
52
+    {
53
+      method: 'PUT',
54
+      data: {person_id: person, attending: false}
55
+    }
56
+  );
57
+
58
+  // Set row state to danger
59
+  $(`tr[data-person-id=${person}][data-activity-id=${activity}]`)
60
+    .removeClass('success warning')
61
+    .addClass('danger');
62
+
63
+  // Update present buttons
64
+  $(`.btn-present[data-person-id=${person}][data-activity-id=${activity}]`)
65
+    .html(check_unselected);
66
+  $(`.btn-absent[data-person-id=${person}][data-activity-id=${activity}]`)
67
+    .html(times_selected);
68
+}
69
+
70
+var check_unselected = '<i class="fa fa-check"></i>';
71
+var check_selected = '<i class="fa fa-check-circle"></i>';
72
+var times_unselected = '<i class="fa fa-times"></i>';
73
+var times_selected = '<i class="fa fa-times-circle"></i>';

+ 15 - 1
app/controllers/activities_controller.rb

@@ -1,6 +1,6 @@
1 1
 class ActivitiesController < ApplicationController
2 2
   include GroupsHelper
3
-  before_action :set_activity, only: [:show, :edit, :update, :destroy]
3
+  before_action :set_activity, only: [:show, :edit, :update, :destroy, :presence]
4 4
   before_action :set_group
5 5
   before_action :require_membership!
6 6
 
@@ -65,6 +65,20 @@ class ActivitiesController < ApplicationController
65 65
     end
66 66
   end
67 67
 
68
+  # PATCH/PUT /groups/:group_id/activities/:id/presence
69
+  # PATCH/PUT /groups/:group_id/activities/:id/presence.json
70
+  def presence
71
+    participant = Participant.find_by(
72
+      person_id: params[:person_id],
73
+      activity: @activity
74
+    )
75
+    if !@activity.may_change?(current_person)
76
+      render status: :forbidden
77
+    end
78
+
79
+    participant.update_attributes(params.permit(:notes, :attending))
80
+  end
81
+
68 82
   private
69 83
     # Use callbacks to share common setup or constraints between actions.
70 84
     def set_activity

+ 6 - 2
app/controllers/dashboard_controller.rb

@@ -2,7 +2,11 @@ class DashboardController < ApplicationController
2 2
   before_action :require_login!
3 3
 
4 4
   def home
5
-    @user_organized = current_person.activities.where(is_organizer: true)
6
-    @need_response = current_person.activities.includes(:participants)
5
+    @user_organized = current_person.participants.includes(:activity).where(is_organizer: true)
6
+    @need_response = current_person.participants.includes(:activity).where(attending: nil)
7
+    @upcoming = current_person.activities.where('start > ?', DateTime.now).includes(:participants)
8
+    @upcoming = current_person.participants
9
+      .includes(:activity).joins(:activity)
10
+      .where("activities.start >= ?", DateTime.now)
7 11
   end
8 12
 end

+ 7 - 0
app/models/activity.rb

@@ -76,6 +76,13 @@ class Activity < ApplicationRecord
76 76
     )
77 77
   end
78 78
 
79
+  # Determine whether the passed Person may change this activity.
80
+  def may_change?(person)
81
+    person.is_admin ||
82
+    self.is_organizer(person) ||
83
+    self.group.is_leader(person)
84
+  end
85
+
79 86
   private
80 87
   # Assert that the deadline for participants to change the deadline, if any,
81 88
   # is set before the event starts.

+ 9 - 0
app/models/group.rb

@@ -21,4 +21,13 @@ class Group < ApplicationRecord
21 21
   def leaders
22 22
     self.members.includes(:person).where(is_leader: true)
23 23
   end
24
+
25
+  # Determine whether the passed person is a group leader.
26
+  def is_leader?(person)
27
+    Member.exists?(
28
+      person: person,
29
+      group: self,
30
+      is_leader: true
31
+    )
32
+  end
24 33
 end

+ 13 - 0
app/models/participant.rb

@@ -23,4 +23,17 @@ class Participant < ApplicationRecord
23 23
       scope: :activity_id,
24 24
       message: "person already participates in this activity"
25 25
     }
26
+
27
+  # TODO: Move to a more appropriate place
28
+  # @return [String]
29
+  #   the class for a row containing this activity.
30
+  def row_class
31
+    if self.attending
32
+      "success"
33
+    elsif self.attending == false
34
+      "danger"
35
+    else
36
+      "warning"
37
+    end
38
+  end
26 39
 end

+ 12 - 0
app/views/activities/_presence_buttons.haml

@@ -0,0 +1,12 @@
1
+.btn-group.btn-group-xs{role: "group"}
2
+  %button.btn.btn-success.btn-present{data: {person_id: person.id, activity_id: activity.id, group_id: activity.group.id}}
3
+    - if !state
4
+      %i.fa.fa-check
5
+    - else
6
+      %i.fa.fa-check-circle
7
+
8
+  %button.btn.btn-danger.btn-absent{data: {person_id: person.id, activity_id: activity.id, group_id: activity.group.id}}
9
+    - if state == false
10
+      %i.fa.fa-times-circle
11
+    - else
12
+      %i.fa.fa-times

+ 14 - 5
app/views/activities/show.html.erb

@@ -9,13 +9,22 @@
9 9
 </ul>
10 10
 
11 11
 <h2>Participants (<%= @activity.participants.count %>)</h2>
12
-<ul>
12
+<table class="table table-bordered">
13 13
   <% @activity.participants.each do |p| %>
14
-    <li>
15
-      <%= p.person.full_name %>, <%= p.is_organizer %>, <%= p.attending %>
16
-    </li>
14
+    <tr class="<%= p.row_class %>" data-person-id="<%= p.person.id %>" data-activity-id="<%= @activity.id %>">
15
+      <td>
16
+        <%= p.person.full_name %>
17
+      </td>
18
+      <td>
19
+        <%= p.is_organizer %>
20
+      </td>
21
+      <td>
22
+        <%= p.attending %>
23
+      </td>
24
+      <td>
25
+        <%= render partial: "activities/presence_buttons", locals: {activity: @activity, person: p.person, state: p.attending} %>
17 26
   <% end %>
18
-</ul>
27
+</table>
19 28
 
20 29
 <%= link_to 'Edit', edit_group_activity_path(@group, @activity) %> |
21 30
 <%= link_to 'Back', group_activities_path(@group) %>

+ 39 - 6
app/views/dashboard/home.html.haml

@@ -1,7 +1,7 @@
1 1
 .container
2 2
   .row
3 3
     - if @need_response.any?
4
-      .col-md.12
4
+      .col-md-12
5 5
         .panel.panel-default
6 6
           .panel-heading
7 7
             Need response
@@ -22,12 +22,14 @@
22 22
                     Actions
23 23
 
24 24
               %tbody
25
-                - @need_response.each do |e|
26
-                  %tr
25
+                - @need_response.each do |p|
26
+                  - e = p.activity
27
+                  %tr{class: p.row_class, data: {activity_id: e.id}}
27 28
                     %td
28
-                      - if e.secret_name && e.participants.first.is_organizer
29
-                        = e.secret_name
30 29
                       = e.public_name
30
+                      - if e.secret_name && e.participants.first.is_organizer
31
+                        %i
32
+                          = "(#{e.secret_name})"
31 33
                     %td
32 34
                       = e.group.name
33 35
                     %td
@@ -35,6 +37,8 @@
35 37
                     %td
36 38
                       = e.location
37 39
                     %td
40
+                      = render partial: "activities/presence_buttons", locals: {activity: e, person: current_person, state: p.attending}
41
+  .row
38 42
     .col-md-6
39 43
       .panel.panel-default
40 44
         .panel-heading
@@ -50,4 +54,33 @@
50 54
                       = group.name
51 55
 
52 56
     .col-md-6
53
-      TODO
57
+      .panel.panel-default
58
+        .panel-heading
59
+          Organized by you
60
+
61
+        .panel-body
62
+          %table.table.table-striped.table-bordered
63
+            %tbody
64
+              - @user_organized.each do |p|
65
+                - a = p.activity
66
+                %tr
67
+                  %td
68
+                    = link_to group_activity_url(a.group, a) do
69
+                      = "#{a.public_name} (#{a.secret_name})"
70
+
71
+  .row
72
+    .col-md-12
73
+      .panel.panel-default
74
+        .panel-heading
75
+          Your activities
76
+
77
+        .panel-body
78
+          %table.table.table-striped
79
+            %tbody
80
+              - @upcoming.each do |p|
81
+                - e = p.activity
82
+                %tr{class: p.row_class, data: {activity_id: e.id}}
83
+                  %td
84
+                    = e.public_name
85
+                  %td
86
+                    = render partial: "activities/presence_buttons", locals: {activity: e, person: current_person, state: p.attending}

+ 4 - 1
config/routes.rb

@@ -19,7 +19,10 @@ Rails.application.routes.draw do
19 19
 
20 20
   resources :groups do
21 21
     resources :members
22
-    resources :activities
22
+    resources :activities do
23
+      put 'presence', to: 'activities#presence', on: :member
24
+      patch 'presence', to: 'activities#presence', on: :member
25
+    end
23 26
   end
24 27
   get 'my_groups', to: 'groups#user_groups', as: :user_groups
25 28