decidim-proposals 0.9.3 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -1
  3. data/app/assets/config/admin/decidim_proposals_manifest.js +1 -0
  4. data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +113 -0
  5. data/app/assets/javascripts/decidim/proposals/identity_selector_dialog.js.es6 +56 -0
  6. data/app/commands/decidim/proposals/admin/answer_proposal.rb +11 -5
  7. data/app/commands/decidim/proposals/admin/create_proposal.rb +25 -3
  8. data/app/commands/decidim/proposals/admin/create_proposal_note.rb +13 -8
  9. data/app/commands/decidim/proposals/admin/import_proposals.rb +83 -0
  10. data/app/commands/decidim/proposals/admin/update_proposal_category.rb +68 -0
  11. data/app/commands/decidim/proposals/create_proposal.rb +0 -12
  12. data/app/commands/decidim/proposals/endorse_proposal.rb +56 -0
  13. data/app/commands/decidim/proposals/publish_proposal.rb +60 -0
  14. data/app/commands/decidim/proposals/unendorse_proposal.rb +40 -0
  15. data/app/commands/decidim/proposals/update_proposal.rb +3 -3
  16. data/app/commands/decidim/proposals/vote_proposal.rb +1 -1
  17. data/app/commands/decidim/proposals/withdraw_proposal.rb +1 -1
  18. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +1 -1
  19. data/app/controllers/decidim/proposals/admin/proposal_notes_controller.rb +2 -2
  20. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +50 -1
  21. data/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb +35 -0
  22. data/app/controllers/decidim/proposals/proposal_endorsements_controller.rb +56 -0
  23. data/app/controllers/decidim/proposals/proposals_controller.rb +82 -9
  24. data/app/events/decidim/proposals/admin/update_proposal_category_event.rb +11 -0
  25. data/app/events/decidim/proposals/creation_enabled_event.rb +8 -0
  26. data/app/events/decidim/proposals/endorsing_enabled_event.rb +8 -0
  27. data/app/events/decidim/proposals/proposal_endorsed_event.rb +29 -0
  28. data/app/events/decidim/proposals/publish_proposal_event.rb +21 -0
  29. data/app/events/decidim/proposals/voting_enabled_event.rb +8 -0
  30. data/app/forms/decidim/proposals/admin/proposal_form.rb +9 -2
  31. data/app/forms/decidim/proposals/admin/proposals_import_form.rb +60 -0
  32. data/app/forms/decidim/proposals/proposal_form.rb +16 -5
  33. data/app/helpers/decidim/proposals/application_helper.rb +1 -0
  34. data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +117 -0
  35. data/app/helpers/decidim/proposals/proposal_votes_helper.rb +13 -6
  36. data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +105 -0
  37. data/app/jobs/decidim/proposals/settings_change_job.rb +48 -0
  38. data/app/models/decidim/proposals/abilities/current_user_ability.rb +30 -8
  39. data/app/models/decidim/proposals/proposal.rb +38 -38
  40. data/app/models/decidim/proposals/proposal_endorsement.rb +31 -0
  41. data/app/models/decidim/proposals/proposal_note.rb +7 -0
  42. data/app/presenters/decidim/proposals/admin_log/proposal_note_presenter.rb +39 -0
  43. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +47 -0
  44. data/app/presenters/decidim/proposals/admin_log/value_types/proposal_state_presenter.rb +16 -0
  45. data/app/queries/decidim/proposals/similar_proposals.rb +53 -0
  46. data/app/types/decidim/proposals/proposal_type.rb +34 -0
  47. data/app/types/decidim/proposals/proposals_type.rb +34 -0
  48. data/app/views/decidim/participatory_processes/participatory_process_groups/_highlighted_proposals.html.erb +8 -0
  49. data/app/views/decidim/participatory_processes/participatory_process_groups/_proposal.html.erb +27 -0
  50. data/app/views/decidim/participatory_spaces/_highlighted_proposals.html.erb +10 -0
  51. data/app/views/decidim/participatory_spaces/_proposal.html.erb +27 -0
  52. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +15 -0
  53. data/app/views/decidim/proposals/admin/proposals/_js-callout.html.erb +6 -0
  54. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +63 -0
  55. data/app/views/decidim/proposals/admin/proposals/index.html.erb +12 -73
  56. data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +25 -0
  57. data/app/views/decidim/proposals/admin/proposals_imports/new.html.erb +28 -0
  58. data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +4 -0
  59. data/app/views/decidim/proposals/proposal_endorsements/identities.html.erb +12 -0
  60. data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +9 -0
  61. data/app/views/decidim/proposals/proposals/_endorsement_button.html.erb +11 -0
  62. data/app/views/decidim/proposals/proposals/_endorsement_identities_cabin.html.erb +13 -0
  63. data/app/views/decidim/proposals/proposals/_endorsement_xxs.html.erb +9 -0
  64. data/app/views/decidim/proposals/proposals/_endorsements_card_row.html.erb +22 -0
  65. data/app/views/decidim/proposals/proposals/_endorsements_count.html.erb +5 -0
  66. data/app/views/decidim/proposals/proposals/_endorsements_listing.html.erb +34 -0
  67. data/app/views/decidim/proposals/proposals/_proposal.html.erb +2 -2
  68. data/app/views/decidim/proposals/proposals/_proposal_preview.html.erb +36 -0
  69. data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +21 -0
  70. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +8 -8
  71. data/app/views/decidim/proposals/proposals/_votes_count.html.erb +23 -6
  72. data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +7 -3
  73. data/app/views/decidim/proposals/proposals/_wizard_aside.html.erb +16 -0
  74. data/app/views/decidim/proposals/proposals/_wizard_header.html.erb +31 -0
  75. data/app/views/decidim/proposals/proposals/compare.html.erb +19 -0
  76. data/app/views/decidim/proposals/proposals/edit_draft.html.erb +55 -0
  77. data/app/views/decidim/proposals/proposals/new.html.erb +7 -20
  78. data/app/views/decidim/proposals/proposals/preview.html.erb +18 -0
  79. data/app/views/decidim/proposals/proposals/show.html.erb +13 -4
  80. data/config/locales/ca.yml +156 -15
  81. data/config/locales/en.yml +156 -15
  82. data/config/locales/es.yml +157 -16
  83. data/config/locales/eu.yml +151 -7
  84. data/config/locales/fi.yml +151 -7
  85. data/config/locales/fr.yml +153 -9
  86. data/config/locales/gl.yml +151 -7
  87. data/config/locales/it.yml +151 -7
  88. data/config/locales/nl.yml +151 -7
  89. data/config/locales/pl.yml +148 -22
  90. data/config/locales/pt-BR.yml +151 -7
  91. data/config/locales/pt.yml +151 -7
  92. data/config/locales/ru.yml +0 -9
  93. data/config/locales/sv.yml +151 -7
  94. data/config/locales/uk.yml +87 -13
  95. data/db/migrate/20170307085300_migrate_proposal_reports_data_to_reports.rb +1 -1
  96. data/db/migrate/20171201115434_create_proposal_endorsements.rb +16 -0
  97. data/db/migrate/20171201122623_add_counter_cache_endorsements_to_proposals.rb +8 -0
  98. data/db/migrate/20171212102250_enable_pg_extensions.rb +7 -0
  99. data/db/migrate/20171220084719_add_published_at_to_proposals.rb +14 -0
  100. data/lib/decidim/proposals.rb +15 -0
  101. data/lib/decidim/proposals/admin_engine.rb +8 -0
  102. data/lib/decidim/proposals/commentable_proposal.rb +39 -0
  103. data/lib/decidim/proposals/engine.rb +69 -1
  104. data/lib/decidim/proposals/feature.rb +51 -6
  105. data/lib/decidim/proposals/test/factories.rb +78 -2
  106. data/lib/decidim/proposals/version.rb +1 -1
  107. metadata +76 -20
  108. data/app/events/decidim/proposals/create_proposal_event.rb +0 -9
@@ -0,0 +1,11 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ module Admin
6
+ class UpdateProposalCategoryEvent < Decidim::Events::SimpleEvent
7
+ include Decidim::Events::AuthorEvent
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class CreationEnabledEvent < Decidim::Events::SimpleEvent
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class EndorsingEnabledEvent < Decidim::Events::SimpleEvent
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class ProposalEndorsedEvent < Decidim::Events::SimpleEvent
6
+ i18n_attributes :endorser_nickname, :endorser_name, :endorser_path, :nickname
7
+
8
+ delegate :nickname, :name, to: :endorser, prefix: true
9
+
10
+ def nickname
11
+ endorser_nickname
12
+ end
13
+
14
+ def endorser_path
15
+ endorser.profile_path
16
+ end
17
+
18
+ private
19
+
20
+ def endorser
21
+ @endorser ||= Decidim::UserPresenter.new(endorser_user)
22
+ end
23
+
24
+ def endorser_user
25
+ @endorser_user ||= Decidim::User.find_by(id: extra[:endorser_id])
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class PublishProposalEvent < Decidim::Events::SimpleEvent
6
+ include Decidim::Events::AuthorEvent
7
+
8
+ private
9
+
10
+ def i18n_scope
11
+ return super unless participatory_space_event?
12
+
13
+ "decidim.events.proposals.proposal_published_for_space"
14
+ end
15
+
16
+ def participatory_space_event?
17
+ extra.dig(:participatory_space)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class VotingEnabledEvent < Decidim::Events::SimpleEvent
6
+ end
7
+ end
8
+ end
@@ -20,7 +20,8 @@ module Decidim
20
20
  validates :address, geocoding: true, if: -> { current_feature.settings.geocoding_enabled? }
21
21
  validates :category, presence: true, if: ->(form) { form.category_id.present? }
22
22
  validates :scope, presence: true, if: ->(form) { form.scope_id.present? }
23
- validate { errors.add(:scope_id, :invalid) if current_participatory_space&.scope && !current_participatory_space&.scope&.ancestor_of?(scope) }
23
+
24
+ validate :scope_belongs_to_participatory_space_scope
24
25
 
25
26
  delegate :categories, to: :current_feature
26
27
 
@@ -43,7 +44,7 @@ module Decidim
43
44
  #
44
45
  # Returns a Decidim::Scope
45
46
  def scope
46
- @scope ||= @scope_id ? current_feature.scopes.find_by(id: @scope_id) : current_participatory_space&.scope
47
+ @scope ||= @scope_id ? current_participatory_space.scopes.find_by(id: @scope_id) : current_participatory_space.scope
47
48
  end
48
49
 
49
50
  # Scope identifier
@@ -52,6 +53,12 @@ module Decidim
52
53
  def scope_id
53
54
  @scope_id || scope&.id
54
55
  end
56
+
57
+ private
58
+
59
+ def scope_belongs_to_participatory_space_scope
60
+ errors.add(:scope_id, :invalid) if current_participatory_space.out_of_scope?(scope)
61
+ end
55
62
  end
56
63
  end
57
64
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ module Admin
6
+ # A form object to be used when admin users want to import a collection of proposals
7
+ # from another component.
8
+ class ProposalsImportForm < Decidim::Form
9
+ mimic :proposals_import
10
+
11
+ attribute :origin_feature_id, Integer
12
+ attribute :import_proposals, Boolean
13
+ attribute :states, Array
14
+
15
+ validates :origin_feature_id, :origin_feature, :states, :current_feature, presence: true
16
+ validates :import_proposals, allow_nil: false, acceptance: true
17
+ validate :valid_states
18
+
19
+ VALID_STATES = %w(accepted not_answered evaluating rejected withdrawn).freeze
20
+
21
+ def states_collection
22
+ VALID_STATES.map do |state|
23
+ OpenStruct.new(
24
+ name: I18n.t(state, scope: "decidim.proposals.answers"),
25
+ value: state
26
+ )
27
+ end
28
+ end
29
+
30
+ def states
31
+ super.reject(&:blank?)
32
+ end
33
+
34
+ def origin_feature
35
+ @origin_feature ||= origin_features.find_by(id: origin_feature_id)
36
+ end
37
+
38
+ def origin_features
39
+ @origin_features ||= current_participatory_space.features.where.not(id: current_feature.id).where(manifest_name: :proposals)
40
+ end
41
+
42
+ def origin_features_collection
43
+ origin_features.map do |feature|
44
+ [feature.name[I18n.locale.to_s], feature.id]
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def valid_states
51
+ return if states.all? do |state|
52
+ VALID_STATES.include?(state)
53
+ end
54
+
55
+ errors.add(:states, :invalid)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -16,15 +16,15 @@ module Decidim
16
16
  attribute :user_group_id, Integer
17
17
  attribute :has_address, Boolean
18
18
  attribute :attachment, AttachmentForm
19
-
20
19
  validates :title, :body, presence: true, etiquette: true
21
20
  validates :title, length: { maximum: 150 }
22
- validates :body, length: { maximum: 500 }, etiquette: true
23
21
  validates :address, geocoding: true, if: ->(form) { Decidim.geocoder.present? && form.has_address? }
24
22
  validates :address, presence: true, if: ->(form) { form.has_address? }
25
23
  validates :category, presence: true, if: ->(form) { form.category_id.present? }
26
24
  validates :scope, presence: true, if: ->(form) { form.scope_id.present? }
27
- validate { errors.add(:scope_id, :invalid) if current_participatory_space&.scope && !current_participatory_space&.scope&.ancestor_of?(scope) }
25
+
26
+ validate :proposal_length
27
+ validate :scope_belongs_to_participatory_space_scope
28
28
 
29
29
  delegate :categories, to: :current_feature
30
30
 
@@ -35,7 +35,6 @@ module Decidim
35
35
  end
36
36
 
37
37
  alias feature current_feature
38
-
39
38
  # Finds the Category from the category_id.
40
39
  #
41
40
  # Returns a Decidim::Category
@@ -47,7 +46,7 @@ module Decidim
47
46
  #
48
47
  # Returns a Decidim::Scope
49
48
  def scope
50
- @scope ||= @scope_id ? current_feature.scopes.find_by(id: @scope_id) : current_participatory_space&.scope
49
+ @scope ||= @scope_id ? current_participatory_space.scopes.find_by(id: @scope_id) : current_participatory_space.scope
51
50
  end
52
51
 
53
52
  # Scope identifier
@@ -60,6 +59,18 @@ module Decidim
60
59
  def has_address?
61
60
  current_feature.settings.geocoding_enabled? && has_address
62
61
  end
62
+
63
+ private
64
+
65
+ def proposal_length
66
+ return unless body.presence
67
+ length = current_feature.settings.proposal_length
68
+ errors.add(:body, :too_long, count: length) if body.length > length
69
+ end
70
+
71
+ def scope_belongs_to_participatory_space_scope
72
+ errors.add(:scope_id, :invalid) if current_participatory_space.out_of_scope?(scope)
73
+ end
63
74
  end
64
75
  end
65
76
  end
@@ -8,6 +8,7 @@ module Decidim
8
8
  include Decidim::Comments::CommentsHelper
9
9
  include PaginateHelper
10
10
  include ProposalVotesHelper
11
+ include ProposalEndorsementsHelper
11
12
  include Decidim::MapHelper
12
13
  include Decidim::Proposals::MapHelper
13
14
 
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # Simple helper to handle markup variations for proposal endorsements partials
6
+ module ProposalEndorsementsHelper
7
+ # Returns the css classes used for proposal endorsements count in both proposals list and show pages
8
+ #
9
+ # from_proposals_list - A boolean to indicate if the template is rendered from the proposals list page
10
+ #
11
+ # Returns a hash with the css classes for the count number and label
12
+ def endorsements_count_classes(from_proposals_list)
13
+ return { number: "card__support__number", label: "" } if from_proposals_list
14
+ { number: "extra__suport-number", label: "extra__suport-text" }
15
+ end
16
+
17
+ # Returns the css classes used for proposal endorsement button in both proposals list and show pages
18
+ #
19
+ # from_proposals_list - A boolean to indicate if the template is rendered from the proposals list page
20
+ #
21
+ # Returns a string with the value of the css classes.
22
+ def endorsement_button_classes(from_proposals_list)
23
+ return "small" if from_proposals_list
24
+ "small compact light button--sc expanded"
25
+ end
26
+
27
+ # Public: Checks if endorsement are enabled in this step.
28
+ #
29
+ # Returns true if enabled, false otherwise.
30
+ def endorsements_enabled?
31
+ current_settings.endorsements_enabled
32
+ end
33
+
34
+ # Public: Checks if endorsements are blocked in this step.
35
+ #
36
+ # Returns true if blocked, false otherwise.
37
+ def endorsements_blocked?
38
+ current_settings.endorsements_blocked
39
+ end
40
+
41
+ # Public: Checks if the current user is allowed to endorse in this step.
42
+ #
43
+ # Returns true if the current user can endorse, false otherwise.
44
+ def current_user_can_endorse?
45
+ current_user && endorsements_enabled? && !endorsements_blocked?
46
+ end
47
+
48
+ # Public: Checks if the card for endorsements should be rendered.
49
+ #
50
+ # Returns true if the endorsements card should be rendered, false otherwise.
51
+ def show_endorsements_card?
52
+ endorsements_enabled?
53
+ end
54
+
55
+ def endorsement_identity(endorsement)
56
+ endorsement.user_group ? endorsement.user_group : endorsement.author
57
+ end
58
+
59
+ # Public: Renders a button to endorse the given proposal.
60
+ # To override the translation for both buttons: endorse and unendorse (use to be the name of the user/user_group).
61
+ #
62
+ # @params (mandatory): proposal, from_proposals_list
63
+ # @params (optional) : user_group, btn_label
64
+ def endorsement_button(proposal, from_proposals_list, btn_label = nil, user_group = nil)
65
+ current_endorsement_url = proposal_proposal_endorsement_path(
66
+ proposal_id: proposal,
67
+ from_proposals_list: from_proposals_list,
68
+ user_group_id: user_group&.id
69
+ )
70
+ endorse_label = btn_label || t(".endorse")
71
+ unendorse_label = btn_label || t("decidim.proposals.proposal_endorsements_helper.endorsement_button.already_endorsed")
72
+
73
+ render partial: "decidim/proposals/proposals/endorsement_button", locals: { proposal: proposal,
74
+ from_proposals_list: from_proposals_list, user_group: user_group,
75
+ current_endorsement_url: current_endorsement_url,
76
+ endorse_label: endorse_label, unendorse_label: unendorse_label }
77
+ end
78
+
79
+ #
80
+ # Public: Checks if the given Proposal has been endorsed by all identities of the user.
81
+ #
82
+ # @param proposal: The Proposal from which endorsements will be checked against.
83
+ # @param user: The user whose identities and endorsements will be checked against.
84
+ #
85
+ def fully_endorsed?(proposal, user)
86
+ return false unless user
87
+
88
+ user_group_endorsements = user.user_groups.verified.all? { |user_group| proposal.endorsed_by?(user, user_group) }
89
+
90
+ user_group_endorsements && proposal.endorsed_by?(user)
91
+ end
92
+
93
+ # Public: Renders an identity for endorsement.
94
+ #
95
+ # @params (mandatory): proposal, from_proposals_list
96
+ # @params (mandatory): user, the user that is endorsing at the end.
97
+ # @params (optional) : user_group, the user_group on behalf of which the endorsement is being done
98
+ def render_endorsement_identity(proposal, user, user_group = nil)
99
+ current_endorsement_url = proposal_proposal_endorsement_path(
100
+ proposal_id: proposal,
101
+ from_proposals_list: false,
102
+ user_group_id: user_group&.id,
103
+ authenticity_token: form_authenticity_token
104
+ )
105
+ presenter = if user_group
106
+ Decidim::UserGroupPresenter.new(user_group)
107
+ else
108
+ Decidim::UserPresenter.new(user)
109
+ end
110
+ selected = proposal.endorsed_by?(user, user_group)
111
+ http_method = selected ? :delete : :post
112
+ render partial: "decidim/proposals/proposal_endorsements/identity", locals:
113
+ { identity: presenter, selected: selected, current_endorsement_url: current_endorsement_url, http_method: http_method }
114
+ end
115
+ end
116
+ end
117
+ end
@@ -39,19 +39,26 @@ module Decidim
39
39
  vote_limit.present?
40
40
  end
41
41
 
42
- # Public: Checks if maximum votes per proposal are set.
42
+ # Public: Checks if threshold per proposal are set.
43
43
  #
44
44
  # Returns true if set, false otherwise.
45
- def maximum_votes_per_proposal_enabled?
46
- maximum_votes_per_proposal.present?
45
+ def threshold_per_proposal_enabled?
46
+ threshold_per_proposal.present?
47
47
  end
48
48
 
49
49
  # Public: Fetches the maximum amount of votes per proposal.
50
50
  #
51
51
  # Returns an Integer with the maximum amount of votes, nil otherwise.
52
- def maximum_votes_per_proposal
53
- return nil unless feature_settings.maximum_votes_per_proposal.positive?
54
- feature_settings.maximum_votes_per_proposal
52
+ def threshold_per_proposal
53
+ return nil unless feature_settings.threshold_per_proposal.positive?
54
+ feature_settings.threshold_per_proposal
55
+ end
56
+
57
+ # Public: Checks if can accumulate more than maxium is enabled
58
+ #
59
+ # Returns true if enabled, false otherwise.
60
+ def can_accumulate_supports_beyond_threshold?
61
+ feature_settings.can_accumulate_supports_beyond_threshold
55
62
  end
56
63
 
57
64
  # Public: Checks if voting is enabled in this step.
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # Simple helpers to handle markup variations for proposal wizard partials
6
+ module ProposalWizardHelper
7
+ # Returns the css classes used for the proposal wizard for the desired step
8
+ #
9
+ # step - A symbol of the target step
10
+ # current_step - A symbol of the current step
11
+ #
12
+ # Returns a string with the css classes for the desired step
13
+ def proposal_wizard_step_classes(step, current_step)
14
+ step_i = step.to_s.split("_").last.to_i
15
+ if step_i == proposal_wizard_step_number(current_step)
16
+ %(step--active #{step} #{current_step})
17
+ elsif step_i < proposal_wizard_step_number(current_step)
18
+ %(step--past #{step})
19
+ else
20
+ %()
21
+ end
22
+ end
23
+
24
+ # Returns the number of the step
25
+ #
26
+ # step - A symbol of the target step
27
+ def proposal_wizard_step_number(step)
28
+ step.to_s.split("_").last.to_i
29
+ end
30
+
31
+ # Returns the name of the step, translated
32
+ #
33
+ # step - A symbol of the target step
34
+ def proposal_wizard_step_name(step)
35
+ t(:"decidim.proposals.proposals.wizard_steps.#{step}")
36
+ end
37
+
38
+ # Returns the page title of the given step, translated
39
+ #
40
+ # action_name - A string of the rendered action
41
+ def proposal_wizard_step_title(action_name)
42
+ step_title = case action_name
43
+ when "create"
44
+ "new"
45
+ when "update_draft"
46
+ "edit_draft"
47
+ else
48
+ action_name
49
+ end
50
+
51
+ t("decidim.proposals.proposals.#{step_title}.title")
52
+ end
53
+
54
+ # Returns the list item of the given step, in html
55
+ #
56
+ # step - A symbol of the target step
57
+ # current_step - A symbol of the current step
58
+ def proposal_wizard_stepper_step(step, current_step)
59
+ content_tag(:li, proposal_wizard_step_name(step), class: proposal_wizard_step_classes(step, current_step).to_s)
60
+ end
61
+
62
+ # Returns the list with all the steps, in html
63
+ #
64
+ # current_step - A symbol of the current step
65
+ def proposal_wizard_stepper(current_step)
66
+ content_tag :ol, class: "wizard__steps" do
67
+ %(
68
+ #{proposal_wizard_stepper_step(:step_1, current_step)}
69
+ #{proposal_wizard_stepper_step(:step_2, current_step)}
70
+ #{proposal_wizard_stepper_step(:step_3, current_step)}
71
+ ).html_safe
72
+ end
73
+ end
74
+
75
+ # Returns a string with the current step number and the total steps number
76
+ #
77
+ # step - A symbol of the target step
78
+ def proposal_wizard_current_step_of(step)
79
+ current_step_num = proposal_wizard_step_number(step)
80
+ content_tag :span, class: "text-small" do
81
+ concat t(:"decidim.proposals.proposals.wizard_steps.step_of", current_step_num: current_step_num, total_steps: 3)
82
+ concat " ("
83
+ concat content_tag :a, t(:"decidim.proposals.proposals.wizard_steps.see_steps"), "data-toggle": "steps"
84
+ concat ")"
85
+ end
86
+ end
87
+
88
+ # Returns a boolean if the step has a help text defined
89
+ #
90
+ # step - A symbol of the target step
91
+ def proposal_wizard_step_help_text?(step)
92
+ translated_attribute(feature_settings.try("proposal_wizard_#{step}_help_text")).present?
93
+ end
94
+
95
+ # Renders a user_group select field in a form.
96
+ # form - FormBuilder object
97
+ # name - attribute user_group_id
98
+ #
99
+ # Returns nothing.
100
+ def user_group_select_field(form, name)
101
+ form.select(name, current_user.user_groups.verified.map { |g| [g.name, g.id] }, prompt: current_user.name)
102
+ end
103
+ end
104
+ end
105
+ end