defmodule BerrypodWeb.Admin.Dashboard do use BerrypodWeb, :live_view alias Berrypod.{Cart, Orders, Products, Settings} @impl true def mount(_params, _session, socket) do if Settings.site_live?() do status_counts = Orders.count_orders_by_status() paid_count = Map.get(status_counts, "paid", 0) recent_orders = Orders.list_orders(status: "paid") |> Enum.take(5) {:ok, socket |> assign(:page_title, "Dashboard") |> assign(:paid_count, paid_count) |> assign(:revenue, Orders.total_revenue()) |> assign(:product_count, Products.count_products()) |> assign(:recent_orders, recent_orders)} else {:ok, push_navigate(socket, to: ~p"/admin/setup")} end end @impl true def render(assigns) do ~H""" <.header> Dashboard <%!-- Stats --%>
<.stat_card label="Orders" value={@paid_count} icon="hero-shopping-bag" href={~p"/admin/orders"} /> <.stat_card label="Revenue" value={format_revenue(@revenue)} icon="hero-banknotes" href={~p"/admin/orders"} /> <.stat_card label="Products" value={@product_count} icon="hero-cube" href={~p"/admin/products"} />
<%!-- Recent orders --%>

Recent orders

<.link navigate={~p"/admin/orders"} class="text-sm text-base-content/60 hover:text-base-content" > View all →
<%= if @recent_orders == [] do %>
<.icon name="hero-inbox" class="size-10 mx-auto mb-3 text-base-content/30" />

No orders yet

Orders will appear here once customers check out.

<% else %>
Order Date Customer Total Fulfilment
{order.order_number} {format_date(order.inserted_at)} {order.customer_email || "—"} {Cart.format_price(order.total)} <.fulfilment_pill status={order.fulfilment_status} />
<% end %>
""" end # ========================================================================== # Components # ========================================================================== attr :label, :string, required: true attr :value, :any, required: true attr :icon, :string, required: true attr :href, :string, required: true defp stat_card(assigns) do ~H""" <.link navigate={@href} class="rounded-lg border border-base-200 p-4 hover:border-base-300 transition-colors" >
<.icon name={@icon} class="size-5 text-base-content/60" />

{@value}

{@label}

""" end defp fulfilment_pill(assigns) do {color, label} = case assigns.status do "unfulfilled" -> {"bg-base-200 text-base-content/60", "unfulfilled"} "submitted" -> {"bg-blue-50 text-blue-700", "submitted"} "processing" -> {"bg-amber-50 text-amber-700", "processing"} "shipped" -> {"bg-purple-50 text-purple-700", "shipped"} "delivered" -> {"bg-green-50 text-green-700", "delivered"} "failed" -> {"bg-red-50 text-red-700", "failed"} _ -> {"bg-base-200 text-base-content/60", assigns.status || "—"} end assigns = assign(assigns, color: color, label: label) ~H""" {@label} """ end # ========================================================================== # Helpers # ========================================================================== defp format_revenue(amount_pence) when is_integer(amount_pence) do Cart.format_price(amount_pence) end defp format_revenue(_), do: "£0.00" defp format_date(datetime) do Calendar.strftime(datetime, "%d %b %Y") end end