diff --git a/lib/towerops/accounts/user.ex b/lib/towerops/accounts/user.ex
index 5fd5f5a1..b55f68e7 100644
--- a/lib/towerops/accounts/user.ex
+++ b/lib/towerops/accounts/user.ex
@@ -23,7 +23,8 @@ defmodule Towerops.Accounts.User do
field :confirmed_at, :utc_datetime
field :authenticated_at, :utc_datetime, virtual: true
field :is_superuser, :boolean, default: false
- field :name, :string
+ field :first_name, :string
+ field :last_name, :string
field :timezone, :string, default: "UTC"
field :totp_secret, :binary, redact: true
field :totp_verified_at, :utc_datetime, virtual: true
@@ -46,7 +47,8 @@ defmodule Towerops.Accounts.User do
confirmed_at: DateTime.t() | nil,
authenticated_at: DateTime.t() | nil,
is_superuser: boolean(),
- name: String.t() | nil,
+ first_name: String.t() | nil,
+ last_name: String.t() | nil,
timezone: String.t(),
totp_secret: binary() | nil,
totp_verified_at: DateTime.t() | nil,
@@ -100,12 +102,13 @@ defmodule Towerops.Accounts.User do
end
@doc """
- A user changeset for updating the profile information (name, timezone).
+ A user changeset for updating the profile information (first_name, last_name, timezone).
"""
def profile_changeset(user, attrs) do
user
- |> cast(attrs, [:name, :timezone])
- |> validate_length(:name, max: 255)
+ |> cast(attrs, [:first_name, :last_name, :timezone])
+ |> validate_length(:first_name, max: 100)
+ |> validate_length(:last_name, max: 100)
|> validate_length(:timezone, max: 100)
end
@@ -124,11 +127,13 @@ defmodule Towerops.Accounts.User do
"""
def registration_changeset(user, attrs, opts \\ []) do
user
- |> cast(attrs, [:email, :password, :timezone, :privacy_policy_consent, :terms_of_service_consent])
+ |> cast(attrs, [:email, :password, :first_name, :last_name, :timezone, :privacy_policy_consent, :terms_of_service_consent])
|> validate_email_for_registration(opts)
|> validate_password(opts)
|> validate_consent()
|> validate_timezone()
+ |> validate_length(:first_name, max: 100)
+ |> validate_length(:last_name, max: 100)
end
defp validate_consent(changeset) do
@@ -255,4 +260,19 @@ defmodule Towerops.Accounts.User do
Argon2.no_user_verify()
false
end
+
+ @doc """
+ Returns the user's full name by combining first_name and last_name.
+
+ Returns nil if both fields are nil or empty.
+ """
+ @spec full_name(t()) :: String.t() | nil
+ def full_name(%__MODULE__{first_name: first, last_name: last}) do
+ [first, last]
+ |> Enum.reject(&(is_nil(&1) or &1 == ""))
+ |> case do
+ [] -> nil
+ parts -> Enum.join(parts, " ")
+ end
+ end
end
diff --git a/lib/towerops_web/controllers/api/account_data_controller.ex b/lib/towerops_web/controllers/api/account_data_controller.ex
index 2ee7cfe9..4fa2431b 100644
--- a/lib/towerops_web/controllers/api/account_data_controller.ex
+++ b/lib/towerops_web/controllers/api/account_data_controller.ex
@@ -47,7 +47,8 @@ defmodule ToweropsWeb.Api.AccountDataController do
%{
id: user.id,
email: user.email,
- name: user.name,
+ first_name: user.first_name,
+ last_name: user.last_name,
timezone: user.timezone,
is_superuser: user.is_superuser,
confirmed_at: user.confirmed_at,
diff --git a/lib/towerops_web/live/account_live/my_data.ex b/lib/towerops_web/live/account_live/my_data.ex
index b5eccec6..431673cd 100644
--- a/lib/towerops_web/live/account_live/my_data.ex
+++ b/lib/towerops_web/live/account_live/my_data.ex
@@ -166,9 +166,15 @@ defmodule ToweropsWeb.AccountLive.MyData do
{@user_data.profile.email}
-
Name
+ First Name
- {@user_data.profile.name || "Not set"}
+ {@user_data.profile.first_name || "Not set"}
+
+
+
+
Last Name
+
+ {@user_data.profile.last_name || "Not set"}
@@ -564,7 +570,8 @@ defmodule ToweropsWeb.AccountLive.MyData do
defp get_user_profile(user) do
%{
email: user.email,
- name: user.name,
+ first_name: user.first_name,
+ last_name: user.last_name,
timezone: user.timezone,
inserted_at: user.inserted_at,
confirmed_at: user.confirmed_at
diff --git a/lib/towerops_web/live/user_registration_live.ex b/lib/towerops_web/live/user_registration_live.ex
index 79ef06b2..20fa686e 100644
--- a/lib/towerops_web/live/user_registration_live.ex
+++ b/lib/towerops_web/live/user_registration_live.ex
@@ -167,13 +167,27 @@ defmodule ToweropsWeb.UserRegistrationLive do
<% end %>
+
+ <.input
+ field={@form[:first_name]}
+ type="text"
+ label="First name"
+ autocomplete="given-name"
+ phx-mounted={JS.focus()}
+ />
+ <.input
+ field={@form[:last_name]}
+ type="text"
+ label="Last name"
+ autocomplete="family-name"
+ />
+
<.input
field={@form[:email]}
type="email"
label="Email"
autocomplete="email"
required
- phx-mounted={JS.focus()}
/>
<.input
field={@form[:password]}
diff --git a/lib/towerops_web/live/user_settings_live.ex b/lib/towerops_web/live/user_settings_live.ex
index 99d21001..bd80c215 100644
--- a/lib/towerops_web/live/user_settings_live.ex
+++ b/lib/towerops_web/live/user_settings_live.ex
@@ -759,17 +759,39 @@ defmodule ToweropsWeb.UserSettingsLive do
class="md:col-span-2"
>
-
-