diff --git a/app/components/admin/poll/officers/officers_component.html.erb b/app/components/admin/poll/officers/officers_component.html.erb
new file mode 100644
index 000000000..baf93a50f
--- /dev/null
+++ b/app/components/admin/poll/officers/officers_component.html.erb
@@ -0,0 +1,36 @@
+<%= tag.table options do %>
+
+
+ | <%= t("admin.poll_officers.officer.name") %> |
+ <%= t("admin.poll_officers.officer.email") %> |
+ <%= t("admin.actions.actions") %> |
+
+
+
+ <% officers.each do |officer| %>
+
+ |
+ <%= officer.name %>
+ |
+
+ <%= officer.email %>
+ |
+
+ <% if officer.persisted? %>
+ <%= render Admin::TableActionsComponent.new(officer,
+ actions: [:destroy],
+ destroy_text: t("admin.poll_officers.officer.delete")
+ ) %>
+ <% else %>
+ <%= render Admin::TableActionsComponent.new(actions: []) do |actions| %>
+ <%= actions.link_to t("admin.poll_officers.officer.add"),
+ add_user_path(officer),
+ method: :post,
+ class: "button success expanded" %>
+ <% end %>
+ <% end %>
+ |
+
+ <% end %>
+
+<% end %>
diff --git a/app/components/admin/poll/officers/officers_component.rb b/app/components/admin/poll/officers/officers_component.rb
new file mode 100644
index 000000000..c9972a641
--- /dev/null
+++ b/app/components/admin/poll/officers/officers_component.rb
@@ -0,0 +1,18 @@
+class Admin::Poll::Officers::OfficersComponent < ApplicationComponent
+ attr_reader :officers, :options
+
+ def initialize(officers, **options)
+ @officers = officers
+ @options = options
+ end
+
+ private
+
+ def add_user_path(officer)
+ {
+ controller: "admin/poll/officers",
+ action: :create,
+ user_id: officer.user_id
+ }
+ end
+end
diff --git a/app/views/admin/poll/officers/_officer.html.erb b/app/views/admin/poll/officers/_officer.html.erb
index dd3202e7d..e026254b0 100644
--- a/app/views/admin/poll/officers/_officer.html.erb
+++ b/app/views/admin/poll/officers/_officer.html.erb
@@ -1,33 +1 @@
-
-
-
- | <%= t("admin.poll_officers.officer.name") %> |
- <%= t("admin.poll_officers.officer.email") %> |
- <%= t("admin.actions.actions") %> |
-
-
-
-
- |
- <%= officer.name %>
- |
-
- <%= officer.email %>
- |
-
- <% if officer.persisted? %>
- <%= render Admin::TableActionsComponent.new(officer,
- actions: [:destroy],
- destroy_text: t("admin.poll_officers.officer.delete")
- ) %>
- <% else %>
- <%= render Admin::TableActionsComponent.new(actions: []) do |actions| %>
- <%= actions.link_to t("admin.poll_officers.officer.add"), { controller: "admin/poll/officers", action: :create, user_id: officer.user_id },
- method: :post,
- class: "button success expanded" %>
- <% end %>
- <% end %>
- |
-
-
-
+<%= render Admin::Poll::Officers::OfficersComponent.new([officer]) %>
diff --git a/app/views/admin/poll/officers/index.html.erb b/app/views/admin/poll/officers/index.html.erb
index 1e2b4e144..c6b5caf74 100644
--- a/app/views/admin/poll/officers/index.html.erb
+++ b/app/views/admin/poll/officers/index.html.erb
@@ -11,43 +11,7 @@
<% if @officers.any? %>
-
-
-
- | <%= t("admin.poll_officers.officer.name") %> |
- <%= t("admin.poll_officers.officer.email") %> |
- <%= t("admin.actions.actions") %> |
-
-
-
- <% @officers.each do |officer| %>
-
- |
- <%= officer.name %>
- |
-
- <%= officer.email %>
- |
-
- <% if officer.persisted? %>
- <%= render Admin::TableActionsComponent.new(officer,
- actions: [:destroy],
- destroy_text: t("admin.poll_officers.officer.delete")
- ) %>
- <% else %>
- <%= render Admin::TableActionsComponent.new(actions: []) do |actions| %>
- <%= actions.link_to t("admin.poll_officers.officer.add"),
- { controller: "admin/poll/officers", action: :create,
- user_id: officer.user_id },
- method: :post,
- class: "button success expanded" %>
- <% end %>
- <% end %>
- |
-
- <% end %>
-
-
+ <%= render Admin::Poll::Officers::OfficersComponent.new(@officers, id: "officers") %>
<%= paginate @officers %>
<% end %>
diff --git a/spec/components/admin/poll/officers/officers_component_spec.rb b/spec/components/admin/poll/officers/officers_component_spec.rb
new file mode 100644
index 000000000..5d8e9a79a
--- /dev/null
+++ b/spec/components/admin/poll/officers/officers_component_spec.rb
@@ -0,0 +1,35 @@
+require "rails_helper"
+
+describe Admin::Poll::Officers::OfficersComponent, type: :component do
+ let(:existing_officer) { create(:poll_officer, name: "Old officer") }
+ let(:new_officer) { build(:poll_officer, name: "New officer") }
+ let(:officers) { [existing_officer, new_officer] }
+ let(:component) { Admin::Poll::Officers::OfficersComponent.new(officers) }
+
+ it "renders as many rows as officers" do
+ within "tbody" do
+ expect(page).to have_css "tr", count: 2
+ expect(page).to have_css "a", count: 2
+ end
+ end
+
+ it "renders link to destroy for existing officers" do
+ render_inline component
+ row = page.find("tr", text: "Old officer")
+
+ expect(row).to have_css "a[data-method='delete']", text: "Delete"
+ end
+
+ it "renders link to add for new officers" do
+ render_inline component
+ row = page.find("tr", text: "New officer")
+
+ expect(row).to have_css "a[data-method='post']", text: "Add"
+ end
+
+ it "accepts table options" do
+ render_inline Admin::Poll::Officers::OfficersComponent.new(officers, class: "my-officers-table")
+
+ expect(page).to have_css "table.my-officers-table"
+ end
+end