decidim-posts 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +40 -0
  4. data/Rakefile +9 -0
  5. data/app/cells/decidim/posts/comments/add_comment.erb +15 -0
  6. data/app/cells/decidim/posts/comments/comments_loading.erb +1 -0
  7. data/app/cells/decidim/posts/comments/order_control.erb +13 -0
  8. data/app/cells/decidim/posts/comments/show.erb +31 -0
  9. data/app/cells/decidim/posts/comments_cell.rb +158 -0
  10. data/app/cells/decidim/posts/content_blocks/posts/show.erb +3 -0
  11. data/app/cells/decidim/posts/content_blocks/posts_cell.rb +50 -0
  12. data/app/cells/decidim/posts/content_blocks/posts_settings_form/show.erb +3 -0
  13. data/app/cells/decidim/posts/content_blocks/posts_settings_form_cell.rb +23 -0
  14. data/app/cells/decidim/posts/feed_dropdown_metadata_cell.rb +19 -0
  15. data/app/cells/decidim/posts/meeting/show.erb +65 -0
  16. data/app/cells/decidim/posts/meeting_cell.rb +44 -0
  17. data/app/cells/decidim/posts/post/show.erb +30 -0
  18. data/app/cells/decidim/posts/post/survey.erb +68 -0
  19. data/app/cells/decidim/posts/post_attachments/show.erb +40 -0
  20. data/app/cells/decidim/posts/post_attachments_cell.rb +17 -0
  21. data/app/cells/decidim/posts/post_cell.rb +44 -0
  22. data/app/cells/decidim/posts/post_comment/show.erb +17 -0
  23. data/app/cells/decidim/posts/post_comment_cell.rb +49 -0
  24. data/app/cells/decidim/posts/post_header/show.erb +53 -0
  25. data/app/cells/decidim/posts/post_header_cell.rb +79 -0
  26. data/app/cells/decidim/posts/post_host/show.erb +74 -0
  27. data/app/cells/decidim/posts/post_host_cell.rb +73 -0
  28. data/app/cells/decidim/posts/post_metadata/show.erb +9 -0
  29. data/app/cells/decidim/posts/post_metadata_cell.rb +67 -0
  30. data/app/cells/decidim/posts/reaction_menu/show.erb +18 -0
  31. data/app/cells/decidim/posts/reaction_menu/styles.erb +7 -0
  32. data/app/cells/decidim/posts/reaction_menu_cell.rb +26 -0
  33. data/app/cells/decidim/posts/reactions/show.erb +8 -0
  34. data/app/cells/decidim/posts/reactions_cell.rb +22 -0
  35. data/app/commands/decidim/posts/add_reaction_to_resource.rb +90 -0
  36. data/app/commands/decidim/posts/create_post.rb +112 -0
  37. data/app/commands/decidim/posts/destroy_post.rb +20 -0
  38. data/app/commands/decidim/posts/remove_reaction_from_resource.rb +41 -0
  39. data/app/commands/decidim/posts/update_post.rb +72 -0
  40. data/app/controllers/concerns/decidim/posts/admin/filterable.rb +46 -0
  41. data/app/controllers/concerns/decidim/posts/reactionable.rb +31 -0
  42. data/app/controllers/decidim/posts/admin/application_controller.rb +26 -0
  43. data/app/controllers/decidim/posts/admin/posts_controller.rb +93 -0
  44. data/app/controllers/decidim/posts/application_controller.rb +18 -0
  45. data/app/controllers/decidim/posts/meetings_controller.rb +176 -0
  46. data/app/controllers/decidim/posts/posts_controller.rb +202 -0
  47. data/app/controllers/decidim/posts/reactions_controller.rb +54 -0
  48. data/app/controllers/decidim/posts/user_answers_controller.rb +36 -0
  49. data/app/events/decidim/posts/resource_reacted_event.rb +38 -0
  50. data/app/forms/decidim/posts/answer_form.rb +13 -0
  51. data/app/forms/decidim/posts/post_form.rb +121 -0
  52. data/app/forms/decidim/posts/question_form.rb +20 -0
  53. data/app/helpers/decidim/posts/admin/posts_helper.rb +8 -0
  54. data/app/helpers/decidim/posts/application_helper.rb +20 -0
  55. data/app/helpers/decidim/posts/post_cells_helper.rb +35 -0
  56. data/app/helpers/decidim/posts/posts_helper.rb +34 -0
  57. data/app/helpers/decidim/posts/reaction_helper.rb +22 -0
  58. data/app/models/decidim/posts/answer.rb +13 -0
  59. data/app/models/decidim/posts/application_record.rb +10 -0
  60. data/app/models/decidim/posts/post.rb +116 -0
  61. data/app/models/decidim/posts/question.rb +17 -0
  62. data/app/models/decidim/posts/reaction.rb +22 -0
  63. data/app/models/decidim/posts/reaction_type.rb +13 -0
  64. data/app/models/decidim/posts/user_answer.rb +11 -0
  65. data/app/packs/entrypoints/decidim_posts.js +5 -0
  66. data/app/packs/entrypoints/decidim_posts.scss +1 -0
  67. data/app/packs/images/decidim/posts/icon.svg +1 -0
  68. data/app/packs/src/decidim/posts/carousel.js +112 -0
  69. data/app/packs/src/decidim/posts/host_status.js +75 -0
  70. data/app/packs/src/decidim/posts/newFeeds.js +98 -0
  71. data/app/packs/src/decidim/posts/posts.js +272 -0
  72. data/app/packs/src/decidim/posts/submenu.js +46 -0
  73. data/app/packs/src/decidim/posts/survey.js +94 -0
  74. data/app/packs/stylesheets/decidim/posts/_variables.scss +10 -0
  75. data/app/packs/stylesheets/decidim/posts/posts.scss +415 -0
  76. data/app/permissions/decidim/posts/admin/permissions.rb +23 -0
  77. data/app/permissions/decidim/posts/permissions.rb +101 -0
  78. data/app/presenters/decidim/posts/post_presenter.rb +45 -0
  79. data/app/views/decidim/posts/admin/posts/_post-tr.html.erb +45 -0
  80. data/app/views/decidim/posts/admin/posts/index.html.erb +54 -0
  81. data/app/views/decidim/posts/meetings/edit.html.erb +24 -0
  82. data/app/views/decidim/posts/posts/_admin_options.html.erb +30 -0
  83. data/app/views/decidim/posts/posts/_attachment.html.erb +24 -0
  84. data/app/views/decidim/posts/posts/_edit_form.html.erb +16 -0
  85. data/app/views/decidim/posts/posts/_feed.html.erb +8 -0
  86. data/app/views/decidim/posts/posts/_form.html.erb +104 -0
  87. data/app/views/decidim/posts/posts/_index.html.erb +49 -0
  88. data/app/views/decidim/posts/posts/_meeting_form.erb +18 -0
  89. data/app/views/decidim/posts/posts/_new.html.erb +33 -0
  90. data/app/views/decidim/posts/posts/_new_survey.html.erb +20 -0
  91. data/app/views/decidim/posts/posts/_new_survey_answer.html.erb +11 -0
  92. data/app/views/decidim/posts/posts/_new_survey_question.html.erb +17 -0
  93. data/app/views/decidim/posts/posts/_post.html.erb +11 -0
  94. data/app/views/decidim/posts/posts/_post_form.html.erb +5 -0
  95. data/app/views/decidim/posts/posts/_sidebar.html.erb +36 -0
  96. data/app/views/decidim/posts/posts/edit.html.erb +34 -0
  97. data/app/views/decidim/posts/posts/index.html.erb +1 -0
  98. data/app/views/decidim/posts/posts/show.html.erb +12 -0
  99. data/app/views/decidim/posts/reactions/_update_buttons_and_counters.html.erb +1 -0
  100. data/config/assets.rb +9 -0
  101. data/config/i18n-tasks.yml +10 -0
  102. data/config/locales/bs.yml +215 -0
  103. data/config/locales/de.yml +217 -0
  104. data/config/locales/en.yml +216 -0
  105. data/config/locales/hr.yml +219 -0
  106. data/config/locales/it.yml +215 -0
  107. data/config/locales/sr.yml +220 -0
  108. data/config/locales/tr.yml +219 -0
  109. data/lib/decidim/posts/admin.rb +10 -0
  110. data/lib/decidim/posts/admin_engine.rb +25 -0
  111. data/lib/decidim/posts/component.rb +59 -0
  112. data/lib/decidim/posts/content_blocks/content_blocks_homepage.rb +19 -0
  113. data/lib/decidim/posts/engine.rb +84 -0
  114. data/lib/decidim/posts/test/factories.rb +14 -0
  115. data/lib/decidim/posts/version.rb +9 -0
  116. data/lib/decidim/posts.rb +13 -0
  117. metadata +183 -0
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Decidim::Posts component (under development)
2
+
3
+ This Feeds component adds social posts functionality to Decidim.
4
+
5
+ **The module is currently in development and not yet ready.**
6
+
7
+ ## Usage
8
+
9
+ Feeds will be available as a Component for a Participatory
10
+ Space.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem "decidim-posts", git: "https://github.com/DecidimAustria/decidim-module-posts.git", branch: "main"
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ ```bash
23
+ bundle
24
+ bundle exec rails decidim_posts:install:migrations
25
+ bundle exec rails db:migrate
26
+ ```
27
+
28
+ ## Contributing
29
+
30
+ Contributions are welcome !
31
+
32
+ We expect the contributions to follow the [Decidim's contribution guide](https://github.com/decidim/decidim/blob/develop/CONTRIBUTING.adoc).
33
+
34
+ ## Security
35
+
36
+ Security is very important to us. If you have any issue regarding security, please disclose the information responsibly by sending an email to __security [at] mitgestalten [dot] jetzt__ and not by creating a Github issue.
37
+
38
+ ## License
39
+
40
+ This engine is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/dev/common_rake"
4
+
5
+ desc "Generates a dummy app for testing"
6
+ task test_app: "decidim:generate_external_test_app"
7
+
8
+ desc "Generates a development app."
9
+ task development_app: "decidim:generate_external_development_app"
@@ -0,0 +1,15 @@
1
+ <div class="add-comment">
2
+ <% if user_signed_in? %>
3
+ <%== cell("decidim/comments/comment_form", model, root_depth:) %>
4
+ <% else %>
5
+ <p>
6
+ <span>
7
+ <%== t(
8
+ "decidim.components.add_comment_form.account_message",
9
+ sign_in_url: decidim.new_user_session_path,
10
+ sign_up_url: decidim.new_user_registration_path
11
+ ) %>
12
+ </span>
13
+ </p>
14
+ <% end %>
15
+ </div>
@@ -0,0 +1 @@
1
+ <%= cell("decidim/announcement", t("decidim.components.comments.loading"), callout_class: "primary loading-comments mb-4") %>
@@ -0,0 +1,13 @@
1
+ <div class="comment-order-by">
2
+ <% available_orders.each do | order_value| %>
3
+ <div class="text-center">
4
+ <%= link_to(
5
+ t("decidim.components.comment_order_selector.order.#{order_value}"),
6
+ decidim_comments.comments_path(commentable_gid: model.to_signed_global_id.to_s, order: order_value, reload: 1),
7
+ class: "button button__sm button__text-secondary only:m-auto comment-order-by__item inline-block #{order_value == order ? "underline font-bold" : ""}",
8
+ remote: true,
9
+ aria: { controls: threads_node_id }
10
+ ) %>
11
+ </div>
12
+ <% end %>
13
+ </div>
@@ -0,0 +1,31 @@
1
+ <%= append_stylesheet_pack_tag "decidim_comments" %>
2
+ <%= content_tag :div, id: node_id, data: { decidim_posts_comments: comments_data } do %>
3
+ <div id="comments">
4
+ <div class="comments">
5
+ <div class="comments__header">
6
+ <h2 class="h4">
7
+ <% if single_comment? %>
8
+ <%= t("decidim.components.comments.comment_details_title") %>
9
+ <% else %>
10
+ <%= icon "chat-1-line", class: "fill-tertiary w-6 h-6 inline-block align-middle" %>
11
+ <span class="comments-count inline-block align-middle">
12
+ <%= t("decidim.components.comments.title", count: comments_count) %>
13
+ </span>
14
+ <% end %>
15
+ </h2>
16
+ <%= render :order_control %>
17
+ </div>
18
+ <%= single_comment_warning %>
19
+ <%= blocked_comments_warning %>
20
+ <div class="comment-threads" id="<%= threads_node_id %>" aria-live="polite">
21
+ <%= comments_loading %>
22
+ <% comments.each do |comment| %>
23
+ <%= cell("decidim/comments/comment_thread", comment, order:) %>
24
+ <% end %>
25
+ </div>
26
+ <%= add_comment %>
27
+ <%= user_comments_blocked_warning %>
28
+ </div>
29
+ <%= cell("decidim/announcement", t("decidim.components.comments.loading"), callout_class: "primary loading-comments hidden") %>
30
+ </div>
31
+ <% end %>
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ # A cell to display a comments section for a commentable object.
6
+ class CommentsCell < Decidim::ViewModel
7
+ include Decidim::IconHelper
8
+
9
+ delegate :user_signed_in?, to: :controller
10
+
11
+ def add_comment
12
+ return if single_comment?
13
+ return if comments_blocked?
14
+ return if user_comments_blocked?
15
+
16
+ render :add_comment
17
+ end
18
+
19
+ def single_comment_warning
20
+ return unless single_comment?
21
+
22
+ render :single_comment_warning
23
+ end
24
+
25
+ def comments_loading
26
+ return if single_comment?
27
+
28
+ render :comments_loading
29
+ end
30
+
31
+ def blocked_comments_warning
32
+ return unless comments_blocked?
33
+ return unless user_comments_blocked?
34
+
35
+ render :blocked_comments_warning
36
+ end
37
+
38
+ def user_comments_blocked_warning
39
+ return if comments_blocked? # Shows already the general warning
40
+ return unless user_comments_blocked?
41
+
42
+ render :user_comments_blocked_warning
43
+ end
44
+
45
+ private
46
+
47
+ def decidim_comments
48
+ Decidim::Comments::Engine.routes.url_helpers
49
+ end
50
+
51
+ def comments
52
+ single_comment? ? [single_comment] : []
53
+ end
54
+
55
+ def comments_count
56
+ model.comments_count
57
+ end
58
+
59
+ def root_depth
60
+ return 0 unless single_comment?
61
+
62
+ single_comment.depth
63
+ end
64
+
65
+ def commentable_path(params = {})
66
+ return resource_locator(Array(options[:polymorphic]).push(model)).path(params) if options[:polymorphic]
67
+
68
+ resource_locator(model).path(params)
69
+ end
70
+
71
+ def alignment_enabled?
72
+ model.comments_have_alignment?
73
+ end
74
+
75
+ def available_orders
76
+ %w(best_rated recent older most_discussed)
77
+ end
78
+
79
+ def order
80
+ options[:order] || "older"
81
+ end
82
+
83
+ def decidim
84
+ Decidim::Core::Engine.routes.url_helpers
85
+ end
86
+
87
+ def node_id
88
+ "comments-for-#{commentable_type.demodulize}-#{model.id}"
89
+ end
90
+
91
+ def threads_node_id
92
+ "#{node_id}-threads"
93
+ end
94
+
95
+ def commentable_type
96
+ model.commentable_type
97
+ end
98
+
99
+ def comments_data
100
+ {
101
+ singleComment: single_comment?,
102
+ toggleTranslations: machine_translations_toggled?,
103
+ commentableGid: model.to_signed_global_id.to_s,
104
+ commentsUrl: decidim_comments.comments_path,
105
+ rootDepth: root_depth,
106
+ order:,
107
+ pollingInterval: 300000
108
+ }
109
+ end
110
+
111
+ def single_comment?
112
+ single_comment.present?
113
+ end
114
+
115
+ def single_comment
116
+ return if options[:single_comment].blank?
117
+
118
+ @single_comment ||= SortedComments.for(model, id: options[:single_comment], order_by: order).first
119
+ end
120
+
121
+ def machine_translations_toggled?
122
+ options[:machine_translations] == true
123
+ end
124
+
125
+ def comments_blocked?
126
+ !model.accepts_new_comments?
127
+ end
128
+
129
+ def user_comments_blocked?
130
+ return false unless user_signed_in?
131
+
132
+ !model.user_allowed_to_comment?(current_user)
133
+ end
134
+
135
+ def comment_permissions?
136
+ [model, current_component].any? do |resource|
137
+ resource.try(:permissions).try(:[], "comment")
138
+ end
139
+ end
140
+
141
+ # action_authorization_link expects current_component to be available
142
+ def current_component
143
+ model.try(:component)
144
+ end
145
+
146
+ def blocked_comments_for_unauthorized_user_warning_link
147
+ options = if current_component.present?
148
+ { resource: model }
149
+ else
150
+ { resource: model, permissions_holder: model }
151
+ end
152
+ action_authorized_link_to(:comment, commentable_path, options) do
153
+ t("decidim.components.comments.blocked_comments_for_unauthorized_user_warning")
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,3 @@
1
+ <section id="feeds" class="home__section feeds">
2
+ <%= render partial: "decidim/posts/posts/index.html" %>
3
+ </section>
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ module ContentBlocks
6
+ class PostsCell < Decidim::ViewModel
7
+ include Cell::ViewModel::Partial
8
+ include FormFactory
9
+
10
+ def show
11
+ @posts = Decidim::Posts::Post
12
+ .where(decidim_component_id: component_id)
13
+ .filter_category(params[:filter_post_category])
14
+ .order(created_at: :desc)
15
+ .limit(10)
16
+ extra_context = {
17
+ current_component: component,
18
+ current_organization: component.organization,
19
+ current_user:,
20
+ current_participatory_space: component.participatory_space
21
+ }
22
+ @form = form(Decidim::Posts::PostForm).from_params(params, extra_context)
23
+ render :show
24
+ end
25
+
26
+ def decidim_feeds
27
+ Decidim::EngineRouter.main_proxy(component)
28
+ end
29
+
30
+ def posts_path
31
+ decidim_feeds.posts_path
32
+ end
33
+
34
+ private
35
+
36
+ def component_id
37
+ @component_id ||= model.settings.try(:component_id)
38
+ end
39
+
40
+ def component
41
+ @component ||= Decidim::Component.find(component_id)
42
+ end
43
+
44
+ def post_creation_params
45
+ params[:post]
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,3 @@
1
+ <% form.fields_for :settings, form.object.settings do |settings_fields| %>
2
+ <%= settings_fields.select :component_id, available_feeds_options, prompt: "", label: t(".component") %>
3
+ <% end %>
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ module ContentBlocks
6
+ class PostsSettingsFormCell < Decidim::ViewModel
7
+ # Found in HighlightedElementsForComponentSettingsFormCell
8
+ #include Decidim::ContentBlocks::HasRelatedComponents
9
+ alias form model
10
+
11
+ def available_feeds_options
12
+ available_feeds.map do |component|
13
+ [translated_attribute(component.name), component.id]
14
+ end
15
+ end
16
+
17
+ def available_feeds
18
+ @available_feeds ||= Decidim::Component.where(manifest_name: "posts").where(participatory_space_id: current_organization.participatory_spaces.pluck(:id))
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ class FeedDropdownMetadataCell < Decidim::ParticipatorySpaceDropdownMetadataCell
6
+ # include FeedsHelper
7
+ include Decidim::ComponentPathHelper
8
+ include ActiveLinkTo
9
+
10
+ def decidim_feeds
11
+ Decidim::Posts::Engine.routes.url_helpers
12
+ end
13
+
14
+ private
15
+
16
+ def nav_items_method = :assembly_nav_items
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,65 @@
1
+ <article class="card__grid posts__post" data-content="calendar">
2
+ <%= cell("decidim/posts/post_header", meeting) %>
3
+ <div class="flex gap-4 py-2 px-2">
4
+ <div class="card__grid-text--meta flex flex-col gap-2">
5
+ <time class="card__calendar" datetime="<%= meeting.start_time.iso8601 %>">
6
+ <span class="card__calendar-month"><%= l(meeting.start_time, format: "%b") %></span>
7
+ <span class="card__calendar-day"><%= l(meeting.start_time, format: "%d") %></span>
8
+ <span class="card__calendar-year"><%= l(meeting.start_time, format: "%Y") %></span>
9
+ </time>
10
+ <% if meeting.start_time.to_date != meeting.end_time.to_date %>
11
+ <span class="self-center font-bold text-xs"><%= t("decidim.components.posts.calendar.date_separator") %></span>
12
+ <time class="card__calendar" datetime="<%= meeting.end_time.iso8601 %>">
13
+ <span class="card__calendar-month"><%= l(meeting.end_time, format: "%b") %></span>
14
+ <span class="card__calendar-day"><%= l(meeting.end_time, format: "%d") %></span>
15
+ <span class="card__calendar-year"><%= l(meeting.end_time, format: "%Y") %></span>
16
+ </time>
17
+ <% end %>
18
+ </div>
19
+ <div class="card__grid-text p-0">
20
+ <h2 class="h3"><%= link_to meeting_title, Decidim::EngineRouter.main_proxy(meeting.component).meeting_path(meeting) %></h2>
21
+ <% should_truncate = strip_tags(meeting_description).length > 300 %>
22
+ <div class="content-block__description editor-content" <%= "data-component='accordion'" if should_truncate %>>
23
+ <% if should_truncate %>
24
+ <% seed = SecureRandom.hex(4) %>
25
+ <div id="panel-view-more-<%= seed %>" aria-hidden="true">
26
+ <%= meeting_description %>
27
+ </div>
28
+ <button class="button button__sm button__text-secondary mt-2" data-controls="panel-view-more-<%= seed %>" aria-expanded="false">
29
+ <span>
30
+ <%= t("view_more", scope: "layouts.decidim.announcements") %>
31
+ </span>
32
+ <%= icon "arrow-down-s-line" %>
33
+ <span>
34
+ <%= t("view_less", scope: "layouts.decidim.announcements") %>
35
+ </span>
36
+ <%= icon "arrow-up-s-line" %>
37
+ </button>
38
+ <% else %>
39
+ <%= meeting_description %>
40
+ <% end %>
41
+ </div>
42
+ <div class="flex gap-4 mt-auto flex-wrap">
43
+ <div class="bg-background p-2 rounded-md font-bold shrink">
44
+ <time datetime="<%= meeting.start_time.iso8601 %>">
45
+ <%= l(meeting.start_time, format: "%H:%M") %>
46
+ </time>
47
+ </time>
48
+ <% if meeting.start_time != meeting.end_time %>
49
+ <%= t("decidim.components.posts.calendar.end_time") %>
50
+ <time datetime="<%= meeting.end_time.iso8601 %>">
51
+ <%= l(meeting.end_time, format: "%H:%M") %>
52
+ </time>
53
+ <% end %>
54
+ </div>
55
+ <% if meeting_location != '' %>
56
+ <div class="bg-background p-2 rounded-md font-bold shrink">
57
+ <%= meeting_location %>
58
+ </div>
59
+ <% end %>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ <%= cell("decidim/posts/post_comment", meeting) %>
64
+ <%= cell("decidim/posts/post_metadata", meeting) %>
65
+ </article>
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ class MeetingCell < Decidim::ViewModel
6
+ include PostCellsHelper
7
+ include Decidim::Meetings::MeetingCellsHelper
8
+ include Cell::ViewModel::Partial
9
+
10
+ def show
11
+ render :show
12
+ end
13
+
14
+ def meeting
15
+ model
16
+ end
17
+
18
+ def meeting_author
19
+ model.decidim_author_id
20
+ end
21
+
22
+ def meeting_title
23
+ translated_attribute model.title
24
+ end
25
+
26
+ def meeting_description
27
+ translated_attribute model.description
28
+ end
29
+
30
+ def meeting_address
31
+ model.address
32
+ end
33
+
34
+ def meeting_location
35
+ translated_attribute model.location
36
+ end
37
+
38
+ def comments_enabled
39
+ model.comments_enabled?
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ <%= cell("decidim/posts/post_header", post) %>
2
+ <%= cell("decidim/posts/post_attachments", post) %>
3
+ <div class="card__grid-text">
4
+ <% should_truncate = strip_tags(post_body).length > 300 %>
5
+ <div class="content-block__description editor-content" <%= "data-component='accordion'" if should_truncate %>>
6
+ <% if should_truncate %>
7
+ <% seed = SecureRandom.hex(4) %>
8
+ <div id="panel-view-more-<%= seed %>" aria-hidden="true">
9
+ <%= post_body %>
10
+ </div>
11
+ <button class="button button__sm button__text-secondary mt-2" data-controls="panel-view-more-<%= seed %>" aria-expanded="false">
12
+ <span>
13
+ <%= t("view_more", scope: "layouts.decidim.announcements") %>
14
+ </span>
15
+ <%= icon "arrow-down-s-line" %>
16
+ <span>
17
+ <%= t("view_less", scope: "layouts.decidim.announcements") %>
18
+ </span>
19
+ <%= icon "arrow-up-s-line" %>
20
+ </button>
21
+ <% else %>
22
+ <%= post_body %>
23
+ <% end %>
24
+ </div>
25
+ </div>
26
+ <% if post_category == 'survey' %>
27
+ <%= render :survey %>
28
+ <% end %>
29
+ <%= cell("decidim/posts/post_comment", post) %>
30
+ <%= cell("decidim/posts/post_metadata", post) %>
@@ -0,0 +1,68 @@
1
+ <div class="posts__post_survey" id="post_<%= post.id %>_survey">
2
+ <span class="text-right py-2">
3
+ <%= t("decidim.posts.survey.participated", count: post.survey_responses_count) %>
4
+ </span>
5
+ <% post.questions.each do |question| %>
6
+ <% if question.question_type == "single_choice" %>
7
+ <fieldset class="posts__post_survey-question">
8
+ <legend><%= translated_attribute question.title %></legend>
9
+ <% question.answers.each do |answer| %>
10
+ <div class="posts__post_survey-question-answer">
11
+ <div class="posts__post_survey-question-answerInput">
12
+ <%= radio_button_tag "post[questions][#{question.id}]", answer.id, answer.user_answers.find_by(decidim_posts_answer_id: answer.id, decidim_user_id: current_user.id).present?, class: "survey-answer-checkbox", data: { question_id: question.id, answer_id: answer.id } %>
13
+ <%= label_tag "post_questions_#{question.id}_#{answer.id}" do %>
14
+ <%= translated_attribute answer.title %>
15
+ <% end %>
16
+ </div>
17
+ <div class="posts__post_survey-question-answerProgressbar flex justify-between p-1 border border-gray rounded-full shadow-md">
18
+ <div class="w-full bg-background rounded-full">
19
+ <% percentage = post.survey_responses_count.zero? ? 0 : (answer.user_answers.count.to_f / post.survey_responses_count) * 100 %>
20
+ <div id="answer-<%= answer.id %>-progressbar" class="bg-success h-full rounded-full shadow-md" style="width: <%= percentage %>%"></div>
21
+ </div>
22
+ <span class="text-sm shrink-0 px-2">
23
+ <span id="answer-<%= answer.id %>-counter">
24
+ <%= answer.user_answers.count %>
25
+ </span>
26
+ /
27
+ <span id="answer-<%= answer.id %>-total">
28
+ <%= post.survey_responses_count %>
29
+ </span>
30
+ <span class="sr-only">haben geantwortet</span>
31
+ </span>
32
+ </div>
33
+ </div>
34
+ <% end %>
35
+ </fieldset>
36
+ <% elsif question.question_type == "multiple_choice" %>
37
+ <fieldset class="posts__post_survey-question">
38
+ <legend><%= translated_attribute question.title %></legend>
39
+ <% question.answers.each do |answer| %>
40
+ <div class="posts__post_survey-question-answer">
41
+ <div class="posts__post_survey-question-answerInput">
42
+ <%= check_box_tag "post[questions][#{question.id}][#{answer.id}]", answer.id, answer.user_answers.find_by(decidim_posts_answer_id: answer.id, decidim_user_id: current_user.id).present?, class: "survey-answer-checkbox", data: { question_id: question.id, answer_id: answer.id } %>
43
+ <%= label_tag "post_questions_#{question.id}_#{answer.id}" do %>
44
+ <%= translated_attribute answer.title %>
45
+ <% end %>
46
+ </div>
47
+ <div class="posts__post_survey-question-answerProgressbar flex justify-between p-1 border border-gray rounded-full shadow-md">
48
+ <div class="w-full bg-background rounded-full">
49
+ <% percentage = post.survey_responses_count.zero? ? 0 : (answer.user_answers.count.to_f / post.survey_responses_count) * 100 %>
50
+ <div id="answer-<%= answer.id %>-progressbar" class="bg-success h-full rounded-full shadow-md" style="width: <%= percentage %>%"></div>
51
+ </div>
52
+ <span class="text-sm shrink-0 px-2">
53
+ <span id="answer-<%= answer.id %>-counter">
54
+ <%= answer.user_answers.count %>
55
+ </span>
56
+ /
57
+ <span id="answer-<%= answer.id %>-total">
58
+ <%= post.survey_responses_count %>
59
+ </span>
60
+ <span class="sr-only">haben geantwortet</span>
61
+ </span>
62
+ </div>
63
+ </div>
64
+ <% end %>
65
+ </fieldset>
66
+ <% end %>
67
+ <% end %>
68
+ </div>
@@ -0,0 +1,40 @@
1
+ <% if post.attachments.any? %>
2
+ <div class="feeds__attachments py-4 px-2">
3
+
4
+ <div class="flex flex-col items-center">
5
+ <ul id="galleryItems_<%= post.id %>" class="posts__post_gallery flex overflow-hidden">
6
+ <% post.attachments.select { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) }.each_with_index do |attachment, index| %>
7
+ <li class="<%= attachment.url.match(/\.(mp4|webm)$/i) ? 'video' : 'image' %> <%= index.zero? ? 'active' : '' %> aspect-4/3 overflow-hidden flex justify-center items-center" data-src="<%= attachment.url %>">
8
+ <% if attachment.url.match(/\.(mp4|webm)$/i) %>
9
+ <%= video_tag(attachment.url, class: "object-cover w-full h-full", controls: true, preload: "auto") %>
10
+ <% else %>
11
+ <div class="w-full h-full flex justify-center items-center">
12
+ <%= image_tag(attachment.url, class: "max-w-full max-h-full object-contain", alt: translated_attribute(attachment.title), width: '400px', height: '300px' ) %>
13
+ </div>
14
+ <% end %>
15
+ </li>
16
+ <% end %>
17
+ </ul>
18
+ <% if post.attachments.select { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) }.count > 1 %>
19
+ <div id="navDots_<%= post.id %>" class="nav-dots p-1 flex flex-wrap justify-center">
20
+ <% total = post.attachments.select { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) }.count %>
21
+ <% post.attachments.select { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) }.each_with_index do |_, index| %>
22
+ <div class="posts__post_gallery_nav_dot flex justify-center items-center cursor-pointer h-6 w-6" role="button" aria-label="<%= t('decidim.components.posts.gallery.navigation', number: index + 1, total: total) %>" data-target="galleryItems_<%= post.id %>" data-index="<%= index %>">
23
+ <span class="h-2 w-2 rounded-full ring-1 ring-offset-1 ring-feeds-notification <%= index.zero? ? 'bg-feeds-notification' : '' %>"></span>
24
+ </div>
25
+ <% end %>
26
+ </div>
27
+ <% end %>
28
+ </div>
29
+ <% non_media_attachments = post.attachments.reject { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) } %>
30
+ <% if non_media_attachments.any? %>
31
+ <ul class="document-list space-y-2 mt-4">
32
+ <% non_media_attachments.each_with_index do |attachment, index| %>
33
+ <li class="<%= index.even? ? 'bg-feeds-formBody' : '' %> py-1 pl-2 pr-4 flex gap-1 items-center">
34
+ <%= icon "file-2-line" %> <%= link_to File.basename(attachment.url), attachment.url, class: 'text-sm break-all', style: 'overflow-wrap: break-word' %>
35
+ </li>
36
+ <% end %>
37
+ </ul>
38
+ <% end %>
39
+ </div>
40
+ <% end %>
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ class PostAttachmentsCell < Decidim::ViewModel
6
+ include Cell::ViewModel::Partial
7
+ def show
8
+ render :show
9
+ end
10
+
11
+ def post
12
+ model
13
+ end
14
+
15
+ end
16
+ end
17
+ end