Skip to content

Commit

Permalink
Merge pull request #5865 from MadelineCollier/admin-user-creation-mod…
Browse files Browse the repository at this point in the history
…ification

[Admin] Add new users admin addresses page
  • Loading branch information
MadelineCollier authored Oct 11, 2024
2 parents 3a92a45 + 53f4b28 commit 489e527
Show file tree
Hide file tree
Showing 9 changed files with 324 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<%= page do %>
<%= page_header do %>
<%= page_header_back(solidus_admin.users_path) %>
<%= page_header_title(t(".title", email: @user.email)) %>
<%= page_header_actions do %>
<%= render component("ui/button").new(tag: :a, text: t(".create_order_for_user"), href: spree.new_admin_order_path(user_id: @user.id)) %>
<% end %>
<% end %>
<%= page_header do %>
<% tabs.each do |tab| %>
<%= render(component("ui/button").new(tag: :a, scheme: :ghost, text: tab[:text], 'aria-current': tab[:current], href: tab[:href])) %>
<% end %>
<% end %>
<%= page_with_sidebar do %>
<%= page_with_sidebar_main do %>
<%= render component('ui/panel').new(title: t(".billing_address")) do %>
<%= form_for @user, url: solidus_admin.update_addresses_user_path(@user), method: :put, html: { id: "#{form_id}_billing", autocomplete: "off", class: "bill_address" } do |f| %>
<%= render component('ui/forms/address').new(address: @bill_address, name: "user[bill_address_attributes]") %>
<div class="py-1.5 text-center">
<%= render component("ui/button").new(tag: :button, text: t(".update"), form: "#{form_id}_billing") %>
<%= render component("ui/button").new(tag: :a, text: t(".cancel"), href: solidus_admin.addresses_user_path(@user), scheme: :secondary) %>
</div>
<% end %>
<% end %>
<%= render component('ui/panel').new(title: t(".shipping_address")) do %>
<%= form_for @user, url: solidus_admin.update_addresses_user_path(@user), method: :put, html: { id: "#{form_id}_shipping", autocomplete: "off", class: "ship_address" } do |f| %>
<%= render component('ui/forms/address').new(address: @ship_address, name: "user[ship_address_attributes]") %>
<div class="py-1.5 text-center">
<%= render component("ui/button").new(tag: :button, text: t(".update"), form: "#{form_id}_shipping") %>
<%= render component("ui/button").new(tag: :a, text: t(".cancel"), href: solidus_admin.addresses_user_path(@user), scheme: :secondary) %>
</div>
<% end %>
<% end %>
<% end %>
<%= page_with_sidebar_aside do %>
<%= render component("ui/panel").new(title: t("spree.lifetime_stats")) do %>
<%= render component("ui/details_list").new(
items: [
{ label: t("spree.total_sales"), value: @user.display_lifetime_value.to_html },
{ label: t("spree.order_count"), value: @user.order_count.to_i },
{ label: t("spree.average_order_value"), value: @user.display_average_order_value.to_html },
{ label: t("spree.member_since"), value: @user.created_at.to_date },
{ label: t(".last_active"), value: last_login(@user) },
]
) %>
<% end %>
<% end %>
<% end %>
<% end %>
72 changes: 72 additions & 0 deletions admin/app/components/solidus_admin/users/addresses/component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# frozen_string_literal: true

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

def initialize(user:, address: nil, type: nil)
@user = user
@bill_address = bill_address(address, type)
@ship_address = ship_address(address, type)
end

def form_id
@form_id ||= "#{stimulus_id}--form-#{@user.id}"
end

def tabs
[
{
text: t('.account'),
href: solidus_admin.user_path(@user),
current: false,
},
{
text: t('.addresses'),
href: solidus_admin.addresses_user_path(@user),
current: true,
},
{
text: t('.order_history'),
href: spree.orders_admin_user_path(@user),
current: false,
},
{
text: t('.items'),
href: spree.items_admin_user_path(@user),
current: false,
},
{
text: t('.store_credit'),
href: spree.admin_user_store_credits_path(@user),
current: false,
},
]
end

def last_login(user)
return t('.last_login.never') if user.try(:last_sign_in_at).blank?

t(
'.last_login.login_time_ago',
# @note The second `.try` is here for the specs and for setups that use a
# custom User class which may not have this attribute.
last_login_time: time_ago_in_words(user.try(:last_sign_in_at))
).capitalize
end

def bill_address(address, type)
if address.present? && type == "bill"
address
else
@user.bill_address || Spree::Address.build_default
end
end

def ship_address(address, type)
if address.present? && type == "ship"
address
else
@user.ship_address || Spree::Address.build_default
end
end
end
18 changes: 18 additions & 0 deletions admin/app/components/solidus_admin/users/addresses/component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
en:
title: "Users / %{email} / Addresses"
account: Account
addresses: Addresses
order_history: Order History
items: Items
store_credit: Store Credit
last_active: Last Active
last_login:
login_time_ago: "%{last_login_time} ago"
never: Never
invitation_sent: Invitation sent
create_order_for_user: Create order for this user
update: Update
cancel: Cancel
back: Back
billing_address: Billing Address
shipping_address: Shipping Address
15 changes: 7 additions & 8 deletions admin/app/components/solidus_admin/users/edit/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,31 @@ def tabs
[
{
text: t('.account'),
href: solidus_admin.users_path,
current: action_name == "show",
href: solidus_admin.user_path(@user),
current: action_name == "edit",
},
{
text: t('.addresses'),
href: spree.addresses_admin_user_path(@user),
# @todo: update this "current" logic once folded into new admin
current: action_name != "show",
href: solidus_admin.addresses_user_path(@user),
current: action_name == "addresses",
},
{
text: t('.order_history'),
href: spree.orders_admin_user_path(@user),
# @todo: update this "current" logic once folded into new admin
current: action_name != "show",
current: action_name != "edit",
},
{
text: t('.items'),
href: spree.items_admin_user_path(@user),
# @todo: update this "current" logic once folded into new admin
current: action_name != "show",
current: action_name != "edit",
},
{
text: t('.store_credit'),
href: spree.admin_user_store_credits_path(@user),
# @todo: update this "current" logic once folded into new admin
current: action_name != "show",
current: action_name != "edit",
},
]
end
Expand Down
49 changes: 46 additions & 3 deletions admin/app/controllers/solidus_admin/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
module SolidusAdmin
class UsersController < SolidusAdmin::BaseController
include SolidusAdmin::ControllerHelpers::Search
include Spree::Core::ControllerHelpers::StrongParameters

before_action :set_user, only: [:edit, :addresses, :update_addresses]

search_scope(:all, default: true)
search_scope(:customers) { _1.left_outer_joins(:role_users).where(role_users: { id: nil }) }
Expand All @@ -23,9 +26,31 @@ def index
end
end

def edit
set_user
def addresses
respond_to do |format|
format.turbo_stream { render turbo_stream: '<turbo-stream action="refresh" />' }
format.html { render component('users/addresses').new(user: @user) }
end
end

def update_addresses
set_address_from_params

if @address.valid? && @user.update(user_params)
flash[:success] = t(".#{@type}.success")

respond_to do |format|
format.turbo_stream { render turbo_stream: '<turbo-stream action="refresh" />' }
format.html { render component('users/addresses').new(user: @user) }
end
else
respond_to do |format|
format.html { render component('users/addresses').new(user: @user, address: @address, type: @type), status: :unprocessable_entity }
end
end
end

def edit
respond_to do |format|
format.html { render component('users/edit').new(user: @user) }
end
Expand All @@ -47,7 +72,25 @@ def set_user
end

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

# @note This method is used to generate validation errors on the address.
# Since the update is being performed via the @user, and not directly on
# the @address, we sadly don't seem to get these errors automatically.
def set_address_from_params
if user_params.key?(:bill_address_attributes)
@address = Spree::Address.new(user_params[:bill_address_attributes])
@type = "bill"
elsif user_params.key?(:ship_address_attributes)
@address = Spree::Address.new(user_params[:ship_address_attributes])
@type = "ship"
end
end

def authorization_subject
Expand Down
6 changes: 6 additions & 0 deletions admin/config/locales/users.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ en:
title: "Users"
destroy:
success: "Users were successfully removed."
update_addresses:
bill:
success: "Billing Address has been successfully updated."
ship:
success: "Shipping Address has been successfully updated."
error: "Address could not be updated."
8 changes: 7 additions & 1 deletion admin/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,13 @@
end
end

admin_resources :users, only: [:index, :edit, :destroy]
admin_resources :users, only: [:index, :edit, :destroy] do
member do
get :addresses
put :update_addresses
end
end

admin_resources :promotions, only: [:index, :destroy]
admin_resources :properties, only: [:index, :destroy]
admin_resources :option_types, only: [:index, :destroy], sortable: true
Expand Down
52 changes: 52 additions & 0 deletions admin/spec/features/users_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,56 @@
expect(page).not_to have_content("[email protected]")
end
end

context "when editing a user's addresses" do
before do
create(:user_with_addresses, email: "[email protected]")
visit "/admin/users"
find_row("[email protected]").click
click_on "Addresses"
end

it "shows the address page" do
expect(page).to have_content("Users / [email protected] / Addresses")
expect(page).to have_content("Lifetime Stats")
expect(page).to have_content("Billing Address")
expect(page).to be_axe_clean
end

it "allows editing of the existing address" do
# Invalid submission
within("form.ship_address") do
fill_in "Name", with: ""
fill_in "Street Address", with: ""
click_on "Update"
end
expect(page).to have_content("can't be blank").twice

# Valid submission
within("form.bill_address") do
fill_in "Name", with: "Galadriel"
click_on "Update"
end
expect(page).to have_content("Billing Address has been successfully updated.")

# Valid submission
within("form.ship_address") do
fill_in "Name", with: "Elrond"
click_on "Update"
end
expect(page).to have_content("Shipping Address has been successfully updated.")

# Cancel submission
within("form.bill_address") do
fill_in "Name", with: "Smeagol"
click_on "Cancel"
end
expect(page).to have_content("Users / [email protected] / Addresses")
expect(page).not_to have_content("Smeagol")

# The address forms weirdly only have values rather than actual text on the page.
expect(page).to have_field("user[bill_address_attributes][name]", with: "Galadriel")
expect(page).to have_field("user[ship_address_attributes][name]", with: "Elrond")
end
end
end
Loading

0 comments on commit 489e527

Please sign in to comment.