effective_polls 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +2 -2
  4. data/Rakefile +5 -19
  5. data/app/controllers/admin/polls_controller.rb +1 -7
  6. data/app/controllers/effective/ballots_controller.rb +4 -1
  7. data/app/datatables/admin/effective_poll_notifications_datatable.rb +4 -1
  8. data/app/datatables/admin/effective_poll_results_datatable.rb +1 -4
  9. data/app/datatables/admin/effective_polls_datatable.rb +1 -0
  10. data/app/datatables/{effective_polls_datatable.rb → effective_polls_available_polls_datatable.rb} +6 -4
  11. data/app/helpers/effective_polls_helper.rb +17 -13
  12. data/app/mailers/effective/polls_mailer.rb +3 -1
  13. data/app/models/concerns/effective_polls_user.rb +67 -0
  14. data/app/models/effective/ballot.rb +11 -2
  15. data/app/models/effective/ballot_response.rb +1 -1
  16. data/app/models/effective/poll.rb +39 -26
  17. data/app/models/effective/poll_notification.rb +2 -2
  18. data/app/models/effective/poll_question.rb +1 -1
  19. data/app/models/effective/poll_question_option.rb +1 -1
  20. data/app/views/admin/poll_notifications/_form.html.haml +3 -5
  21. data/app/views/admin/poll_questions/_form.html.haml +12 -5
  22. data/app/views/admin/polls/_form.html.haml +10 -5
  23. data/app/views/admin/polls/_form_content.html.haml +16 -20
  24. data/app/views/admin/polls/_form_poll.html.haml +16 -7
  25. data/app/views/admin/polls/_poll.html.haml +5 -0
  26. data/app/views/effective/ballots/_content.html.haml +10 -0
  27. data/app/views/effective/ballots/_layout.html.haml +3 -0
  28. data/app/views/effective/ballots/complete.html.haml +13 -8
  29. data/app/views/effective/ballots/start.html.haml +29 -12
  30. data/app/views/effective/ballots/submit.html.haml +10 -13
  31. data/app/views/effective/ballots/vote.html.haml +10 -15
  32. data/app/views/effective/poll_results/_results.html.haml +2 -2
  33. data/app/views/effective/polls/_dashboard.html.haml +25 -0
  34. data/app/views/effective/polls_mailer/poll_before_poll_ends.liquid +0 -1
  35. data/app/views/effective/polls_mailer/poll_reminder.liquid +0 -1
  36. data/app/views/effective/polls_mailer/poll_upcoming_reminder.liquid +0 -1
  37. data/app/views/effective/polls_mailer/poll_when_poll_ends.liquid +0 -1
  38. data/app/views/effective/polls_mailer/poll_when_poll_starts.liquid +0 -1
  39. data/config/effective_polls.rb +2 -19
  40. data/config/locales/effective_polls.yml +14 -0
  41. data/config/routes.rb +2 -5
  42. data/db/migrate/{01_create_effective_polls.rb.erb → 101_create_effective_polls.rb} +19 -17
  43. data/db/seeds.rb +36 -0
  44. data/lib/effective_polls/engine.rb +7 -0
  45. data/lib/effective_polls/version.rb +1 -1
  46. data/lib/effective_polls.rb +2 -4
  47. data/lib/generators/effective_polls/install_generator.rb +1 -9
  48. data/lib/tasks/effective_polls_tasks.rake +23 -12
  49. metadata +144 -12
  50. data/app/views/admin/polls/results.html.haml +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57df19aaa933dd133ba655525265e129ca1c2bd7a60a78a5a8f2fe89ec1aa5cc
4
- data.tar.gz: 86fe4a6defeef051e4ff9c8543480fd6db703e213d80cf100781f4c71cc60e4b
3
+ metadata.gz: 637320f25a72489ada773806629e70590bb5c8435e871a6de40497e2eb6300ed
4
+ data.tar.gz: e797d1afdad6be66099b291ec7a809cbb65ef32d7963ca04f03d3ac3d91fe2a9
5
5
  SHA512:
6
- metadata.gz: 1b6f6ace193a55d55b49184f8a2b9a1a0766b0e1249c5c3daa65bfac034a7bb7b8ae1920b66ed04d1605137a88798d749951f0f714e2289774f63dfc5d820ca4
7
- data.tar.gz: e0b94cefd83a9af17f232cedc37369615ed0042543b886a496174fd807a3117cab3a876bcb6eb34d61f2ca50a70ede2c2c92d965df67d4b0619dc9a3fd05f052
6
+ metadata.gz: 7317013d4063bdd11eaf4a72b6d5ca964c7acb2c35ac29653e9c7043c4e4c40de4e1b4b55079ed023b758f08982a51ca17926e37c5abafbca2462cf0b4a9e657
7
+ data.tar.gz: d3fe9a3b04a9ca98c5a27fa956fb82d536db6b9662b6d61a0e8fd954f603673384f6d70c3ec33e51fabde548063b126892508e858be72e616d2c9ff30318e732
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2021 Code and Effect Inc.
1
+ Copyright 2023 Code and Effect Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -10,7 +10,7 @@ Works with action_text for content bodies, and active_storage for file uploads.
10
10
 
11
11
  ## Getting Started
12
12
 
13
- This requires Rails 6+ and Twitter Bootstrap 4 and just works with Devise.
13
+ This requires Rails 6 and Twitter Bootstrap 4 and just works with Devise.
14
14
 
15
15
  Please first install the [effective_datatables](https://github.com/code-and-effect/effective_datatables) gem.
16
16
 
@@ -19,7 +19,7 @@ Please download and install the [Twitter Bootstrap4](http://getbootstrap.com)
19
19
  Add to your Gemfile:
20
20
 
21
21
  ```ruby
22
- gem 'haml-rails' # or try using gem 'hamlit-rails'
22
+ gem 'haml'
23
23
  gem 'effective_polls'
24
24
  ```
25
25
 
data/Rakefile CHANGED
@@ -1,27 +1,13 @@
1
- begin
2
- require 'bundler/setup'
3
- rescue LoadError
4
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
- end
6
-
7
- require 'rdoc/task'
8
-
9
- RDoc::Task.new(:rdoc) do |rdoc|
10
- rdoc.rdoc_dir = 'rdoc'
11
- rdoc.title = 'EffectivePolls'
12
- rdoc.options << '--line-numbers'
13
- rdoc.rdoc_files.include('README.md')
14
- rdoc.rdoc_files.include('lib/**/*.rb')
15
- end
1
+ require "bundler/setup"
16
2
 
17
3
  APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
- load 'rails/tasks/engine.rake'
4
+ load "rails/tasks/engine.rake"
19
5
 
20
- load 'rails/tasks/statistics.rake'
6
+ load "rails/tasks/statistics.rake"
21
7
 
22
- require 'bundler/gem_tasks'
8
+ require "bundler/gem_tasks"
23
9
 
24
- require 'rake/testtask'
10
+ require "rake/testtask"
25
11
 
26
12
  Rake::TestTask.new(:test) do |t|
27
13
  t.libs << 'test'
@@ -5,13 +5,7 @@ module Admin
5
5
 
6
6
  include Effective::CrudController
7
7
 
8
- def results
9
- @poll = Effective::Poll.find(params[:id])
10
- EffectiveResources.authorize!(self, :results, @poll)
11
-
12
- @datatable = Admin::EffectivePollResultsDatatable.new(poll_token: @poll.token)
13
- @page_title = "#{@poll} Results"
14
- end
8
+ on :save, only: :create, redirect: :edit
15
9
 
16
10
  def permitted_params
17
11
  params.require(:effective_poll).permit!
@@ -1,6 +1,9 @@
1
1
  module Effective
2
2
  class BallotsController < ApplicationController
3
- before_action(:authenticate_user!) if defined?(Devise)
3
+
4
+ if defined?(Devise)
5
+ before_action :authenticate_user!, unless: -> { action_name == 'new' || (action_name == 'show' && params[:id] == 'start') }
6
+ end
4
7
 
5
8
  include Effective::WizardController
6
9
 
@@ -31,7 +31,10 @@ class Admin::EffectivePollNotificationsDatatable < Effective::Datatable
31
31
  end
32
32
 
33
33
  col :subject
34
- col :body
34
+
35
+ col :body do |notification|
36
+ simple_format(notification.body.to_s)
37
+ end
35
38
 
36
39
  col :started_at, visible: false
37
40
  col :completed_at
@@ -41,10 +41,7 @@ class Admin::EffectivePollResultsDatatable < Effective::Datatable
41
41
  end
42
42
 
43
43
  def poll
44
- @poll ||= begin
45
- raise('expected datatable poll_token attribute') unless attributes[:poll_token]
46
- Effective::Poll.deep_results.find(attributes[:poll_token])
47
- end
44
+ @poll ||= Effective::Poll.deep_results.where(id: attributes[:poll_id]).first!
48
45
  end
49
46
 
50
47
  end
@@ -18,6 +18,7 @@ class Admin::EffectivePollsDatatable < Effective::Datatable
18
18
  col :end_at
19
19
  col :audience
20
20
 
21
+ col :poll_notifications
21
22
  col :poll_questions, visible: false
22
23
 
23
24
  actions_col
@@ -1,13 +1,14 @@
1
+ # Dashboard available polls
1
2
  # Displays available polls that the current_user may complete
2
3
 
3
- class EffectivePollsDatatable < Effective::Datatable
4
+ class EffectivePollsAvailablePollsDatatable < Effective::Datatable
4
5
  datatable do
5
6
  order :start_at
6
7
 
7
8
  col :start_at, visible: false
8
9
 
9
10
  col :title
10
- col :available_date, label: 'Date'
11
+ col :available_date
11
12
 
12
13
  actions_col(actions: []) do |poll|
13
14
  ballot = poll.ballots.where(user: current_user).first
@@ -15,16 +16,17 @@ class EffectivePollsDatatable < Effective::Datatable
15
16
  if ballot.blank?
16
17
  dropdown_link_to('Start', effective_polls.poll_ballot_build_path(poll, :new, :start))
17
18
  elsif ballot.completed?
19
+ #dropdown_link_to('Show', effective_polls.poll_ballot_path(poll, ballot))
18
20
  'Complete'
19
21
  else
20
22
  dropdown_link_to('Continue', effective_polls.poll_ballot_build_path(poll, ballot, ballot.next_step))
23
+ dropdown_link_to('Delete', effective_polls.poll_ballot_path(poll, ballot), 'data-confirm': "Really delete #{ballot}?", 'data-method': :delete)
21
24
  end
22
25
  end
23
26
  end
24
27
 
25
28
  collection do
26
- raise('expected a current_user') unless current_user.present?
27
- Effective::Poll.available.select { |poll| poll.available_for?(current_user) }
29
+ Effective::Poll.where(id: current_user.available_polls)
28
30
  end
29
31
 
30
32
  end
@@ -1,22 +1,26 @@
1
1
  module EffectivePollsHelper
2
2
 
3
+ # Used on dashboard
4
+ def polls_name_label
5
+ et('effective_polls.name')
6
+ end
7
+
3
8
  # Used by admin/polls form
4
- def effective_polls_audience_scope_collection
5
- # Normalize the collection into [[label, value], [label, value]]
6
- scopes = Array(EffectivePolls.audience_user_scopes).map do |key, value|
7
- (key.present? && value.present?) ? [key, value] : [key.to_s.titleize, key]
8
- end
9
+ def effective_polls_audience_scope_collection(poll)
10
+ klass = poll.try(:audience_class)
11
+ raise('expected a poll with an audience_class') unless klass.try(:effective_polls_user?)
9
12
 
10
- # Makes sure the User model responds to all values
11
- scopes.each do |_, scope|
12
- unless defined?(User) && User.respond_to?(scope)
13
- raise("invalid effective_polls config.audience_user_scopes value. The user model must respond to the scope User.#{scope}")
14
- end
15
- end
13
+ resource = klass.new
14
+
15
+ scopes = resource.poll_audience_scopes
16
+ raise('expected poll audience scopes') unless scopes.kind_of?(Array)
16
17
 
17
18
  # Append the number of users in this scope
18
- scopes.map! do |label, scope|
19
- ["#{label} (#{pluralize(User.send(scope).count, 'user')})", scope]
19
+ scopes.map do |label, scope|
20
+ relation = resource.poll_audience_scope(scope)
21
+ raise("invalid poll_audience_scope for #{scope}") unless relation.kind_of?(ActiveRecord::Relation)
22
+
23
+ ["#{label} (#{pluralize(relation.count, 'user')})", scope]
20
24
  end
21
25
  end
22
26
 
@@ -75,7 +75,9 @@ module Effective
75
75
  title: poll.title,
76
76
  url: effective_polls.poll_url(poll),
77
77
  user: {
78
- name: user.to_s,
78
+ name: (user.try(:email_to_s) || user.to_s),
79
+ first_name: user.try(:first_name).to_s,
80
+ last_name: user.try(:last_name).to_s,
79
81
  email: user.email
80
82
  }
81
83
  }
@@ -0,0 +1,67 @@
1
+ # EffectivePollsUser
2
+ #
3
+ # Mark your user model with effective_polls_user to get all the includes
4
+
5
+ module EffectivePollsUser
6
+ extend ActiveSupport::Concern
7
+
8
+ module Base
9
+ def effective_polls_user
10
+ include ::EffectivePollsUser
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def effective_polls_user?; true; end
16
+ end
17
+
18
+ included do
19
+ has_many :ballots, -> { Effective::Ballot.sorted }, inverse_of: :user, as: :user, class_name: 'Effective::Ballot'
20
+ end
21
+
22
+ # The list of all available audience scopes for the Poll Selected Users
23
+ def poll_audience_scopes
24
+ scopes = [
25
+ ['All Users', :all]
26
+ ]
27
+
28
+ if self.class.try(:effective_memberships_user?)
29
+ scopes += [
30
+ ['All members', :members],
31
+ ['All removed members', :membership_removed],
32
+ ['All members in good standing', :membership_in_good_standing],
33
+ ['All members not in good standing', :membership_not_in_good_standing],
34
+ ['All members renewed this period', :membership_renewed_this_period],
35
+ ]
36
+
37
+ scopes += EffectiveMemberships.Category.sorted.map do |category|
38
+ ["All #{category} members", "members_with_category_id_#{category.id}"]
39
+ end
40
+ end
41
+
42
+ scopes
43
+ end
44
+
45
+ # Turns the given audience_scope value into the actual ActiveRecord::Relation scope
46
+ def poll_audience_scope(value)
47
+ collection = self.class.respond_to?(:unarchived) ? self.class.unarchived : self.class
48
+
49
+ # If we respond to the fill value, call it
50
+ return collection.send(value) if collection.respond_to?(value)
51
+
52
+ # Parse the value
53
+ name, id = value.to_s.split('_id_')
54
+
55
+ case name.try(:to_sym)
56
+ when :members_with_category
57
+ collection.members_with_category(EffectiveMemberships.Category.find(id))
58
+ else
59
+ raise("unknown poll_audience_scope for #{value}")
60
+ end
61
+ end
62
+
63
+ def available_polls
64
+ Effective::Poll.available.select { |poll| poll.available_for?(self) }
65
+ end
66
+
67
+ end
@@ -3,14 +3,19 @@ module Effective
3
3
  attr_accessor :current_user
4
4
  attr_accessor :current_step
5
5
 
6
+ # Application namespace
7
+ belongs_to :user, polymorphic: true
8
+
9
+ # Effective namespace
6
10
  belongs_to :poll
7
- belongs_to :user
8
11
 
9
12
  has_many :ballot_responses, dependent: :destroy
10
13
  accepts_nested_attributes_for :ballot_responses
11
14
 
12
15
  acts_as_tokened
13
16
 
17
+ log_changes(to: :poll) if respond_to?(:log_changes)
18
+
14
19
  acts_as_wizard(
15
20
  start: 'Start',
16
21
  vote: 'Ballot',
@@ -34,6 +39,10 @@ module Effective
34
39
 
35
40
  scope :deep, -> { includes(:poll, :user, ballot_responses: [:poll, :poll_question, :poll_question_options]) }
36
41
  scope :sorted, -> { order(:id) }
42
+
43
+ scope :in_progress, -> { where(completed_at: nil) }
44
+ scope :done, -> { where.not(completed_at: nil) }
45
+
37
46
  scope :completed, -> { where.not(completed_at: nil) }
38
47
 
39
48
  before_validation(if: -> { new_record? }) do
@@ -48,7 +57,7 @@ module Effective
48
57
  validates :ballot_responses, associated: true
49
58
 
50
59
  def to_s
51
- 'ballot'
60
+ model_name.human
52
61
  end
53
62
 
54
63
  # Find or build
@@ -64,7 +64,7 @@ module Effective
64
64
  length: { maximum: 5, message: 'please select 5 options or fewer' }
65
65
 
66
66
  def to_s
67
- 'ballot reponse'
67
+ model_name.human
68
68
  end
69
69
 
70
70
  def response
@@ -1,10 +1,6 @@
1
1
  module Effective
2
2
  class Poll < ActiveRecord::Base
3
- has_rich_text :all_steps_content
4
- has_rich_text :start_content
5
- has_rich_text :vote_content
6
- has_rich_text :submit_content
7
- has_rich_text :complete_content
3
+ acts_as_tokened
8
4
 
9
5
  has_many :poll_notifications, -> { order(:id) }, inverse_of: :poll, dependent: :destroy
10
6
  accepts_nested_attributes_for :poll_notifications, allow_destroy: true
@@ -19,7 +15,12 @@ module Effective
19
15
  has_many :completed_ballots, -> { Effective::Ballot.completed }, class_name: 'Effective::Ballot'
20
16
  has_many :completed_ballot_responses, -> { where(ballot: Effective::Ballot.completed) }, class_name: 'Effective::BallotResponse'
21
17
 
22
- acts_as_tokened
18
+ has_many_rich_texts
19
+ # rich_text_all_steps_content
20
+ # rich_text_start_content
21
+ # rich_text_vote_content
22
+ # rich_text_submit_content
23
+ # rich_text_complete_content
23
24
 
24
25
  if respond_to?(:log_changes)
25
26
  log_changes(except: [:ballots, :ballot_responses, :completed_ballots, :completed_ballot_responses])
@@ -29,29 +30,23 @@ module Effective
29
30
 
30
31
  effective_resource do
31
32
  # Acts as tokened
32
- token :string, permitted: false
33
+ token :string, permitted: false
33
34
 
34
35
  title :string
35
36
 
36
37
  start_at :datetime
37
38
  end_at :datetime
38
39
 
39
- audience :string
40
- audience_scope :text # An Array of user_ids or named scopes on the User model
40
+ audience :string
41
+ audience_class_name :string
42
+ audience_scope :text # An Array of user_ids or named scopes on the User model
41
43
 
42
44
  timestamps
43
45
  end
44
46
 
45
47
  serialize :audience_scope, Array
46
48
 
47
- scope :deep, -> {
48
- includes(poll_questions: :poll_question_options)
49
- .with_rich_text_all_steps_content
50
- .with_rich_text_start_content
51
- .with_rich_text_vote_content
52
- .with_rich_text_submit_content
53
- .with_rich_text_complete_content
54
- }
49
+ scope :deep, -> { includes(poll_questions: :poll_question_options) }
55
50
 
56
51
  scope :deep_results, -> {
57
52
  includes(poll_questions: :poll_question_options)
@@ -68,6 +63,8 @@ module Effective
68
63
  validates :start_at, presence: true
69
64
 
70
65
  validates :audience, inclusion: { in: AUDIENCES }
66
+ validates :audience_class_name, presence: true
67
+
71
68
  validates :audience_scope, presence: true, unless: -> { audience == 'All Users' }
72
69
 
73
70
  validate(if: -> { start_at.present? && end_at.present? }) do
@@ -75,33 +72,49 @@ module Effective
75
72
  end
76
73
 
77
74
  def to_s
78
- title.presence || 'New Poll'
75
+ title.presence || model_name.human
79
76
  end
80
77
 
81
78
  def available_for?(user)
82
- raise('expected a user') unless user.kind_of?(User)
79
+ raise('expected an effective_polls_user') unless user.class.try(:effective_polls_user?)
83
80
  available? && users.include?(user)
84
81
  end
85
82
 
83
+ def audience_class
84
+ klass = audience_class_name.safe_constantize
85
+ raise('expected an effective_polls_user klass') unless klass.try(:effective_polls_user?)
86
+ klass
87
+ end
88
+
86
89
  def users(except_completed: false)
90
+ klass = audience_class()
91
+ resource = klass.new
92
+
87
93
  users = case audience
88
94
  when 'All Users'
89
- User.all
95
+ klass.try(:unarchived) || klass.all
90
96
  when 'Individual Users'
91
- User.where(id: audience_scope)
97
+ (klass.try(:unarchived) || klass.all).where(id: audience_scope)
92
98
  when 'Selected Users'
93
- collection = User.none
94
- audience_scope.each { |scope| collection = collection.or(User.send(scope)) }
99
+ collection = klass.none
100
+
101
+ audience_scope.each do |scope|
102
+ relation = resource.poll_audience_scope(scope)
103
+ raise("invalid poll_audience_scope for #{scope}") unless relation.kind_of?(ActiveRecord::Relation)
104
+
105
+ collection = collection.or(relation)
106
+ end
107
+
95
108
  collection
96
109
  else
97
110
  raise('unexpected audience')
98
111
  end
99
112
 
100
113
  if except_completed
101
- users.where.not(id: completed_ballots.select('user_id as id'))
102
- else
103
- users
114
+ users = users.where.not(id: completed_ballots.select('user_id as id'))
104
115
  end
116
+
117
+ users
105
118
  end
106
119
 
107
120
  def available?
@@ -72,7 +72,7 @@ module Effective
72
72
  validates :subject, presence: true
73
73
  validates :body, presence: true
74
74
 
75
- if EffectivePolls.use_effective_email_templates
75
+ with_options(if: -> { EffectivePolls.use_effective_email_templates }) do
76
76
  validates :body, liquid: true
77
77
  validates :subject, liquid: true
78
78
  end
@@ -81,7 +81,7 @@ module Effective
81
81
  presence: true, uniqueness: { scope: [:poll_id, :category], message: 'already exists' }
82
82
 
83
83
  def to_s
84
- 'poll notification'
84
+ [category.presence, subject.presence].compact.join(' - ') || model_name.human
85
85
  end
86
86
 
87
87
  def email_template
@@ -62,7 +62,7 @@ module Effective
62
62
  end
63
63
 
64
64
  def to_s
65
- title.presence || 'New Poll Question'
65
+ title.presence || model_name.human
66
66
  end
67
67
 
68
68
  def poll_question_option?
@@ -19,7 +19,7 @@ module Effective
19
19
  validates :position, presence: true
20
20
 
21
21
  def to_s
22
- title.presence || 'New Poll Question Option'
22
+ title.presence || model_name.human
23
23
  end
24
24
 
25
25
  end
@@ -12,22 +12,20 @@
12
12
  - template = 'poll_' + category.parameterize.underscore
13
13
 
14
14
  = f.show_if :category, category do
15
- = render "/admin/poll_notifications/form_#{template}", f: f
15
+ .my-3= render "/admin/poll_notifications/form_#{template}", f: f
16
+
17
+ = f.select :from, EffectivePolls.mailer_froms
16
18
 
17
19
  - if f.object.category == category
18
- = f.email_field :from
19
20
  = f.text_field :subject
20
21
  = f.text_area :body, rows: 10
21
22
 
22
23
  - elsif EffectivePolls.use_effective_email_templates == false
23
- = f.email_field :from, value: EffectivePolls.mailer[:default_from]
24
24
  = f.text_field :subject, value: ''
25
25
  = f.text_area :body, rows: 10, value: ''
26
26
 
27
27
  - else
28
28
  - email_template = Effective::EmailTemplate.where(template_name: template).first!
29
-
30
- = f.email_field :from, value: email_template.from
31
29
  = f.text_field :subject, value: email_template.subject
32
30
  = f.text_area :body, rows: 10, value: email_template.body
33
31
 
@@ -2,19 +2,26 @@
2
2
  - if inline_datatable?
3
3
  = f.hidden_field :poll_id
4
4
  - else
5
- = f.select :poll_id, Effective::Poll.sorted.editable.all
5
+ = f.select :poll_id, Effective::Poll.all
6
6
 
7
7
  = f.text_field :title, label: 'Question Title'
8
- = f.rich_text_area :body, label: 'Body (optional)'
8
+
9
+ - if defined?(EffectiveArticleEditor)
10
+ = f.article_editor :body, label: 'Body (optional)'
11
+ - else
12
+ = f.rich_text_area :body, label: 'Body (optional)'
9
13
 
10
14
  = f.check_box :required, hint: 'A response to this question will be required'
11
15
  = f.select :category, Effective::PollQuestion::CATEGORIES
12
16
 
13
17
  = f.show_if :category, 'Choose one' do
14
- .card
18
+ .mt-3.card
15
19
  .card-body
16
- %h5 Choose one
17
- %p Display radio buttons to choose one option
20
+ %h5 Options
21
+ %p Display the following options:
22
+
23
+ = f.has_many :poll_question_options, build: true do |fa|
24
+ = fa.text_field :title, label: false
18
25
 
19
26
  = f.show_if :category, 'Select all that apply' do
20
27
  .card
@@ -7,18 +7,23 @@
7
7
  = render 'admin/polls/form_content', poll: poll
8
8
 
9
9
  = tab 'Questions' do
10
- - datatable = Admin::EffectivePollQuestionsDatatable.new(poll_id: poll.id)
10
+ - datatable = Admin::EffectivePollQuestionsDatatable.new(poll: poll)
11
11
  = render_datatable(datatable, inline: true, simple: true)
12
12
 
13
13
  = tab 'Notifications' do
14
14
  %p
15
15
  The following email notifications will be sent to
16
- = pluralize(poll.users.count, 'users')
16
+ = pluralize(poll.users.count, 'user')
17
17
  in the audience.
18
18
 
19
- - datatable = Admin::EffectivePollNotificationsDatatable.new(poll_id: poll.id)
19
+ %p
20
+ The url for this #{et(poll)} is:
21
+ - url = effective_polls.poll_url(poll)
22
+ = link_to(url, url, target: '_blank')
23
+
24
+ - datatable = Admin::EffectivePollNotificationsDatatable.new(poll: poll)
20
25
  = render_datatable(datatable, inline: true, simple: true)
21
26
 
22
- - if poll.respond_to?(:log_changes_datatable)
27
+ - if poll.respond_to?(:logs_datatable)
23
28
  = tab 'Logs' do
24
- = render_datatable(poll.log_changes_datatable)
29
+ = render_datatable(poll.logs_datatable)
@@ -1,27 +1,23 @@
1
+ %p Each of the following content areas will be displayed on the ballot wizard.
2
+
1
3
  = effective_form_with(model: [:admin, poll], engine: true) do |f|
2
- .card.mb-4
3
- .card-body
4
- %h5.card-title All Steps Content
5
- = f.rich_text_area :all_steps_content, label: false, hint: 'displayed on all ballot steps'
4
+ = card("All Steps") do
5
+ - if defined?(EffectiveArticleEditor)
6
+ = f.article_editor "rich_text_all_steps_content", label: false, hint: "displayed on all steps"
7
+ - else
8
+ = f.rich_text_area "rich_text_all_steps_content", label: false, hint: "displayed on all steps"
6
9
 
7
- .card.mb-4
8
- .card-body
9
- %h5.card-title Start Step
10
- = f.rich_text_area :start_content, label: false, hint: 'displayed on the start step only'
10
+ %hr
11
11
 
12
- .card.mb-4
13
- .card-body
14
- %h5.card-title Vote Step
15
- = f.rich_text_area :vote_content, label: false, hint: 'displayed on the vote step only'
12
+ - enabled = Effective::Ballot.all_wizard_steps
16
13
 
17
- .card.mb-4
18
- .card-body
19
- %h5.card-title Review and Submit Step
20
- = f.rich_text_area :submit_content, label: false, hint: 'displayed on the review and submit step only'
14
+ - Effective::Ballot::WIZARD_STEPS.each do |step, title|
15
+ - next unless enabled.include?(step)
21
16
 
22
- .card.mb-4
23
- .card-body
24
- %h5.card-title Complete Step
25
- = f.rich_text_area :complete_content, label: false, hint: 'displayed on the complete step only'
17
+ = card("#{title}") do
18
+ - if defined?(EffectiveArticleEditor)
19
+ = f.article_editor "rich_text_#{step}_content", label: false, hint: "displayed on the ballot #{step} wizard step only"
20
+ - else
21
+ = f.rich_text_area "rich_text_#{step}_content", label: false, hint: "displayed on the ballot #{step} wizard step only"
26
22
 
27
23
  = f.submit