Skip to content

Commit 3f002fc

Browse files
committed
view: improve group members table
- Adds column headings (Avatar, Name, Email, Mobile, T&C) - Adds T&C indicator using Font Awesome icons (green check / red x) - Adds TomSelect search dropdown for finding members by name/email - Adds Pagy pagination controls at bottom of table - Renders counts from instance variables to avoid N+1 queries
1 parent 4c5842a commit 3f002fc

2 files changed

Lines changed: 74 additions & 4 deletions

File tree

app/controllers/admin/groups_controller.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,15 @@ def create
2222
def show
2323
@group = Group.find(params[:id])
2424
authorize @group
25+
26+
@eligible_count = @group.eligible_members.count
27+
@total_count = @group.members.count
28+
@pagy, @members = pagy(Group.members_by_recent_rsvp(@group), items: 20)
2529
end
2630

2731
private
2832

2933
def group_params
30-
params.expect(group: [:name, :description, :chapter_id])
34+
params.expect(group: %i[name description chapter_id])
3135
end
3236
end
Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,84 @@
1+
- content_for :head do
2+
%link{ href: 'https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/css/tom-select.bootstrap5.min.css', rel: 'stylesheet', type: 'text/css' }
3+
%script{ src: 'https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/js/tom-select.complete.min.js' }
4+
15
.container.py-4.py-lg-5
26
.row.mb-4
37
.col
48
%h1
59
= @group.name
6-
%small.text-muted #{@group.chapter.name}
10+
%small.text-muted= @group.chapter.name
11+
12+
.row
13+
.col
14+
%h3.mb-3 Members (#{@eligible_count} eligible, #{@total_count} total)
15+
16+
.row.mb-4
17+
.col-12.col-md-6
18+
= select_tag 'member_lookup_id', nil, class: 'form-control', placeholder: 'Search members by name or email...'
19+
.col-auto
20+
= link_to 'View Profile', '#', { class: 'btn btn-primary', id: 'view_profile' }
721

822
.row
923
.col
10-
%h3.mb-3 Members (#{@group.eligible_members.count} eligible, #{@group.members.count} total)
1124
%table.table.table-striped.table-hover
25+
%thead
26+
%tr
27+
%th Avatar
28+
%th Name
29+
%th Email
30+
%th Mobile
31+
%th T&C
1232
%tbody
13-
- @group.members.each do |member|
33+
- @members.each do |member|
1434
%tr
1535
%td= image_tag(member.avatar(32), class: 'rounded-circle', title: member.full_name, alt: member.full_name)
1636
%td= link_to member.full_name, admin_member_path(member)
1737
%td= mail_to member.email, member.email
1838
%td= member.mobile
39+
%td
40+
- if member.accepted_toc_at
41+
%i.fa.fa-check.text-success{ title: "Accepted on #{member.accepted_toc_at.to_date}" }
42+
- else
43+
%i.fa.fa-times.text-danger{ title: 'Not accepted' }
44+
45+
.row
46+
.col
47+
= render partial: 'shared/pagination', locals: { pagy: @pagy, model: 'member' }
48+
49+
-# TomSelect initialization
50+
:javascript
51+
document.addEventListener('DOMContentLoaded', function() {
52+
var control = document.getElementById('member_lookup_id');
53+
var viewLink = document.getElementById('view_profile');
54+
55+
var ts = new TomSelect(control, {
56+
create: false,
57+
maxItems: 1,
58+
placeholder: 'Search members by name or email...',
59+
valueField: 'id',
60+
labelField: 'full_name',
61+
searchField: ['full_name', 'email'],
62+
load: function(query, callback) {
63+
if (query.length < 3) {
64+
callback();
65+
return;
66+
}
67+
68+
var url = '/admin/members/search?q=' + encodeURIComponent(query);
69+
fetch(url)
70+
.then(function(response) { return response.json(); })
71+
.then(function(data) { callback(data); })
72+
.catch(function() { callback(); });
73+
},
74+
onChange: function(value) {
75+
if (value) {
76+
viewLink.href = '/admin/members/' + value;
77+
viewLink.classList.remove('disabled');
78+
} else {
79+
viewLink.href = '#';
80+
viewLink.classList.add('disabled');
81+
}
82+
}
83+
});
84+
});

0 commit comments

Comments
 (0)