defmodule BerrypodWeb.Admin.OrderShow do use BerrypodWeb, :live_view alias Berrypod.Orders alias Berrypod.Cart @impl true def mount(%{"id" => id}, _session, socket) do case Orders.get_order(id) do nil -> socket = socket |> put_flash(:error, "Order not found") |> push_navigate(to: ~p"/admin/orders") {:ok, socket} order -> socket = socket |> assign(:page_title, order.order_number) |> assign(:order, order) {:ok, socket} end end @impl true def render(assigns) do ~H""" <.header> <.link navigate={~p"/admin/orders"} class="text-sm font-normal text-base-content/60 hover:underline" > ← Orders
{@order.order_number} <.status_badge status={@order.payment_status} />
<%!-- order info --%>

Order details

<.list> <:item title="Date">{format_date(@order.inserted_at)} <:item title="Customer">{@order.customer_email || "—"} <:item title="Payment status"> <.status_badge status={@order.payment_status} /> <:item :if={@order.stripe_payment_intent_id} title="Stripe payment"> {@order.stripe_payment_intent_id} <:item title="Currency">{String.upcase(@order.currency)}
<%!-- shipping address --%>

Shipping address

<%= if @order.shipping_address != %{} do %> <.list> <:item :if={@order.shipping_address["name"]} title="Name"> {@order.shipping_address["name"]} <:item :if={@order.shipping_address["line1"]} title="Address"> {@order.shipping_address["line1"]}
{@order.shipping_address["line2"]}
<:item :if={@order.shipping_address["city"]} title="City"> {@order.shipping_address["city"]} <:item :if={@order.shipping_address["state"] not in [nil, ""]} title="State"> {@order.shipping_address["state"]} <:item :if={@order.shipping_address["postal_code"]} title="Postcode"> {@order.shipping_address["postal_code"]} <:item :if={@order.shipping_address["country"]} title="Country"> {@order.shipping_address["country"]} <% else %>

No shipping address provided

<% end %>
<%!-- fulfilment --%>

Fulfilment

<.fulfilment_badge status={@order.fulfilment_status} />
<.list> <:item :if={@order.provider_order_id} title="Provider order ID"> {@order.provider_order_id} <:item :if={@order.provider_status} title="Provider status"> {@order.provider_status} <:item :if={@order.submitted_at} title="Submitted"> {format_date(@order.submitted_at)} <:item :if={@order.tracking_number} title="Tracking"> <%= if @order.tracking_url do %> {@order.tracking_number} <% else %> {@order.tracking_number} <% end %> <:item :if={@order.shipped_at} title="Shipped"> {format_date(@order.shipped_at)} <:item :if={@order.delivered_at} title="Delivered"> {format_date(@order.delivered_at)} <:item :if={@order.fulfilment_error} title="Error"> {@order.fulfilment_error}
<%!-- line items --%>

Items

Product Variant Qty Unit price Total
{item.product_name} {item.variant_title} {item.quantity} {Cart.format_price(item.unit_price)} {Cart.format_price(item.unit_price * item.quantity)}
Subtotal {Cart.format_price(@order.subtotal)}
Total {Cart.format_price(@order.total)}
""" end @impl true def handle_event("submit_to_provider", _params, socket) do order = socket.assigns.order case Orders.submit_to_provider(order) do {:ok, updated} -> socket = socket |> assign(:order, updated) |> put_flash(:info, "Order submitted to provider") {:noreply, socket} {:error, _reason} -> order = Orders.get_order(order.id) socket = socket |> assign(:order, order) |> put_flash(:error, order.fulfilment_error || "Submission failed") {:noreply, socket} end end def handle_event("refresh_status", _params, socket) do order = socket.assigns.order case Orders.refresh_fulfilment_status(order) do {:ok, updated} -> socket = socket |> assign(:order, updated) |> put_flash(:info, "Status refreshed") {:noreply, socket} {:error, reason} -> {:noreply, put_flash(socket, :error, "Failed to refresh: #{inspect(reason)}")} end end defp can_submit?(order) do order.payment_status == "paid" and order.fulfilment_status in ["unfulfilled", "failed"] end defp can_refresh?(order) do not is_nil(order.provider_order_id) and order.fulfilment_status in ["submitted", "processing", "shipped"] end defp fulfilment_badge(assigns) do {bg, text, ring, icon} = case assigns.status do "submitted" -> {"bg-blue-50", "text-blue-700", "ring-blue-600/20", "hero-paper-airplane-mini"} "processing" -> {"bg-amber-50", "text-amber-700", "ring-amber-600/20", "hero-cog-6-tooth-mini"} "shipped" -> {"bg-purple-50", "text-purple-700", "ring-purple-600/20", "hero-truck-mini"} "delivered" -> {"bg-green-50", "text-green-700", "ring-green-600/20", "hero-check-circle-mini"} "failed" -> {"bg-red-50", "text-red-700", "ring-red-600/20", "hero-x-circle-mini"} "cancelled" -> {"bg-base-200/50", "text-base-content/60", "ring-base-content/10", "hero-no-symbol-mini"} _ -> {"bg-base-200/50", "text-base-content/60", "ring-base-content/10", "hero-minus-circle-mini"} end assigns = assign(assigns, bg: bg, text: text, ring: ring, icon: icon) ~H""" <.icon name={@icon} class="size-3" /> {@status} """ end defp status_badge(assigns) do {bg, text, ring, icon} = case assigns.status do "paid" -> {"bg-green-50", "text-green-700", "ring-green-600/20", "hero-check-circle-mini"} "pending" -> {"bg-amber-50", "text-amber-700", "ring-amber-600/20", "hero-clock-mini"} "failed" -> {"bg-red-50", "text-red-700", "ring-red-600/20", "hero-x-circle-mini"} "refunded" -> {"bg-base-200/50", "text-base-content/60", "ring-base-content/10", "hero-arrow-uturn-left-mini"} _ -> {"bg-base-200/50", "text-base-content/60", "ring-base-content/10", "hero-question-mark-circle-mini"} end assigns = assign(assigns, bg: bg, text: text, ring: ring, icon: icon) ~H""" <.icon name={@icon} class="size-3" /> {@status} """ end defp format_date(datetime) do Calendar.strftime(datetime, "%d %b %Y %H:%M") end end