Permalink
Browse files

417 - WIP ability to select, rank, and cast a vote.

  • Loading branch information...
1 parent 34175fc commit 98bac1b8e57e26994591348546f18bc27a475328 @paramaw paramaw committed May 21, 2012
@@ -2,6 +2,7 @@ class OpportunityVotesController < ApplicationController
layout 'opportunity'
before_filter :require_user
before_filter :find_conversation
+ before_filter :restrict_voter_access, :only => [:select_options,:create_select_options,:rank_options, :create_rank_options]
DEFAULT_NUM_OF_OPTIONS = 1
def new
@@ -21,17 +22,59 @@ def create
else
render :action => "new"
end
-
end
def show
@vote = @conversation.surveys.find(params[:id])
- @vote_response_presenter = VoteResponsePresenter.new(:person_id => current_person.id, :survey_id => @vote.id)
+ @vote_response_presenter = VoteResponsePresenter.new(:person_id => current_person.id, :survey_id => @vote.id)
+ end
+
+ def select_options
+ @vote = @conversation.surveys.find(params[:id])
+ selected_option_ids = params[:selected_option_ids].to_s.split(',') || []
+ @vote_response_presenter = VoteResponsePresenter.new({:person_id => current_person.id, :survey_id => @vote.id}.merge!(:selected_option_ids => selected_option_ids))
+ render :action => :show
+ end
+
+ def create_select_options
+ vote_response_params = params[:vote_response_presenter] || {}
+ @vote = @conversation.surveys.find(params[:id])
+ @vote_response_presenter = VoteResponsePresenter.new({:person_id => current_person.id, :survey_id => @vote.id}.merge!(vote_response_params))
+ if @vote_response_presenter.valid_selected_options?
+ redirect_to rank_options_conversation_vote_path(@conversation,@vote,:selected_option_ids => @vote_response_presenter.selected_option_ids.join(','))
+ else
+ render :action => :show
+ end
+ end
+
+ def rank_options
+ selected_option_ids = params[:selected_option_ids].to_s.split(',') || []
+ @vote = @conversation.surveys.find(params[:id])
+ @vote_response_presenter = VoteResponsePresenter.new({:person_id => current_person.id, :survey_id => @vote.id}.merge!(:selected_option_ids => selected_option_ids))
+ end
+
+ def create_rank_options
+ vote_response_params = params[:vote_response_presenter] || {}
+ @vote = @conversation.surveys.find(params[:id])
+ @vote_response_presenter = VoteResponsePresenter.new({:person_id => current_person.id, :survey_id => @vote.id}.merge!(vote_response_params))
+ if @vote_response_presenter.save
+ flash[:notice] = "Thank you for voting!"
+ redirect_to rank_options_conversation_vote_path(@conversation,@vote)
+ else
+ render :action => :rank_options
+ end
end
+
+
protected
def find_conversation
@conversation = Conversation.find(params[:conversation_id])
end
+
+ def restrict_voter_access
+ vote = VoteResponsePresenter.new({:person_id => current_person.id, :survey_id => params[:id]})
+ redirect_to conversation_vote_path(@conversation,params[:id]) unless vote.allowed?
+ end
end
@@ -19,4 +19,10 @@ def add_object_link(name, form, object, partial, where, options={})
}, options
end
+ def opportunity_vote_tab_nav(step)
+ selected_option_ids = @vote_response_presenter && @vote_response_presenter.selected_option_ids.join(',')
+ select_options_link = (step == 'select_options') ? '#' : select_options_conversation_vote_path(@conversation,@vote, :selected_option_ids => selected_option_ids)
+ render :partial => 'vote_tab_nav', :locals => {:step => step, :select_options_link => select_options_link}
+ end
+
end
@@ -1,21 +1,52 @@
class SurveyResponse < ActiveRecord::Base
+ attr_accessor :selected_option_ids, :validate_presence_of_selected_option
has_many :selected_survey_options, :dependent => :destroy
belongs_to :person
belongs_to :survey
validates_presence_of :person_id
validates_uniqueness_of :person_id, :scope => :survey_id, :allow_blank => true, :allow_nil => true, :message => 'already exists'
+ validate :selected_should_be_under_max_selected_options
+ validate :presence_of_selected_options, :if => :validate_presence_of_selected_option?
+
after_commit :send_survey_confirmation, :on => :create
scope :sort_last_created_first, {:order=> 'created_at DESC'}
delegate :id, :title, :type, :to => :survey, :prefix => true
delegate :name, :to => :person, :prefix => true
+ def validate_presence_of_selected_option?
+ @validate_presence_of_selected_option ||= false
+ end
+
+ def selected_option_ids=(option_ids=[])
+ @selected_option_ids = option_ids
+ @selected_option_ids.each do |option_id|
+ self.selected_survey_options.build(:survey_option_id => option_id)
+ end
+ end
+
+ def selected_option_ids
+ selected_survey_options.collect(&:survey_option_id)
+ end
+
def selected_survey_option_titles
selected_survey_options.collect{|selected_option| selected_option.survey_option.title }
end
def send_survey_confirmation
Notifier.survey_confirmation(self).deliver
end
+
+ def selected_should_be_under_max_selected_options
+ if self.survey && selected_option_ids.length > survey.max_selected_options
+ self.errors[:selected_option_ids] << "You cannot select more than #{survey.max_selected_options} option(s)"
+ end
+ end
+ def presence_of_selected_options
+ if selected_option_ids.length < 1
+ self.errors[:selected_option_ids] << "You must select at least one option"
+ end
+ end
+
end
@@ -1,7 +1,7 @@
class VoteResponsePresenter
attr_accessor :survey_response, :confirmed
- delegate :id, :class, :errors, :to_param, :new_record?, :selected_survey_options, :survey, :person, :persisted?,
+ delegate :id, :class, :errors, :to_param, :new_record?, :selected_survey_options, :selected_option_ids, :selected_option_ids=, :survey, :person, :persisted?,
:to => :survey_response
delegate :max_selected_options, :expired?,
:to => :survey
@@ -37,7 +37,10 @@ def allowed?
def available_options
survey.options.position_sorted - selected_survey_options.collect{|record| record.survey_option}
end
-
+
+ def options_sorted
+ survey.options.position_sorted
+ end
def define_methods_for_selected_options
max_selected_options.times do |i|
@@ -84,6 +87,12 @@ def define_methods_for_selected_options
end
end
+
+ def valid_selected_options?
+ survey_response.validate_presence_of_selected_option = true
+ survey_response.valid?
+ survey_response.errors[:selected_option_ids].blank?
+ end
def save
ActiveRecord::Base.transaction do
@@ -0,0 +1,25 @@
+<% content_for :header do %>
+ <%= javascript_include_tag '/javascripts/lib/opportunity_votes/voting' %>
+<% end %>
+<%= form_for @vote_response_presenter, :as => :vote_response_presenter, :url => rank_options_conversation_vote_path(@conversation,@vote) do |form|%>
+ <%= opportunity_vote_tab_nav('rank_options') %>
+ <h4 class="mtl mbl">Drag the selected options into order of importance:</h4>
+
+ <ol class="opportunities-ol">
+ <% @vote_response_presenter.selected_survey_options.each_with_index do |option,index| %>
+ <% index+=1 %>
+ <li class="opportunities-outline">
+ <%= hidden_field_tag "survey_response_presenter[selected_option_#{index}_id]", option.survey_option.id, :class => 'selected_option' %>
+ <h4><%= option.survey_option.title %></h4>
+ <p><%= sanitize option.survey_option.description %></p>
+ </li>
+ <% end %>
+ </ol>
+
+ <fieldset>
+ <%= form.submit 'Cast my Vote', :class => "continue button opportunity-button" %> or
+ <%= link_to 'Cancel', conversation_actions_path(@conversation), :id => 'cancel-contribution' %>
+ </fieldset>
+
+<% end %>
+
@@ -0,0 +1,31 @@
+<%= form_for @vote_response_presenter, :as => :vote_response_presenter, :url => select_options_conversation_vote_path(@conversation,@vote) do |form|%>
+ <%= opportunity_vote_tab_nav('select_options') %>
+
+ <h4 class="mtl mbl">Please select up to <%= pluralize(@vote_response_presenter.max_selected_options,'option') %></h4>
+
+ <% if @vote_response_presenter.errors[:selected_option_ids].present? %>
+ <div class="alert alert-error mbl">
+ <h4>
+ <%= @vote_response_presenter.errors[:selected_option_ids].first.to_s %>
+ </h4>
+
+ </div>
+ <% end %>
+
+ <% @vote_response_presenter.options_sorted.each do |option| %>
+ <div class="media mbl inset">
+ <!-- <input class="tab-checkbox img" type="checkbox" name="vehicle" value="#" /> -->
+ <%= check_box_tag 'vote_response_presenter[selected_option_ids][]', option.id, @vote_response_presenter.selected_option_ids.include?(option.id), :class => 'tab-checkbox img' %>
+ <div class="bd">
+ <h4><%= option.title %></h4>
+ <%= sanitize option.description %>
+ </div>
+ </div>
+ <% end %>
+
+ <fieldset>
+ <%= form.submit 'Continue', :class => "continue button opportunity-button" %> or
+ <%= link_to 'Cancel', conversation_actions_path(@conversation), :id => 'cancel-contribution' %>
+ </fieldset>
+
+<% end %>
@@ -0,0 +1,26 @@
+<div class="wrapper">
+ <div class="content-container">
+
+ <div class="main-content">
+ <h2 class="mtn"><%= @vote.title %></h2>
+ <p><strong>By: <%= text_profile(@vote.person) %> on <%= @vote.created_at.to_date.to_s(:long) %></p>
+ <%= sanitize @vote.description %>
+
+ <%= yield %>
+
+ </div><!-- /.main-content -->
+
+ <div class='aside supplementary'>
+ <div class="recent-item">
+ <div class="offset-2 ">
+ <%= member_profile(@vote.person) %>
+ <p><strong><%= text_profile(@vote.person) %></strong><br />
+ <%= link_to 'View Profile', user_path(@vote.person) %>
+ </div>
+ </div>
+ </div><!-- /.aside -->
+
+
+ </div>
+</div>
+
@@ -0,0 +1 @@
+<p>Vote Result</p>
@@ -0,0 +1,8 @@
+<ul class="tab tab-section mtl mbl">
+ <li class="<%= 'active' if step == 'select_options' %>">
+ <%= link_to raw('<strong>Step 1:</strong> Select Options'), select_options_link %>
+ </li>
+ <li class="<%= 'active' if step == 'rank_options' %>">
+ <%= link_to_function raw('<strong>Step 2:</strong> Rank Options'), (step == 'rank_options') ? 'return false;' : "$(this).closest('form').submit();return false;" %>
+ </li>
+</ul>
@@ -0,0 +1,5 @@
+<% render :layout => 'vote_layout' do %>
+
+ <%= render :partial => "opportunity_votes/rank_options_form" %>
+
+<% end %>
@@ -1,47 +1,14 @@
-<div class="wrapper">
- <div class="content-container">
-
- <div class="main-content">
- <h2 class="mtn"><%= @vote.title %></h2>
- <p><strong>By: <%= text_profile(@vote.person) %> on <%= @vote.created_at.to_date.to_s(:long) %></p>
-
- <%= sanitize @vote.description %>
- <ul class="tab tab-section mtl mbl">
- <li class="active">
- <a href="#"><strong>Step 1:</strong> Select Options</a>
- </li>
- <li><a href="vote_permalink_step_2"><strong>Step 2:</strong> Rank Options</a></li>
- </ul>
- <form>
- <% @vote.options.each do |option| %>
- <div class="media mbl inset">
- <input class="tab-checkbox img" type="checkbox" name="vehicle" value="#" />
- <div class="bd">
- <h4><%= option.title %></h4>
- <%= sanitize option.description %>
- </div>
- </div>
- <% end %>
-
- <fieldset>
- <input class="continue" id="contribution_submit" name="Continue" type="continue" value="Continue" /> &nbsp; or
- <a href="#" id="cancel-contribution">Cancel</a>
- </fieldset>
- </form>
-
- </div><!-- /.main-content -->
-
- <div class='aside supplementary'>
- <div class="recent-item">
- <div class="offset-2 ">
- <%= member_profile(@vote.person) %>
- <p><strong><%= text_profile(@vote.person) %></strong><br />
- <%= link_to 'View Profile', user_path(@vote.person) %>
- </div>
- </div>
- </div><!-- /.aside -->
-
-
- </div>
-</div>
-
+<% render :layout => 'vote_layout' do %>
+
+ <% if @vote_response_presenter.allowed? %>
+ <%= render :partial => "opportunity_votes/select_options_form" %>
+ <% else %>
+ <% if @vote.show_progress? %>
+ <% @vote_progress_service = VoteProgressService.new(@survey) %>
+ <%= render :partial =>"opportunity_votes/vote_result" %>
+ <% else %>
+ <%= render :partial => "opportunity_votes/vote_hidden_result" %>
+ <% end %>
+ <% end %>
+
+<% end %>
View
@@ -156,7 +156,13 @@
get :print, :to => 'petitions#print', :on => :member
end
resources :actions, :only => [:index]
- resources :votes, controller: :opportunity_votes
+ resources :votes, controller: :opportunity_votes do
+ post :create_response, :on => :member
+ get :select_options, :on => :member
+ post :create_select_options, :on => :member, :path => 'select_options'
+ get :rank_options, :on => :member
+ post :create_rank_options, :on => :member, :path => 'rank_options'
+ end
end
# Created by Jonathan Penn (February 17, 2012)
@@ -0,0 +1,13 @@
+var reset_selected_option_positions = function(){
+ $('input.selected_option').each(function(i){
+ var index = i + 1
+ $(this).attr('name', 'survey_response_presenter[selected_option_'+ index +'_id]');
+ $(this).attr('id', 'survey_response_presenter_selected_option_'+ index +'_id');
+ })
+}
+$(document).ready(function() {
+ $('.opportunities-ol').sortable({
+ update: reset_selected_option_positions
+ });
+})
+
@@ -3154,6 +3154,9 @@ input.textbox.input-short {
/* max-width:588px;*/
max-width:100%;
}
+.button.opportunity-button{
+ width:143px;
+}
/*- SELF CLEARING FLOATS
----------------------------------------------------------------------*/
Oops, something went wrong.

0 comments on commit 98bac1b

Please sign in to comment.