Skip to content

Commit 9276214

Browse files
Add new users admin edit page
This migrates the `users/:id/edit` page to the new admin. It still relies on the old backend admin controller for the `#update` action as well as the other top level user tabs such as address, order history, and so on. Co-authored-by: benjamin wil <[email protected]>
1 parent 0f77e8b commit 9276214

File tree

13 files changed

+348
-3
lines changed

13 files changed

+348
-3
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<%= render component('ui/panel').new(title: t('.api_access')) do %>
2+
<section>
3+
<% if @user.spree_api_key.present? %>
4+
<div id="current-api-key">
5+
<h2 class="py-1.5 font-semibold"><%= t('.key') %></h2>
6+
<% if @user == helpers.current_solidus_admin_user %>
7+
<%= @user.spree_api_key %>
8+
<% else %>
9+
<i>(<%= t('spree.hidden') %>)</i>
10+
<% end %>
11+
</div>
12+
13+
<div class="py-1.5 text-center">
14+
<%= form_with url: spree.admin_user_api_key_path(@user), method: :delete, local: true, html: { class: 'clear_api_key inline-flex' } do %>
15+
<%= render component("ui/button").new(
16+
text: t('.clear_key'),
17+
scheme: :secondary,
18+
type: :submit,
19+
"data-action": "click->#{stimulus_id}#confirm",
20+
"data-#{stimulus_id}-message-param": t(".confirm_clear_key"),
21+
) %>
22+
<% end %>
23+
24+
<%= form_with url: spree.admin_user_api_key_path(@user), method: :post, local: true, html: { class: 'regen_api_key inline-flex' } do %>
25+
<%= render component("ui/button").new(
26+
text: t('.regenerate_key'),
27+
scheme: :secondary,
28+
type: :submit,
29+
"data-action": "click->#{stimulus_id}#confirm",
30+
"data-#{stimulus_id}-message-param": t(".confirm_regenerate_key"),
31+
) %>
32+
<% end %>
33+
</div>
34+
35+
<% else %>
36+
<div class="no-objects-found"><%= t('.no_key') %></div>
37+
<div class="filter-actions actions">
38+
<div class="py-1.5 text-center">
39+
<%= form_with url: spree.admin_user_api_key_path(@user), method: :post, local: true, html: { class: 'generate_api_key inline-flex' } do %>
40+
<%= render component("ui/button").new(
41+
text: t('.generate_key'),
42+
type: :submit,
43+
) %>
44+
<% end %>
45+
</div>
46+
</div>
47+
<% end %>
48+
</section>
49+
<% end %>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Controller } from "@hotwired/stimulus"
2+
3+
export default class extends Controller {
4+
confirm(event) {
5+
if (!confirm(event.params.message)) {
6+
event.preventDefault()
7+
}
8+
}
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
class SolidusAdmin::Users::Edit::ApiAccess::Component < SolidusAdmin::BaseComponent
4+
def initialize(user:)
5+
@user = user
6+
end
7+
end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
en:
2+
api_access: API Access
3+
no_key: No key
4+
key: "Key"
5+
generate_key: Generate API key
6+
clear_key: Clear key
7+
regenerate_key: Regenerate key
8+
hidden: Hidden
9+
confirm_clear_key: Are you sure you want to clear this user's API key? It will invalidate the existing key.
10+
confirm_regenerate_key: Are you sure you want to regenerate this user's API key? It will invalidate the existing key.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<%= page do %>
2+
<%= page_header do %>
3+
<%= page_header_back(solidus_admin.users_path) %>
4+
<%= page_header_title(t(".title", email: @user.email)) %>
5+
6+
<% # @todo: I am not sure how we want to handle Cancan stuff in the new admin. %>
7+
<% # if can?(:admin, Spree::Order) && can?(:create, Spree::Order) %>
8+
<%= page_header_actions do %>
9+
<%= render component("ui/button").new(tag: :a, text: t(".create_order_for_user"), href: spree.new_admin_order_path(user_id: @user.id)) %>
10+
<% end %>
11+
<% # end %>
12+
<% end %>
13+
14+
<%= page_header do %>
15+
<% tabs.each do |tab| %>
16+
<%= render(component("ui/button").new(tag: :a, scheme: :ghost, text: tab[:text], 'aria-current': tab[:current], href: tab[:href])) %>
17+
<% end %>
18+
<% end %>
19+
20+
<%= page_with_sidebar do %>
21+
<%= page_with_sidebar_main do %>
22+
23+
<%= render component('ui/panel').new(title: Spree.user_class.model_name.human) do %>
24+
<%= form_for @user, url: solidus_admin.user_path(@user), html: { id: form_id } do |f| %>
25+
<div class="py-1.5">
26+
<%= render component("ui/forms/field").text_field(f, :email) %>
27+
</div>
28+
<div class="py-1.5">
29+
<%= render component("ui/forms/field").text_field(f, :password) %>
30+
</div>
31+
<div class="py-1.5">
32+
<%= render component("ui/forms/field").text_field(f, :password_confirmation) %>
33+
</div>
34+
<div class="py-1.5">
35+
<%= render component("ui/checkbox_row").new(options: role_options, row_title: "Roles", form: f, method: "spree_role_ids", layout: :subsection) %>
36+
</div>
37+
<div class="py-1.5 text-center">
38+
<%= render component("ui/button").new(tag: :button, text: t(".update"), form: form_id) %>
39+
<%= render component("ui/button").new(tag: :a, text: t(".cancel"), href: solidus_admin.user_path(@user), scheme: :secondary) %>
40+
</div>
41+
<% end %>
42+
<% end %>
43+
44+
<%= render component("users/edit/api_access").new(user: @user) %>
45+
46+
<% end %>
47+
48+
<%= page_with_sidebar_aside do %>
49+
<%= render component("ui/panel").new(title: t("spree.lifetime_stats")) do %>
50+
<%= render component("ui/details_list").new(
51+
items: [
52+
{ label: t("spree.total_sales"), value: @user.display_lifetime_value.to_html },
53+
{ label: t("spree.order_count"), value: @user.order_count.to_i },
54+
{ label: t("spree.average_order_value"), value: @user.display_average_order_value.to_html },
55+
{ label: t("spree.member_since"), value: @user.created_at.to_date },
56+
{ label: t(".last_active"), value: last_login(@user) },
57+
]
58+
) %>
59+
<% end %>
60+
<% end %>
61+
<% end %>
62+
<% end %>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# frozen_string_literal: true
2+
3+
class SolidusAdmin::Users::Edit::Component < SolidusAdmin::BaseComponent
4+
include SolidusAdmin::Layout::PageHelpers
5+
6+
def initialize(user:)
7+
@user = user
8+
end
9+
10+
def form_id
11+
@form_id ||= "#{stimulus_id}--form-#{@user.id}"
12+
end
13+
14+
def tabs
15+
[
16+
{
17+
text: t('.account'),
18+
href: solidus_admin.users_path,
19+
current: action_name == "show",
20+
},
21+
{
22+
text: t('.addresses'),
23+
href: spree.addresses_admin_user_path(@user),
24+
# @todo: update this "current" logic once folded into new admin
25+
current: action_name != "show",
26+
},
27+
{
28+
text: t('.order_history'),
29+
href: spree.orders_admin_user_path(@user),
30+
# @todo: update this "current" logic once folded into new admin
31+
current: action_name != "show",
32+
},
33+
{
34+
text: t('.items'),
35+
href: spree.items_admin_user_path(@user),
36+
# @todo: update this "current" logic once folded into new admin
37+
current: action_name != "show",
38+
},
39+
{
40+
text: t('.store_credit'),
41+
href: spree.admin_user_store_credits_path(@user),
42+
# @todo: update this "current" logic once folded into new admin
43+
current: action_name != "show",
44+
},
45+
]
46+
end
47+
48+
def last_login(user)
49+
return t('.last_login.never') if user.try(:last_sign_in_at).blank?
50+
51+
t(
52+
'.last_login.login_time_ago',
53+
# @note The second `.try` is only here for the specs to work.
54+
last_login_time: time_ago_in_words(user.try(:last_sign_in_at))
55+
).capitalize
56+
end
57+
58+
def role_options
59+
Spree::Role.all.map do |role|
60+
{ label: role.name, id: role.id }
61+
end
62+
end
63+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
en:
2+
title: "Users / %{email}"
3+
account: Account
4+
addresses: Addresses
5+
order_history: Order History
6+
items: Items
7+
store_credit: Store Credit
8+
last_active: Last Active
9+
last_login:
10+
login_time_ago: "%{last_login_time} ago"
11+
never: Never
12+
invitation_sent: Invitation sent
13+
create_order_for_user: Create order for this user
14+
update: Update
15+
cancel: Cancel
16+
back: Back

admin/app/components/solidus_admin/users/index/component.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def search_url
1414
end
1515

1616
def row_url(user)
17-
spree.admin_user_path(user)
17+
solidus_admin.edit_user_path(user)
1818
end
1919

2020
def page_actions

admin/app/controllers/solidus_admin/users_controller.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ def index
2323
end
2424
end
2525

26+
def edit
27+
set_user
28+
29+
respond_to do |format|
30+
format.html { render component('users/edit').new(user: @user) }
31+
end
32+
end
33+
2634
def destroy
2735
@users = Spree.user_class.where(id: params[:id])
2836

@@ -34,6 +42,10 @@ def destroy
3442

3543
private
3644

45+
def set_user
46+
@user = Spree.user_class.find(params[:id])
47+
end
48+
3749
def user_params
3850
params.require(:user).permit(:user_id, permitted_user_attributes)
3951
end

admin/config/routes.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
end
4646
end
4747

48-
admin_resources :users, only: [:index, :destroy]
48+
admin_resources :users, only: [:index, :edit, :destroy]
4949
admin_resources :promotions, only: [:index, :destroy]
5050
admin_resources :properties, only: [:index, :destroy]
5151
admin_resources :option_types, only: [:index, :destroy], sortable: true

0 commit comments

Comments
 (0)