effective_polls 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +132 -0
- data/Rakefile +32 -0
- data/app/assets/config/effective_polls_manifest.js +1 -0
- data/app/assets/stylesheets/effective_polls.scss +0 -0
- data/app/controllers/admin/poll_notifications_controller.rb +15 -0
- data/app/controllers/admin/poll_questions_controller.rb +15 -0
- data/app/controllers/admin/polls_controller.rb +23 -0
- data/app/controllers/effective/ballots_controller.rb +70 -0
- data/app/controllers/effective/polls_controller.rb +19 -0
- data/app/datatables/admin/effective_poll_notifications_datatable.rb +43 -0
- data/app/datatables/admin/effective_poll_questions_datatable.rb +28 -0
- data/app/datatables/admin/effective_poll_results_datatable.rb +50 -0
- data/app/datatables/admin/effective_polls_datatable.rb +29 -0
- data/app/datatables/effective_polls_datatable.rb +30 -0
- data/app/helpers/effective_polls_helper.rb +23 -0
- data/app/mailers/effective/polls_mailer.rb +23 -0
- data/app/models/effective/access_denied.rb +17 -0
- data/app/models/effective/ballot.rb +73 -0
- data/app/models/effective/ballot_response.rb +92 -0
- data/app/models/effective/ballot_response_option.rb +6 -0
- data/app/models/effective/poll.rb +149 -0
- data/app/models/effective/poll_notification.rb +144 -0
- data/app/models/effective/poll_question.rb +76 -0
- data/app/models/effective/poll_question_option.rb +26 -0
- data/app/views/admin/poll_notifications/_form.html.haml +55 -0
- data/app/views/admin/poll_questions/_form.html.haml +100 -0
- data/app/views/admin/polls/_form.html.haml +20 -0
- data/app/views/admin/polls/_form_content.html.haml +27 -0
- data/app/views/admin/polls/_form_poll.html.haml +32 -0
- data/app/views/admin/polls/_poll.html.haml +2 -0
- data/app/views/admin/polls/results.html.haml +6 -0
- data/app/views/effective/ballot_responses/_ballot_response.html.haml +2 -0
- data/app/views/effective/ballot_responses/_fields.html.haml +14 -0
- data/app/views/effective/ballot_responses/fields/_choose_one.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_date.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_email.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_long_answer.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_number.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_select_all_that_apply.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_select_upto_1.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_select_upto_2.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_select_upto_3.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_select_upto_4.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_select_upto_5.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_short_answer.html.haml +1 -0
- data/app/views/effective/ballot_responses/fields/_upload_file.html.haml +1 -0
- data/app/views/effective/ballot_responses/responses/_choose_one.html.haml +1 -0
- data/app/views/effective/ballot_responses/responses/_date.html.haml +1 -0
- data/app/views/effective/ballot_responses/responses/_email.html.haml +1 -0
- data/app/views/effective/ballot_responses/responses/_long_answer.html.haml +1 -0
- data/app/views/effective/ballot_responses/responses/_number.html.haml +1 -0
- data/app/views/effective/ballot_responses/responses/_select_all_that_apply.html.haml +5 -0
- data/app/views/effective/ballot_responses/responses/_select_upto_1.html.haml +1 -0
- data/app/views/effective/ballot_responses/responses/_select_upto_2.html.haml +5 -0
- data/app/views/effective/ballot_responses/responses/_select_upto_3.html.haml +5 -0
- data/app/views/effective/ballot_responses/responses/_select_upto_4.html.haml +5 -0
- data/app/views/effective/ballot_responses/responses/_select_upto_5.html.haml +5 -0
- data/app/views/effective/ballot_responses/responses/_short_answer.html.haml +1 -0
- data/app/views/effective/ballot_responses/responses/_upload_file.html.haml +4 -0
- data/app/views/effective/ballots/_ballot.html.haml +14 -0
- data/app/views/effective/ballots/complete.html.haml +11 -0
- data/app/views/effective/ballots/start.html.haml +17 -0
- data/app/views/effective/ballots/submit.html.haml +17 -0
- data/app/views/effective/ballots/vote.html.haml +19 -0
- data/app/views/effective/poll_results/_poll_result.html.haml +2 -0
- data/app/views/effective/poll_results/_results.html.haml +38 -0
- data/app/views/effective/poll_results/results/_choose_one.html.haml +2 -0
- data/app/views/effective/poll_results/results/_date.html.haml +14 -0
- data/app/views/effective/poll_results/results/_email.html.haml +14 -0
- data/app/views/effective/poll_results/results/_long_answer.html.haml +2 -0
- data/app/views/effective/poll_results/results/_number.html.haml +14 -0
- data/app/views/effective/poll_results/results/_poll_question_option.html.haml +17 -0
- data/app/views/effective/poll_results/results/_select_all_that_apply.html.haml +2 -0
- data/app/views/effective/poll_results/results/_select_upto_1.html.haml +2 -0
- data/app/views/effective/poll_results/results/_select_upto_2.html.haml +2 -0
- data/app/views/effective/poll_results/results/_select_upto_3.html.haml +2 -0
- data/app/views/effective/poll_results/results/_select_upto_4.html.haml +2 -0
- data/app/views/effective/poll_results/results/_select_upto_5.html.haml +2 -0
- data/app/views/effective/poll_results/results/_short_answer.html.haml +2 -0
- data/app/views/effective/poll_results/results/_upload_file.html.haml +3 -0
- data/app/views/effective/polls/_form.html.haml +10 -0
- data/app/views/effective/polls/_poll.html.haml +2 -0
- data/app/views/layouts/effective_polls_mailer_layout.html.haml +7 -0
- data/config/effective_polls.rb +59 -0
- data/config/routes.rb +23 -0
- data/db/migrate/01_create_effective_polls.rb.erb +92 -0
- data/lib/effective_polls.rb +50 -0
- data/lib/effective_polls/engine.rb +11 -0
- data/lib/effective_polls/version.rb +3 -0
- data/lib/generators/effective_polls/install_generator.rb +46 -0
- data/lib/generators/templates/effective_polls_mailer_preview.rb +35 -0
- data/lib/tasks/effective_polls_tasks.rake +24 -0
- metadata +276 -0
@@ -0,0 +1,144 @@
|
|
1
|
+
module Effective
|
2
|
+
class PollNotification < ActiveRecord::Base
|
3
|
+
belongs_to :poll
|
4
|
+
|
5
|
+
BATCHSIZE = (Rails.env.test? ? 3 : 250)
|
6
|
+
CATEGORIES = ['Upcoming reminder', 'When poll starts', 'Reminder', 'When poll ends']
|
7
|
+
|
8
|
+
UPCOMING_REMINDERS = {
|
9
|
+
'1 hour before' => 1.hours.to_i,
|
10
|
+
'3 hours before' => 3.hours.to_i,
|
11
|
+
'6 hours before' => 6.hours.to_i,
|
12
|
+
'12 hours before' => 12.hours.to_i,
|
13
|
+
'1 day before' => 1.days.to_i,
|
14
|
+
'2 days before' => 2.days.to_i,
|
15
|
+
'3 days before' => 3.days.to_i,
|
16
|
+
'4 days before' => 4.days.to_i,
|
17
|
+
'5 days before' => 5.days.to_i,
|
18
|
+
'6 days before' => 6.days.to_i,
|
19
|
+
'1 week before' => 1.weeks.to_i,
|
20
|
+
'2 weeks before' => 2.weeks.to_i,
|
21
|
+
'3 weeks before' => 3.weeks.to_i,
|
22
|
+
'1 month before' => 1.month.to_i
|
23
|
+
}
|
24
|
+
|
25
|
+
REMINDERS = {
|
26
|
+
'1 hour after' => 1.hours.to_i,
|
27
|
+
'3 hours after' => 3.hours.to_i,
|
28
|
+
'6 hours after' => 6.hours.to_i,
|
29
|
+
'12 hours after' => 12.hours.to_i,
|
30
|
+
'1 day after' => 1.days.to_i,
|
31
|
+
'2 days after' => 2.days.to_i,
|
32
|
+
'3 days after' => 3.days.to_i,
|
33
|
+
'4 days after' => 4.days.to_i,
|
34
|
+
'5 days after' => 5.days.to_i,
|
35
|
+
'6 days after' => 6.days.to_i,
|
36
|
+
'1 week after' => 1.weeks.to_i,
|
37
|
+
'2 weeks after' => 2.weeks.to_i,
|
38
|
+
'3 weeks after' => 3.weeks.to_i,
|
39
|
+
'1 month after' => 1.month.to_i
|
40
|
+
}
|
41
|
+
|
42
|
+
effective_resource do
|
43
|
+
category :string
|
44
|
+
reminder :integer # Number of seconds before poll.start_at
|
45
|
+
|
46
|
+
# Email
|
47
|
+
subject :string
|
48
|
+
body :text
|
49
|
+
|
50
|
+
# Tracking background jobs email send out
|
51
|
+
started_at :datetime
|
52
|
+
completed_at :datetime
|
53
|
+
|
54
|
+
timestamps
|
55
|
+
end
|
56
|
+
|
57
|
+
scope :sorted, -> { order(:id) }
|
58
|
+
scope :deep, -> { includes(:poll) }
|
59
|
+
|
60
|
+
scope :started, -> { where.not(started_at: nil) }
|
61
|
+
scope :completed, -> { where.not(completed_at: nil) }
|
62
|
+
|
63
|
+
# Called by the poll_notifier rake task
|
64
|
+
scope :notifiable, -> { where(started_at: nil, completed_at: nil) }
|
65
|
+
|
66
|
+
validates :poll, presence: true
|
67
|
+
validates :category, presence: true, inclusion: { in: CATEGORIES }
|
68
|
+
validates :subject, presence: true
|
69
|
+
validates :body, presence: true
|
70
|
+
|
71
|
+
validates :reminder, if: -> { reminder? || upcoming_reminder? },
|
72
|
+
presence: true, uniqueness: { scope: [:poll_id, :category], message: 'already exists' }
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
'poll notification'
|
76
|
+
end
|
77
|
+
|
78
|
+
def upcoming_reminder?
|
79
|
+
category == 'Upcoming reminder'
|
80
|
+
end
|
81
|
+
|
82
|
+
def poll_start?
|
83
|
+
category == 'When poll starts'
|
84
|
+
end
|
85
|
+
|
86
|
+
def reminder?
|
87
|
+
category == 'Reminder'
|
88
|
+
end
|
89
|
+
|
90
|
+
def poll_end?
|
91
|
+
category == 'When poll ends'
|
92
|
+
end
|
93
|
+
|
94
|
+
def notifiable?
|
95
|
+
started_at.blank? && completed_at.blank?
|
96
|
+
end
|
97
|
+
|
98
|
+
def notify_now?
|
99
|
+
return false unless notifiable?
|
100
|
+
|
101
|
+
case category
|
102
|
+
when 'When poll starts'
|
103
|
+
poll.available?
|
104
|
+
when 'When poll ends'
|
105
|
+
poll.ended?
|
106
|
+
when 'Upcoming reminder'
|
107
|
+
!poll.started? && poll.start_at < (Time.zone.now + reminder)
|
108
|
+
when 'Reminder'
|
109
|
+
!poll.ended? && poll.start_at < (Time.zone.now - reminder)
|
110
|
+
else
|
111
|
+
raise('unexpected category')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def notify!
|
116
|
+
return false unless notify_now?
|
117
|
+
|
118
|
+
# We send to all email addresses, except for the 'Reminder' that exclude completed users
|
119
|
+
emails = poll.emails(exclude_completed: (category == 'Reminder'))
|
120
|
+
|
121
|
+
update_column(:started_at, Time.zone.now)
|
122
|
+
|
123
|
+
emails.in_groups_of(BATCHSIZE, false).each do |emails|
|
124
|
+
mail = case category
|
125
|
+
when 'When poll starts'
|
126
|
+
Effective::PollsMailer.poll_start(self, emails)
|
127
|
+
when 'When poll ends'
|
128
|
+
Effective::PollsMailer.poll_end(self, emails)
|
129
|
+
when 'Upcoming reminder'
|
130
|
+
Effective::PollsMailer.poll_upcoming_reminder(self, emails)
|
131
|
+
when 'Reminder'
|
132
|
+
Effective::PollsMailer.poll_reminder(self, emails)
|
133
|
+
else
|
134
|
+
raise('unexpected category')
|
135
|
+
end
|
136
|
+
|
137
|
+
mail.deliver_now
|
138
|
+
end
|
139
|
+
|
140
|
+
update_column(:completed_at, Time.zone.now)
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Effective
|
2
|
+
class PollQuestion < ActiveRecord::Base
|
3
|
+
belongs_to :poll
|
4
|
+
|
5
|
+
has_many :poll_question_options, -> { order(:position) }, inverse_of: :poll_question, dependent: :delete_all
|
6
|
+
accepts_nested_attributes_for :poll_question_options, reject_if: :all_blank, allow_destroy: true
|
7
|
+
|
8
|
+
has_rich_text :body
|
9
|
+
|
10
|
+
CATEGORIES = [
|
11
|
+
'Choose one', # Radios
|
12
|
+
'Select all that apply', # Checks
|
13
|
+
'Select upto 1',
|
14
|
+
'Select upto 2',
|
15
|
+
'Select upto 3',
|
16
|
+
'Select upto 4',
|
17
|
+
'Select upto 5',
|
18
|
+
'Date', # Date Field
|
19
|
+
'Email', # Email Field
|
20
|
+
'Number', # Numeric Field
|
21
|
+
'Long Answer', # Text Area
|
22
|
+
'Short Answer', # Text Field
|
23
|
+
'Upload File' # File field
|
24
|
+
]
|
25
|
+
|
26
|
+
WITH_OPTIONS_CATEGORIES = [
|
27
|
+
'Choose one', # Radios
|
28
|
+
'Select all that apply', # Checks
|
29
|
+
'Select upto 1',
|
30
|
+
'Select upto 2',
|
31
|
+
'Select upto 3',
|
32
|
+
'Select upto 4',
|
33
|
+
'Select upto 5'
|
34
|
+
]
|
35
|
+
|
36
|
+
effective_resource do
|
37
|
+
title :string
|
38
|
+
category :string
|
39
|
+
required :boolean
|
40
|
+
|
41
|
+
position :integer
|
42
|
+
|
43
|
+
timestamps
|
44
|
+
end
|
45
|
+
|
46
|
+
before_validation(if: -> { poll.present? }) do
|
47
|
+
self.position ||= (poll.poll_questions.map { |obj| obj.position }.compact.max || -1) + 1
|
48
|
+
end
|
49
|
+
|
50
|
+
scope :deep, -> { with_rich_text_body_and_embeds.includes(:poll_question_options) }
|
51
|
+
scope :sorted, -> { order(:position) }
|
52
|
+
|
53
|
+
validates :title, presence: true
|
54
|
+
validates :category, presence: true, inclusion: { in: CATEGORIES }
|
55
|
+
validates :position, presence: true
|
56
|
+
validates :poll_question_options, presence: true, if: -> { poll_question_option? }
|
57
|
+
|
58
|
+
# Create choose_one? and select_all_that_apply? methods for each category
|
59
|
+
CATEGORIES.each do |category|
|
60
|
+
define_method(category.parameterize.underscore + '?') { self.category == category }
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
title.presence || 'New Poll Question'
|
65
|
+
end
|
66
|
+
|
67
|
+
def poll_question_option?
|
68
|
+
WITH_OPTIONS_CATEGORIES.include?(category)
|
69
|
+
end
|
70
|
+
|
71
|
+
def category_partial
|
72
|
+
category.to_s.parameterize.underscore
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Effective
|
2
|
+
class PollQuestionOption < ActiveRecord::Base
|
3
|
+
belongs_to :poll_question
|
4
|
+
|
5
|
+
effective_resource do
|
6
|
+
title :text
|
7
|
+
position :integer
|
8
|
+
|
9
|
+
timestamps
|
10
|
+
end
|
11
|
+
|
12
|
+
before_validation(if: -> { poll_question.present? }) do
|
13
|
+
self.position ||= (poll_question.poll_question_options.map { |obj| obj.position }.compact.max || -1) + 1
|
14
|
+
end
|
15
|
+
|
16
|
+
scope :sorted, -> { order(:position) }
|
17
|
+
|
18
|
+
validates :title, presence: true
|
19
|
+
validates :position, presence: true
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
title.presence || 'New Poll Question Option'
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
= effective_form_with(model: [:admin, poll_notification], engine: true) do |f|
|
2
|
+
- if inline_datatable?
|
3
|
+
= f.hidden_field :poll_id
|
4
|
+
- else
|
5
|
+
= f.select :poll_id, Effective::Poll.sorted.editable.all
|
6
|
+
|
7
|
+
= f.select :category, Effective::PollNotification::CATEGORIES,
|
8
|
+
label: 'Send an email notification'
|
9
|
+
|
10
|
+
= f.show_if :category, 'Upcoming reminder' do
|
11
|
+
|
12
|
+
= f.select :reminder, Effective::PollNotification::UPCOMING_REMINDERS, label: false,
|
13
|
+
hint: "before the poll starts on #{f.object.poll&.start_at&.strftime('%F')}."
|
14
|
+
|
15
|
+
.alert.alert-warning
|
16
|
+
%strong Upcoming Reminders
|
17
|
+
are sent to the entire audience before the poll starts.
|
18
|
+
%br
|
19
|
+
Use upcoming reminders to advertise, prepare, or communicate to your audience before the poll begins.
|
20
|
+
|
21
|
+
= f.show_if :category, 'When poll starts' do
|
22
|
+
.alert.alert-warning
|
23
|
+
%strong When poll starts
|
24
|
+
notifications will be sent within 10 minutes of the poll start time.
|
25
|
+
|
26
|
+
= f.show_if :category, 'Reminder' do
|
27
|
+
|
28
|
+
= f.select :reminder, Effective::PollNotification::REMINDERS, label: false,
|
29
|
+
hint: "after the poll starts on #{f.object.poll&.start_at&.strftime('%F')}."
|
30
|
+
|
31
|
+
.alert.alert-warning
|
32
|
+
%strong Reminders
|
33
|
+
are sent to users in the audience who have not yet completed their ballot.
|
34
|
+
%br
|
35
|
+
Use reminders to boost your audience participation and remind people to vote.
|
36
|
+
|
37
|
+
= f.show_if :category, 'When poll ends' do
|
38
|
+
.alert.alert-warning
|
39
|
+
%strong When poll ends
|
40
|
+
notifications will be sent within 10 minutes of the poll end time.
|
41
|
+
|
42
|
+
= f.text_field :subject, label: 'Email Subject'
|
43
|
+
= f.text_area :body, label: 'Email Body'
|
44
|
+
|
45
|
+
.alert.alert-warning
|
46
|
+
Email content must not contain any personal details.
|
47
|
+
%br
|
48
|
+
This content will be sent in a mass email with hundreds of bcc'd recipients.
|
49
|
+
|
50
|
+
- if poll_notification.poll.present?
|
51
|
+
%br
|
52
|
+
The url for this poll will be:
|
53
|
+
= effective_polls.poll_url(poll_notification.poll)
|
54
|
+
|
55
|
+
= effective_submit(f)
|
@@ -0,0 +1,100 @@
|
|
1
|
+
= effective_form_with(model: [:admin, poll_question], engine: true) do |f|
|
2
|
+
- if inline_datatable?
|
3
|
+
= f.hidden_field :poll_id
|
4
|
+
- else
|
5
|
+
= f.select :poll_id, Effective::Poll.sorted.editable.all
|
6
|
+
|
7
|
+
= f.text_field :title, label: 'Question Title'
|
8
|
+
= f.rich_text_area :body, label: 'Body (optional)'
|
9
|
+
|
10
|
+
= f.check_box :required, hint: 'A response to this question will be required'
|
11
|
+
= f.select :category, Effective::PollQuestion::CATEGORIES
|
12
|
+
|
13
|
+
= f.show_if :category, 'Choose one' do
|
14
|
+
.card
|
15
|
+
.card-body
|
16
|
+
%h5 Choose one
|
17
|
+
%p Display radio buttons to choose one option
|
18
|
+
|
19
|
+
= f.show_if :category, 'Select all that apply' do
|
20
|
+
.card
|
21
|
+
.card-body
|
22
|
+
%h5 Select all that apply
|
23
|
+
%p Display checkboxes to select all options that apply
|
24
|
+
|
25
|
+
= f.show_if :category, 'Select upto 1' do
|
26
|
+
.card
|
27
|
+
.card-body
|
28
|
+
%h5 Select upto 1 (one)
|
29
|
+
%p Display checkboxes to select upto 1 option
|
30
|
+
|
31
|
+
= f.show_if :category, 'Select upto 2' do
|
32
|
+
.card
|
33
|
+
.card-body
|
34
|
+
%h5 Select upto 2 (two)
|
35
|
+
%p Display checkboxes to select upto 2 options
|
36
|
+
|
37
|
+
= f.show_if :category, 'Select upto 3' do
|
38
|
+
.card
|
39
|
+
.card-body
|
40
|
+
%h5 Select upto 3 (three)
|
41
|
+
%p Display checkboxes to select upto 3 options
|
42
|
+
|
43
|
+
= f.show_if :category, 'Select upto 4' do
|
44
|
+
.card
|
45
|
+
.card-body
|
46
|
+
%h5 Select upto 4 (four)
|
47
|
+
%p Display checkboxes to select upto 4 options
|
48
|
+
|
49
|
+
= f.show_if :category, 'Select upto 5' do
|
50
|
+
.card
|
51
|
+
.card-body
|
52
|
+
%h5 Select upto 5 (five)
|
53
|
+
%p Display checkboxes to select upto 5 options
|
54
|
+
|
55
|
+
= f.show_if :category, 'Short Answer' do
|
56
|
+
.card
|
57
|
+
.card-body
|
58
|
+
%h5 Short Answer
|
59
|
+
%p Display a text field to enter a short text answer
|
60
|
+
|
61
|
+
= f.show_if :category, 'Long Answer' do
|
62
|
+
.card
|
63
|
+
.card-body
|
64
|
+
%h5 Long Answer
|
65
|
+
%p Display a textarea to enter a long text answer
|
66
|
+
|
67
|
+
= f.show_if :category, 'Date' do
|
68
|
+
.card
|
69
|
+
.card-body
|
70
|
+
%h5 Date
|
71
|
+
%p Display a date field to enter a date
|
72
|
+
|
73
|
+
= f.show_if :category, 'Email' do
|
74
|
+
.card
|
75
|
+
.card-body
|
76
|
+
%h5 Email
|
77
|
+
%p Display an email field to enter an email
|
78
|
+
|
79
|
+
= f.show_if :category, 'Number' do
|
80
|
+
.card
|
81
|
+
.card-body
|
82
|
+
%h5 Number
|
83
|
+
%p Display a number field to enter an integer number
|
84
|
+
|
85
|
+
= f.show_if :category, 'Upload File' do
|
86
|
+
.card
|
87
|
+
.card-body
|
88
|
+
%h5 Upload File
|
89
|
+
%p Display a file field to upload a file
|
90
|
+
|
91
|
+
= f.show_if_any :category, Effective::PollQuestion::WITH_OPTIONS_CATEGORIES do
|
92
|
+
.mt-3.card
|
93
|
+
.card-body
|
94
|
+
%h5 Options
|
95
|
+
%p Display the following options:
|
96
|
+
|
97
|
+
= f.has_many :poll_question_options, class: 'tight' do |fa|
|
98
|
+
= fa.text_field :title, label: false
|
99
|
+
|
100
|
+
= effective_submit(f)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
= tabs do
|
2
|
+
= tab 'Poll' do
|
3
|
+
= render 'admin/polls/form_poll', poll: poll
|
4
|
+
|
5
|
+
- if poll.persisted?
|
6
|
+
= tab 'Content' do
|
7
|
+
= render 'admin/polls/form_content', poll: poll
|
8
|
+
|
9
|
+
= tab 'Questions' do
|
10
|
+
- datatable = Admin::EffectivePollQuestionsDatatable.new(poll_id: poll.id)
|
11
|
+
= render_datatable(datatable, inline: true, simple: true)
|
12
|
+
|
13
|
+
= tab 'Notifications' do
|
14
|
+
%p
|
15
|
+
The following email notification will be sent to all
|
16
|
+
= pluralize(poll.users.count, 'users')
|
17
|
+
in the audience.
|
18
|
+
|
19
|
+
- datatable = Admin::EffectivePollNotificationsDatatable.new(poll_id: poll.id)
|
20
|
+
= render_datatable(datatable, inline: true, simple: true)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
= 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'
|
6
|
+
|
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'
|
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'
|
16
|
+
|
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'
|
21
|
+
|
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'
|
26
|
+
|
27
|
+
= f.submit
|