From 4fe0f870f580de763c1a0dc428428f1d41b85978 Mon Sep 17 00:00:00 2001 From: Petko Bordjukov Date: Sun, 9 Oct 2016 07:17:34 +0300 Subject: [PATCH] Implement volunteer management --- .../management/volunteers_controller.rb | 37 ++++++++++++ app/models/volunteer_search.rb | 8 +++ .../layouts/management/_navigation.html.slim | 4 +- .../management/volunteers/_form.html.slim | 23 ++++++++ .../management/volunteers/edit.html.slim | 12 ++++ app/views/management/volunteers/index.csv.erb | 16 +++++ .../management/volunteers/index.html.slim | 58 +++++++++++++++++++ .../management/volunteers/show.html.slim | 50 ++++++++++++++++ config/routes.rb | 1 + 9 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 app/controllers/management/volunteers_controller.rb create mode 100644 app/models/volunteer_search.rb create mode 100644 app/views/management/volunteers/_form.html.slim create mode 100644 app/views/management/volunteers/edit.html.slim create mode 100644 app/views/management/volunteers/index.csv.erb create mode 100644 app/views/management/volunteers/index.html.slim create mode 100644 app/views/management/volunteers/show.html.slim diff --git a/app/controllers/management/volunteers_controller.rb b/app/controllers/management/volunteers_controller.rb new file mode 100644 index 0000000..bb792c9 --- /dev/null +++ b/app/controllers/management/volunteers_controller.rb @@ -0,0 +1,37 @@ +module Management + class VolunteersController < ManagementController + include CurrentConferenceAssigning + + def index + @filters = params[:filters] || {} + @volunteers = VolunteerSearch.new(scope: Volunteer.where(conference: current_conference).eager_load(:volunteer_teams), filters: params[:filters]).results + end + + def show + @volunteer = current_conference.volunteers.find(params[:id]) + end + + def edit + @volunteer = current_conference.volunteers.find(params[:id]) + end + + def update + @volunteer = current_conference.volunteers.find(params[:id]) + + if @volunteer.update volunteer_params + redirect_to management_conference_volunteer_path(@volunteer, conference_id: current_conference.id) + else + render :edit, status: :unprocessable_entity + end + end + + private + def volunteer_params + params.require(:volunteer).permit(:name, :picture, :email, :phone, + :tshirt_size, :tshirt_cut, + :food_preferences, :previous_experience, + :notes, :language, + volunteer_team_ids: []) + end + end +end diff --git a/app/models/volunteer_search.rb b/app/models/volunteer_search.rb new file mode 100644 index 0000000..5f34076 --- /dev/null +++ b/app/models/volunteer_search.rb @@ -0,0 +1,8 @@ +class VolunteerSearch + include SearchObject.module(:sorting) + + option(:volunteer_team_id) { |scope, value| scope.joins(:volunteer_teams).where volunteer_teams: {id: value} } + + sort_by 'name' + config[:defaults]['sort'] = "#{config[:sort_attributes].first} asc" +end diff --git a/app/views/layouts/management/_navigation.html.slim b/app/views/layouts/management/_navigation.html.slim index a1e6477..e128d57 100644 --- a/app/views/layouts/management/_navigation.html.slim +++ b/app/views/layouts/management/_navigation.html.slim @@ -26,8 +26,8 @@ nav.navbar.navbar-static-top.navbar-inverse role="navigation" / li class="#{'active' if controller_name == 'sponsorship_offers'}" / = link_to '#' do / => icon 'money', t('activerecord.models.sponsorship_offer', count: 2).mb_chars.capitalize, class: 'fa-fw' - li class="#{'active' if controller_name == 'volunteerships'}" - = link_to '#' do + li class="#{'active' if controller_name == 'volunteers'}" + = link_to management_conference_volunteers_path(current_conference) do => icon 'hand-o-up', t('activerecord.models.volunteership', count: 2).mb_chars.capitalize, class: 'fa-fw' / li class="#{'active' if controller_name == 'propositions'}" / = link_to [:management, current_conference, :propositions] do diff --git a/app/views/management/volunteers/_form.html.slim b/app/views/management/volunteers/_form.html.slim new file mode 100644 index 0000000..8b4522b --- /dev/null +++ b/app/views/management/volunteers/_form.html.slim @@ -0,0 +1,23 @@ += simple_form_for [:management, current_conference, @volunteer], wrapper: :horizontal_form, html: { class: 'form-horizontal' } do |f| + .panel.panel-default + .panel-body + .row + .col-lg-12 + - if f.object.picture.present? + .col-sm-offset-3.col-sm-9 + = attachment_image_tag(@volunteer, :picture, :fill, 150, 150) if @volunteer.picture.present? + + = f.input :picture, as: :attachment, wrapper: :horizontal_file_input, direct: true + + = f.input :name, autofocus: true + = f.input :email + = f.association :volunteer_teams, as: :check_boxes, wrapper: :horizontal_radio_and_checkboxes, collection: current_conference.volunteer_teams + = f.input :phone, input_html: {value: @volunteer.phone.try(:phony_formatted, format: :international)} + = f.input :language, as: :radio_buttons, wrapper: :horizontal_radio_and_checkboxes, collection: locale_collection, include_blank: false, checked: (@volunteer.language.presence || I18n.locale) + = f.input :tshirt_size, collection: Volunteer::TSHIRT_SIZES, as: :radio_buttons, wrapper: :horizontal_radio_and_checkboxes, checked: (@volunteer.tshirt_size.presence || :m) + = f.input :tshirt_cut, collection: Volunteer::TSHIRT_CUTS, wrapper: :horizontal_radio_and_checkboxes, as: :radio_buttons, checked: (@volunteer.tshirt_cut.presence || :unisex) + = f.input :food_preferences, collection: Volunteer::FOOD_PREFERENCES, wrapper: :horizontal_radio_and_checkboxes, as: :radio_buttons, checked: (@volunteer.food_preferences.presence || :none) + = f.input :previous_experience + = f.input :notes + .panel-footer.text-right + = f.submit class: 'btn btn-primary' diff --git a/app/views/management/volunteers/edit.html.slim b/app/views/management/volunteers/edit.html.slim new file mode 100644 index 0000000..e33a62c --- /dev/null +++ b/app/views/management/volunteers/edit.html.slim @@ -0,0 +1,12 @@ +- content_for :title + => t 'actions.edit.title', model: Volunteer.model_name.human + = @volunteer.name + +.row + .col-xs-12 + h1.page-header + = @volunteer.name + +.row + .col-lg-12 + = render 'form' diff --git a/app/views/management/volunteers/index.csv.erb b/app/views/management/volunteers/index.csv.erb new file mode 100644 index 0000000..506382c --- /dev/null +++ b/app/views/management/volunteers/index.csv.erb @@ -0,0 +1,16 @@ +<%- csv_headers = %w{id name email language unique_id phone tshirt_size tshirt_cut food_preferences previous_experience notes teams} -%> +<%= CSV.generate_line(csv_headers).html_safe -%> +<%- @volunteers.each do |volunteer| -%> + <%= CSV.generate_line([volunteer.id, + volunteer.name, + volunteer.email, + volunteer.language, + volunteer.unique_id, + volunteer.phone, + volunteer.tshirt_size, + volunteer.tshirt_cut, + volunteer.food_preferences, + volunteer.previous_experience, + volunteer.notes, + volunteer.volunteer_teams.map(&:name).join(', ')]).html_safe -%> +<%- end -%> diff --git a/app/views/management/volunteers/index.html.slim b/app/views/management/volunteers/index.html.slim new file mode 100644 index 0000000..95eb28e --- /dev/null +++ b/app/views/management/volunteers/index.html.slim @@ -0,0 +1,58 @@ +- content_for :title + = Conference.human_attribute_name(:volunteers).mb_chars.capitalize + +.row + .col-lg-12 + h1.page-header + = Volunteer.model_name.human(count: 2).mb_chars.capitalize + small< + | ( + = t '.total', current: @volunteers.count, total: current_conference.volunteers.count + =< Volunteer.model_name.human(count: current_conference.volunteers.count).mb_chars.downcase + | ) + +.row + .col-md-2.collapse#filters + .panel.panel-default + .panel-heading + = VolunteerTeam.model_name.human.mb_chars.capitalize + .panel-body + ul.nav.nav-pills.nav-stacked + = content_tag :li, role: "presentation", class: @filters[:volunteer_team_id].blank? ? 'active' : nil + = link_to management_conference_volunteers_path(current_conference, filters: @filters.except(:volunteer_team_id)) + = t '.all' + - current_conference.volunteer_teams.each do |volunteer_team| + = content_tag :li, role: "presentation", class: @filters[:volunteer_team_id] == volunteer_team.id.to_s ? 'active' : nil + = link_to management_conference_volunteers_path(current_conference, filters: @filters.merge({volunteer_team_id: volunteer_team.id})) + = volunteer_team.name + .col-md-10 + .panel.panel-default + table.table.table-striped.table-hover.record-table#conferences + thead + tr + th = t '.profile' + th = Volunteer.human_attribute_name :volunteer_teams + th.actions + tbody + - @volunteers.each do |volunteer| + tr + td + .media + .media-left + - if volunteer.picture.present? + = attachment_image_tag(volunteer, :picture, :fill, 50, 50) + - else + = image_tag(PictureUploader.new.thumb.url) + .media-body + h4.media-heading + = volunteer.name + p + = icon(:envelope, volunteer.email) + td + = volunteer.volunteer_teams.map(&:name).join(', ') + td.actions + div.btn-group.btn-group-sm + = action_buttons(current_conference, volunteer, [:show, :edit]) + .panel-footer.text-right + = link_to management_conference_volunteers_path(current_conference, format: 'csv'), class: 'btn btn-info' + = icon :download, t('.export') diff --git a/app/views/management/volunteers/show.html.slim b/app/views/management/volunteers/show.html.slim new file mode 100644 index 0000000..75def37 --- /dev/null +++ b/app/views/management/volunteers/show.html.slim @@ -0,0 +1,50 @@ +- content_for :title + = @volunteer.name + +.row + .col-lg-12 + h1.page-header + = Volunteer.model_name.human.mb_chars.titleize + +.panel.panel-default + .panel-body + .media + .media-left.hidden-sm.hidden-xs + - if @volunteer.picture.present? + = attachment_image_tag(@volunteer, :picture, :fill, 150, 150) + - else + = image_tag(PictureUploader.new.medium.url) + + .media-body + .text-center.visible-sm.visible-xs + - if @volunteer.picture.present? + = attachment_image_tag(@volunteer, :picture, :fill, 150, 150) + - else + = image_tag(PictureUploader.new.medium.url) + h4.media-heading + = @volunteer.name + hr + h4 = Volunteer.human_attribute_name(:volunteer_teams) + = @volunteer.volunteer_teams.map(&:name).join(', ') + - if @volunteer.previous_experience.present? + h4 = Volunteer.human_attribute_name(:previous_experience) + = simple_format @volunteer.previous_experience + - if @volunteer.notes.present? + h4 = Volunteer.human_attribute_name(:notes) + = simple_format @volunteer.notes + h4 = t '.other_info' + = icon(:language, t("locales.#{@volunteer.language}")) + br + = icon(:envelope, @volunteer.email) + br + = icon(:phone, @volunteer.phone.try(:phony_formatted, format: :international)) + br + | 👕 + =< t("simple_form.options.volunteer.tshirt_cut.#{@volunteer.tshirt_cut}") + =< t("simple_form.options.volunteer.tshirt_size.#{@volunteer.tshirt_size}") + br + = icon(:cutlery, t("simple_form.options.volunteer.food_preferences.#{@volunteer.food_preferences}")) + .panel-footer + .text-right + .btn-group.btn-group-sm + = action_buttons current_conference, @volunteer, [:edit, :destroy] diff --git a/config/routes.rb b/config/routes.rb index 90673b6..9fc0e1f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,6 +25,7 @@ Rails.application.routes.draw do resources :event_types, only: :index resources :halls, only: :index resources :slots, only: :index + resources :volunteers end end