-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This migrates the `users/:id/addresses` page to the new admin. Instead of squashing everything into one controller action with an `if request.put?` wrapper (like the legacy backend controller did), I chose to break this new admin into two actions separated by their methods and responsibilities. The old admin page did not have anything in the way of validations or error messages, it would simply fail to update the address and leave it as is if the user provided invalid values. (While also showing a message saying that the update was successful?) This page improves upon that flow, adding validations to the address forms when their values are invalid and preventing the update, but since we are submitting an update against the user and not the address directly, we still need to do some extra work to run the validations and generate errors for the form (rather than silently failing to update like the legacy back-end controller used to do).
- Loading branch information
1 parent
3a92a45
commit 53f4b28
Showing
9 changed files
with
324 additions
and
13 deletions.
There are no files selected for viewing
56 changes: 56 additions & 0 deletions
56
admin/app/components/solidus_admin/users/addresses/component.html.erb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
72
admin/app/components/solidus_admin/users/addresses/component.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
18
admin/app/components/solidus_admin/users/addresses/component.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 |
Oops, something went wrong.