Polls in the dashboard

A reduced version of polls has been added to the dashboard
This commit is contained in:
Juan Salvador Pérez García
2018-06-26 08:05:38 +02:00
parent bafdd697b8
commit 2ce9f95283
24 changed files with 463 additions and 37 deletions

View File

@@ -0,0 +1,22 @@
class Dashboard::BaseController < ApplicationController
before_action :authenticate_user!
helper_method :proposal, :proposed_actions, :resources
respond_to :html
layout 'proposals_dashboard'
private
def proposal
@proposal ||= Proposal.find(params[:proposal_id])
end
def proposed_actions
@proposed_actions ||= ProposalDashboardAction.proposed_actions.active_for(proposal)
end
def resources
@resources ||= ProposalDashboardAction.resources.active_for(proposal)
end
end

View File

@@ -0,0 +1,89 @@
class Dashboard::PollsController < Dashboard::BaseController
before_action :load_geozones, only: [:new, :create, :edit, :update]
helper_method :poll
def index
authorize! :manage_polls, proposal
@polls = Poll.for(proposal)
end
def new
authorize! :manage_polls, proposal
@poll = Poll.new
end
def show
authorize! :manage_polls, proposal
end
def create
authorize! :manage_polls, proposal
@poll = Poll.new(poll_params.merge(author: current_user, related: proposal))
if @poll.save
redirect_to proposal_dashboard_poll_path(proposal, poll), notice: t("flash.actions.create.poll")
else
render :new
end
end
def edit
authorize! :manage_polls, proposal
end
def update
authorize! :manage_polls, proposal
byebug
if poll.update(poll_params)
redirect_to proposal_dashboard_poll_path(proposal, poll), notice: t("flash.actions.update.poll")
else
render :edit
end
end
def results
authorize! :manage_polls, proposal
@partial_results = poll.partial_results
end
private
def poll
@poll ||= Poll.includes(:questions).find(params[:id])
end
def load_geozones
@geozones = Geozone.all.order(:name)
end
def poll_params
params.require(:poll).permit(poll_attributes)
end
def poll_attributes
[:name, :starts_at, :ends_at, :geozone_restricted, :summary, :description,
:results_enabled, :stats_enabled, geozone_ids: [],
questions_attributes: question_attributes,
image_attributes: image_attributes]
end
def image_attributes
[:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
end
def question_attributes
[:id, :title, :author_id, :proposal_id, :_destroy, question_answers_attributes: question_answers_attributes]
end
def question_answers_attributes
[:id, :_destroy, :title, :description, :question_id, documents_attributes: documents_attributes]
end
def documents_attributes
[:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
end
end

View File

@@ -1,9 +1,5 @@
class ProposalsDashboardController < ApplicationController class ProposalsDashboardController < Dashboard::BaseController
before_action :authenticate_user! helper_method :proposal_dashboard_action
helper_method :proposal, :proposed_actions, :resources, :proposal_dashboard_action
respond_to :html
layout 'proposals_dashboard'
def index def index
authorize! :dashboard, proposal authorize! :dashboard, proposal
@@ -65,16 +61,4 @@ class ProposalsDashboardController < ApplicationController
def proposal_dashboard_action def proposal_dashboard_action
@proposal_dashboard_action ||= ProposalDashboardAction.find(params[:id]) @proposal_dashboard_action ||= ProposalDashboardAction.find(params[:id])
end end
def proposal
@proposal ||= Proposal.find(params[:proposal_id])
end
def proposed_actions
@proposed_actions ||= ProposalDashboardAction.proposed_actions.active_for(proposal)
end
def resources
@resources ||= ProposalDashboardAction.resources.active_for(proposal)
end
end end

View File

@@ -22,6 +22,9 @@ module Abilities
can :dashboard, Proposal do |proposal| can :dashboard, Proposal do |proposal|
proposal.author.id == user.id proposal.author.id == user.id
end end
can :manage_polls, Proposal do |proposal|
proposal.author.id == user.id
end
can [:retire_form, :retire], Proposal, author_id: user.id can [:retire_form, :retire], Proposal, author_id: user.id

View File

@@ -18,11 +18,15 @@ class Poll < ActiveRecord::Base
has_and_belongs_to_many :geozones has_and_belongs_to_many :geozones
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
belongs_to :related, polymorphic: true
validates :name, presence: true validates :name, presence: true
validate :date_range validate :date_range
accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true
scope :for, ->(element) { where(related: element) }
scope :current, -> { where('starts_at <= ? and ? <= ends_at', Date.current.beginning_of_day, Date.current.beginning_of_day) } scope :current, -> { where('starts_at <= ? and ? <= ends_at', Date.current.beginning_of_day, Date.current.beginning_of_day) }
scope :incoming, -> { where('? < starts_at', Date.current.beginning_of_day) } scope :incoming, -> { where('? < starts_at', Date.current.beginning_of_day) }
scope :expired, -> { where('ends_at < ?', Date.current.beginning_of_day) } scope :expired, -> { where('ends_at < ?', Date.current.beginning_of_day) }

View File

@@ -20,6 +20,8 @@ class Poll::Question < ActiveRecord::Base
validates :title, length: { minimum: 4 } validates :title, length: { minimum: 4 }
accepts_nested_attributes_for :question_answers, reject_if: :all_blank, allow_destroy: true
scope :by_poll_id, ->(poll_id) { where(poll_id: poll_id) } scope :by_poll_id, ->(poll_id) { where(poll_id: poll_id) }
scope :sort_for_list, -> { order('poll_questions.proposal_id IS NULL', :created_at)} scope :sort_for_list, -> { order('poll_questions.proposal_id IS NULL', :created_at)}

View File

@@ -0,0 +1,76 @@
<%= form_for [proposal, :dashboard, poll] do |f| %>
<div class="row">
<div class="small-12 medium-6 column">
<%= f.text_field :name %>
</div>
</div>
<div class="row">
<div class="small-12 medium-6 column">
<%= f.text_field :starts_at,
value: poll.starts_at.present? ? l(poll.starts_at.to_date) : nil,
class: "js-calendar-full" %>
</div>
<div class="small-12 medium-6 column">
<%= f.text_field :ends_at,
value: poll.ends_at.present? ? l(poll.ends_at.to_date) : nil,
class: "js-calendar-full" %>
</div>
</div>
<div class="row">
<div class="small-12 column">
<%=f.text_area :summary, rows: 4%>
</div>
</div>
<div class="row">
<div class="small-12 column">
<%=f.text_area :description, rows: 8%>
</div>
</div>
<div class="row">
<div class="small-12 column">
<%= render 'images/admin_image', imageable: poll, f: f %>
</div>
</div>
<div class="row">
<div class="small-6 medium-6 column">
<%= f.check_box :geozone_restricted, data: { checkbox_toggle: "#geozones" } %>
</div>
</div>
<div id="geozones" style="<%= poll.geozone_restricted? ? '' : 'display:none' %>">
<div class="row">
<%= f.collection_check_boxes(:geozone_ids, @geozones, :id, :name) do |b| %>
<div class="small-6 medium-3 column">
<%= b.label do %>
<%= b.check_box %><%= b.text %>
<% end %>
</div>
<% end %>
</div>
</div>
<div id="questions">
<%= f.fields_for :questions do |question| %>
<%= render 'question_fields', f: question %>
<% end %>
<div id="links row">
<div class="small-12">
<%= link_to_add_association t('.add_question'), f, :questions, class: 'button hollow' %>
</div>
</div>
</div>
<div class="row">
<div class="small-12 medium-4 column">
<%= f.submit t("admin.polls.#{admin_submit_action(poll)}.submit_button"),
class: "button success expanded" %>
</div>
</div>
<% end %>

View File

@@ -0,0 +1,18 @@
<tr id="<%= dom_id(poll) %>" class="poll">
<td>
<strong>
<%= link_to poll.name, proposal_dashboard_poll_path(proposal, poll) %>
</strong>
</td>
<td>
<%= l poll.starts_at.to_date %> - <%= l poll.ends_at.to_date %>
</td>
<td class="text-right">
<%= link_to t("admin.actions.edit"),
edit_proposal_dashboard_poll_path(proposal, poll),
class: "button hollow" %>
<%= link_to t("admin.actions.configure"),
proposal_dashboard_poll_path(proposal, poll),
class: "button hollow" %>
</td>
</tr>

View File

@@ -0,0 +1,25 @@
<%= link_to t("admin.polls.edit.title"),
edit_proposal_dashboard_poll_path(proposal, poll),
class: "button hollow float-right" %>
<h2 class="inline-block">
<%= poll.name %>
</h2>
<div class="clear"></div>
<div class="callout highlight">
<div class="inline-block">
<strong><%= t("admin.polls.index.dates") %></strong>
<br>
<%= l poll.starts_at.to_date %> - <%= l poll.ends_at.to_date %>
</div>
<% if poll.geozone_restricted %>
<div class="inline-block margin-left">
<strong><%= t("admin.polls.index.geozone_restricted") %></strong>
<br>
<%= poll.geozones.pluck(:name).to_sentence %>
</div>
<% end %>
</div>

View File

@@ -0,0 +1,21 @@
<div class="nested-fields">
<div class="row">
<div class="small-12 large-9 column">
<%= f.text_field :title %>
</div>
<div class="small-12 large-3 column" style="padding-top: 20px">
<%= link_to_remove_association f, class: 'button hollow' do %>
<span class="icon-x" aria-hidden="true"></span>
<span><%=t(".remove_answer") %></span>
<% end %>
</div>
</div>
<div class="ckeditor">
<%= f.cktext_area :description,
maxlength: Poll::Question.description_max_length,
ckeditor: { language: I18n.locale } %>
</div>
<hr style="max-width:100%">
</div>

View File

@@ -0,0 +1,29 @@
<div class="nested-fields">
<%= f.hidden_field :author_id, value: f.object.author_id || current_user.id %>
<%= f.hidden_field :proposal_id, value: f.object.proposal_id || proposal.id %>
<div class="row">
<div class="small-12 large-9 column">
<%= f.text_field :title %>
</div>
<div class="small-12 large-3 column" style="padding-top: 20px">
<%= link_to_remove_association f, class: 'button hollow' do %>
<span class="icon-x" aria-hidden="true"></span>
<span><%=t(".remove_question") %></span>
<% end %>
</div>
</div>
<div id="answers">
<%= f.fields_for :question_answers do |answer| %>
<%= render 'question_answer_fields', f: answer %>
<% end %>
<div id="links row">
<div class="small-12">
<%= link_to_add_association t('.add_answer'), f, :question_answers, class: 'button hollow' %>
</div>
</div>
</div>
<hr style="max-width:100%">
</div>

View File

@@ -0,0 +1,24 @@
<h3><%= t("admin.polls.show.questions_title") %></h3>
<% if poll.questions.empty? %>
<div class="callout primary margin-top">
<%= t('admin.polls.show.no_questions') %>
</div>
<% else %>
<table class="fixed margin">
<thead>
<tr>
<th><%= t('admin.polls.show.table_title') %></th>
</tr>
</thead>
<% poll.questions.each do |question| %>
<tr id="<%= dom_id(question) %>">
<td>
<strong>
<%= question.title %>
</strong>
</td>
</tr>
<% end %>
</table>
<% end %>

View File

@@ -0,0 +1,30 @@
<ul class="menu simple clear" id="assigned-resources-tabs">
<% if action_name == "show" %>
<li class="is-active">
<h2>
<%= t("admin.polls.show.questions_tab") %>
(<%= poll.questions.count %>)
</h2>
</li>
<% else %>
<li>
<%= link_to proposal_dashboard_poll_path(proposal, poll) do %>
<%= t("admin.polls.show.questions_tab") %>
(<%= poll.questions.count %>)
<% end %>
</li>
<% end %>
<% if action_name == "results" %>
<li class="is-active">
<h2>
<%= t("admin.polls.show.results_tab") %>
</h2>
</li>
<% else %>
<li>
<%= link_to t("admin.polls.show.results_tab"), results_proposal_dashboard_poll_path(proposal, poll) %>
</li>
<% end %>
</ul>

View File

@@ -0,0 +1,7 @@
<%= back_link_to %>
<h2><%= t("admin.polls.edit.title") %></h2>
<div class="polls-form">
<%= render "form" %>
</div>

View File

@@ -0,0 +1,22 @@
<h2 class="inline-block"><%= t("admin.polls.index.title") %></h2>
<%= link_to t("admin.polls.index.create"),
new_proposal_dashboard_poll_path(proposal),
class: "button success float-right" %>
<% if @polls.any? %>
<table>
<thead>
<th class="medium-6"><%= t("admin.polls.index.name") %></th>
<th><%= t("admin.polls.index.dates") %></th>
<th class="text-right"><%= t("admin.actions.actions") %></th>
</thead>
<tbody>
<%= render @polls %>
</tbody>
</table>
<% else %>
<div class="callout primary">
<%= t("admin.polls.index.no_polls") %>
</div>
<% end %>

View File

@@ -0,0 +1,7 @@
<%= back_link_to %>
<h2><%= t("admin.polls.new.title") %></h2>
<div class="polls-form">
<%= render "form" %>
</div>

View File

@@ -0,0 +1,18 @@
<%= render 'poll_header' %>
<div id="poll-resources">
<%= render "subnav" %>
<h3><%= t("admin.results.index.title") %></h3>
<% if @partial_results.empty? %>
<div class="callout primary margin-top">
<%= t("admin.results.index.no_results") %>
</div>
<% else %>
<%= render "/admin/poll/polls/recount", resource: @poll %>
<%= render "/admin/poll/polls/result" %>
<%= render "/admin/poll/polls/results_by_booth" %>
<%= render "/admin/poll/polls/show_results", resource: @poll %>
<% end %>
</div>

View File

@@ -0,0 +1,7 @@
<%= render "poll_header" %>
<div id="poll-resources">
<%= render "subnav" %>
<%= render "questions" %>
</div>

View File

@@ -75,13 +75,21 @@
</div> </div>
</div> </div>
<% if resources.any? %> <div class="row">
<div class="row">
<div class="small-2 columns"></div> <div class="small-2 columns"></div>
<div class="small-10 columns"><%= t '.resources' %></div> <div class="small-10 columns"><%= t '.resources' %></div>
</div> </div>
<% resources.each do |resource| %> <% if can?(:manage_polls, proposal) %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<%= link_to t('.polls'), proposal_dashboard_polls_path(proposal.to_param) %>
</div>
</div>
<% end %>
<% resources.each do |resource| %>
<div class="row"> <div class="row">
<div class="small-2 columns"></div> <div class="small-2 columns"></div>
<div class="small-10 columns"> <div class="small-10 columns">
@@ -95,5 +103,4 @@
</span> </span>
</div> </div>
</div> </div>
<% end %>
<% end %> <% end %>

View File

@@ -501,6 +501,7 @@ en:
resources: Resources resources: Resources
actions: Actions actions: Actions
graphic: Graphic graphic: Graphic
polls: Polls
proposed_action: proposed_action:
execute: Execute execute: Execute
form: form:
@@ -514,6 +515,12 @@ en:
group_by_date: Group by date group_by_date: Group by date
progress: Acumulated progress progress: Acumulated progress
supports: Supports supports: Supports
dashboard:
polls:
form:
add_question: Add question
question_fields:
remove_question: Remove question
polls: polls:
all: "All" all: "All"
no_dates: "no date assigned" no_dates: "no date assigned"

View File

@@ -501,6 +501,7 @@ es:
resources: Recursos resources: Recursos
actions: Acciones actions: Acciones
graphic: Gráfico graphic: Gráfico
polls: Encuestas
proposed_action: proposed_action:
execute: Ejecutar execute: Ejecutar
form: form:
@@ -514,6 +515,12 @@ es:
group_by_date: Agrupar por fechas group_by_date: Agrupar por fechas
progress: Progreso acumulado progress: Progreso acumulado
supports: Apoyos supports: Apoyos
dashboard:
polls:
form:
add_question: Añadir pregunta
question_fields:
remove_question: Borrar pregunta
polls: polls:
all: "Todas" all: "Todas"
no_dates: "sin fecha asignada" no_dates: "sin fecha asignada"

View File

@@ -11,6 +11,15 @@ resources :proposals do
get :new_request get :new_request
post :create_request post :create_request
end end
end
namespace :dashboard do
resources :polls, except: :destroy do
member do
get :results
end
end
end end
member do member do

View File

@@ -0,0 +1,5 @@
class AddRelatedToPolls < ActiveRecord::Migration
def change
add_reference :polls, :related, index: true, polymorphic: true
end
end

View File

@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180615102215) do ActiveRecord::Schema.define(version: 20180625075520) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@@ -886,8 +886,11 @@ ActiveRecord::Schema.define(version: 20180615102215) do
t.boolean "stats_enabled", default: false t.boolean "stats_enabled", default: false
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.integer "related_id"
t.string "related_type"
end end
add_index "polls", ["related_type", "related_id"], name: "index_polls_on_related_type_and_related_id", using: :btree
add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree
create_table "proposal_dashboard_actions", force: :cascade do |t| create_table "proposal_dashboard_actions", force: :cascade do |t|