Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Order#use_shipping and address management to the admin dashboard #5461

Merged
merged 8 commits into from
Nov 8, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<div class="<%= stimulus_id %>">
<%= render component("orders/show").new(order: @order) %>
<%= render component("ui/modal").new(title: t(".title.#{@type}"), close_path: solidus_admin.order_path(@order)) do |modal| %>
<%= form_for @order, url: solidus_admin.send("order_#{@type}_address_path", @order), html: { id: form_id } do |form| %>
<div class="w-full flex flex-col mb-4">
<h2 class="text-sm mb-4 font-semibold"><%= t(".subtitle.#{@type}") %></h2>
<div class="w-full flex gap-4">
<%= form.fields_for :"#{@type}_address" do |address_form| %>
<%= render component('ui/forms/address').new(form: address_form, disabled: false) %>
<% end %>
</div>

<label class="flex gap-2 items-center">
<%= form.hidden_field use_attribute, value: '0', id: false %>

<%= render component("ui/forms/checkbox").new(
name: "#{form.object_name}[#{use_attribute}]",
checked: form.object.send("#{@type}_address").new_record? || form.object.bill_address == form.object.ship_address,
value: '1'
) %>

<span class="body-text-sm">
<%= t(".use_this_address.#{@type}") %>
</span>
</label>
</div>
<% end %>

<% modal.with_actions do %>
<%= render component("ui/button").new(
tag: :a,
scheme: :secondary,
text: t(".cancel"),
href: solidus_admin.order_path(@order)
) %>

<%= render component("ui/button").new(
tag: :button,
text: t(".save"),
form: form_id
) %>
<% end %>
<% end %>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

class SolidusAdmin::Orders::Show::Address::Component < SolidusAdmin::BaseComponent
include SolidusAdmin::Layout::PageHelpers

VALID_TYPES = ['ship', 'bill'].freeze

def initialize(order:, type: 'ship')
@order = order
@type = validate_address_type(type)
end

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

def use_attribute
case @type
when 'ship'
'use_shipping'
when 'bill'
'use_billing'
end
end

def validate_address_type(type)
VALID_TYPES.include?(type) ? type : raise(ArgumentError, "Invalid address type: #{type}")
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Add your component translations here.
# Use the translation in the example in your template with `t(".hello")`.
en:
save: Save
cancel: Cancel
back: Back
title:
ship: Edit Shipping Address
bill: Edit Billing Address
subtitle:
ship: Shipping Address
bill: Billing Address
use_this_address:
ship: Use this address also for Billing
bill: Use this address also for Shipping
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
<%= page_with_sidebar_aside do %>
<%= render component('ui/panel').new(title: panel_title_with_more_links(t(".customer"), [
link_to(t(".edit_email"), solidus_admin.order_customer_path(@order), class: "p-2 hover:bg-gray-25 rounded-sm text-black"),
link_to(t(".edit_shipping"), "#", class: "p-2 hover:bg-gray-25 rounded-sm text-black"),
link_to(t(".edit_billing"), "#", class: "p-2 hover:bg-gray-25 rounded-sm text-black"),
link_to(t(".edit_shipping"), solidus_admin.new_order_ship_address_path(@order), class: "p-2 hover:bg-gray-25 rounded-sm text-black"),
link_to(t(".edit_billing"), solidus_admin.new_order_bill_address_path(@order), class: "p-2 hover:bg-gray-25 rounded-sm text-black"),
elia marked this conversation as resolved.
Show resolved Hide resolved
link_to(t(".remove_customer"), solidus_admin.order_customer_path(@order), 'data-turbo-method': :delete, class: "p-2 hover:bg-gray-25 rounded-sm text-red-500"),
])) do %>
<div class="flex flex-col -m-6 p-6 gap-6 border-t border-gray-100 mt-0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
closeMenus() {
this.event.querySelectorAll('details').forEach(details => details.removeAttribute('open'));
this.element.querySelectorAll('details').forEach(details => details.removeAttribute('open'));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def format_address(address)
address.address2,
address.city,
address.zipcode,
address.state.name,
address.state&.name,
tag.br,
address.country.name,
tag.br,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<%= render component("ui/forms/field").text_field(@form, :name) %>
<%= render component("ui/forms/field").text_field(@form, :address1) %>
<%= render component("ui/forms/field").text_field(@form, :address2) %>
<div class="flex w-full space-x-4">
<%= render component("ui/forms/field").text_field(@form, :city, class: "flex-1") %>
<%= render component("ui/forms/field").text_field(@form, :zipcode, class: "flex-1") %>
<div class="flex gap-4 w-full">
<%= render component("ui/forms/field").text_field(@form, :city) %>
<%= render component("ui/forms/field").text_field(@form, :zipcode) %>
</div>

<%= render component("ui/forms/field").select(
Expand All @@ -23,8 +23,9 @@
<%= render component("ui/forms/field").select(
@form,
:state_id,
[],
state_options,
value: @form.object.try(:state_id),
disabled: @form.object.country&.states&.empty?,
"data-#{stimulus_id}-target": "state"
) %>

Expand Down
21 changes: 11 additions & 10 deletions admin/app/components/solidus_admin/ui/forms/address/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static targets = ["country", "state"]

connect() {
this.loadStates()
}

loadStates() {
const countryId = this.countryTarget.value

Expand All @@ -22,12 +18,17 @@ export default class extends Controller {

stateSelect.innerHTML = ""

data.forEach(state => {
const option = document.createElement("option")
if (data.length === 0) {
stateSelect.disabled = true
} else {
stateSelect.disabled = false

option.value = state.id
option.innerText = state.name
stateSelect.appendChild(option)
})
data.forEach((state) => {
const option = document.createElement("option")
option.value = state.id
option.innerText = state.name
stateSelect.appendChild(option)
})
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ def initialize(form:, disabled: false)
@form = form
@disabled = disabled
end

def state_options
return [] unless @form.object.country
@form.object.country.states.map { |s| [s.name, s.id] }
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
) %>
</header>

<div class="p-4 overflow-auto max-h-96">
<div class="p-4 overflow-auto">
<%= content %>
</div>

Expand Down
67 changes: 67 additions & 0 deletions admin/app/controllers/solidus_admin/addresses_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# frozen_string_literal: true

module SolidusAdmin
class AddressesController < BaseController
include Spree::Core::ControllerHelpers::StrongParameters

before_action :load_order
before_action :validate_address_type

def new
address = @order.send("#{address_type}_address")
@order.send("build_#{address_type}_address", country_id: default_country_id) if address.nil?
address ||= @order.send("#{address_type}_address")
address.country_id ||= default_country_id if address.country.nil?

respond_to do |format|
format.html { render component('orders/show/address').new(order: @order, type: address_type) }
end
end

def update
if @order.contents.update_cart(order_params)
redirect_to order_path(@order), status: :see_other, notice: t('.success')
else
flash.now[:error] = @order.errors[:base].join(", ") if @order.errors[:base].any?

respond_to do |format|
format.html { render component('orders/show/address').new(order: @order, type: address_type), status: :unprocessable_entity }
end
end
end

private

def address_type
params[:type].presence_in(%w[bill ship])
end

def validate_address_type
unless address_type
flash[:error] = t('.errors.address_type_invalid')
redirect_to spree.admin_order_url(@order)
end
end

def default_country_id
@default_country_id ||= begin
country = Spree::Country.default
country.id if Spree::Country.available.exists?(id: country.id)
end
elia marked this conversation as resolved.
Show resolved Hide resolved
end

def load_order
@order = Spree::Order.find_by!(number: params[:order_id])
authorize! action_name, @order
end

def order_params
params.require(:order).permit(
:use_billing,
:use_shipping,
bill_address_attributes: permitted_address_attributes,
ship_address_attributes: permitted_address_attributes
)
end
end
end
6 changes: 6 additions & 0 deletions admin/config/locales/orders.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ en:
title: "Orders"
update:
success: "Order was updated successfully"
addresses:
title: "Addresses"
update:
success: "The address has been successfully updated."
errors:
address_type_invalid: "Invalid address type. Please select either billing or shipping address."
2 changes: 2 additions & 0 deletions admin/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
resources :orders, only: [:index, :show, :edit, :update] do
resources :line_items, only: [:destroy, :create, :update]
resource :customer
resource :ship_address, only: [:new, :update], controller: "addresses", type: "ship"
resource :bill_address, only: [:new, :update], controller: "addresses", type: "bill"

member do
get :variants_for
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

# @component "orders/show/address"
class SolidusAdmin::Orders::Show::Address::ComponentPreview < ViewComponent::Preview
include SolidusAdmin::Preview

def overview
type = "ship"
order = fake_order(type)

render_with_template(
locals: {
order: order,
type: type
}
)
end

# @param type select :type_options
def playground(type: "ship")
order = fake_order(type)
render current_component.new(order: order, type: type)
end

private

def fake_order(type)
order = Spree::Order.new
country = Spree::Country.find_or_initialize_by(iso: Spree::Config.default_country_iso)

order.define_singleton_method(:id) { 1 }
order.define_singleton_method(:persisted?) { true }
order.define_singleton_method(:to_param) { id.to_s }
order.send("build_#{type}_address", { country: country })
order
end

def type_options
current_component::VALID_TYPES
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= render current_component.new(order: order, type: type) %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

require "spec_helper"

RSpec.describe SolidusAdmin::Orders::Show::Address::Component, type: :component do
it "renders the overview preview" do
render_preview(:overview)
end
end
2 changes: 2 additions & 0 deletions api/openapi/solidus-api.oas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6754,6 +6754,8 @@ components:
type: string
use_billing:
type: boolean
use_shipping:
type: boolean
bill_address_attributes:
$ref: '#/components/schemas/address-input'
ship_address_attributes:
Expand Down
11 changes: 11 additions & 0 deletions core/app/models/spree/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ def states
before_validation :set_currency
before_validation :generate_order_number, on: :create
before_validation :assign_billing_to_shipping_address, if: :use_billing?
before_validation :assign_shipping_to_billing_address, if: :use_shipping?
attr_accessor :use_billing
attr_accessor :use_shipping

before_create :create_token
before_create :link_by_email
Expand Down Expand Up @@ -271,6 +273,11 @@ def assign_billing_to_shipping_address
true
end

def assign_shipping_to_billing_address
self.bill_address = ship_address if ship_address
true
end

def allow_cancel?
return false unless completed? && state != 'canceled'
shipment_state.nil? || %w{ready backorder pending}.include?(shipment_state)
Expand Down Expand Up @@ -860,6 +867,10 @@ def use_billing?
use_billing.in?([true, 'true', '1'])
end

def use_shipping?
use_shipping.in?([true, 'true', '1'])
end

def set_currency
self.currency = Spree::Config[:currency] if self[:currency].nil?
end
Expand Down
1 change: 1 addition & 0 deletions core/lib/spree/permitted_attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ module PermittedAttributes

@@checkout_address_attributes = [
:use_billing,
:use_shipping,
:email,
bill_address_attributes: address_attributes,
ship_address_attributes: address_attributes
Expand Down
Loading
Loading