defmodule BerrypodWeb.Admin.Orders do use BerrypodWeb, :live_view alias Berrypod.Orders alias Berrypod.Cart @impl true def mount(_params, _session, socket) do counts = Orders.count_orders_by_status() orders = Orders.list_orders() socket = socket |> assign(:page_title, "Orders") |> assign(:status_filter, "all") |> assign(:status_counts, counts) |> assign(:order_count, length(orders)) |> stream(:orders, orders) {:ok, socket} end @impl true def handle_event("filter", %{"status" => status}, socket) do orders = Orders.list_orders(status: status) socket = socket |> assign(:status_filter, status) |> assign(:order_count, length(orders)) |> stream(:orders, orders, reset: true) {:noreply, socket} end @impl true def render(assigns) do ~H""" <.header> Orders
<.filter_tab status="all" label="All" count={total_count(@status_counts)} active={@status_filter} /> <.filter_tab status="paid" label="Paid" count={@status_counts["paid"]} active={@status_filter} /> <.filter_tab status="pending" label="Pending" count={@status_counts["pending"]} active={@status_filter} /> <.filter_tab status="failed" label="Failed" count={@status_counts["failed"]} active={@status_filter} /> <.filter_tab status="refunded" label="Refunded" count={@status_counts["refunded"]} active={@status_filter} />
<.table :if={@order_count > 0} id="orders" rows={@streams.orders} row_item={fn {_id, order} -> order end} row_click={fn {_id, order} -> JS.navigate(~p"/admin/orders/#{order}") end} > <:col :let={order} label="Order">{order.order_number} <:col :let={order} label="Date">{format_date(order.inserted_at)} <:col :let={order} label="Customer">{order.customer_email || "—"} <:col :let={order} label="Total">{Cart.format_price(order.total)} <:col :let={order} label="Status"><.status_badge status={order.payment_status} /> <:col :let={order} label="Fulfilment"> <.fulfilment_badge status={order.fulfilment_status} />
<.icon name="hero-inbox" class="size-12 mx-auto mb-4" />

No orders yet

Orders will appear here once customers check out.

""" end defp filter_tab(assigns) do count = assigns[:count] || 0 active = assigns.active == assigns.status assigns = assign(assigns, count: count, active: active) ~H""" """ 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 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 total_count(counts) do counts |> Map.values() |> Enum.sum() end end