Packages
phoenix_kit
1.7.21
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/billing_profile_form.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_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/profiles")}
class="btn btn-ghost btn-sm"
>
<.icon name="hero-arrow-left" class="w-4 h-4" />
</.link>
<div>
<h1 class="text-2xl font-bold">{@page_title}</h1>
<p class="text-base-content/60">
<%= if @profile do %>
Edit billing profile details
<% else %>
Create a new billing profile for a user
<% end %>
</p>
</div>
</div>
<.form for={@form} phx-change="validate" phx-submit="save" class="space-y-6">
<%!-- User Selection --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">
<.icon name="hero-user" class="w-5 h-5" /> User
</h2>
<div class="form-control">
<label class="label">
<span class="label-text">Select User *</span>
</label>
<select
name="user_id"
class="select select-bordered"
phx-change="select_user"
disabled={@profile != nil}
>
<option value="">Select a user...</option>
<%= for user <- @users do %>
<option value={user.id} selected={@selected_user_id == user.id}>
{user.email}
<%= if user.first_name do %>
({user.first_name} {user.last_name})
<% end %>
</option>
<% end %>
</select>
<%= if @profile do %>
<label class="label">
<span class="label-text-alt text-info">
User cannot be changed after creation
</span>
</label>
<% end %>
</div>
</div>
</div>
<%!-- Profile Type --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">
<.icon name="hero-identification" class="w-5 h-5" /> Profile Type
</h2>
<div class="flex gap-4">
<label class="cursor-pointer flex items-center gap-2">
<input
type="radio"
name="type"
value="individual"
class="radio radio-primary"
checked={@profile_type == "individual"}
phx-click="change_type"
phx-value-type="individual"
/>
<span class="label-text">
<span class="font-medium">Individual</span>
<span class="text-base-content/60 block text-sm">Personal billing profile</span>
</span>
</label>
<label class="cursor-pointer flex items-center gap-2">
<input
type="radio"
name="type"
value="company"
class="radio radio-primary"
checked={@profile_type == "company"}
phx-click="change_type"
phx-value-type="company"
/>
<span class="label-text">
<span class="font-medium">Company</span>
<span class="text-base-content/60 block text-sm">
Business billing profile (EU)
</span>
</span>
</label>
</div>
</div>
</div>
<%!-- Individual Fields --%>
<%= if @profile_type == "individual" do %>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">
<.icon name="hero-user-circle" class="w-5 h-5" /> Personal Information
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="form-control">
<label class="label">
<span class="label-text">First Name *</span>
</label>
<input
type="text"
name="billing_profile[first_name]"
value={@form[:first_name].value}
class="input input-bordered"
placeholder="John"
/>
<.error :for={msg <- @form[:first_name].errors |> Enum.map(&elem(&1, 0))}>
{msg}
</.error>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Middle Name</span>
</label>
<input
type="text"
name="billing_profile[middle_name]"
value={@form[:middle_name].value}
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Last Name *</span>
</label>
<input
type="text"
name="billing_profile[last_name]"
value={@form[:last_name].value}
class="input input-bordered"
placeholder="Doe"
/>
<.error :for={msg <- @form[:last_name].errors |> Enum.map(&elem(&1, 0))}>
{msg}
</.error>
</div>
</div>
<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">Email</span>
</label>
<input
type="email"
name="billing_profile[email]"
value={@form[:email].value}
class="input input-bordered"
placeholder="john@example.com"
/>
<label class="label">
<span class="label-text-alt">
Billing email (can differ from account email)
</span>
</label>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Phone</span>
</label>
<input
type="tel"
name="billing_profile[phone]"
value={@form[:phone].value}
class="input input-bordered"
placeholder="+372 5555 5555"
/>
</div>
</div>
</div>
</div>
<% end %>
<%!-- Company Fields --%>
<%= if @profile_type == "company" do %>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">
<.icon name="hero-building-office" class="w-5 h-5" /> Company Information
</h2>
<div class="form-control">
<label class="label">
<span class="label-text">Company Name *</span>
</label>
<input
type="text"
name="billing_profile[company_name]"
value={@form[:company_name].value}
class="input input-bordered"
placeholder="Acme Corp OÜ"
/>
<.error :for={msg <- @form[:company_name].errors |> Enum.map(&elem(&1, 0))}>
{msg}
</.error>
</div>
<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">VAT Number</span>
</label>
<input
type="text"
name="billing_profile[company_vat_number]"
value={@form[:company_vat_number].value}
class="input input-bordered font-mono"
placeholder="EE123456789"
/>
<label class="label">
<span class="label-text-alt">EU VAT format: Country code + number</span>
</label>
<.error :for={msg <- @form[:company_vat_number].errors |> Enum.map(&elem(&1, 0))}>
{msg}
</.error>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Registration Number</span>
</label>
<input
type="text"
name="billing_profile[company_registration_number]"
value={@form[:company_registration_number].value}
class="input input-bordered font-mono"
placeholder="12345678"
/>
</div>
</div>
<div class="form-control mt-4">
<label class="label">
<span class="label-text">Legal Address</span>
</label>
<textarea
name="billing_profile[company_legal_address]"
class="textarea textarea-bordered"
rows="2"
placeholder="Registered legal address"
>{@form[:company_legal_address].value}</textarea>
</div>
<div class="divider">Contact</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="form-control">
<label class="label">
<span class="label-text">Contact Email</span>
</label>
<input
type="email"
name="billing_profile[email]"
value={@form[:email].value}
class="input input-bordered"
placeholder="billing@company.com"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Phone</span>
</label>
<input
type="tel"
name="billing_profile[phone]"
value={@form[:phone].value}
class="input input-bordered"
placeholder="+372 5555 5555"
/>
</div>
</div>
</div>
</div>
<% end %>
<%!-- Billing Address --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">
<.icon name="hero-map-pin" class="w-5 h-5" /> Billing Address
</h2>
<div class="form-control">
<label class="label">
<span class="label-text">Address Line 1</span>
</label>
<input
type="text"
name="billing_profile[address_line1]"
value={@form[:address_line1].value}
class="input input-bordered"
placeholder="Street address"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Address Line 2</span>
</label>
<input
type="text"
name="billing_profile[address_line2]"
value={@form[:address_line2].value}
class="input input-bordered"
placeholder="Apartment, suite, etc."
/>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-4">
<div class="form-control">
<label class="label">
<span class="label-text">City</span>
</label>
<input
type="text"
name="billing_profile[city]"
value={@form[:city].value}
class="input input-bordered"
placeholder="Tallinn"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">{@subdivision_label}</span>
</label>
<input
type="text"
name="billing_profile[state]"
value={@form[:state].value}
class="input input-bordered"
placeholder="Harju"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Postal Code</span>
</label>
<input
type="text"
name="billing_profile[postal_code]"
value={@form[:postal_code].value}
class="input input-bordered"
placeholder="10115"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Country</span>
</label>
<select name="billing_profile[country]" class="select select-bordered">
<option value="">Select country...</option>
<%= for {name, code} <- @countries do %>
<option value={code} selected={@form[:country].value == code}>
{name}
</option>
<% end %>
</select>
</div>
</div>
</div>
</div>
<%!-- Options --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">
<.icon name="hero-cog-6-tooth" class="w-5 h-5" /> Options
</h2>
<div class="form-control">
<label class="cursor-pointer label justify-start gap-4">
<input
type="checkbox"
name="billing_profile[is_default]"
value="true"
class="checkbox checkbox-primary"
checked={@form[:is_default].value == true || @form[:is_default].value == "true"}
/>
<div>
<span class="label-text font-medium">Set as default profile</span>
<span class="label-text-alt block">
This profile will be used by default for new orders
</span>
</div>
</label>
</div>
<div class="form-control mt-4">
<label class="label">
<span class="label-text">Profile Name (Optional)</span>
</label>
<input
type="text"
name="billing_profile[name]"
value={@form[:name].value}
class="input input-bordered"
placeholder="e.g., Home Address, Work, Company HQ"
/>
<label class="label">
<span class="label-text-alt">Custom name to identify this profile</span>
</label>
</div>
</div>
</div>
<%!-- Actions --%>
<div class="flex justify-end gap-4">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/profiles")}
class="btn btn-ghost"
>
Cancel
</.link>
<button type="submit" class="btn btn-primary">
<.icon name="hero-check" class="w-4 h-4" />
{if @profile, do: "Update Profile", else: "Create Profile"}
</button>
</div>
</.form>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>