defmodule PhoenixKit.Modules.Shop.Web.Carts do @moduledoc """ Carts admin list LiveView for E-Commerce module. """ use PhoenixKitWeb, :live_view alias PhoenixKit.Modules.Billing.Currency alias PhoenixKit.Modules.Shop alias PhoenixKit.Utils.Routes @per_page 25 @impl true def mount(_params, _session, socket) do {carts, total} = Shop.list_carts_with_count(per_page: @per_page) currency = Shop.get_default_currency() socket = socket |> assign(:page_title, "Shopping Carts") |> assign(:carts, carts) |> assign(:total, total) |> assign(:page, 1) |> assign(:per_page, @per_page) |> assign(:status_filter, nil) |> assign(:search, "") |> assign(:currency, currency) {:ok, socket} end @impl true def handle_params(params, _uri, socket) do page = String.to_integer(params["page"] || "1") status = params["status"] search = params["search"] || "" {carts, total} = Shop.list_carts_with_count( page: page, per_page: @per_page, status: status, search: search ) socket = socket |> assign(:carts, carts) |> assign(:total, total) |> assign(:page, page) |> assign(:status_filter, status) |> assign(:search, search) {:noreply, socket} end @impl true def handle_event("filter_status", %{"status" => status}, socket) do status = if status == "", do: nil, else: status {:noreply, push_patch(socket, to: build_url(socket.assigns, status: status, page: 1))} end @impl true def handle_event("search", %{"search" => search}, socket) do {:noreply, push_patch(socket, to: build_url(socket.assigns, search: search, page: 1))} end defp build_url(assigns, overrides) do params = %{ status: Keyword.get(overrides, :status, assigns.status_filter), search: Keyword.get(overrides, :search, assigns.search), page: Keyword.get(overrides, :page, assigns.page) } |> Enum.filter(fn {_k, v} -> v && v != "" end) |> URI.encode_query() if params == "" do Routes.path("/admin/shop/carts") else Routes.path("/admin/shop/carts?#{params}") end end @impl true def render(assigns) do ~H"""

Shopping Carts

{@total} carts total

<%!-- Filters --%>
<%!-- Carts Table --%>
<%= if @carts == [] do %> <% else %> <%= for cart <- @carts do %> <% end %> <% end %>
Customer Items Total Status Updated
<.icon name="hero-shopping-cart" class="w-12 h-12 mx-auto mb-3 opacity-50" />

No carts found

Carts will appear here when customers add items

<%= if cart.user do %>
{cart.user.email}
User ID: {cart.user.id}
<% else %>
Guest
{String.slice(cart.session_id || "", 0, 16)}...
<% end %>
{cart.items_count || 0} items <%= if cart.total_weight_grams && cart.total_weight_grams > 0 do %> {format_weight(cart.total_weight_grams)} <% end %>
{format_price(cart.total, @currency)}
<%= if Decimal.compare(cart.subtotal || Decimal.new("0"), cart.total || Decimal.new("0")) != :eq do %>
Subtotal: {format_price(cart.subtotal, @currency)}
<% end %>
{cart.status}
{format_datetime(cart.updated_at)}
<%= if cart.expires_at do %>
Expires: {format_datetime(cart.expires_at)}
<% end %>
<%!-- Pagination --%> <%= if @total > @per_page do %>
<%= for page_num <- 1..ceil(@total / @per_page) do %> <.link patch={build_url(assigns, page: page_num)} class={["join-item btn btn-sm", if(@page == page_num, do: "btn-active")]} > {page_num} <% end %>
<% end %>
""" end defp status_badge_class("active"), do: "badge badge-success" defp status_badge_class("converted"), do: "badge badge-info" defp status_badge_class("abandoned"), do: "badge badge-warning" defp status_badge_class("expired"), do: "badge badge-neutral" defp status_badge_class("merged"), do: "badge badge-secondary" defp status_badge_class(_), do: "badge" defp format_price(nil, _currency), do: "-" defp format_price(amount, %Currency{} = currency) do Currency.format_amount(amount, currency) end defp format_price(amount, nil) do "$#{Decimal.round(amount, 2)}" end defp format_weight(grams) when grams >= 1000, do: "#{Float.round(grams / 1000, 1)} kg" defp format_weight(grams), do: "#{grams} g" defp format_datetime(nil), do: "-" defp format_datetime(datetime) do Calendar.strftime(datetime, "%Y-%m-%d %H:%M") end end