Packages
phoenix_kit
1.2.7
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/phoenix_kit_web/users/registration_live.ex
defmodule PhoenixKitWeb.Users.RegistrationLive do
use PhoenixKitWeb, :live_view
alias PhoenixKit.Admin.Presence
alias PhoenixKit.ReferralCodes
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth
alias PhoenixKit.Users.Auth.User
alias PhoenixKit.Utils.Routes
def render(assigns) do
~H"""
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="{@project_title} - Create account"
>
<div class="flex items-center justify-center py-8 min-h-[80vh] bg-base-200">
<div class="card bg-base-100 w-full max-w-sm shadow-2xl">
<div class="card-body">
<h1 class="text-2xl font-bold text-center mb-6">{@project_title} Create account</h1>
<.form
for={@form}
id="registration_form"
phx-submit="save"
phx-change="validate"
phx-trigger-action={@trigger_submit}
action={Routes.path("/users/log-in?_action=registered")}
method="post"
>
<fieldset class="fieldset">
<legend class="fieldset-legend sr-only">Account Information</legend>
<div :if={@check_errors} class="alert alert-error text-sm mb-4">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>Oops, something went wrong! Please check the errors below.</span>
</div>
<div phx-feedback-for="user[email]">
<.label for="user_email">Email</.label>
<.input
field={@form[:email]}
type="email"
placeholder="Enter your email address"
required
/>
</div>
<%!-- Username Field (optional) --%>
<div phx-feedback-for="user[username]">
<.label for="user_username">Username</.label>
<.input
field={@form[:username]}
type="text"
placeholder="Choose a unique username (optional)"
/>
<div class="text-xs text-base-content/60 mt-1">
If not provided, we'll generate one from your email
</div>
</div>
<%!-- Referral Code Field (shown when referral codes are enabled) --%>
<%= if @referral_codes_enabled do %>
<div phx-feedback-for="referral_code">
<.label for="referral_code">
Referral Code<%= if @referral_codes_required do %>
*
<% end %>
</.label>
<input
id="referral_code"
name="referral_code"
type="text"
class={[
"input input-bordered",
(@referral_code_error ||
(@check_errors && @referral_codes_required &&
(is_nil(@referral_code) || @referral_code == ""))) && "input-error"
]}
placeholder="Enter your referral code"
value={@referral_code || ""}
required={@referral_codes_required}
/>
<%= if @referral_code_error do %>
<.error>{@referral_code_error}</.error>
<% end %>
</div>
<% end %>
<div phx-feedback-for="user[password]">
<.label for="user_password">Password</.label>
<.input
field={@form[:password]}
type="password"
placeholder="Choose a secure password"
required
/>
</div>
<button
type="submit"
phx-disable-with="Creating account..."
class="btn btn-primary w-full mt-4"
>
Create account <span aria-hidden="true">→</span>
</button>
</fieldset>
</.form>
<!-- Login link -->
<div class="text-center mt-4 text-sm">
<span>Already have an account? </span>
<.link
navigate={Routes.path("/users/log-in")}
class="font-semibold text-primary hover:underline"
>
Sign in
</.link>
</div>
<!-- Development Mode Notice -->
<div :if={show_dev_notice?()} class="alert alert-info text-sm mt-4">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
>
</path>
</svg>
<span>
Development mode: Check
<.link href="/dev/mailbox" class="font-semibold underline">mailbox</.link>
for confirmation emails
</span>
</div>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>
"""
end
def mount(_params, session, socket) do
# Track anonymous visitor session
if connected?(socket) do
session_id = session["live_socket_id"] || generate_session_id()
Presence.track_anonymous(session_id, %{
connected_at: DateTime.utc_now(),
ip_address: get_connect_info(socket, :peer_data) |> extract_ip_address(),
user_agent: get_connect_info(socket, :user_agent),
current_page: Routes.path("/users/register")
})
end
# Get project title from settings
project_title = Settings.get_setting("project_title", "PhoenixKit")
# Get referral codes configuration
referral_codes_config = ReferralCodes.get_config()
changeset = Auth.change_user_registration(%User{})
socket =
socket
|> assign(trigger_submit: false, check_errors: false)
|> assign(project_title: project_title)
|> assign(referral_codes_enabled: referral_codes_config.enabled)
|> assign(referral_codes_required: referral_codes_config.required)
|> assign(referral_code: nil)
|> assign(referral_code_error: nil)
|> assign_form(changeset)
{:ok, socket, temporary_assigns: [form: nil]}
end
def handle_event("save", %{"user" => user_params} = params, socket) do
referral_code = params["referral_code"]
# Validate referral code if system is enabled
case validate_referral_code(referral_code, socket) do
{:ok, validated_code} ->
case Auth.register_user(user_params) do
{:ok, user} ->
# Record referral code usage if provided and valid
if validated_code do
ReferralCodes.use_code(validated_code.code, user.id)
end
case Auth.deliver_user_confirmation_instructions(
user,
&Routes.url("/users/confirm/#{&1}")
) do
{:ok, _} ->
# Email sent successfully
:ok
{:error, error} ->
# Log error but don't fail registration
require Logger
Logger.error("Failed to send confirmation email: #{inspect(error)}")
:ok
end
changeset = Auth.change_user_registration(user)
{:noreply, socket |> assign(trigger_submit: true) |> assign_form(changeset)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, socket |> assign(check_errors: true) |> assign_form(changeset)}
end
{:error, error_message} ->
socket =
socket
|> assign(referral_code: referral_code)
|> assign(referral_code_error: error_message)
|> assign(check_errors: true)
{:noreply, socket}
end
end
def handle_event("validate", %{"user" => user_params} = params, socket) do
referral_code = params["referral_code"]
# Validate referral code and update error state
case validate_referral_code(referral_code, socket) do
{:ok, _} ->
socket =
socket
|> assign(referral_code: referral_code)
|> assign(referral_code_error: nil)
changeset = Auth.change_user_registration(%User{}, user_params)
{:noreply, assign_form(socket, Map.put(changeset, :action, :validate))}
{:error, error_message} ->
socket =
socket
|> assign(referral_code: referral_code)
|> assign(referral_code_error: error_message)
changeset = Auth.change_user_registration(%User{}, user_params)
{:noreply, assign_form(socket, Map.put(changeset, :action, :validate))}
end
end
defp assign_form(socket, %Ecto.Changeset{} = changeset) do
form = to_form(changeset, as: "user")
if changeset.valid? do
assign(socket, form: form, check_errors: false)
else
assign(socket, form: form)
end
end
defp validate_referral_code(referral_code, socket) do
cond do
# If referral codes are disabled, always allow registration
not socket.assigns.referral_codes_enabled ->
{:ok, nil}
# If referral codes are required but none provided
socket.assigns.referral_codes_required and
(is_nil(referral_code) or String.trim(referral_code) == "") ->
{:error, "Referral code is required"}
# If referral code is provided, validate it
referral_code && String.trim(referral_code) != "" ->
validate_referral_code_value(String.trim(referral_code))
# If referral codes are optional and none provided
true ->
{:ok, nil}
end
end
defp validate_referral_code_value(code_string) do
case ReferralCodes.get_code_by_string(code_string) do
nil ->
{:error, "Invalid referral code"}
code ->
cond do
not code.status ->
{:error, "This referral code is no longer active"}
PhoenixKit.ReferralCodes.expired?(code) ->
{:error, "This referral code has expired"}
PhoenixKit.ReferralCodes.usage_limit_reached?(code) ->
{:error, "This referral code has reached its usage limit"}
true ->
{:ok, code}
end
end
end
defp show_dev_notice? do
case Application.get_env(:phoenix_kit, PhoenixKit.Mailer)[:adapter] do
Swoosh.Adapters.Local -> true
_ -> false
end
end
defp generate_session_id do
:crypto.strong_rand_bytes(16) |> Base.encode64()
end
defp extract_ip_address(nil), do: "unknown"
defp extract_ip_address(%{address: {a, b, c, d}}), do: "#{a}.#{b}.#{c}.#{d}"
defp extract_ip_address(%{address: address}), do: to_string(address)
defp extract_ip_address(_), do: "unknown"
end