Packages
phoenix_kit
1.7.21
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
Current section
Files
lib/modules/billing/web/index.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="{@project_title} Billing"
current_path={@url_path}
project_title={@project_title}
>
<div class="container mx-auto px-4 py-6">
<%!-- Header --%>
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-6 gap-4">
<div>
<h1 class="text-3xl font-bold">Billing Dashboard</h1>
<p class="text-base-content/60 mt-1">
Overview of orders, invoices, and billing activity
</p>
</div>
<div class="flex gap-2">
<button phx-click="refresh" class="btn btn-ghost btn-sm">
<.icon name="hero-arrow-path" class="w-4 h-4" /> Refresh
</button>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/orders/new")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-plus" class="w-4 h-4" /> New Order
</.link>
</div>
</div>
<%!-- Stats Cards --%>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
<div class="stat bg-base-100 rounded-box shadow">
<div class="stat-figure text-primary">
<.icon name="hero-clipboard-document-list" class="w-8 h-8" />
</div>
<div class="stat-title">Total Orders</div>
<div class="stat-value text-primary">{@stats.total_orders}</div>
<div class="stat-desc">{@stats.orders_this_month} this month</div>
</div>
<div class="stat bg-base-100 rounded-box shadow">
<div class="stat-figure text-secondary">
<.icon name="hero-document-text" class="w-8 h-8" />
</div>
<div class="stat-title">Total Invoices</div>
<div class="stat-value text-secondary">{@stats.total_invoices}</div>
<div class="stat-desc">{@stats.invoices_this_month} this month</div>
</div>
<div class="stat bg-base-100 rounded-box shadow">
<div class="stat-figure text-success">
<.icon name="hero-banknotes" class="w-8 h-8" />
</div>
<div class="stat-title">Paid Revenue</div>
<div class="stat-value text-success">
<.currency_compact
amount={@stats.total_paid_revenue}
currency={@stats.default_currency}
/>
</div>
<div class="stat-desc">{@stats.paid_invoices_count} paid invoices</div>
</div>
<div class="stat bg-base-100 rounded-box shadow">
<div class="stat-figure text-warning">
<.icon name="hero-clock" class="w-8 h-8" />
</div>
<div class="stat-title">Pending</div>
<div class="stat-value text-warning">
<.currency_compact amount={@stats.pending_revenue} currency={@stats.default_currency} />
</div>
<div class="stat-desc">{@stats.pending_invoices_count} pending invoices</div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<%!-- Recent Orders --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex justify-between items-center mb-4">
<h2 class="card-title">Recent Orders</h2>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/orders")}
class="btn btn-ghost btn-sm"
>
View All <.icon name="hero-arrow-right" class="w-4 h-4" />
</.link>
</div>
<%= if Enum.empty?(@recent_orders) do %>
<div class="text-center py-8 text-base-content/50">
<.icon
name="hero-clipboard-document-list"
class="w-12 h-12 mx-auto mb-2 opacity-50"
/>
<p>No orders yet</p>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/orders/new")}
class="btn btn-primary btn-sm mt-4"
>
Create First Order
</.link>
</div>
<% else %>
<div class="overflow-x-auto">
<table class="table table-sm">
<thead>
<tr>
<th>Order #</th>
<th>Status</th>
<th>Total</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<%= for order <- @recent_orders do %>
<tr
class="hover cursor-pointer"
phx-click="view_order"
phx-value-id={order.id}
>
<td class="font-mono text-sm">{order.order_number}</td>
<td><.order_status_badge status={order.status} /></td>
<td>
<.currency_compact amount={order.total} currency={order.currency} />
</td>
<td class="text-sm text-base-content/60">
<.time_ago datetime={order.inserted_at} />
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
</div>
</div>
<%!-- Recent Invoices --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex justify-between items-center mb-4">
<h2 class="card-title">Recent Invoices</h2>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/invoices")}
class="btn btn-ghost btn-sm"
>
View All <.icon name="hero-arrow-right" class="w-4 h-4" />
</.link>
</div>
<%= if Enum.empty?(@recent_invoices) do %>
<div class="text-center py-8 text-base-content/50">
<.icon name="hero-document-text" class="w-12 h-12 mx-auto mb-2 opacity-50" />
<p>No invoices yet</p>
<p class="text-sm mt-2">Create an order first to generate invoices</p>
</div>
<% else %>
<div class="overflow-x-auto">
<table class="table table-sm">
<thead>
<tr>
<th>Invoice #</th>
<th>Status</th>
<th>Total</th>
<th>Due Date</th>
</tr>
</thead>
<tbody>
<%= for invoice <- @recent_invoices do %>
<tr
class="hover cursor-pointer"
phx-click="view_invoice"
phx-value-id={invoice.id}
>
<td class="font-mono text-sm">{invoice.invoice_number}</td>
<td><.invoice_status_badge status={invoice.status} /></td>
<td>
<.currency_compact amount={invoice.total} currency={invoice.currency} />
</td>
<td class="text-sm text-base-content/60">
<%= if invoice.due_date do %>
{Calendar.strftime(invoice.due_date, "%b %d, %Y")}
<% else %>
<span class="text-base-content/40">-</span>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
</div>
</div>
</div>
<%!-- Quick Actions --%>
<div class="card bg-base-100 shadow-xl mt-6">
<div class="card-body">
<h2 class="card-title mb-4">Quick Actions</h2>
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/orders/new")}
class="btn btn-outline"
>
<.icon name="hero-plus" class="w-5 h-5" /> New Order
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/subscriptions")}
class="btn btn-outline"
>
<.icon name="hero-credit-card" class="w-5 h-5" /> Subscriptions
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/plans")}
class="btn btn-outline"
>
<.icon name="hero-squares-2x2" class="w-5 h-5" /> Plans
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/profiles")}
class="btn btn-outline"
>
<.icon name="hero-users" class="w-5 h-5" /> Billing Profiles
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/billing")}
class="btn btn-outline"
>
<.icon name="hero-cog-6-tooth" class="w-5 h-5" /> Settings
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/billing/providers")}
class="btn btn-primary"
>
<.icon name="hero-credit-card" class="w-5 h-5" /> Payment Providers
</.link>
</div>
</div>
</div>
<%!-- Active Currencies --%>
<div class="card bg-base-100 shadow-xl mt-6">
<div class="card-body">
<div class="flex justify-between items-center mb-4">
<h2 class="card-title">Active Currencies</h2>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/currencies")}
class="btn btn-ghost btn-sm"
>
Manage <.icon name="hero-arrow-right" class="w-4 h-4" />
</.link>
</div>
<div class="flex flex-wrap gap-2">
<%= for currency <- @currencies do %>
<.currency_badge code={currency.code} name={currency.name} size={:md} />
<% end %>
<%= if Enum.empty?(@currencies) do %>
<span class="text-base-content/50">No currencies configured</span>
<% end %>
</div>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>