Skip to content

Commit

Permalink
Merge pull request #5519 from solidusio/elia/admin/users/index
Browse files Browse the repository at this point in the history
[admin] Add users index
  • Loading branch information
elia authored Nov 28, 2023
2 parents 5dd0817 + 2830c38 commit 733eba1
Show file tree
Hide file tree
Showing 13 changed files with 262 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
url: ->(order) { spree.edit_admin_order_path(order) },
batch_actions: batch_actions,
columns: columns,
prev: prev_page_link,
next: next_page_link,
prev: prev_page_path,
next: next_page_path,
},
search: {
name: :q,
Expand Down
8 changes: 4 additions & 4 deletions admin/app/components/solidus_admin/orders/index/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ def title
Spree::Order.model_name.human.pluralize
end

def prev_page_link
@page.first? ? nil : solidus_admin.url_for(host: request.host, port: request.port, **request.params, page: @page.number - 1)
def prev_page_path
solidus_admin.url_for(**request.params, page: @page.number - 1, only_path: true) unless @page.first?
end

def next_page_link
@page.last? ? nil : solidus_admin.url_for(host: request.host, port: request.port, **request.params, page: @page.next_param)
def next_page_path
solidus_admin.url_for(**request.params, page: @page.next_param, only_path: true) unless @page.last?
end

def batch_actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
class: Spree::Product,
rows: @page.records,
url: ->(product) { solidus_admin.product_path(product) },
prev: prev_page_link,
next: next_page_link,
prev: prev_page_path,
next: next_page_path,
columns: columns,
batch_actions: batch_actions,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ def title
Spree::Product.model_name.human.pluralize
end

def prev_page_link
@page.first? ? nil : solidus_admin.url_for(host: request.host, port: request.port, **request.params, page: @page.number - 1)
def prev_page_path
solidus_admin.url_for(**request.params, page: @page.number - 1, only_path: true) unless @page.first?
end

def next_page_link
@page.last? ? nil : solidus_admin.url_for(host: request.host, port: request.port, **request.params, page: @page.next_param)
def next_page_path
solidus_admin.url_for(**request.params, page: @page.next_param, only_path: true) unless @page.last?
end

def batch_actions
Expand Down
34 changes: 34 additions & 0 deletions admin/app/components/solidus_admin/users/index/component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<%= page do %>
<%= page_header do %>
<%= page_header_title title %>
<%= page_header_actions do %>
<%= render component("ui/button").new(
tag: :a,
text: t('.add'),
href: spree.new_admin_user_path,
icon: "add-line",
) %>
<% end %>
<% end %>

<%= render component('ui/table').new(
id: stimulus_id,
data: {
class: Spree.user_class,
rows: @page.records,
url: ->(user) { spree.admin_user_path(user) },
prev: prev_page_path,
next: next_page_path,
columns: columns,
batch_actions: batch_actions,
},
search: {
name: :q,
value: params[:q],
url: solidus_admin.users_path,
searchbar_key: :email_cont,
filters: filters,
scopes: scopes,
},
) %>
<% end %>
89 changes: 89 additions & 0 deletions admin/app/components/solidus_admin/users/index/component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# frozen_string_literal: true

class SolidusAdmin::Users::Index::Component < SolidusAdmin::BaseComponent
include SolidusAdmin::Layout::PageHelpers

def initialize(page:)
@page = page
end

def title
Spree.user_class.model_name.human.pluralize
end

def prev_page_path
solidus_admin.url_for(**request.params, page: @page.number - 1, only_path: true) unless @page.first?
end

def next_page_path
solidus_admin.url_for(**request.params, page: @page.next_param, only_path: true) unless @page.last?
end

def batch_actions
[
{
display_name: t('.batch_actions.delete'),
action: solidus_admin.users_path,
method: :delete,
icon: 'delete-bin-7-line',
},
]
end

def filters
[
{
presentation: Spree::Role.model_name.human.pluralize,
attribute: "spree_roles_id",
predicate: "in",
options: Spree::Role.pluck(:name, :id)
}
]
end

def scopes
[
{ name: :customers, label: t('.scopes.customers'), default: true },
{ name: :admin, label: t('.scopes.admin') },
{ name: :with_orders, label: t('.scopes.with_orders') },
{ name: :without_orders, label: t('.scopes.without_orders') },
{ name: :all, label: t('.scopes.all') },
]
end

def columns
[
{
header: :email,
data: :email,
},
{
header: :roles,
data: ->(user) do
roles = user.spree_roles.presence || [Spree::Role.new(name: 'customer')]
safe_join(roles.map {
color =
case _1.name
when 'admin' then :blue
when 'customer' then :green
else :graphite_light
end
render component('ui/badge').new(name: _1.name, color: color)
})
end,
},
{
header: :order_count,
data: ->(user) { user.order_count },
},
{
header: :lifetime_value,
data: -> { _1.display_lifetime_value.to_html },
},
{
header: :created_at,
data: ->(user) { l(user.created_at.to_date, format: :long) },
},
]
end
end
18 changes: 18 additions & 0 deletions admin/app/components/solidus_admin/users/index/component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
en:
promotion_image: 'Image'
add: 'Add Promotion'
batch_actions:
delete: 'Delete'
discontinue: 'Discontinue'
activate: 'Activate'
filters:
with_deleted: Include deleted
scopes:
customers: Customers
admin: Admins
with_orders: With Orders
without_orders: Without Orders
all: All
status:
active: Active
inactive: Inactive
50 changes: 50 additions & 0 deletions admin/app/controllers/solidus_admin/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

module SolidusAdmin
class UsersController < SolidusAdmin::BaseController
include SolidusAdmin::ControllerHelpers::Search

search_scope(:customers, default: true) { _1.left_outer_joins(:role_users).where(role_users: { id: nil }) }
search_scope(:admin) { _1.joins(:role_users).distinct }
search_scope(:with_orders) { _1.joins(:orders).distinct }
search_scope(:without_orders) { _1.left_outer_joins(:orders).where(orders: { id: nil }) }
search_scope(:all)

def index
users = apply_search_to(
Spree.user_class.order(created_at: :desc, id: :desc),
param: :q,
)

set_page_and_extract_portion_from(users)

respond_to do |format|
format.html { render component('users/index').new(page: @page) }
end
end

def destroy
@users = Spree.user_class.where(id: params[:id])

Spree.user_class.transaction { @users.destroy_all }

flash[:notice] = t('.success')
redirect_back_or_to users_path, status: :see_other
end

private

def load_user
@user = Spree.user_class.find_by!(number: params[:id])
authorize! action_name, @user
end

def user_params
params.require(:user).permit(:user_id, permitted_user_attributes)
end

def authorization_subject
Spree.user_class
end
end
end
6 changes: 6 additions & 0 deletions admin/config/locales/users.en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
en:
solidus_admin:
users:
title: "Users"
destroy:
success: "Users were successfully removed."
6 changes: 6 additions & 0 deletions admin/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@
get :customers_for
end
end

resources :users, only: [:index] do
collection do
delete :destroy
end
end
end
2 changes: 1 addition & 1 deletion admin/spec/features/products_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
create(:product, name: "Another product", price: 29.99)

visit "/admin/products"
find('main tbody tr:nth-child(2)').find('input').check
select_row("Just a product")
click_button "Delete"

expect(page).to have_content("Products were successfully removed.", wait: 5)
Expand Down
34 changes: 34 additions & 0 deletions admin/spec/features/users_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

require 'spec_helper'

describe "Users", :js, type: :feature do
before { sign_in create(:admin_user, email: '[email protected]') }

it "lists users and allows deleting them" do
create(:user, email: "[email protected]")
create(:admin_user, email: "[email protected]")
create(:user, :with_orders, email: "[email protected]")

visit "/admin/users"
expect(page).to have_content("[email protected]")
expect(page).not_to have_content("[email protected]")
click_on "Admins"
expect(page).to have_content("[email protected]")
expect(page).not_to have_content("[email protected]")
click_on "With Orders"
expect(page).to have_content("[email protected]")
click_on "All"
expect(page).to have_content("[email protected]")
expect(page).to have_content("[email protected]")
expect(page).to have_content("[email protected]")

expect(page).to be_axe_clean

select_row("[email protected]")
click_on "Delete"
expect(page).to have_content("Users were successfully removed.")
expect(page).not_to have_content("[email protected]")
expect(Spree.user_class.count).to eq(3)
end
end
12 changes: 12 additions & 0 deletions admin/spec/support/solidus_admin/feature_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,17 @@ def stub_authorization!(user)
allow_any_instance_of(SolidusAdmin::BaseController).to receive(:current_ability).and_return(ability)
allow_any_instance_of(Spree::Admin::BaseController).to receive(:current_ability).and_return(ability)
end

def find_row(text)
find('table tbody tr', text: text)
end

def find_row_checkbox(text)
find_row(text).find('td:first-child input[type="checkbox"]')
end

def select_row(text)
find_row_checkbox(text).check
end
end
end

0 comments on commit 733eba1

Please sign in to comment.