Packages
phoenix_kit
1.7.42
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
Current section
Files
lib/modules/billing/web/order_form.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="{@project_title} {@page_title}"
current_path={@url_path}
project_title={@project_title}
>
<div class="container mx-auto px-4 py-6 max-w-4xl">
<%!-- Header --%>
<div class="flex items-center gap-4 mb-6">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/orders")}
class="btn btn-ghost btn-sm"
>
<.icon name="hero-arrow-left" class="w-4 h-4" />
</.link>
<div>
<h1 class="text-3xl font-bold">{@page_title}</h1>
<p class="text-base-content/60 mt-1">
{if @order, do: "Modify order details", else: "Create a new order"}
</p>
</div>
</div>
<.form for={@form} phx-submit="save" class="space-y-6">
<%!-- Customer Selection --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">Customer</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
<div class="form-control">
<label class="label">
<span class="label-text">Select Customer</span>
</label>
<select
name="user_id"
class="select select-bordered"
phx-change="select_user"
>
<option value="">Select a customer...</option>
<%= for user <- @users do %>
<option
value={user.uuid}
selected={to_string(@selected_user_uuid) == to_string(user.uuid)}
>
{user.email}
</option>
<% end %>
</select>
</div>
<%= if @selected_user_uuid do %>
<%= if length(@billing_profiles) > 0 do %>
<div class="form-control">
<label class="label">
<span class="label-text">
Billing Profile <span class="text-error">*</span>
</span>
</label>
<select
name="order[billing_profile_uuid]"
class="select select-bordered"
phx-change="select_billing_profile"
required
>
<%= for profile <- @billing_profiles do %>
<option
value={profile.uuid}
selected={
to_string(@selected_billing_profile_uuid) == to_string(profile.uuid)
}
>
<%= if profile.type == "company" do %>
{profile.company_name}
<% else %>
{profile.first_name} {profile.last_name}
<% end %>
{if profile.is_default, do: "(Default)"}
</option>
<% end %>
</select>
</div>
<% else %>
<%!-- Warning: No billing profiles - block order creation --%>
<div class="md:col-span-2">
<div class="alert alert-warning">
<.icon name="hero-exclamation-triangle" class="w-5 h-5" />
<div>
<p class="font-semibold">No billing profile found</p>
<p class="text-sm">
This customer has no billing profile. A billing profile is required to create an order.
<.link
navigate={
PhoenixKit.Utils.Routes.path(
"/admin/billing/profiles/new?user_id=#{@selected_user_uuid}"
)
}
class="link font-medium"
>
Create one now
</.link>
</p>
</div>
</div>
</div>
<% end %>
<% end %>
</div>
</div>
</div>
<%!-- Line Items --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex justify-between items-center">
<h2 class="card-title">Line Items</h2>
<button type="button" phx-click="add_line_item" class="btn btn-outline btn-sm">
<.icon name="hero-plus" class="w-4 h-4" /> Add Item
</button>
</div>
<div class="overflow-x-auto mt-4">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th class="w-24">Qty</th>
<th class="w-32">Unit Price</th>
<th class="w-16"></th>
</tr>
</thead>
<tbody>
<%= for item <- @line_items do %>
<tr>
<td>
<input
type="text"
value={item.name}
class="input input-bordered input-sm w-full"
placeholder="Item name"
phx-blur="update_line_item"
phx-value-id={item.id}
phx-value-field="name"
name={"line_item_#{item.id}_name"}
/>
</td>
<td>
<input
type="text"
value={item.description}
class="input input-bordered input-sm w-full"
placeholder="Description (optional)"
phx-blur="update_line_item"
phx-value-id={item.id}
phx-value-field="description"
name={"line_item_#{item.id}_desc"}
/>
</td>
<td>
<input
type="number"
value={item.quantity}
class="input input-bordered input-sm w-full"
min="1"
phx-blur="update_line_item"
phx-value-id={item.id}
phx-value-field="quantity"
name={"line_item_#{item.id}_qty"}
/>
</td>
<td>
<input
type="text"
value={item.unit_price}
class="input input-bordered input-sm w-full font-mono"
placeholder="0.00"
phx-blur="update_line_item"
phx-value-id={item.id}
phx-value-field="unit_price"
name={"line_item_#{item.id}_price"}
/>
</td>
<td>
<button
type="button"
phx-click="remove_line_item"
phx-value-id={item.id}
class="btn btn-ghost btn-sm btn-square text-error"
>
<.icon name="hero-trash" class="w-4 h-4" />
</button>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
<%!-- Order Settings --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">Order Settings</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
<div class="form-control">
<label class="label">
<span class="label-text">Currency</span>
</label>
<select name="order[currency]" class="select select-bordered">
<%= for currency <- @currencies do %>
<option value={currency.code} selected={@form[:currency].value == currency.code}>
{currency.code} - {currency.name}
</option>
<% end %>
</select>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Status</span>
</label>
<select
name="order[status]"
class="select select-bordered"
disabled={is_nil(@order)}
>
<option value="draft" selected={@form[:status].value == "draft"}>Draft</option>
<option value="pending" selected={@form[:status].value == "pending"}>
Pending
</option>
<option value="confirmed" selected={@form[:status].value == "confirmed"}>
Confirmed
</option>
</select>
</div>
</div>
</div>
</div>
<%!-- Notes --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">Notes</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
<div class="form-control">
<label class="label">
<span class="label-text">Customer Notes</span>
</label>
<textarea
name="order[notes]"
class="textarea textarea-bordered"
rows="3"
placeholder="Notes visible to customer..."
>{@form[:notes].value}</textarea>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Internal Notes</span>
</label>
<textarea
name="order[internal_notes]"
class="textarea textarea-bordered"
rows="3"
placeholder="Admin-only notes..."
>{@form[:internal_notes].value}</textarea>
</div>
</div>
</div>
</div>
<%!-- Actions --%>
<div class="flex justify-end gap-4">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/orders")}
class="btn btn-ghost"
>
Cancel
</.link>
<button
type="submit"
class="btn btn-primary"
disabled={@selected_user_uuid && Enum.empty?(@billing_profiles)}
>
<.icon name="hero-check" class="w-4 h-4" />
{if @order, do: "Update Order", else: "Create Order"}
</button>
</div>
</.form>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>