Packages

phoenix_kit

1.7.44
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 modules billing web invoices.html.heex
Raw

lib/modules/billing/web/invoices.html.heex

<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="{@project_title} Invoices"
current_path={@url_path}
project_title={@project_title}
>
<div class="container mx-auto px-4 py-6">
<%!-- Header --%>
<.admin_page_header back={PhoenixKit.Utils.Routes.path("/admin/billing")}>
<h1 class="text-xl sm:text-2xl lg:text-3xl font-bold text-base-content">Invoices</h1>
<p class="text-sm text-base-content/60 mt-0.5">{@total_count} total invoices</p>
<:actions>
<button phx-click="refresh" class="btn btn-ghost btn-sm">
<.icon name="hero-arrow-path" class="w-4 h-4" /> Refresh
</button>
</:actions>
</.admin_page_header>
<%!-- Filters --%>
<div class="card bg-base-100 shadow mb-6">
<div class="card-body py-4">
<form phx-change="filter" phx-submit="filter" class="flex flex-wrap gap-4 items-end">
<div class="form-control flex-1 min-w-[200px]">
<label class="label">
<span class="label-text">Search</span>
</label>
<input
type="text"
name="search"
value={@search}
placeholder="Invoice number, customer..."
class="input input-bordered input-sm"
phx-debounce="300"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Status</span>
</label>
<select name="status" class="select select-bordered select-sm">
<option value="all" selected={@status_filter == "all"}>All Statuses</option>
<option value="draft" selected={@status_filter == "draft"}>Draft</option>
<option value="sent" selected={@status_filter == "sent"}>Sent</option>
<option value="paid" selected={@status_filter == "paid"}>Paid</option>
<option value="void" selected={@status_filter == "void"}>Void</option>
<option value="overdue" selected={@status_filter == "overdue"}>Overdue</option>
</select>
</div>
<button type="button" phx-click="clear_filters" class="btn btn-ghost btn-sm">
Clear Filters
</button>
</form>
</div>
</div>
<%!-- Invoices Table --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body p-0">
<%= if @loading do %>
<div class="flex justify-center items-center py-12">
<span class="loading loading-spinner loading-lg"></span>
</div>
<% else %>
<%= if Enum.empty?(@invoices) do %>
<div class="text-center py-12">
<.icon
name="hero-document-text"
class="w-16 h-16 mx-auto mb-4 text-base-content/30"
/>
<h3 class="text-xl font-semibold mb-2">No invoices found</h3>
<p class="text-base-content/60 mb-4">
<%= if @search != "" or @status_filter != "all" do %>
Try adjusting your filters or search terms
<% else %>
Invoices are generated from orders
<% end %>
</p>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/orders")}
class="btn btn-primary"
>
View Orders
</.link>
</div>
<% else %>
<div class="overflow-x-auto">
<table class="table">
<thead>
<tr>
<th>Invoice #</th>
<th>Order #</th>
<th>Customer</th>
<th>Status</th>
<th>Total</th>
<th>Due Date</th>
<th></th>
</tr>
</thead>
<tbody>
<%= for invoice <- @invoices do %>
<tr
class="hover cursor-pointer"
phx-click="view_invoice"
phx-value-uuid={invoice.uuid}
>
<td class="font-mono">{invoice.invoice_number}</td>
<td class="font-mono text-sm text-base-content/60">
<%= if invoice.order do %>
{invoice.order.order_number}
<% else %>
<span class="text-base-content/40">-</span>
<% end %>
</td>
<td>
<%= if invoice.user do %>
<div class="flex items-center gap-2">
<.user_avatar user={invoice.user} size="sm" />
<div class="font-medium text-sm">{invoice.user.email}</div>
</div>
<% else %>
<span class="text-base-content/50">-</span>
<% end %>
</td>
<td><.invoice_status_badge status={invoice.status} /></td>
<td>
<.currency_compact amount={invoice.total} currency={invoice.currency} />
</td>
<td class="text-sm">
<%= if invoice.due_date do %>
<% is_overdue =
Date.compare(invoice.due_date, Date.utc_today()) == :lt and
invoice.status != "paid" %>
<span class={
if is_overdue,
do: "text-error font-medium",
else: "text-base-content/60"
}>
{Calendar.strftime(invoice.due_date, "%b %d, %Y")}
</span>
<% else %>
<span class="text-base-content/40">-</span>
<% end %>
</td>
<td>
<.link
navigate={
PhoenixKit.Utils.Routes.path(
"/admin/billing/invoices/#{invoice.uuid}"
)
}
class="btn btn-ghost btn-xs"
>
<.icon name="hero-eye" class="w-4 h-4" />
</.link>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<%!-- Pagination --%>
<%= if @total_pages > 1 do %>
<div class="flex justify-center py-4">
<.pagination
current_page={@page}
total_pages={@total_pages}
base_path={PhoenixKit.Utils.Routes.path("/admin/billing/invoices")}
params={%{"search" => @search, "status" => @status_filter}}
/>
</div>
<% end %>
<% end %>
<% end %>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>