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

[Admin] Add order shipments component #5514

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
<%= page_with_sidebar_main do %>
<%= render component("orders/cart").new(order: @order) %>
<%= render component("orders/show/summary").new(order: @order) %>

<% if @order.shipments.count > 0 %>
<%= render component('ui/panel').new(title: t('.shipments')) do %>
<% @order.shipments.each.with_index(1) do |shipment, index| %>
<%= render component("orders/show/shipment").new(shipment: shipment, index: index) %>
<% end %>
<% end %>
<% end %>
<% end %>

<%= page_with_sidebar_aside do %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ en:
order_email: Order contact email
back: Back to orders
same_as_shipping: Same as shipping address
shipments: Shipments

edit_email: "Edit order email"
add_email: "Add order email"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<div class="<%= stimulus_id %>" data-controller="<%= stimulus_id %>">
<div class="rounded p-2">
<%= render component('ui/panel').new do |panel| %>
<% panel.with_menu t(".edit"), solidus_admin.edit_order_shipment_path(@order, @shipment) %>
<% panel.with_menu t(".split"), solidus_admin.split_edit_order_shipment_path(@order, @shipment) %>
<% panel.with_menu t(".merge"), solidus_admin.merge_edit_order_shipment_path(@order, @shipment) %>
<% panel.with_menu t(".change_location"), solidus_admin.order_shipment_path(@order, @shipment) %>

<% panel.with_section(wide: true, high: true) do %>
<section class="border-gray-100 border-t w-full first-of-type:border-t-0 p-6">
<h2>
<span class="text-xl">
<%= t('.title', index: @index, number: @shipment.number, location: @shipment.stock_location.name) %>
<%= render component('ui/badge').new(name: @shipment.state.titleize) %>
</span>
</h2>
</section>
<% end %>

<% panel.with_section(wide: true, high: true) do %>
<div class="rounded-b-lg overflow-hidden">
<table class="table-auto w-full">
<thead>
<tr>
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none">
<%= t(".product") %>
</th>
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none w-16">
<%= t(".quantity") %>
</th>
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none w-16 whitespace-nowrap">
<%= t(".total") %>
</th>
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none w-16">
<span class="sr-only">
<%= t(".actions") %>
</span>
</th>
</tr>
</thead>
<tbody>
<% manifest.each do |item| %>
<tr class="border-gray-100 border-t">
<td class="px-6 py-4">
<div class="flex gap-2 grow">
<% variant = item.variant %>
<%= render component("ui/thumbnail").new(
src: (variant.images.first || variant.product.gallery.images.first)&.url(:small),
alt: variant.name
) %>
<div class="flex-col">
<div class="leading-5 text-black body-small-bold"><%= variant.name %></div>
<div class="leading-5 text-gray-500 body-small">
SKU: <%= variant.sku %>
<%= variant.options_text.presence&.prepend("- ") %>
</div>
</div>
</div>
</td>
<td class="px-6 py-4">
<span class="text-gray-500 body-small whitespace-nowrap">
<% item.states.each do |state, count| %>
<%= count %> x <%= t(state, scope: '.inventory_states') %>
<% end %>
</span>
</td>
<td class="px-6 py-4">
<span class="text-gray-500 body-small"><%= item.line_item.display_amount %></span>
</td>
<td class="px-6 py-4 text-right">
<%= form_for(item.line_item, url: solidus_admin.order_line_item_path(@order, item.line_item), method: :delete) do |f| %>
<%= render component('ui/button').new(
scheme: :ghost,
size: :s,
title: t("spree.delete"),
icon: 'close-line',
"data-controller": "confirm",
"data-confirm-text-value": t("spree.are_you_sure"),
) %>
<% end %>
</td>
</tr>
<% end %>
<tr class="border-gray-100 border-t">
<td colspan="4" class="px-6 py-4">
<ul class="text-sm">
<li class="flex justify-between py-1.5">
<label class="flex flex-col w-full">
<span class="text-gray-700 body-tiny-bold body-text-xs-semibold">
<%= @shipment.class.human_attribute_name(:shipping_method) %>
</span>
<%= @shipment.shipping_method.name %> - <%= @shipment.display_cost %>
</label>
</li>
<li class="flex justify-between py-1.5">
<label class="flex flex-col w-full py-1.5">
<span class="text-gray-700 body-tiny-bold body-text-xs-semibold">
<%= @shipment.class.human_attribute_name(:tracking) %>
</span>
<%= @shipment.tracking || t(".none") %>
</label>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<% end %>
<% end %>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static targets = ['output']

typed(event) {
this.text = event.currentTarget.value
this.render()
}

render() {
this.outputTarget.innerText = this.text
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

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

def initialize(shipment:, index:)
@shipment = shipment
@order = shipment.order
@index = index
end

def manifest
Spree::ShippingManifest.new(
inventory_units: @shipment.inventory_units.where(carton_id: nil),
).items.sort_by { |item| item.line_item.created_at }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
en:
title: "#%{index}: %{number} from %{location}"
product: Product
quantity: Quantity
total: Total Price
actions: Actions
none: No tracking details provided
edit: Edit
split: Split
merge: Merge
change_location: Change Location
inventory_states:
backordered: Backordered
canceled: Canceled
on_hand: On hand
returned: Returned
shipped: Shipped
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<div class="<%= stimulus_id %>">
<%= render component("orders/show").new(order: @order) %>
<%= render component("ui/modal").new(title: t(".title", number: @shipment.number), close_path: close_path) do |modal| %>
<%= form_for @shipment, url: solidus_admin.order_shipment_path(@order, @shipment), html: { id: form_id } do |f| %>
<%= render component("ui/forms/field").text_field(f, :tracking) %>
<%= render component("ui/forms/field").select(
f,
:selected_shipping_rate_id,
@shipment.shipping_rates.map { |sr| [sr.shipping_method.name, sr.id] },
) %>
<% end %>

<% modal.with_actions do %>
<%= render component("ui/button").new(tag: :a, scheme: :secondary, href: close_path, type: :submit, text: t('.cancel')) %>
<%= render component("ui/button").new(form: form_id, type: :submit, text: t('.submit')) %>
<% end %>
<% end %>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static targets = ['output']

typed(event) {
this.text = event.currentTarget.value
this.render()
}

render() {
this.outputTarget.innerText = this.text
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

class SolidusAdmin::Orders::Show::Shipment::Edit::Component < SolidusAdmin::BaseComponent
include SolidusAdmin::Layout::PageHelpers

def initialize(shipment:)
@order = shipment.order
@shipment = shipment
end

def form_id
dom_id(@order, "#{stimulus_id}_shipment_form_#{@shipment.id}")
end

def close_path
@close_path ||= solidus_admin.order_path(@order)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
en:
title: "Edit shipment %{number}"
submit: "Save"
cancel: "Cancel"
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<div class="<%= stimulus_id %>" data-controller="<%= stimulus_id %>">
<%= render component("orders/show").new(order: @order) %>
<%= render component("ui/modal").new(title: t(".title", number: @shipment.number), close_path: close_path) do |modal| %>
<table class="table-auto w-full">
<thead>
<tr>
<th class="py-2 px-4 h-10 bg-gray-15 w-16">
<%=
render component("ui/forms/checkbox").new(
form: form_id,
"data-action": "#{stimulus_id}#selectAllRows",
"data-#{stimulus_id}-target": "headerCheckbox",
"aria-label": t('.select_all'),
)
%>
</th>
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none">
<%= t(".product") %>
</th>
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none w-16">
<%= t(".quantity") %>
</th>
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none w-16 whitespace-nowrap">
<%= t(".total") %>
</th>
</tr>
</thead>
<tbody>
<% manifest.each do |item| %>
<tr class="border-gray-100 border-t">
<td class="py-2 px-4">
<%=
render component("ui/forms/checkbox").new(
form: form_id,
value: item.variant.id,
"data-#{stimulus_id}-target": "checkbox",
)
%>
</td>

<td class="px-6 py-4">
<div class="flex gap-2 grow">
<% variant = item.variant %>
<%= render component("ui/thumbnail").new(
src: (variant.images.first || variant.product.gallery.images.first)&.url(:small),
alt: variant.name
) %>
<div class="flex-col">
<div class="leading-5 text-black body-small-bold"><%= variant.name %></div>
<div class="leading-5 text-gray-500 body-small">
SKU: <%= variant.sku %>
<%= variant.options_text.presence&.prepend("- ") %>
</div>
</div>
</div>
</td>
<td class="px-6 py-4">
<span class="text-gray-500 body-small whitespace-nowrap">
<%= render component("ui/forms/input").new(
value: item.states["on_hand"],
form: form_id,
name: "variants[#{item.variant.id}][quantity]",
type: :number,
step: 1,
min: "1",
max: item.states["on_hand"],
"data-#{stimulus_id}-target": "quantity",
"data-action": "focus->#{stimulus_id}#selectRow",
) %>
</span>
</td>
<td class="px-6 py-4">
<span class="text-gray-500 body-small"><%= item.line_item.display_amount %></span>
</td>
</tr>
<% end %>
</tbody>
</table>

<% modal.with_actions do %>
<%= form_tag solidus_admin.split_create_order_shipment_path(@order, @shipment), method: :put, id: form_id, "data-action": "submit->#{stimulus_id}#submit" %>
<%= render component("ui/button").new(tag: :a, scheme: :secondary, href: close_path, type: :submit, text: t('.cancel')) %>
<%= render_split_action_button %>
<% end %>
<% end %>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static targets = ['output']

typed(event) {
this.text = event.currentTarget.value
this.render()
}

render() {
this.outputTarget.innerText = this.text
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class SolidusAdmin::Orders::Show::Shipment::Merge::Component < SolidusAdmin::BaseComponent
def initialize(shipment:)
@shipment = shipment
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
en:
title: "Merge shipment %{number}"
submit: "Save"
cancel: "Cancel"
product: Product
quantity: Quantity
total: Total Price
actions: Actions
select_all: Select All
inventory_states:
backordered: Backordered
canceled: Canceled
on_hand: On hand
returned: Returned
shipped: Shipped
Loading
Loading