From 3f073d43659165851400e7d8262c9f2926c0be09 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 16 Jun 2026 15:30:56 +0200 Subject: [PATCH] refactor(membership-fees): share fee-type delete handling between LiveViews --- lib/mv_web/helpers/membership_fee_helpers.ex | 67 +++++++++++++++++++ .../live/membership_fee_settings_live.ex | 49 +------------- .../live/membership_fee_type_live/index.ex | 48 +------------ priv/gettext/default.pot | 15 ++--- 4 files changed, 74 insertions(+), 105 deletions(-) diff --git a/lib/mv_web/helpers/membership_fee_helpers.ex b/lib/mv_web/helpers/membership_fee_helpers.ex index b9ebd71..1fddda8 100644 --- a/lib/mv_web/helpers/membership_fee_helpers.ex +++ b/lib/mv_web/helpers/membership_fee_helpers.ex @@ -9,8 +9,10 @@ defmodule MvWeb.Helpers.MembershipFeeHelpers do use Gettext, backend: MvWeb.Gettext alias Mv.Membership.Member + alias Mv.MembershipFees alias Mv.MembershipFees.CalendarCycles alias Mv.MembershipFees.MembershipFeeCycle + alias Mv.MembershipFees.MembershipFeeType alias MvWeb.Helpers.DateFormatter @doc """ @@ -249,4 +251,69 @@ defmodule MvWeb.Helpers.MembershipFeeHelpers do def status_icon(:paid), do: "hero-check-circle" def status_icon(:unpaid), do: "hero-x-circle" def status_icon(:suspended), do: "hero-pause-circle" + + @doc """ + Handles a membership-fee-type "delete" event for the fee-type list and the + fee-settings LiveViews. + + Loads the fee type, attempts to destroy it, and returns the updated socket + with the matching flash. On success the deleted type and its member count are + dropped from the `:membership_fee_types` and `:member_counts` assigns. The + NotFound, Forbidden (delete and access), and generic error branches preserve + the exact messages both views used before they shared this block. + """ + @spec delete_fee_type(Phoenix.LiveView.Socket.t(), String.t(), term()) :: + {:noreply, Phoenix.LiveView.Socket.t()} + def delete_fee_type(socket, id, actor) do + case Ash.get(MembershipFeeType, id, domain: MembershipFees, actor: actor) do + {:ok, fee_type} -> + destroy_fee_type(socket, fee_type, id, actor) + + {:error, %Ash.Error.Query.NotFound{}} -> + {:noreply, + Phoenix.LiveView.put_flash(socket, :error, gettext("Membership fee type not found"))} + + {:error, %Ash.Error.Forbidden{}} -> + {:noreply, + Phoenix.LiveView.put_flash( + socket, + :error, + gettext("You do not have permission to access this membership fee type") + )} + + {:error, error} -> + {:noreply, Phoenix.LiveView.put_flash(socket, :error, fee_error_message(error))} + end + end + + defp destroy_fee_type(socket, fee_type, id, actor) do + case Ash.destroy(fee_type, domain: MembershipFees, actor: actor) do + :ok -> + updated_types = Enum.reject(socket.assigns.membership_fee_types, &(&1.id == id)) + updated_counts = Map.delete(socket.assigns.member_counts, id) + + {:noreply, + socket + |> Phoenix.Component.assign(:membership_fee_types, updated_types) + |> Phoenix.Component.assign(:member_counts, updated_counts) + |> Phoenix.LiveView.put_flash(:success, gettext("Membership fee type deleted"))} + + {:error, %Ash.Error.Forbidden{}} -> + {:noreply, + Phoenix.LiveView.put_flash( + socket, + :error, + gettext("You do not have permission to delete this membership fee type") + )} + + {:error, error} -> + {:noreply, Phoenix.LiveView.put_flash(socket, :error, fee_error_message(error))} + end + end + + defp fee_error_message(%Ash.Error.Invalid{} = error) do + Enum.map_join(error.errors, ", ", fn e -> e.message end) + end + + defp fee_error_message(_error), do: gettext("An error occurred") end diff --git a/lib/mv_web/live/membership_fee_settings_live.ex b/lib/mv_web/live/membership_fee_settings_live.ex index 4df6608..56de3b5 100644 --- a/lib/mv_web/live/membership_fee_settings_live.ex +++ b/lib/mv_web/live/membership_fee_settings_live.ex @@ -15,7 +15,6 @@ defmodule MvWeb.MembershipFeeSettingsLive do alias Mv.Membership alias Mv.Membership.Member - alias Mv.MembershipFees alias Mv.MembershipFees.MembershipFeeType alias MvWeb.Helpers.MembershipFeeHelpers @@ -92,47 +91,7 @@ defmodule MvWeb.MembershipFeeSettingsLive do @impl true def handle_event("delete", %{"id" => id}, socket) do - actor = current_actor(socket) - - case Ash.get(MembershipFeeType, id, domain: MembershipFees, actor: actor) do - {:ok, fee_type} -> - case Ash.destroy(fee_type, domain: MembershipFees, actor: actor) do - :ok -> - updated_types = Enum.reject(socket.assigns.membership_fee_types, &(&1.id == id)) - updated_counts = Map.delete(socket.assigns.member_counts, id) - - {:noreply, - socket - |> assign(:membership_fee_types, updated_types) - |> assign(:member_counts, updated_counts) - |> put_flash(:success, gettext("Membership fee type deleted"))} - - {:error, %Ash.Error.Forbidden{}} -> - {:noreply, - put_flash( - socket, - :error, - gettext("You do not have permission to delete this membership fee type") - )} - - {:error, error} -> - {:noreply, put_flash(socket, :error, format_error(error))} - end - - {:error, %Ash.Error.Query.NotFound{}} -> - {:noreply, put_flash(socket, :error, gettext("Membership fee type not found"))} - - {:error, %Ash.Error.Forbidden{}} -> - {:noreply, - put_flash( - socket, - :error, - gettext("You do not have permission to access this membership fee type") - )} - - {:error, error} -> - {:noreply, put_flash(socket, :error, format_error(error))} - end + MembershipFeeHelpers.delete_fee_type(socket, id, current_actor(socket)) end @impl true @@ -465,12 +424,6 @@ defmodule MvWeb.MembershipFeeSettingsLive do Map.get(member_counts, fee_type.id, 0) end - defp format_error(%Ash.Error.Invalid{} = error) do - Enum.map_join(error.errors, ", ", fn e -> e.message end) - end - - defp format_error(_error), do: gettext("An error occurred") - defp assign_form(%{assigns: %{settings: settings}} = socket) do form = AshPhoenix.Form.for_update( diff --git a/lib/mv_web/live/membership_fee_type_live/index.ex b/lib/mv_web/live/membership_fee_type_live/index.ex index 1d51ce1..b6290e2 100644 --- a/lib/mv_web/live/membership_fee_type_live/index.ex +++ b/lib/mv_web/live/membership_fee_type_live/index.ex @@ -141,47 +141,7 @@ defmodule MvWeb.MembershipFeeTypeLive.Index do @impl true def handle_event("delete", %{"id" => id}, socket) do - actor = current_actor(socket) - - case Ash.get(MembershipFeeType, id, domain: MembershipFees, actor: actor) do - {:ok, fee_type} -> - case Ash.destroy(fee_type, domain: MembershipFees, actor: actor) do - :ok -> - updated_types = Enum.reject(socket.assigns.membership_fee_types, &(&1.id == id)) - updated_counts = Map.delete(socket.assigns.member_counts, id) - - {:noreply, - socket - |> assign(:membership_fee_types, updated_types) - |> assign(:member_counts, updated_counts) - |> put_flash(:success, gettext("Membership fee type deleted"))} - - {:error, %Ash.Error.Forbidden{}} -> - {:noreply, - put_flash( - socket, - :error, - gettext("You do not have permission to delete this membership fee type") - )} - - {:error, error} -> - {:noreply, put_flash(socket, :error, format_error(error))} - end - - {:error, %Ash.Error.Query.NotFound{}} -> - {:noreply, put_flash(socket, :error, gettext("Membership fee type not found"))} - - {:error, %Ash.Error.Forbidden{} = _error} -> - {:noreply, - put_flash( - socket, - :error, - gettext("You do not have permission to access this membership fee type") - )} - - {:error, error} -> - {:noreply, put_flash(socket, :error, format_error(error))} - end + MembershipFeeHelpers.delete_fee_type(socket, id, current_actor(socket)) end # Helper functions @@ -215,12 +175,6 @@ defmodule MvWeb.MembershipFeeTypeLive.Index do Map.get(member_counts, fee_type.id, 0) end - defp format_error(%Ash.Error.Invalid{} = error) do - Enum.map_join(error.errors, ", ", fn e -> e.message end) - end - - defp format_error(_error), do: gettext("An error occurred") - # Info card explaining the membership fee type concept defp info_card(assigns) do ~H""" diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 3c21f67..4c9a10a 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -193,8 +193,7 @@ msgid "An account with this email already exists. Please verify your password to msgstr "" #: lib/mv_web/helpers/ash_error_helpers.ex -#: lib/mv_web/live/membership_fee_settings_live.ex -#: lib/mv_web/live/membership_fee_type_live/index.ex +#: lib/mv_web/helpers/membership_fee_helpers.ex #: lib/mv_web/live/role_live/helpers.ex #, elixir-autogen, elixir-format msgid "An error occurred" @@ -2289,14 +2288,12 @@ msgstr "" msgid "Membership fee start" msgstr "" -#: lib/mv_web/live/membership_fee_settings_live.ex -#: lib/mv_web/live/membership_fee_type_live/index.ex +#: lib/mv_web/helpers/membership_fee_helpers.ex #, elixir-autogen, elixir-format msgid "Membership fee type deleted" msgstr "" -#: lib/mv_web/live/membership_fee_settings_live.ex -#: lib/mv_web/live/membership_fee_type_live/index.ex +#: lib/mv_web/helpers/membership_fee_helpers.ex #, elixir-autogen, elixir-format msgid "Membership fee type not found" msgstr "" @@ -3956,8 +3953,7 @@ msgstr "" msgid "You do not have permission to %{action} members." msgstr "" -#: lib/mv_web/live/membership_fee_settings_live.ex -#: lib/mv_web/live/membership_fee_type_live/index.ex +#: lib/mv_web/helpers/membership_fee_helpers.ex #, elixir-autogen, elixir-format msgid "You do not have permission to access this membership fee type" msgstr "" @@ -3973,8 +3969,7 @@ msgstr "" msgid "You do not have permission to delete this member" msgstr "" -#: lib/mv_web/live/membership_fee_settings_live.ex -#: lib/mv_web/live/membership_fee_type_live/index.ex +#: lib/mv_web/helpers/membership_fee_helpers.ex #, elixir-autogen, elixir-format msgid "You do not have permission to delete this membership fee type" msgstr ""