feat: consistent and accessible modal on delete
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
2922a4d1ee
commit
e422e5f4ef
10 changed files with 424 additions and 102 deletions
|
|
@ -313,14 +313,7 @@ defmodule MvWeb.UserLive.Form do
|
|||
<.button
|
||||
type="button"
|
||||
variant="danger"
|
||||
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.",
|
||||
email: @user.email
|
||||
)
|
||||
}
|
||||
phx-click="open_delete_modal"
|
||||
data-testid="user-delete"
|
||||
aria-label={gettext("Delete user %{email}", email: @user.email)}
|
||||
>
|
||||
|
|
@ -331,6 +324,40 @@ defmodule MvWeb.UserLive.Form do
|
|||
</section>
|
||||
<% end %>
|
||||
|
||||
<%!-- Delete User Confirmation Modal (WCAG: focus in modal, keyboard confirm/cancel) --%>
|
||||
<%= if @user && assigns[:show_delete_modal] do %>
|
||||
<dialog id="delete-user-form-modal" class="modal modal-open" role="dialog" aria-labelledby="delete-user-form-modal-title">
|
||||
<div class="modal-box">
|
||||
<h3 id="delete-user-form-modal-title" class="text-lg font-bold">{gettext("Delete User")}</h3>
|
||||
<p class="py-4">
|
||||
{gettext("Are you sure you want to delete the user %{email}? This action cannot be undone.",
|
||||
email: @user.email
|
||||
)}
|
||||
</p>
|
||||
<div class="modal-action">
|
||||
<.button
|
||||
type="button"
|
||||
variant="neutral"
|
||||
phx-click="cancel_delete_modal"
|
||||
phx-mounted={JS.focus()}
|
||||
id="delete-user-form-modal-cancel"
|
||||
aria-label={gettext("Cancel")}
|
||||
>
|
||||
{gettext("Cancel")}
|
||||
</.button>
|
||||
<.button
|
||||
type="button"
|
||||
variant="danger"
|
||||
phx-click={JS.push("delete", value: %{id: @user.id})}
|
||||
aria-label={gettext("Delete user")}
|
||||
>
|
||||
{gettext("Delete")}
|
||||
</.button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
<% end %>
|
||||
|
||||
<div class="mt-4">
|
||||
<.button navigate={return_path(@return_to, @user)} variant="neutral">
|
||||
{gettext("Cancel")}
|
||||
|
|
@ -399,6 +426,7 @@ defmodule MvWeb.UserLive.Form do
|
|||
|> assign(:selected_member_name, nil)
|
||||
|> assign(:unlink_member, false)
|
||||
|> assign(:focused_member_index, nil)
|
||||
|> assign_new(:show_delete_modal, fn -> false end)
|
||||
|> load_initial_members()
|
||||
|> assign_form()}
|
||||
end
|
||||
|
|
@ -454,6 +482,17 @@ defmodule MvWeb.UserLive.Form do
|
|||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@impl true
|
||||
def handle_event("open_delete_modal", _params, socket) do
|
||||
{:noreply, assign(socket, :show_delete_modal, true)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("cancel_delete_modal", _params, socket) do
|
||||
{:noreply, assign(socket, :show_delete_modal, false)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
user = socket.assigns.user
|
||||
|
|
@ -461,13 +500,22 @@ defmodule MvWeb.UserLive.Form do
|
|||
|
||||
cond do
|
||||
is_nil(user) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("User not found"))}
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, gettext("User not found"))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
|
||||
to_string(id) != to_string(user.id) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("User not found"))}
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, gettext("User not found"))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
|
||||
Mv.Helpers.SystemActor.system_user?(user) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("System user cannot be deleted."))}
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, gettext("System user cannot be deleted."))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
|
||||
true ->
|
||||
handle_user_delete_destroy(socket, user, actor)
|
||||
|
|
@ -594,10 +642,15 @@ defmodule MvWeb.UserLive.Form do
|
|||
|
||||
{:error, %Ash.Error.Forbidden{}} ->
|
||||
{:noreply,
|
||||
put_flash(socket, :error, gettext("You do not have permission to delete this user"))}
|
||||
socket
|
||||
|> put_flash(:error, gettext("You do not have permission to delete this user"))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
|
||||
{:error, error} ->
|
||||
{:noreply, put_flash(socket, :error, format_ash_error(error))}
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, format_ash_error(error))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -102,14 +102,7 @@ defmodule MvWeb.UserLive.Show do
|
|||
</p>
|
||||
<.button
|
||||
variant="danger"
|
||||
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.",
|
||||
email: @user.email
|
||||
)
|
||||
}
|
||||
phx-click="open_delete_modal"
|
||||
data-testid="user-delete"
|
||||
aria-label={gettext("Delete user %{email}", email: @user.email)}
|
||||
>
|
||||
|
|
@ -119,6 +112,40 @@ defmodule MvWeb.UserLive.Show do
|
|||
</div>
|
||||
</section>
|
||||
<% end %>
|
||||
|
||||
<%!-- Delete User Confirmation Modal (WCAG: focus in modal, keyboard confirm/cancel) --%>
|
||||
<%= if assigns[:show_delete_modal] do %>
|
||||
<dialog id="delete-user-modal" class="modal modal-open" role="dialog" aria-labelledby="delete-user-modal-title">
|
||||
<div class="modal-box">
|
||||
<h3 id="delete-user-modal-title" class="text-lg font-bold">{gettext("Delete User")}</h3>
|
||||
<p class="py-4">
|
||||
{gettext("Are you sure you want to delete the user %{email}? This action cannot be undone.",
|
||||
email: @user.email
|
||||
)}
|
||||
</p>
|
||||
<div class="modal-action">
|
||||
<.button
|
||||
type="button"
|
||||
variant="neutral"
|
||||
phx-click="cancel_delete_modal"
|
||||
phx-mounted={JS.focus()}
|
||||
id="delete-user-modal-cancel"
|
||||
aria-label={gettext("Cancel")}
|
||||
>
|
||||
{gettext("Cancel")}
|
||||
</.button>
|
||||
<.button
|
||||
type="button"
|
||||
variant="danger"
|
||||
phx-click={JS.push("delete", value: %{id: @user.id})}
|
||||
aria-label={gettext("Delete user")}
|
||||
>
|
||||
{gettext("Delete")}
|
||||
</.button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
<% end %>
|
||||
</Layouts.app>
|
||||
"""
|
||||
end
|
||||
|
|
@ -139,10 +166,21 @@ defmodule MvWeb.UserLive.Show do
|
|||
{:ok,
|
||||
socket
|
||||
|> assign(:page_title, gettext("Show User"))
|
||||
|> assign(:user, user)}
|
||||
|> assign(:user, user)
|
||||
|> assign(:show_delete_modal, false)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("open_delete_modal", _params, socket) do
|
||||
{:noreply, assign(socket, :show_delete_modal, true)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("cancel_delete_modal", _params, socket) do
|
||||
{:noreply, assign(socket, :show_delete_modal, false)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
user = socket.assigns.user
|
||||
|
|
@ -150,10 +188,16 @@ defmodule MvWeb.UserLive.Show do
|
|||
|
||||
cond do
|
||||
to_string(id) != to_string(user.id) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("User not found"))}
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, gettext("User not found"))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
|
||||
Mv.Helpers.SystemActor.system_user?(user) ->
|
||||
{:noreply, put_flash(socket, :error, gettext("System user cannot be deleted."))}
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, gettext("System user cannot be deleted."))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
|
||||
true ->
|
||||
handle_user_delete_destroy(socket, user, actor)
|
||||
|
|
@ -170,10 +214,15 @@ defmodule MvWeb.UserLive.Show do
|
|||
|
||||
{:error, %Ash.Error.Forbidden{}} ->
|
||||
{:noreply,
|
||||
put_flash(socket, :error, gettext("You do not have permission to delete this user"))}
|
||||
socket
|
||||
|> put_flash(:error, gettext("You do not have permission to delete this user"))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
|
||||
{:error, error} ->
|
||||
{:noreply, put_flash(socket, :error, format_ash_error(error))}
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, format_ash_error(error))
|
||||
|> assign(:show_delete_modal, false)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue