style: consistent back button and some translations
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
91cf7cca6a
commit
0f12befd11
26 changed files with 747 additions and 710 deletions
|
|
@ -111,7 +111,7 @@ defmodule MvWeb.CoreComponents do
|
|||
<.button variant="ghost" size="sm">Edit</.button>
|
||||
<.button disabled={true}>Disabled</.button>
|
||||
"""
|
||||
attr :rest, :global, include: ~w(href navigate patch method data-testid)
|
||||
attr :rest, :global, include: ~w(href navigate patch method data-testid form)
|
||||
|
||||
attr :variant, :string,
|
||||
values: ~w(primary secondary neutral ghost outline danger link icon),
|
||||
|
|
@ -633,17 +633,24 @@ defmodule MvWeb.CoreComponents do
|
|||
|
||||
@doc """
|
||||
Renders a header with title.
|
||||
|
||||
Use the `:leading` slot for the Back button (left side, consistent with data fields).
|
||||
Use the `:actions` slot for primary actions (e.g. Save) on the right.
|
||||
"""
|
||||
attr :class, :string, default: nil
|
||||
|
||||
slot :leading, doc: "Content on the left (e.g. Back button)"
|
||||
slot :inner_block, required: true
|
||||
slot :subtitle
|
||||
slot :actions
|
||||
|
||||
def header(assigns) do
|
||||
~H"""
|
||||
<header class={[@actions != [] && "flex items-center justify-between gap-6", "pb-4", @class]}>
|
||||
<div>
|
||||
<header class={["flex items-center gap-6 pb-4", @class]}>
|
||||
<div :if={@leading != []} class="shrink-0">
|
||||
{render_slot(@leading)}
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<h1 class="text-xl font-semibold leading-8">
|
||||
{render_slot(@inner_block)}
|
||||
</h1>
|
||||
|
|
@ -651,7 +658,9 @@ defmodule MvWeb.CoreComponents do
|
|||
{render_slot(@subtitle)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-4 justify-end">{render_slot(@actions)}</div>
|
||||
<div :if={@actions != []} class="shrink-0 flex gap-4 justify-end">
|
||||
{render_slot(@actions)}
|
||||
</div>
|
||||
</header>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ defmodule MvWeb.Components.FieldVisibilityDropdownComponent do
|
|||
|
||||
defp find_custom_field_name(id, _field_string, custom_fields) do
|
||||
case Enum.find(custom_fields, fn cf -> to_string(cf.id) == id end) do
|
||||
nil -> gettext("Custom Field %{id}", id: id)
|
||||
nil -> gettext("Datafield %{id}", id: id)
|
||||
custom_field -> custom_field.name
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ defmodule MvWeb.Components.MemberFilterComponent do
|
|||
<!-- Custom Fields Group -->
|
||||
<div :if={length(@boolean_custom_fields) > 0} class="mb-2">
|
||||
<div class="text-xs font-semibold opacity-70 mb-2 uppercase tracking-wider">
|
||||
{gettext("Custom Fields")}
|
||||
{gettext("Individual datafields")}
|
||||
</div>
|
||||
<div class="max-h-60 overflow-y-auto pr-2">
|
||||
<fieldset
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ defmodule MvWeb.CustomFieldLive.FormComponent do
|
|||
<div class="border border-base-300 rounded-lg p-4 bg-base-100">
|
||||
<p class="text-base-content/70 mb-4">
|
||||
{gettext(
|
||||
"Deleting this data field cannot be undone. All custom field values for this field will be permanently removed."
|
||||
"Deleting this data field cannot be undone. All datafield values for this field will be permanently removed."
|
||||
)}
|
||||
</p>
|
||||
<.button
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do
|
|||
phx-target={@myself}
|
||||
disabled={@slug_confirmation != @custom_field_to_delete.slug}
|
||||
>
|
||||
{gettext("Delete Custom Field and All Values")}
|
||||
{gettext("Delete Datafields and All Values")}
|
||||
</.button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ defmodule MvWeb.GlobalSettingsLive do
|
|||
</div>
|
||||
|
||||
<.button phx-disable-with={gettext("Saving...")} variant="primary">
|
||||
{gettext("Save Settings")}
|
||||
{gettext("Save Name")}
|
||||
</.button>
|
||||
</.form>
|
||||
</.form_section>
|
||||
|
|
|
|||
|
|
@ -79,12 +79,14 @@ defmodule MvWeb.GroupLive.Form do
|
|||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.form for={@form} id="group-form" phx-change="validate" phx-submit="save">
|
||||
<.header>
|
||||
{@page_title}
|
||||
<:actions>
|
||||
<:leading>
|
||||
<.button navigate={return_path(@return_to, @group)} variant="neutral">
|
||||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
{@page_title}
|
||||
<:actions>
|
||||
<.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
|
||||
{gettext("Save")}
|
||||
</.button>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ defmodule MvWeb.GroupLive.Show do
|
|||
end
|
||||
end
|
||||
|
||||
defp load_group_by_slug(socket, slug, actor, params \\ %{}) do
|
||||
defp load_group_by_slug(socket, slug, actor, params) do
|
||||
# Load group with members and member_count
|
||||
# Using explicit load ensures efficient preloading of members relationship
|
||||
require Ash.Query
|
||||
|
|
@ -92,8 +92,7 @@ defmodule MvWeb.GroupLive.Show do
|
|||
~H"""
|
||||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.header>
|
||||
{@group.name}
|
||||
<:actions>
|
||||
<:leading>
|
||||
<.button
|
||||
navigate={~p"/groups"}
|
||||
variant="neutral"
|
||||
|
|
@ -102,13 +101,16 @@ defmodule MvWeb.GroupLive.Show do
|
|||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
{@group.name}
|
||||
<:actions>
|
||||
<%= if can?(@current_user, :update, @group) do %>
|
||||
<.button
|
||||
variant="primary"
|
||||
navigate={~p"/groups/#{@group.slug}/edit"}
|
||||
data-testid="group-show-edit-btn"
|
||||
>
|
||||
{gettext("Edit group")}
|
||||
<.icon name="hero-pencil-square" /> {gettext("Edit group")}
|
||||
</.button>
|
||||
<% end %>
|
||||
</:actions>
|
||||
|
|
|
|||
|
|
@ -39,16 +39,18 @@ defmodule MvWeb.MemberLive.Form do
|
|||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.form for={@form} id="member-form" phx-change="validate" phx-submit="save">
|
||||
<.header>
|
||||
<:leading>
|
||||
<.button navigate={return_path(@return_to, @member)} variant="neutral">
|
||||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
<%= if @member do %>
|
||||
{MvWeb.Helpers.MemberHelpers.display_name(@member)}
|
||||
<% else %>
|
||||
{gettext("New Member")}
|
||||
<% end %>
|
||||
<:actions>
|
||||
<.button navigate={return_path(@return_to, @member)} variant="neutral">
|
||||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
<.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
|
||||
{gettext("Save")}
|
||||
</.button>
|
||||
|
|
@ -408,32 +410,33 @@ defmodule MvWeb.MemberLive.Form do
|
|||
member = socket.assigns.member
|
||||
actor = current_actor(socket)
|
||||
|
||||
if is_nil(member) do
|
||||
{:noreply, put_flash(socket, :error, gettext("Member not found"))}
|
||||
else
|
||||
if to_string(id) != to_string(member.id) do
|
||||
cond do
|
||||
is_nil(member) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("Member not found"))}
|
||||
else
|
||||
case Ash.destroy(member, actor: actor) do
|
||||
:ok ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:success, gettext("Member deleted successfully"))
|
||||
|> push_navigate(to: ~p"/members")}
|
||||
|
||||
{:error, %Ash.Error.Forbidden{}} ->
|
||||
{:noreply,
|
||||
put_flash(
|
||||
socket,
|
||||
:error,
|
||||
gettext("You do not have permission to delete this member")
|
||||
)}
|
||||
to_string(id) != to_string(member.id) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("Member not found"))}
|
||||
|
||||
{:error, error} ->
|
||||
Logger.warning("Member delete failed: member_id=#{member.id} error=#{inspect(error)}")
|
||||
{:noreply, put_flash(socket, :error, format_destroy_error(error))}
|
||||
end
|
||||
end
|
||||
true ->
|
||||
handle_member_delete_destroy(socket, member, actor)
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_member_delete_destroy(socket, member, actor) do
|
||||
case Ash.destroy(member, actor: actor) do
|
||||
:ok ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:success, gettext("Member deleted successfully"))
|
||||
|> push_navigate(to: ~p"/members")}
|
||||
|
||||
{:error, %Ash.Error.Forbidden{}} ->
|
||||
{:noreply,
|
||||
put_flash(socket, :error, gettext("You do not have permission to delete this member"))}
|
||||
|
||||
{:error, error} ->
|
||||
Logger.warning("Member delete failed: member_id=#{member.id} error=#{inspect(error)}")
|
||||
{:noreply, put_flash(socket, :error, format_destroy_error(error))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ defmodule MvWeb.MemberLive.Show do
|
|||
~H"""
|
||||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.header>
|
||||
{MvWeb.Helpers.MemberHelpers.display_name(@member)}
|
||||
<:actions>
|
||||
<:leading>
|
||||
<.button
|
||||
navigate={~p"/members?highlight=#{@member.id}"}
|
||||
variant="neutral"
|
||||
|
|
@ -41,13 +40,16 @@ defmodule MvWeb.MemberLive.Show do
|
|||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
{MvWeb.Helpers.MemberHelpers.display_name(@member)}
|
||||
<:actions>
|
||||
<%= if can?(@current_user, :update, @member) do %>
|
||||
<.button
|
||||
variant="primary"
|
||||
navigate={~p"/members/#{@member}/edit?return_to=show"}
|
||||
data-testid="member-edit"
|
||||
>
|
||||
{gettext("Edit member")}
|
||||
<.icon name="hero-pencil-square" /> {gettext("Edit member")}
|
||||
</.button>
|
||||
<% end %>
|
||||
</:actions>
|
||||
|
|
|
|||
|
|
@ -27,10 +27,26 @@ defmodule MvWeb.MembershipFeeTypeLive.Form do
|
|||
~H"""
|
||||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.header>
|
||||
<:leading>
|
||||
<.button navigate={return_path(@return_to, @membership_fee_type)} variant="neutral">
|
||||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
{@page_title}
|
||||
<:subtitle>
|
||||
{gettext("Use this form to manage membership fee types in your database.")}
|
||||
</:subtitle>
|
||||
<:actions>
|
||||
<.button
|
||||
form="membership-fee-type-form"
|
||||
phx-disable-with={gettext("Saving...")}
|
||||
variant="primary"
|
||||
type="submit"
|
||||
>
|
||||
{gettext("Save")}
|
||||
</.button>
|
||||
</:actions>
|
||||
</.header>
|
||||
|
||||
<.form
|
||||
|
|
|
|||
|
|
@ -23,13 +23,15 @@ defmodule MvWeb.RoleLive.Form do
|
|||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.form class="max-w-xl" for={@form} id="role-form" phx-change="validate" phx-submit="save">
|
||||
<.header>
|
||||
{@page_title}
|
||||
<:subtitle>{gettext("Use this form to manage roles in your database.")}</:subtitle>
|
||||
<:actions>
|
||||
<:leading>
|
||||
<.button navigate={return_path(@return_to, @role)} variant="neutral">
|
||||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
{@page_title}
|
||||
<:subtitle>{gettext("Use this form to manage roles in your database.")}</:subtitle>
|
||||
<:actions>
|
||||
<.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
|
||||
{gettext("Save")}
|
||||
</.button>
|
||||
|
|
|
|||
|
|
@ -161,10 +161,7 @@ defmodule MvWeb.RoleLive.Show do
|
|||
~H"""
|
||||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.header>
|
||||
{gettext("Role")} {@role.name}
|
||||
<:subtitle>{gettext("Role details and permissions.")}</:subtitle>
|
||||
|
||||
<:actions>
|
||||
<:leading>
|
||||
<.button
|
||||
navigate={~p"/admin/roles"}
|
||||
variant="neutral"
|
||||
|
|
@ -173,13 +170,18 @@ defmodule MvWeb.RoleLive.Show do
|
|||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
{gettext("Role")} {@role.name}
|
||||
<:subtitle>{gettext("Role details and permissions.")}</:subtitle>
|
||||
|
||||
<:actions>
|
||||
<%= if can?(@current_user, :update, Mv.Authorization.Role) do %>
|
||||
<.button
|
||||
variant="primary"
|
||||
navigate={~p"/admin/roles/#{@role}/edit"}
|
||||
data-testid="role-show-edit-btn"
|
||||
>
|
||||
{gettext("Edit role")}
|
||||
<.icon name="hero-pencil-square" /> {gettext("Edit role")}
|
||||
</.button>
|
||||
<% end %>
|
||||
</:actions>
|
||||
|
|
|
|||
|
|
@ -46,8 +46,24 @@ defmodule MvWeb.UserLive.Form do
|
|||
~H"""
|
||||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.header>
|
||||
<:leading>
|
||||
<.button navigate={return_path(@return_to, @user)} variant="neutral">
|
||||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
{@page_title}
|
||||
<:subtitle>{gettext("Use this form to manage user records in your database.")}</:subtitle>
|
||||
<:actions>
|
||||
<.button
|
||||
form="user-form"
|
||||
phx-disable-with={gettext("Saving...")}
|
||||
variant="primary"
|
||||
type="submit"
|
||||
>
|
||||
{gettext("Save User")}
|
||||
</.button>
|
||||
</:actions>
|
||||
</.header>
|
||||
|
||||
<.form class="max-w-xl" for={@form} id="user-form" phx-change="validate" phx-submit="save">
|
||||
|
|
@ -300,7 +316,8 @@ defmodule MvWeb.UserLive.Form do
|
|||
phx-click="delete"
|
||||
phx-value-id={@user.id}
|
||||
data-confirm={
|
||||
gettext("Are you sure you want to delete the user %{email}? This action cannot be undone.",
|
||||
gettext(
|
||||
"Are you sure you want to delete the user %{email}? This action cannot be undone.",
|
||||
email: @user.email
|
||||
)
|
||||
}
|
||||
|
|
@ -442,36 +459,18 @@ defmodule MvWeb.UserLive.Form do
|
|||
user = socket.assigns.user
|
||||
actor = current_actor(socket)
|
||||
|
||||
if is_nil(user) do
|
||||
{:noreply, put_flash(socket, :error, gettext("User not found"))}
|
||||
else
|
||||
if to_string(id) != to_string(user.id) do
|
||||
cond do
|
||||
is_nil(user) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("User not found"))}
|
||||
else
|
||||
if Mv.Helpers.SystemActor.system_user?(user) do
|
||||
{:noreply,
|
||||
put_flash(socket, :error, gettext("System user cannot be deleted."))}
|
||||
else
|
||||
case Ash.destroy(user, domain: Mv.Accounts, actor: actor) do
|
||||
:ok ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:success, gettext("User deleted successfully"))
|
||||
|> push_navigate(to: ~p"/users")}
|
||||
|
||||
{:error, %Ash.Error.Forbidden{}} ->
|
||||
{:noreply,
|
||||
put_flash(
|
||||
socket,
|
||||
:error,
|
||||
gettext("You do not have permission to delete this user")
|
||||
)}
|
||||
to_string(id) != to_string(user.id) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("User not found"))}
|
||||
|
||||
{:error, error} ->
|
||||
{:noreply, put_flash(socket, :error, format_ash_error(error))}
|
||||
end
|
||||
end
|
||||
end
|
||||
Mv.Helpers.SystemActor.system_user?(user) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("System user cannot be deleted."))}
|
||||
|
||||
true ->
|
||||
handle_user_delete_destroy(socket, user, actor)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -585,6 +584,23 @@ defmodule MvWeb.UserLive.Form do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
defp handle_user_delete_destroy(socket, user, actor) do
|
||||
case Ash.destroy(user, domain: Mv.Accounts, actor: actor) do
|
||||
:ok ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:success, gettext("User deleted successfully"))
|
||||
|> push_navigate(to: ~p"/users")}
|
||||
|
||||
{:error, %Ash.Error.Forbidden{}} ->
|
||||
{:noreply,
|
||||
put_flash(socket, :error, gettext("You do not have permission to delete this user"))}
|
||||
|
||||
{:error, error} ->
|
||||
{:noreply, put_flash(socket, :error, format_ash_error(error))}
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_member_linking(socket, user, actor) do
|
||||
result = perform_member_link_action(socket, user, actor)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,15 +7,10 @@ defmodule MvWeb.UserLive.Index do
|
|||
- Sort users by email (default)
|
||||
- Navigate to user details (row click) and edit from details header
|
||||
- Delete only via Danger zone on user show/edit
|
||||
- Bulk selection for future batch operations
|
||||
|
||||
## Relationships
|
||||
Displays linked member information when a user is connected to a member account.
|
||||
|
||||
## Events
|
||||
- `select_user` - Toggle individual user selection
|
||||
- `select_all` - Toggle selection of all visible users
|
||||
|
||||
## Security
|
||||
User deletion requires admin permissions (enforced by Ash policies).
|
||||
"""
|
||||
|
|
@ -42,24 +37,7 @@ defmodule MvWeb.UserLive.Index do
|
|||
|> assign(:page_title, gettext("Listing Users"))
|
||||
|> assign(:sort_field, :email)
|
||||
|> assign(:sort_order, :asc)
|
||||
|> assign(:users, sorted)
|
||||
|> assign(:selected_users, [])}
|
||||
end
|
||||
|
||||
# Selects one user in the list of users
|
||||
@impl true
|
||||
def handle_event("select_user", %{"id" => id}, socket) do
|
||||
# Normalize ID to string for consistent comparison
|
||||
id_str = to_string(id)
|
||||
|
||||
selected =
|
||||
if id_str in socket.assigns.selected_users do
|
||||
List.delete(socket.assigns.selected_users, id_str)
|
||||
else
|
||||
[id_str | socket.assigns.selected_users]
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, :selected_users, selected)}
|
||||
|> assign(:users, sorted)}
|
||||
end
|
||||
|
||||
# Sorts the list of users according to a field, when you click on the column header
|
||||
|
|
@ -86,24 +64,6 @@ defmodule MvWeb.UserLive.Index do
|
|||
|> assign(:users, sorted_users)}
|
||||
end
|
||||
|
||||
# Selects all users in the list of users
|
||||
@impl true
|
||||
def handle_event("select_all", _params, socket) do
|
||||
users = socket.assigns.users
|
||||
|
||||
# Normalize IDs to strings for consistent comparison
|
||||
all_ids = Enum.map(users, &to_string(&1.id))
|
||||
|
||||
selected =
|
||||
if Enum.sort(socket.assigns.selected_users) == Enum.sort(all_ids) do
|
||||
[]
|
||||
else
|
||||
all_ids
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, :selected_users, selected)}
|
||||
end
|
||||
|
||||
defp toggle_order(:asc), do: :desc
|
||||
defp toggle_order(:desc), do: :asc
|
||||
defp sort_fun(:asc), do: &<=/2
|
||||
|
|
|
|||
|
|
@ -19,33 +19,6 @@
|
|||
sort_field={@sort_field}
|
||||
sort_order={@sort_order}
|
||||
>
|
||||
<:col
|
||||
:let={user}
|
||||
label={
|
||||
~H"""
|
||||
<.input
|
||||
type="checkbox"
|
||||
name="select_all"
|
||||
phx-click="select_all"
|
||||
checked={Enum.sort(@selected_users) == Enum.map(@users, &to_string(&1.id)) |> Enum.sort()}
|
||||
aria-label={gettext("Select all users")}
|
||||
role="checkbox"
|
||||
/>
|
||||
"""
|
||||
}
|
||||
>
|
||||
<.input
|
||||
type="checkbox"
|
||||
name={to_string(user.id)}
|
||||
phx-click="select_user"
|
||||
phx-value-id={to_string(user.id)}
|
||||
checked={to_string(user.id) in @selected_users}
|
||||
phx-capture-click
|
||||
phx-stop-propagation
|
||||
aria-label={gettext("Select user")}
|
||||
role="checkbox"
|
||||
/>
|
||||
</:col>
|
||||
<:col
|
||||
:let={user}
|
||||
sort_field={:email}
|
||||
|
|
|
|||
|
|
@ -34,14 +34,20 @@ defmodule MvWeb.UserLive.Show do
|
|||
~H"""
|
||||
<Layouts.app flash={@flash} current_user={@current_user}>
|
||||
<.header>
|
||||
<:leading>
|
||||
<.button
|
||||
navigate={~p"/users"}
|
||||
variant="neutral"
|
||||
aria-label={gettext("Back to users list")}
|
||||
>
|
||||
<.icon name="hero-arrow-left" class="size-4" />
|
||||
{gettext("Back")}
|
||||
</.button>
|
||||
</:leading>
|
||||
{gettext("User")} {@user.email}
|
||||
<:subtitle>{gettext("This is a user record from your database.")}</:subtitle>
|
||||
|
||||
<:actions>
|
||||
<.button navigate={~p"/users"} variant="neutral" aria-label={gettext("Back to users list")}>
|
||||
<.icon name="hero-arrow-left" />
|
||||
<span class="sr-only">{gettext("Back to users list")}</span>
|
||||
</.button>
|
||||
<%= if can?(@current_user, :update, @user) do %>
|
||||
<.button
|
||||
variant="primary"
|
||||
|
|
@ -99,7 +105,8 @@ defmodule MvWeb.UserLive.Show do
|
|||
phx-click="delete"
|
||||
phx-value-id={@user.id}
|
||||
data-confirm={
|
||||
gettext("Are you sure you want to delete the user %{email}? This action cannot be undone.",
|
||||
gettext(
|
||||
"Are you sure you want to delete the user %{email}? This action cannot be undone.",
|
||||
email: @user.email
|
||||
)
|
||||
}
|
||||
|
|
@ -141,33 +148,32 @@ defmodule MvWeb.UserLive.Show do
|
|||
user = socket.assigns.user
|
||||
actor = current_actor(socket)
|
||||
|
||||
if to_string(id) != to_string(user.id) do
|
||||
{:noreply, put_flash(socket, :error, gettext("User not found"))}
|
||||
else
|
||||
if Mv.Helpers.SystemActor.system_user?(user) do
|
||||
cond do
|
||||
to_string(id) != to_string(user.id) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("User not found"))}
|
||||
|
||||
Mv.Helpers.SystemActor.system_user?(user) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("System user cannot be deleted."))}
|
||||
|
||||
true ->
|
||||
handle_user_delete_destroy(socket, user, actor)
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_user_delete_destroy(socket, user, actor) do
|
||||
case Ash.destroy(user, domain: Mv.Accounts, actor: actor) do
|
||||
:ok ->
|
||||
{:noreply,
|
||||
put_flash(socket, :error, gettext("System user cannot be deleted."))}
|
||||
else
|
||||
case Ash.destroy(user, domain: Mv.Accounts, actor: actor) do
|
||||
:ok ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:success, gettext("User deleted successfully"))
|
||||
|> push_navigate(to: ~p"/users")}
|
||||
socket
|
||||
|> put_flash(:success, gettext("User deleted successfully"))
|
||||
|> push_navigate(to: ~p"/users")}
|
||||
|
||||
{:error, %Ash.Error.Forbidden{}} ->
|
||||
{:noreply,
|
||||
put_flash(
|
||||
socket,
|
||||
:error,
|
||||
gettext("You do not have permission to delete this user")
|
||||
)}
|
||||
{:error, %Ash.Error.Forbidden{}} ->
|
||||
{:noreply,
|
||||
put_flash(socket, :error, gettext("You do not have permission to delete this user"))}
|
||||
|
||||
{:error, error} ->
|
||||
{:noreply,
|
||||
put_flash(socket, :error, format_ash_error(error))}
|
||||
end
|
||||
end
|
||||
{:error, error} ->
|
||||
{:noreply, put_flash(socket, :error, format_ash_error(error))}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue