style: consitent flash messages
This commit is contained in:
parent
b7c93f19cb
commit
ff9f98f8e7
22 changed files with 117 additions and 103 deletions
|
|
@ -286,11 +286,11 @@ Notes:
|
||||||
- warning: 6–8s
|
- warning: 6–8s
|
||||||
- error: 8–12s (or manual dismiss for critical errors)
|
- error: 8–12s (or manual dismiss for critical errors)
|
||||||
- **MUST:** Keep a dismiss button for accessibility and user control.
|
- **MUST:** Keep a dismiss button for accessibility and user control.
|
||||||
|
- **Status:** Not yet implemented. See [feature-roadmap](docs/feature-roadmap.md) → Flash: Auto-dismiss and consistency.
|
||||||
|
|
||||||
### 9.3 Variants + special “email copied”
|
### 9.3 Variants (unified)
|
||||||
- Supported semantic variants: `info`, `success`, `warning`, `error`.
|
- Supported semantic variants: `info`, `success`, `warning`, `error`.
|
||||||
- **Special case:** clipboard “Email copied” uses a **soft/light blue** tone distinct from normal info.
|
- **MUST:** Use the same variants for all flash types, : e.g. `success` for copy success, no separate tone or styling. This keeps flash UX consistent across the app.
|
||||||
- **MUST:** Model this as `tone="soft"` (or similar prop) on the flash component, not hard-coded colors in views.
|
|
||||||
|
|
||||||
### 9.4 Accessibility
|
### 9.4 Accessibility
|
||||||
- Flash must work with screen readers (live region behavior belongs in the flash component implementation).
|
- Flash must work with screen readers (live region behavior belongs in the flash component implementation).
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,11 @@
|
||||||
- ❌ Mobile navigation
|
- ❌ Mobile navigation
|
||||||
- ❌ Context-sensitive help
|
- ❌ Context-sensitive help
|
||||||
- ❌ Onboarding tooltips
|
- ❌ Onboarding tooltips
|
||||||
|
- ❌ **Flash: Auto-dismiss and consistency** (Design Guidelines §9)
|
||||||
|
- Auto-dismiss: info/success 4–6s, warning 6–8s, error 8–12s; dismiss button kept for accessibility.
|
||||||
|
- Implement via JS hook (e.g. `FlashAutoDismiss`) + `data-dismiss-ms` (or `data-kind`) on flash component; on timeout push `lv:clear-flash` and hide element.
|
||||||
|
- LiveView: add shared `handle_event("lv:clear-flash", %{"key" => key}, socket)` (e.g. in `MvWeb` live_view quote) calling `clear_flash(socket, key)`.
|
||||||
|
- All flashes (including “Email copied”) use the same variants (info, success, warning, error); no special tone. See `DESIGN_DUIDELINES.md` §9.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ defmodule MvWeb.CoreComponents do
|
||||||
id={@id}
|
id={@id}
|
||||||
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
|
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
|
||||||
role="alert"
|
role="alert"
|
||||||
class="z-50 toast toast-bottom toast-end"
|
class="pointer-events-auto"
|
||||||
{@rest}
|
{@rest}
|
||||||
>
|
>
|
||||||
<div class={[
|
<div class={[
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,11 @@ defmodule MvWeb.Layouts do
|
||||||
|
|
||||||
def flash_group(assigns) do
|
def flash_group(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div id={@id} aria-live="polite" class="z-50 flex flex-col gap-2 toast toast-bottom toast-end">
|
<div
|
||||||
|
id={@id}
|
||||||
|
aria-live="polite"
|
||||||
|
class="z-50 toast toast-bottom toast-end flex flex-col gap-2 pointer-events-none"
|
||||||
|
>
|
||||||
<.flash kind={:success} flash={@flash} />
|
<.flash kind={:success} flash={@flash} />
|
||||||
<.flash kind={:warning} flash={@flash} />
|
<.flash kind={:warning} flash={@flash} />
|
||||||
<.flash kind={:info} flash={@flash} />
|
<.flash kind={:info} flash={@flash} />
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ defmodule MvWeb.AuthController do
|
||||||
|> store_in_session(user)
|
|> store_in_session(user)
|
||||||
# If your resource has a different name, update the assign name here (i.e :current_admin)
|
# If your resource has a different name, update the assign name here (i.e :current_admin)
|
||||||
|> assign(:current_user, user)
|
|> assign(:current_user, user)
|
||||||
|> put_flash(:info, message)
|
|> put_flash(:success, message)
|
||||||
|> redirect(to: return_to)
|
|> redirect(to: return_to)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -322,7 +322,7 @@ defmodule MvWeb.AuthController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> clear_session(:mv)
|
|> clear_session(:mv)
|
||||||
|> put_flash(:info, gettext("You are now signed out"))
|
|> put_flash(:success, gettext("You are now signed out"))
|
||||||
|> redirect(to: return_to)
|
|> redirect(to: return_to)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ defmodule MvWeb.LinkOidcAccountLive do
|
||||||
|
|
||||||
socket
|
socket
|
||||||
|> put_flash(
|
|> put_flash(
|
||||||
:info,
|
:success,
|
||||||
dgettext("auth", "Account activated! Redirecting to complete sign-in...")
|
dgettext("auth", "Account activated! Redirecting to complete sign-in...")
|
||||||
)
|
)
|
||||||
|> Phoenix.LiveView.redirect(to: ~p"/auth/user/oidc")
|
|> Phoenix.LiveView.redirect(to: ~p"/auth/user/oidc")
|
||||||
|
|
@ -217,7 +217,7 @@ defmodule MvWeb.LinkOidcAccountLive do
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> put_flash(
|
|> put_flash(
|
||||||
:info,
|
:success,
|
||||||
dgettext(
|
dgettext(
|
||||||
"auth",
|
"auth",
|
||||||
"Your OIDC account has been successfully linked! Redirecting to complete sign-in..."
|
"Your OIDC account has been successfully linked! Redirecting to complete sign-in..."
|
||||||
|
|
|
||||||
|
|
@ -64,12 +64,12 @@ defmodule MvWeb.DatafieldsLive do
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> assign(:active_editing_section, nil)
|
|> assign(:active_editing_section, nil)
|
||||||
|> put_flash(:info, gettext("Data field %{action} successfully", action: action))}
|
|> put_flash(:success, gettext("Data field %{action} successfully", action: action))}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:custom_field_deleted, _custom_field}, socket) do
|
def handle_info({:custom_field_deleted, _custom_field}, socket) do
|
||||||
{:noreply, put_flash(socket, :info, gettext("Data field deleted successfully"))}
|
{:noreply, put_flash(socket, :success, gettext("Data field deleted successfully"))}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
@ -115,7 +115,7 @@ defmodule MvWeb.DatafieldsLive do
|
||||||
socket
|
socket
|
||||||
|> assign(:settings, updated_settings)
|
|> assign(:settings, updated_settings)
|
||||||
|> assign(:active_editing_section, nil)
|
|> assign(:active_editing_section, nil)
|
||||||
|> put_flash(:info, gettext("Member field %{action} successfully", action: action))}
|
|> put_flash(:success, gettext("Member field %{action} successfully", action: action))}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
|
||||||
|
|
@ -357,20 +357,21 @@ defmodule MvWeb.GlobalSettingsLive do
|
||||||
errors_with_names = enrich_sync_errors(errors)
|
errors_with_names = enrich_sync_errors(errors)
|
||||||
result = %{synced: synced, errors: errors_with_names}
|
result = %{synced: synced, errors: errors_with_names}
|
||||||
|
|
||||||
|
{flash_kind, flash_message} =
|
||||||
|
if(errors_with_names == [],
|
||||||
|
do: {:success, gettext("Synced %{count} member(s) to Vereinfacht.", count: synced)},
|
||||||
|
else:
|
||||||
|
{:warning,
|
||||||
|
gettext("Synced %{count} member(s). %{error_count} failed.",
|
||||||
|
count: synced,
|
||||||
|
error_count: length(errors_with_names)
|
||||||
|
)}
|
||||||
|
)
|
||||||
|
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> assign(:last_vereinfacht_sync_result, result)
|
|> assign(:last_vereinfacht_sync_result, result)
|
||||||
|> put_flash(
|
|> put_flash(flash_kind, flash_message)
|
||||||
:info,
|
|
||||||
if(errors_with_names == [],
|
|
||||||
do: gettext("Synced %{count} member(s) to Vereinfacht.", count: synced),
|
|
||||||
else:
|
|
||||||
gettext("Synced %{count} member(s). %{error_count} failed.",
|
|
||||||
count: synced,
|
|
||||||
error_count: length(errors_with_names)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
|
|
||||||
|
|
@ -409,7 +410,7 @@ defmodule MvWeb.GlobalSettingsLive do
|
||||||
|> assign(:oidc_client_secret_set, present?(fresh_settings.oidc_client_secret))
|
|> assign(:oidc_client_secret_set, present?(fresh_settings.oidc_client_secret))
|
||||||
|> assign(:oidc_configured, Mv.Config.oidc_configured?())
|
|> assign(:oidc_configured, Mv.Config.oidc_configured?())
|
||||||
|> assign(:vereinfacht_test_result, test_result)
|
|> assign(:vereinfacht_test_result, test_result)
|
||||||
|> put_flash(:info, gettext("Settings updated successfully"))
|
|> put_flash(:success, gettext("Settings updated successfully"))
|
||||||
|> assign_form()
|
|> assign_form()
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ defmodule MvWeb.GroupLive.Form do
|
||||||
|
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> put_flash(:info, gettext("Group saved successfully."))
|
|> put_flash(:success, gettext("Group saved successfully."))
|
||||||
|> push_navigate(to: redirect_path)
|
|> push_navigate(to: redirect_path)
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
|
|
|
||||||
|
|
@ -76,24 +76,24 @@ defmodule MvWeb.GroupLive.Index do
|
||||||
<:col :let={group} label={gettext("Members")} class="text-right">
|
<:col :let={group} label={gettext("Members")} class="text-right">
|
||||||
{group.member_count || 0}
|
{group.member_count || 0}
|
||||||
</:col>
|
</:col>
|
||||||
<:action :let={group}>
|
<:action :let={group}>
|
||||||
<.button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
navigate={~p"/groups/#{group.slug}"}
|
|
||||||
>
|
|
||||||
{gettext("View")}
|
|
||||||
</.button>
|
|
||||||
<%= if can?(@current_user, :update, Mv.Membership.Group) do %>
|
|
||||||
<.button
|
<.button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
navigate={~p"/groups/#{group.slug}/edit"}
|
navigate={~p"/groups/#{group.slug}"}
|
||||||
>
|
>
|
||||||
{gettext("Edit group")}
|
{gettext("View")}
|
||||||
</.button>
|
</.button>
|
||||||
<% end %>
|
<%= if can?(@current_user, :update, Mv.Membership.Group) do %>
|
||||||
</:action>
|
<.button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
navigate={~p"/groups/#{group.slug}/edit"}
|
||||||
|
>
|
||||||
|
{gettext("Edit group")}
|
||||||
|
</.button>
|
||||||
|
<% end %>
|
||||||
|
</:action>
|
||||||
</.table>
|
</.table>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ defmodule MvWeb.GroupLive.Show do
|
||||||
<form phx-change="search_members" class="flex-1">
|
<form phx-change="search_members" class="flex-1">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<div class="input input-bordered join-item w-full flex flex-wrap gap-1 items-center py-1 px-2">
|
<div class="input input-bordered join-item w-full flex flex-wrap gap-1 items-center py-1 px-2">
|
||||||
<%= for member <- @selected_members do %>
|
<%= for member <- @selected_members do %>
|
||||||
<span class="badge badge-outline badge flex items-center gap-1">
|
<span class="badge badge-outline badge flex items-center gap-1">
|
||||||
{MvWeb.Helpers.MemberHelpers.display_name(member)}
|
{MvWeb.Helpers.MemberHelpers.display_name(member)}
|
||||||
<.tooltip content={gettext("Remove")} position="top">
|
<.tooltip content={gettext("Remove")} position="top">
|
||||||
|
|
@ -909,7 +909,7 @@ defmodule MvWeb.GroupLive.Show do
|
||||||
:ok ->
|
:ok ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> put_flash(:info, gettext("Group deleted successfully."))
|
|> put_flash(:success, gettext("Group deleted successfully."))
|
||||||
|> redirect(to: ~p"/groups")}
|
|> redirect(to: ~p"/groups")}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
|
|
|
||||||
|
|
@ -390,7 +390,7 @@ defmodule MvWeb.MemberLive.Form do
|
||||||
|
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> put_flash(:info, flash_message)
|
|> put_flash(:success, flash_message)
|
||||||
|> maybe_put_vereinfacht_sync_flash(member.id)
|
|> maybe_put_vereinfacht_sync_flash(member.id)
|
||||||
|> push_navigate(to: return_path(socket.assigns.return_to, member))
|
|> push_navigate(to: return_path(socket.assigns.return_to, member))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> assign(:members, updated_members)
|
|> assign(:members, updated_members)
|
||||||
|> put_flash(:info, gettext("Member deleted successfully"))}
|
|> put_flash(:success, gettext("Member deleted successfully"))}
|
||||||
|
|
||||||
{:error, %Ash.Error.Forbidden{}} ->
|
{:error, %Ash.Error.Forbidden{}} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
|
||||||
|
|
@ -562,7 +562,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
get_available_fee_types(updated_member, actor)
|
get_available_fee_types(updated_member, actor)
|
||||||
)
|
)
|
||||||
|> assign(:interval_warning, nil)
|
|> assign(:interval_warning, nil)
|
||||||
|> put_flash(:info, gettext("Membership fee type removed"))}
|
|> put_flash(:success, gettext("Membership fee type removed"))}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:noreply, put_flash(socket, :error, format_error(error))}
|
{:noreply, put_flash(socket, :error, format_error(error))}
|
||||||
|
|
@ -621,7 +621,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
get_available_fee_types(updated_member, actor)
|
get_available_fee_types(updated_member, actor)
|
||||||
)
|
)
|
||||||
|> assign(:interval_warning, nil)
|
|> assign(:interval_warning, nil)
|
||||||
|> put_flash(:info, gettext("Membership fee type updated. Cycles regenerated."))}
|
|> put_flash(:success, gettext("Membership fee type updated. Cycles regenerated."))}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:noreply, put_flash(socket, :error, format_error(error))}
|
{:noreply, put_flash(socket, :error, format_error(error))}
|
||||||
|
|
@ -649,7 +649,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> assign(:cycles, updated_cycles)
|
|> assign(:cycles, updated_cycles)
|
||||||
|> put_flash(:info, gettext("Cycle status updated"))}
|
|> put_flash(:success, gettext("Cycle status updated"))}
|
||||||
|
|
||||||
{:error, %Ash.Error.Invalid{} = error} ->
|
{:error, %Ash.Error.Invalid{} = error} ->
|
||||||
error_msg =
|
error_msg =
|
||||||
|
|
@ -705,7 +705,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
|> assign(:member, updated_member)
|
|> assign(:member, updated_member)
|
||||||
|> assign(:cycles, cycles)
|
|> assign(:cycles, cycles)
|
||||||
|> assign(:regenerating, false)
|
|> assign(:regenerating, false)
|
||||||
|> put_flash(:info, gettext("Cycles regenerated successfully"))}
|
|> put_flash(:success, gettext("Cycles regenerated successfully"))}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
@ -755,7 +755,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
socket
|
socket
|
||||||
|> assign(:cycles, updated_cycles)
|
|> assign(:cycles, updated_cycles)
|
||||||
|> assign(:editing_cycle, nil)
|
|> assign(:editing_cycle, nil)
|
||||||
|> put_flash(:info, gettext("Cycle amount updated"))}
|
|> put_flash(:success, gettext("Cycle amount updated"))}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
@ -794,7 +794,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
socket
|
socket
|
||||||
|> assign(:cycles, updated_cycles)
|
|> assign(:cycles, updated_cycles)
|
||||||
|> assign(:deleting_cycle, nil)
|
|> assign(:deleting_cycle, nil)
|
||||||
|> put_flash(:info, gettext("Cycle deleted"))}
|
|> put_flash(:success, gettext("Cycle deleted"))}
|
||||||
|
|
||||||
{:ok, _destroyed} ->
|
{:ok, _destroyed} ->
|
||||||
# Handle case where return_destroyed? is true
|
# Handle case where return_destroyed? is true
|
||||||
|
|
@ -804,7 +804,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
socket
|
socket
|
||||||
|> assign(:cycles, updated_cycles)
|
|> assign(:cycles, updated_cycles)
|
||||||
|> assign(:deleting_cycle, nil)
|
|> assign(:deleting_cycle, nil)
|
||||||
|> put_flash(:info, gettext("Cycle deleted"))}
|
|> put_flash(:success, gettext("Cycle deleted"))}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
@ -950,7 +950,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
|> assign(:creating_cycle, false)
|
|> assign(:creating_cycle, false)
|
||||||
|> assign(:create_cycle_date, nil)
|
|> assign(:create_cycle_date, nil)
|
||||||
|> assign(:create_cycle_error, nil)
|
|> assign(:create_cycle_error, nil)
|
||||||
|> put_flash(:info, gettext("Cycle created successfully"))}
|
|> put_flash(:success, gettext("Cycle created successfully"))}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
@ -1013,7 +1013,7 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
|> assign(:member, updated_member)
|
|> assign(:member, updated_member)
|
||||||
|> assign(:cycles, updated_cycles)
|
|> assign(:cycles, updated_cycles)
|
||||||
|> reset_modal.()
|
|> reset_modal.()
|
||||||
|> put_flash(:info, gettext("All cycles deleted"))}
|
|> put_flash(:success, gettext("All cycles deleted"))}
|
||||||
|
|
||||||
{:ok, _} ->
|
{:ok, _} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ defmodule MvWeb.MembershipFeeSettingsLive do
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> assign(:settings, updated_settings)
|
|> assign(:settings, updated_settings)
|
||||||
|> put_flash(:info, gettext("Settings saved successfully."))
|
|> put_flash(:success, gettext("Settings saved successfully."))
|
||||||
|> assign_form()}
|
|> assign_form()}
|
||||||
|
|
||||||
{:error, form} ->
|
{:error, form} ->
|
||||||
|
|
@ -105,7 +105,7 @@ defmodule MvWeb.MembershipFeeSettingsLive do
|
||||||
socket
|
socket
|
||||||
|> assign(:membership_fee_types, updated_types)
|
|> assign(:membership_fee_types, updated_types)
|
||||||
|> assign(:member_counts, updated_counts)
|
|> assign(:member_counts, updated_counts)
|
||||||
|> put_flash(:info, gettext("Membership fee type deleted"))}
|
|> put_flash(:success, gettext("Membership fee type deleted"))}
|
||||||
|
|
||||||
{:error, %Ash.Error.Forbidden{}} ->
|
{:error, %Ash.Error.Forbidden{}} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,7 @@ defmodule MvWeb.MembershipFeeTypeLive.Form do
|
||||||
|
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> put_flash(:info, gettext("Membership fee type saved successfully"))
|
|> put_flash(:success, gettext("Membership fee type saved successfully"))
|
||||||
|> push_navigate(to: return_path(socket.assigns.return_to, membership_fee_type))
|
|> push_navigate(to: return_path(socket.assigns.return_to, membership_fee_type))
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ defmodule MvWeb.MembershipFeeTypeLive.Index do
|
||||||
socket
|
socket
|
||||||
|> assign(:membership_fee_types, updated_types)
|
|> assign(:membership_fee_types, updated_types)
|
||||||
|> assign(:member_counts, updated_counts)
|
|> assign(:member_counts, updated_counts)
|
||||||
|> put_flash(:info, gettext("Membership fee type deleted"))}
|
|> put_flash(:success, gettext("Membership fee type deleted"))}
|
||||||
|
|
||||||
{:error, %Ash.Error.Forbidden{}} ->
|
{:error, %Ash.Error.Forbidden{}} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
|
||||||
|
|
@ -39,50 +39,50 @@ defmodule MvWeb.RoleLive.Form do
|
||||||
<div class="mt-6 space-y-6">
|
<div class="mt-6 space-y-6">
|
||||||
<.input field={@form[:name]} type="text" label={gettext("Name")} required />
|
<.input field={@form[:name]} type="text" label={gettext("Name")} required />
|
||||||
|
|
||||||
<.input
|
<.input
|
||||||
field={@form[:description]}
|
field={@form[:description]}
|
||||||
type="textarea"
|
type="textarea"
|
||||||
label={gettext("Description")}
|
label={gettext("Description")}
|
||||||
rows="3"
|
rows="3"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label class="label" for="role-form_permission_set_name">
|
<label class="label" for="role-form_permission_set_name">
|
||||||
<span class="label-text font-semibold">
|
<span class="label-text font-semibold">
|
||||||
{gettext("Permission Set")}
|
{gettext("Permission Set")}
|
||||||
<span class="text-red-700">*</span>
|
<span class="text-red-700">*</span>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
class={[
|
class={[
|
||||||
"select select-bordered w-full",
|
"select select-bordered w-full",
|
||||||
@form.errors[:permission_set_name] && "select-error"
|
@form.errors[:permission_set_name] && "select-error"
|
||||||
]}
|
]}
|
||||||
name="role[permission_set_name]"
|
name="role[permission_set_name]"
|
||||||
id="role-form_permission_set_name"
|
id="role-form_permission_set_name"
|
||||||
required
|
required
|
||||||
aria-label={gettext("Permission Set")}
|
aria-label={gettext("Permission Set")}
|
||||||
>
|
>
|
||||||
<option value="">{gettext("Select permission set")}</option>
|
<option value="">{gettext("Select permission set")}</option>
|
||||||
<%= for permission_set <- all_permission_sets() do %>
|
<%= for permission_set <- all_permission_sets() do %>
|
||||||
<option
|
<option
|
||||||
value={permission_set}
|
value={permission_set}
|
||||||
selected={@form[:permission_set_name].value == permission_set}
|
selected={@form[:permission_set_name].value == permission_set}
|
||||||
>
|
>
|
||||||
{format_permission_set_option(permission_set)}
|
{format_permission_set_option(permission_set)}
|
||||||
</option>
|
</option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
<%= if @form.errors[:permission_set_name] do %>
|
||||||
|
<%= for error <- List.wrap(@form.errors[:permission_set_name]) do %>
|
||||||
|
<% {msg, _opts} = if is_tuple(error), do: error, else: {error, []} %>
|
||||||
|
<p class="mt-1.5 flex gap-2 items-center text-sm text-error">
|
||||||
|
<.icon name="hero-exclamation-circle" class="size-5" />
|
||||||
|
{msg}
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</select>
|
</div>
|
||||||
<%= if @form.errors[:permission_set_name] do %>
|
|
||||||
<%= for error <- List.wrap(@form.errors[:permission_set_name]) do %>
|
|
||||||
<% {msg, _opts} = if is_tuple(error), do: error, else: {error, []} %>
|
|
||||||
<p class="mt-1.5 flex gap-2 items-center text-sm text-error">
|
|
||||||
<.icon name="hero-exclamation-circle" class="size-5" />
|
|
||||||
{msg}
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</.form>
|
</.form>
|
||||||
</Layouts.app>
|
</Layouts.app>
|
||||||
|
|
@ -177,7 +177,7 @@ defmodule MvWeb.RoleLive.Form do
|
||||||
|
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> put_flash(:info, gettext("Role saved successfully."))
|
|> put_flash(:success, gettext("Role saved successfully."))
|
||||||
|> push_navigate(to: redirect_path)
|
|> push_navigate(to: redirect_path)
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ defmodule MvWeb.RoleLive.Index do
|
||||||
socket
|
socket
|
||||||
|> assign(:roles, updated_roles)
|
|> assign(:roles, updated_roles)
|
||||||
|> assign(:user_counts, updated_counts)
|
|> assign(:user_counts, updated_counts)
|
||||||
|> put_flash(:info, gettext("Role deleted successfully."))}
|
|> put_flash(:success, gettext("Role deleted successfully."))}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
error_message = format_error(error)
|
error_message = format_error(error)
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ defmodule MvWeb.RoleLive.Show do
|
||||||
:ok ->
|
:ok ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> put_flash(:info, gettext("Role deleted successfully."))
|
|> put_flash(:success, gettext("Role deleted successfully."))
|
||||||
|> push_navigate(to: ~p"/admin/roles")}
|
|> push_navigate(to: ~p"/admin/roles")}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
|
|
@ -165,7 +165,11 @@ defmodule MvWeb.RoleLive.Show do
|
||||||
<:subtitle>{gettext("Role details and permissions.")}</:subtitle>
|
<:subtitle>{gettext("Role details and permissions.")}</:subtitle>
|
||||||
|
|
||||||
<:actions>
|
<:actions>
|
||||||
<.button navigate={~p"/admin/roles"} variant="neutral" aria-label={gettext("Back to roles list")}>
|
<.button
|
||||||
|
navigate={~p"/admin/roles"}
|
||||||
|
variant="neutral"
|
||||||
|
aria-label={gettext("Back to roles list")}
|
||||||
|
>
|
||||||
<.icon name="hero-arrow-left" class="size-4" />
|
<.icon name="hero-arrow-left" class="size-4" />
|
||||||
{gettext("Back")}
|
{gettext("Back")}
|
||||||
</.button>
|
</.button>
|
||||||
|
|
|
||||||
|
|
@ -556,7 +556,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
|
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> put_flash(:info, gettext("User %{action} successfully", action: action))
|
|> put_flash(:success, gettext("User %{action} successfully", action: action))
|
||||||
|> push_navigate(to: return_path(socket.assigns.return_to, updated_user))
|
|> push_navigate(to: return_path(socket.assigns.return_to, updated_user))
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ defmodule MvWeb.UserLive.Index do
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> assign(:users, updated_users)
|
|> assign(:users, updated_users)
|
||||||
|> put_flash(:info, gettext("User deleted successfully"))}
|
|> put_flash(:success, gettext("User deleted successfully"))}
|
||||||
|
|
||||||
{:error, %Ash.Error.Forbidden{}} ->
|
{:error, %Ash.Error.Forbidden{}} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue