defmodule BerrypodWeb.Admin.OrderShow do use BerrypodWeb, :live_view alias Berrypod.{ActivityLog, 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 -> if connected?(socket), do: ActivityLog.subscribe(order.id) timeline = ActivityLog.list_for_order(order.id) socket = socket |> assign(:page_title, order.order_number) |> assign(:order, order) |> assign(:timeline, timeline) {:ok, socket} end end @impl true def handle_info({:new_activity, entry}, socket) do {:noreply, assign(socket, :timeline, socket.assigns.timeline ++ [entry])} end @impl true def render(assigns) do ~H""" <.header> <.link navigate={~p"/admin/orders"} class="admin-back-link"> ← 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 %>
<%!-- timeline --%>

Timeline

<.fulfilment_badge status={@order.fulfilment_status} />
<.icon name="hero-truck-mini" class="size-4" /> {@order.tracking_number} Track shipment →
<.order_timeline entries={@timeline} />
<%!-- 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 # ── Components ── defp order_timeline(assigns) do ~H"""
No activity recorded yet.
  1. {entry.message}

""" end defp timeline_dot_class("error"), do: "admin-timeline-dot-error" defp timeline_dot_class("warning"), do: "admin-timeline-dot-warning" defp timeline_dot_class(_), do: "admin-timeline-dot-info" defp format_timeline_time(datetime) do today = Date.utc_today() event_date = DateTime.to_date(datetime) diff_days = Date.diff(today, event_date) cond do diff_days == 0 -> Calendar.strftime(datetime, "%H:%M") diff_days < 7 -> Calendar.strftime(datetime, "%d %b %H:%M") true -> Calendar.strftime(datetime, "%d %b %Y") 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 {color, icon} = case assigns.status do "submitted" -> {"admin-status-pill-blue", "hero-paper-airplane-mini"} "processing" -> {"admin-status-pill-amber", "hero-cog-6-tooth-mini"} "shipped" -> {"admin-status-pill-purple", "hero-truck-mini"} "delivered" -> {"admin-status-pill-green", "hero-check-circle-mini"} "failed" -> {"admin-status-pill-red", "hero-x-circle-mini"} "cancelled" -> {"admin-status-pill-zinc", "hero-no-symbol-mini"} _ -> {"admin-status-pill-zinc", "hero-minus-circle-mini"} end assigns = assign(assigns, color: color, icon: icon) ~H""" <.icon name={@icon} class="size-3" /> {@status} """ end defp status_badge(assigns) do {color, icon} = case assigns.status do "paid" -> {"admin-status-pill-green", "hero-check-circle-mini"} "pending" -> {"admin-status-pill-amber", "hero-clock-mini"} "failed" -> {"admin-status-pill-red", "hero-x-circle-mini"} "refunded" -> {"admin-status-pill-zinc", "hero-arrow-uturn-left-mini"} _ -> {"admin-status-pill-zinc", "hero-question-mark-circle-mini"} end assigns = assign(assigns, color: color, 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