defmodule PhoenixKit.Modules.Billing.Web.UserBillingProfiles do @moduledoc """ User billing profiles list LiveView. Allows users to manage their own billing profiles. """ use PhoenixKitWeb, :live_view alias PhoenixKit.Modules.Billing alias PhoenixKit.Modules.Billing.Events alias PhoenixKit.Utils.Routes @impl true def mount(_params, _session, socket) do user = get_current_user(socket) cond do not Billing.enabled?() -> {:ok, socket |> put_flash(:error, "Billing module is not enabled") |> push_navigate(to: Routes.path("/dashboard"))} is_nil(user) -> {:ok, socket |> put_flash(:error, "Please log in to view your billing profiles") |> push_navigate(to: Routes.path("/phoenix_kit/users/log-in"))} true -> # Subscribe to billing profile events for real-time updates if connected?(socket), do: Events.subscribe_profiles() profiles = Billing.list_user_billing_profiles(user.uuid) socket = socket |> assign(:page_title, "My Billing Profiles") |> assign(:profiles, profiles) |> assign(:user, user) {:ok, socket} end end @impl true def handle_event("set_default", %{"uuid" => uuid}, socket) do profile = Enum.find(socket.assigns.profiles, &(&1.uuid == uuid)) if profile && profile.user_uuid == socket.assigns.user.uuid do case Billing.set_default_billing_profile(profile) do {:ok, _profile} -> profiles = Billing.list_user_billing_profiles(socket.assigns.user.uuid) {:noreply, socket |> assign(:profiles, profiles) |> put_flash(:info, "Default profile updated")} {:error, _} -> {:noreply, put_flash(socket, :error, "Failed to set default profile")} end else {:noreply, put_flash(socket, :error, "Profile not found")} end end @impl true def handle_event("delete", %{"uuid" => uuid}, socket) do profile = Enum.find(socket.assigns.profiles, &(&1.uuid == uuid)) if profile && profile.user_uuid == socket.assigns.user.uuid do case Billing.delete_billing_profile(profile) do {:ok, _} -> profiles = Billing.list_user_billing_profiles(socket.assigns.user.uuid) {:noreply, socket |> assign(:profiles, profiles) |> put_flash(:info, "Profile deleted successfully")} {:error, _} -> {:noreply, put_flash(socket, :error, "Failed to delete profile")} end else {:noreply, put_flash(socket, :error, "Profile not found")} end end # PubSub event handlers for real-time updates @impl true def handle_info({event, _profile}, socket) when event in [:profile_created, :profile_updated, :profile_deleted] do # Only refresh if we have a user assigned if socket.assigns[:user] do profiles = Billing.list_user_billing_profiles(socket.assigns.user.uuid) {:noreply, assign(socket, :profiles, profiles)} else {:noreply, socket} end end @impl true def handle_info(_msg, socket) do {:noreply, socket} end @impl true def render(assigns) do ~H"""
<%!-- Header --%>

My Billing Profiles

Manage your billing information for orders and invoices

<.link navigate={Routes.path("/dashboard/billing-profiles/new")} class="btn btn-primary" > <.icon name="hero-plus" class="w-5 h-5 mr-2" /> New Profile
<%!-- Profiles List --%> <%= if Enum.empty?(@profiles) do %>
<.icon name="hero-identification" class="w-16 h-16 mx-auto mb-4 opacity-30" />

No billing profiles yet

Create a billing profile to use for your orders

<.link navigate={Routes.path("/dashboard/billing-profiles/new")} class="btn btn-primary"> Create Your First Profile
<% else %>
<%= for profile <- @profiles do %>
<%!-- Profile Info --%>
{String.capitalize(profile.type)} <%= if profile.is_default do %> Default <% end %>
<%= if profile.type == "company" do %>

{profile.company_name}

<%= if profile.company_vat_number do %>

VAT: {profile.company_vat_number}

<% end %> <% else %>

{profile.first_name} {profile.last_name}

<%= if profile.email do %>

{profile.email}

<% end %> <% end %> <%= if profile.address_line1 do %>

{profile.address_line1} <%= if profile.city do %> , {profile.city} <% end %> <%= if profile.country do %> , {profile.country} <% end %>

<% end %>
<%!-- Actions --%>
<.link navigate={Routes.path("/dashboard/billing-profiles/#{profile.uuid}/edit")} class="btn btn-outline btn-sm" > <.icon name="hero-pencil" class="w-4 h-4" /> Edit <%= if not profile.is_default do %> <% end %>
<% end %>
<% end %>
""" end # Private helpers defp get_current_user(socket) do case socket.assigns[:phoenix_kit_current_scope] do %{user: %{uuid: _} = user} -> user _ -> nil end end end