Packages

phoenix_kit

1.7.13
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit_web live modules billing subscriptions.ex
Raw

lib/phoenix_kit_web/live/modules/billing/subscriptions.ex

defmodule PhoenixKitWeb.Live.Modules.Billing.Subscriptions do
@moduledoc """
Subscriptions list LiveView for the billing module.
Displays all subscriptions with filtering and search capabilities.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Billing
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
@impl true
def mount(_params, _session, socket) do
if Billing.enabled?() do
project_title = Settings.get_setting("project_title", "PhoenixKit")
socket =
socket
|> assign(:page_title, "Subscriptions")
|> assign(:project_title, project_title)
|> assign(:url_path, Routes.path("/admin/billing/subscriptions"))
|> assign(:status_filter, "all")
|> assign(:search, "")
|> load_subscriptions()
{:ok, socket}
else
{:ok,
socket
|> put_flash(:error, "Billing module is not enabled")
|> push_navigate(to: Routes.path("/admin"))}
end
end
@impl true
def handle_params(params, _url, socket) do
status = params["status"] || "all"
search = params["search"] || ""
socket =
socket
|> assign(:status_filter, status)
|> assign(:search, search)
|> load_subscriptions()
{:noreply, socket}
end
defp load_subscriptions(socket) do
opts =
[preload: [:user, :plan, :payment_method]]
|> add_status_filter(socket.assigns.status_filter)
|> add_search_filter(socket.assigns.search)
subscriptions = Billing.list_subscriptions(opts)
stats = calculate_stats(subscriptions)
socket
|> assign(:subscriptions, subscriptions)
|> assign(:stats, stats)
end
defp add_status_filter(opts, "all"), do: opts
defp add_status_filter(opts, status), do: Keyword.put(opts, :status, status)
defp add_search_filter(opts, ""), do: opts
defp add_search_filter(opts, search), do: Keyword.put(opts, :search, search)
defp calculate_stats(subscriptions) do
%{
total: length(subscriptions),
active: Enum.count(subscriptions, &(&1.status == "active")),
trialing: Enum.count(subscriptions, &(&1.status == "trialing")),
past_due: Enum.count(subscriptions, &(&1.status == "past_due")),
cancelled: Enum.count(subscriptions, &(&1.status == "cancelled"))
}
end
@impl true
def handle_event("filter_status", %{"status" => status}, socket) do
{:noreply,
push_patch(socket,
to:
Routes.path("/admin/billing/subscriptions") <>
build_query_string(status, socket.assigns.search)
)}
end
@impl true
def handle_event("search", %{"search" => search}, socket) do
{:noreply,
push_patch(socket,
to:
Routes.path("/admin/billing/subscriptions") <>
build_query_string(socket.assigns.status_filter, search)
)}
end
@impl true
def handle_event("cancel_subscription", %{"id" => id}, socket) do
subscription = Enum.find(socket.assigns.subscriptions, &(to_string(&1.id) == id))
if subscription do
case Billing.cancel_subscription(subscription, immediately: false) do
{:ok, _subscription} ->
{:noreply,
socket
|> load_subscriptions()
|> put_flash(:info, "Subscription will be cancelled at period end")}
{:error, reason} ->
{:noreply, put_flash(socket, :error, "Failed to cancel: #{inspect(reason)}")}
end
else
{:noreply, put_flash(socket, :error, "Subscription not found")}
end
end
defp build_query_string(status, search) do
params =
[]
|> then(fn p -> if status != "all", do: [{"status", status} | p], else: p end)
|> then(fn p -> if search != "", do: [{"search", search} | p], else: p end)
case params do
[] -> ""
_ -> "?" <> URI.encode_query(params)
end
end
# Helper functions for template
def status_badge_class(status) do
case status do
"active" -> "badge-success"
"trialing" -> "badge-info"
"past_due" -> "badge-warning"
"paused" -> "badge-neutral"
"cancelled" -> "badge-error"
_ -> "badge-ghost"
end
end
def format_interval(interval, interval_count) do
case {interval, interval_count} do
{"month", 1} -> "Monthly"
{"month", n} -> "Every #{n} months"
{"year", 1} -> "Yearly"
{"year", n} -> "Every #{n} years"
{"week", 1} -> "Weekly"
{"week", n} -> "Every #{n} weeks"
{"day", 1} -> "Daily"
{"day", n} -> "Every #{n} days"
_ -> "#{interval_count} #{interval}(s)"
end
end
end