Skip to content

Commit

Permalink
Assign Multiple Volunteers //
Browse files Browse the repository at this point in the history
major redesign
  • Loading branch information
Sam Williams committed Jan 13, 2024
1 parent 1bcd01e commit 409aedc
Show file tree
Hide file tree
Showing 13 changed files with 380 additions and 758 deletions.
503 changes: 0 additions & 503 deletions 3

This file was deleted.

1 change: 0 additions & 1 deletion app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
);
@use "bootstrap-datepicker/dist/css/bootstrap-datepicker";
@use "datatables.net-dt/css/jquery.dataTables";
@use "jquery-datatables-checkboxes/css/dataTables.checkboxes";
@use "@fortawesome/fontawesome-free/scss/fontawesome";
@use "@fortawesome/fontawesome-free/scss/solid";
@use "select2/dist/css/select2";
Expand Down
94 changes: 39 additions & 55 deletions app/controllers/supervisor_volunteers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,42 @@ class SupervisorVolunteersController < ApplicationController

def create
authorize :supervisor_volunteer
supervisor_volunteer = supervisor_volunteer_parent.supervisor_volunteers.find_or_create_by!(supervisor_volunteer_params)
supervisor_volunteer.is_active = true unless supervisor_volunteer&.is_active?
volunteer = supervisor_volunteer.volunteer
supervisor = supervisor_volunteer.supervisor
supervisor_volunteer.save
flash_message = "#{volunteer.display_name} successfully assigned to #{supervisor.display_name}."
volunteer = Volunteer.find(supervisor_volunteer_params[:volunteer_id])
supervisor = set_supervisor
if assign_volunteer_to_supervisor(volunteer, supervisor)
flash[:notice] = "#{volunteer.display_name} successfully assigned to #{supervisor.display_name}."
else
flash[:alert] = "Something went wrong. Please try again."
end

redirect_to request.referer, notice: flash_message
redirect_to request.referer
end

def unassign
authorize :supervisor_volunteer
volunteer = Volunteer.find(params[:id])
supervisor_volunteer = volunteer.supervisor_volunteer
supervisor = volunteer.supervisor
supervisor_volunteer.is_active = false
supervisor_volunteer.save!
flash_message = "#{volunteer.display_name} was unassigned from #{supervisor.display_name}."
supervisor = volunteer.supervisor_volunteer.supervisor
if unassign_volunteers_supervisor(volunteer)
flash[:notice] = "#{volunteer.display_name} was unassigned from #{supervisor.display_name}."
else
flash[:alert] = "Something went wrong. Please try again."
end

redirect_to request.referer, notice: flash_message
redirect_to request.referer
end

def bulk_assignment
authorize :supervisor_volunteer
if mass_assign_volunteers?
volunteer_ids = supervisor_volunteer_params[:volunteer_ids]
supervisor = supervisor_volunteer_params[:supervisor_id]
vol = "Volunteer".pluralize(volunteer_ids.length)

if supervisor == "unassign"
name_array = bulk_unassign!(volunteer_ids)
flash_message = "#{vol} #{name_array.to_sentence} successfully unassigned"
else
supervisor = supervisor_volunteer_parent
name_array = bulk_assign!(supervisor, volunteer_ids)
flash_message = "#{vol} #{name_array.to_sentence} successfully reassigned to #{supervisor.display_name}"
end

redirect_to volunteers_path, notice: flash_message
volunteers = policy_scope(current_organization.volunteers).where(id: params[:supervisor_volunteer][:volunteer_ids])
supervisor = policy_scope(current_organization.supervisors).where(id: params[:supervisor_volunteer][:supervisor_id]).first
if bulk_change_supervisor(supervisor, volunteers)
flash[:notice] = "#{"Volunteer".pluralize(volunteers.count)} successfully assigned to new supervisor."
else
redirect_to volunteers_path, notice: "Please select at least one volunteer and one supervisor."
flash[:alert] = "Something went wrong. The #{"volunteer".pluralize(volunteers.count)} could not be assigned."
end

redirect_to volunteers_path
end

private
Expand All @@ -53,39 +47,29 @@ def supervisor_volunteer_params
params.require(:supervisor_volunteer).permit(:supervisor_id, :volunteer_id, volunteer_ids: [])
end

def supervisor_volunteer_parent
def set_supervisor
Supervisor.find(params[:supervisor_id] || supervisor_volunteer_params[:supervisor_id])
end

def mass_assign_volunteers?
supervisor_volunteer_params[:volunteer_ids] && supervisor_volunteer_params[:supervisor_id] ? true : false
end

def bulk_assign!(supervisor, volunteer_ids)
created_volunteers = []
volunteer_ids.each do |vol_id|
if (supervisor_volunteer = SupervisorVolunteer.find_by(volunteer_id: vol_id.to_i))
supervisor_volunteer.update!(supervisor_id: supervisor.id)
else
supervisor_volunteer = supervisor.supervisor_volunteers.create(volunteer_id: vol_id.to_i)
def bulk_change_supervisor(supervisor, volunteers)
if supervisor
volunteers.each do |volunteer|
assign_volunteer_to_supervisor(volunteer, supervisor)
end
else
volunteers.each do |volunteer|
unassign_volunteers_supervisor(volunteer)
end
supervisor_volunteer.is_active = true
volunteer = supervisor_volunteer.volunteer
supervisor_volunteer.save
created_volunteers << volunteer.display_name.to_s
end
created_volunteers
end

def bulk_unassign!(volunteer_ids)
unassigned_volunteers = []
volunteer_ids.each do |vol_id|
supervisor_volunteer = SupervisorVolunteer.find_by(volunteer_id: vol_id.to_i)
supervisor_volunteer.update(is_active: false)
volunteer = supervisor_volunteer.volunteer
supervisor_volunteer.save
unassigned_volunteers << volunteer.display_name.to_s # take into account single assignments and give multiple assignments proper format
end
unassigned_volunteers
def assign_volunteer_to_supervisor(volunteer, supervisor)
unassign_volunteers_supervisor(volunteer)
supervisor_volunteer = supervisor.supervisor_volunteers.find_or_create_by!(volunteer: volunteer)
supervisor_volunteer.update!(is_active: true)
end

def unassign_volunteers_supervisor(volunteer)
volunteer.supervisor_volunteer&.update(is_active: false)
end
end
2 changes: 0 additions & 2 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import '@rails/actiontext'
import './datatable.js'

require('datatables.net-dt')(null, window.jQuery) // First parameter is the global object. Defaults to window if null
require('datatables.net-select')(null, window.jQuery)
require('jquery-datatables-checkboxes')(null, window.jQuery)
require('select2')(window.jQuery)
require('@rails/ujs').start()
require('@rails/activestorage').start()
Expand Down
29 changes: 29 additions & 0 deletions app/javascript/controllers/disable_form_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static targets = ['submitButton', 'input']
static values = {
unallowed: { type: Array }
}

static classes = ['disabled', 'enabled']

validate () {
let invalid = false
this.inputTargets.forEach(input => {
if (this.unallowedValue.includes(input.value)) {
invalid = true
}
})

if (invalid) {
this.submitButtonTarget.disabled = true
this.submitButtonTarget.classList.add(this.disabledClass)
this.submitButtonTarget.classList.remove(...this.enabledClasses)
} else {
this.submitButtonTarget.disabled = false
this.submitButtonTarget.classList.remove(this.disabledClass)
this.submitButtonTarget.classList.add(...this.enabledClasses)
}
}
}
6 changes: 6 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import { application } from './application'

import DisableFormController from './disable_form_controller'

import DismissController from './dismiss_controller'

import ExtendedNestedFormController from './extended_nested_form_controller'
Expand All @@ -14,13 +16,17 @@ import MultipleSelectController from './multiple_select_controller'

import NavbarController from './navbar_controller'

import SelectAllController from './select_all_controller'

import SidebarController from './sidebar_controller'

import SidebarGroupController from './sidebar_group_controller'
application.register('disable-form', DisableFormController)
application.register('dismiss', DismissController)
application.register('extended-nested-form', ExtendedNestedFormController)
application.register('hello', HelloController)
application.register('multiple-select', MultipleSelectController)
application.register('navbar', NavbarController)
application.register('select-all', SelectAllController)
application.register('sidebar', SidebarController)
application.register('sidebar-group', SidebarGroupController)
69 changes: 69 additions & 0 deletions app/javascript/controllers/select_all_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Controller } from '@hotwired/stimulus'

// Connects to data-controller="select-all"
export default class extends Controller {
static targets = ['checkboxAll', 'checkbox', 'button', 'buttonLabel']
static values = {
allChecked: { type: Boolean, default: false },
buttonLabel: { type: String }
}

static classes = ['hidden']

toggleAll () {
this.allCheckedValue = !this.allCheckedValue

this.checkboxTargets.forEach(checkbox => {
checkbox.checked = this.allCheckedValue
})

this.toggleButton()
}

toggleSingle () {
this.toggleCheckedAll()
this.toggleButton()
}

toggleCheckedAll () {
const numChecked = this.getNumberChecked()
const numTotal = this.getTotalCheckboxes()

this.allCheckedValue = numChecked === numTotal
this.checkboxAllTarget.checked = this.allCheckedValue

if (numChecked === 0) {
this.checkboxAllTarget.indeterminate = false
} else {
this.checkboxAllTarget.indeterminate = numChecked < numTotal
}
}

toggleButton () {
if (this.hasButtonTarget) {
const numChecked = this.getNumberChecked()
if (numChecked > 0) {
if (this.hasButtonLabelTarget) {
let label = this.buttonLabelValue
if (numChecked > 1) {
label += 's'
}
label += ' (' + numChecked + ')'
this.buttonLabelTarget.innerHTML = label
}

this.buttonTarget.classList.remove(this.hiddenClass)
} else {
this.buttonTarget.classList.add(this.hiddenClass)
}
}
}

getNumberChecked () {
return this.checkboxTargets.filter((checkbox) => checkbox.checked).length
}

getTotalCheckboxes () {
return this.checkboxTargets.length
}
}
37 changes: 6 additions & 31 deletions app/javascript/src/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,16 @@ $(() => { // JQuery's callback for the DOM loading
})
},
order: [[7, 'desc']],
select: {
style: 'multi'
},
columns: [
{
data: 'id',
targets: 0,
searchable: false,
orderable: false,
checkboxes: {
selectRow: true,
stateSave: false
render: (data, type, row, meta) => {
return `
<input type="checkbox" name="supervisor_volunteer[volunteer_ids][]" id="supervisor_volunteer_volunteer_ids_${row.id}" value="${row.id}" class="form-check-input" data-select-all-target="checkbox" data-action="select-all#toggleSingle">
`
}
},
{
Expand Down Expand Up @@ -261,10 +259,10 @@ $(() => { // JQuery's callback for the DOM loading
render: (data, type, row, meta) => {
return `
<span class="mobile-label">Actions</span>
<a href="${editVolunteerPath(row.id)}" class="btn btn-primary">
<a href="${editVolunteerPath(row.id)}" class="btn btn-primary text-white">
Edit
</a>
<a href="${impersonateVolunteerPath(row.id)}" class="btn btn-secondary">
<a href="${impersonateVolunteerPath(row.id)}" class="btn btn-secondary text-white">
Impersonate
</a>
`
Expand Down Expand Up @@ -306,29 +304,6 @@ $(() => { // JQuery's callback for the DOM loading
}
})

$('#form-bulk-assignment').on('submit', function (e) {
const form = this
const rowsSelected = volunteersTable.column(0).checkboxes.selected()

$.each(rowsSelected, function (index, rowId) {
$(form).append(
$('<input>')
.attr('type', 'hidden')
.attr('name', 'supervisor_volunteer[volunteer_ids][]')
.val(rowId)
)
})
})

volunteersTable.column(0).on('change', function () {
const rowsSelected = volunteersTable.column(0).checkboxes.selected()
if (rowsSelected.count() === 0) {
$('#volunteers-selected').html('')
} else {
$('#volunteers-selected').html('s (' + rowsSelected.count() + ')')
}
})

// Because the table saves state, we have to check/uncheck modal inputs based on what
// columns are visible
volunteersTable.columns().every(function (index) {
Expand Down
27 changes: 14 additions & 13 deletions app/views/volunteers/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -157,26 +157,27 @@
</div>
</div>

<div class="tables-wrapper">
<div class="tables-wrapper" data-controller="select-all" data-select-all-hidden-class="d-none" data-select-all-button-label-value="Manage Volunteer">
<div class="row">
<div class="col-lg-12">
<div class="card-style mb-30">
<h6 class="mb-10">Responsive Data Table</h6>
<span class="mb-3">
<button type="button" class="main-btn dark-btn btn-sm mb-2 mb-md-0" data-bs-toggle="modal" data-bs-target="#bulk-assigment-modal">
<div class="mb-3">
<button type="button" class="main-btn dark-btn btn-sm mb-2 mb-md-0 d-none" data-bs-toggle="modal" data-bs-target="#bulk-assigment-modal" data-select-all-target="button">
<i class="lni lni-users mr-10"></i>
Manage Volunteer<span class="d-inline" id="volunteers-selected"></span>
<span class="d-inline" data-select-all-target="buttonLabel"></span>
</button>
</span>
</div>
<div class="table-responsive">
<%= form_with(url: bulk_assignment_supervisor_volunteers_path, id: "form-bulk-assignment") do |form| %>
<%= form_with(url: bulk_assignment_supervisor_volunteers_path, id: "form-bulk-assignment", data: { controller: "disable-form", "disable-form-unallowed-value": '["unselected"]', "disable-form-disabled-class": "deactive-btn", "disable-form-enabled-class": "btn-hover dark-btn" }) do |form| %>
<table
class="table hover"
id="volunteers"
data-source="<%= datatable_volunteers_path format: :json %>">
<thead>
<tr>
<th></th>
<th>
<input type="checkbox" class="form-check-input" data-select-all-target="checkboxAll" data-action="select-all#toggleAll">
</th>
<th>Name</th>
<th>Email</th>
<th>Supervisor</th>
Expand Down Expand Up @@ -211,11 +212,11 @@
<div class="mb-30">
<div class="select-style-1">
<label for='supervisor_volunteer_supervisor_id'>
Choose a new supervisor from the dropdown below to reassign selected volunteers, or select “No Supervisor” to unassign volunteers. When you're ready, go ahead and click the "Confirm" button to apply the changes.
Choose a new supervisor from the dropdown below to reassign selected volunteers. Once you're ready, click the "Confirm" button to apply the changes.
</label>
<select name='supervisor_volunteer[supervisor_id]' class='supervisor-bulk-assignment form-control' required="required">
<option value="default">Choose A Supervisor</option>
<option value="unassign">-- No Supervisor --</option>
<select name='supervisor_volunteer[supervisor_id]' id="supervisor_volunteer_supervisor_id" class='supervisor-bulk-assignment form-control' required="required" data-disable-form-target="input" data-action="disable-form#validate">
<option value="unselected">Choose a supervisor</option>
<option value="">None</option>
<% @supervisors&.active&.each do |supervisor| %>
<option value="<%= supervisor.id %>"><%= supervisor.display_name %></option>
<% end %>
Expand All @@ -229,7 +230,7 @@
type="button"><i class="lni lni-ban mr-10"></i>
Close
</button>
<%= form.button type: :submit, class: "submit-bulk-assignment main-btn dark-btn btn-hover m-1" do %>
<%= form.button type: :submit, class: "main-btn deactive-btn m-1", data: { "disable-form-target": "submitButton" }, disabled: true do %>
Confirm
<% end %>
</div>
Expand Down
Loading

0 comments on commit 409aedc

Please sign in to comment.