Collection of small UI Improvements closes #511 #527

Merged
moritz merged 7 commits from issue/mitgliederverwaltung-511 into main 2026-06-15 15:44:58 +02:00
10 changed files with 144 additions and 44 deletions
Showing only changes of commit 035edae522 - Show all commits

View file

@ -586,15 +586,25 @@ defmodule MvWeb.GlobalSettingsLive do
>
{gettext("Test Integration")}
</.button>
<.button
<.tooltip
:if={Mv.Config.vereinfacht_configured?()}
type="button"
variant="secondary"
phx-click="sync_vereinfacht_contacts"
phx-disable-with={gettext("Syncing...")}
content={
gettext(
"Creates a Vereinfacht finance contact for every member that does not have one yet."
)
}
position="top"
>
{gettext("Sync all members without Vereinfacht contact")}
</.button>
<.button
type="button"
variant="secondary"
phx-click="sync_vereinfacht_contacts"
phx-disable-with={gettext("Syncing...")}
aria-label={gettext("Sync all members without Vereinfacht contact")}
>
{gettext("Sync all members without Vereinfacht contact")}
</.button>
</.tooltip>
</div>
<%= if @vereinfacht_test_result do %>
<.vereinfacht_test_result result={@vereinfacht_test_result} />

View file

@ -250,17 +250,19 @@ defmodule MvWeb.GroupLive.Show do
<% end %>
</div>
</form>
<.button
type="button"
variant="primary"
phx-click="add_selected_members"
data-testid="group-show-add-selected-members-btn"
disabled={Enum.empty?(@selected_member_ids)}
aria-label={gettext("Add members")}
class="join-item"
>
<.icon name="hero-plus" class="size-5" />
</.button>
<.tooltip content={gettext("Add members")} position="top">
<.button
type="button"
variant="primary"
phx-click="add_selected_members"
data-testid="group-show-add-selected-members-btn"
disabled={Enum.empty?(@selected_member_ids)}
aria-label={gettext("Add members")}
class="join-item"
>
<.icon name="hero-plus" class="size-5" />
</.button>
</.tooltip>
<.button
type="button"
variant="neutral"

View file

@ -143,16 +143,21 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
<%!-- Action Buttons (only when user has permission) --%>
<div class="flex gap-2 mb-4">
<.button
<.tooltip
:if={@member.membership_fee_type != nil and @can_create_cycle}
phx-click="regenerate_cycles"
phx-target={@myself}
class={["btn btn-sm btn-outline", if(@regenerating, do: "btn-disabled", else: "")]}
title={gettext("Generate cycles from the last existing cycle to today")}
content={gettext("Generate cycles from the last existing cycle to today")}
position="top"
>
<.icon name="hero-arrow-path" class="size-4" />
{if(@regenerating, do: gettext("Regenerating..."), else: gettext("Regenerate Cycles"))}
</.button>
<.button
phx-click="regenerate_cycles"
phx-target={@myself}
class={["btn btn-sm btn-outline", if(@regenerating, do: "btn-disabled", else: "")]}
aria-label={gettext("Regenerate membership fee cycles")}
>
<.icon name="hero-arrow-path" class="size-4" />
{if(@regenerating, do: gettext("Regenerating..."), else: gettext("Regenerate Cycles"))}
</.button>
</.tooltip>
<.button
:if={Enum.any?(@cycles) and @can_destroy_cycle}
variant="outline"

View file

@ -298,17 +298,22 @@ defmodule MvWeb.MembershipFeeSettingsLive do
<.icon name="hero-trash" class="size-4" />
</button>
</.tooltip>
<.button
<.tooltip
:if={get_member_count(mft, @member_counts) == 0}
variant="danger"
size="sm"
phx-click="delete"
phx-value-id={mft.id}
data-confirm={gettext("Are you sure?")}
aria-label={gettext("Delete Membership Fee Type")}
content={gettext("Delete Membership Fee Type")}
position="left"
>
<.icon name="hero-trash" class="size-4" />
</.button>
<.button
variant="danger"
size="sm"
phx-click="delete"
phx-value-id={mft.id}
data-confirm={gettext("Are you sure?")}
aria-label={gettext("Delete Membership Fee Type")}
>
<.icon name="hero-trash" class="size-4" />
</.button>
</.tooltip>
</:action>
</.table>
</div>

View file

@ -115,17 +115,22 @@ defmodule MvWeb.MembershipFeeTypeLive.Index do
<.icon name="hero-trash" class="size-4" />
</button>
</.tooltip>
<.button
<.tooltip
:if={get_member_count(mft, @member_counts) == 0}
variant="danger"
size="sm"
phx-click="delete"
phx-value-id={mft.id}
data-confirm={gettext("Are you sure?")}
aria-label={gettext("Delete Membership Fee Type")}
content={gettext("Delete Membership Fee Type")}
position="left"
>
<.icon name="hero-trash" class="size-4" />
</.button>
<.button
variant="danger"
size="sm"
phx-click="delete"
phx-value-id={mft.id}
data-confirm={gettext("Are you sure?")}
aria-label={gettext("Delete Membership Fee Type")}
>
<.icon name="hero-trash" class="size-4" />
</.button>
</.tooltip>
</:action>
</.table>

View file

@ -791,6 +791,11 @@ msgstr "Beitragsart erstellen"
msgid "Created at:"
msgstr "Erstellt am:"
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Creates a Vereinfacht finance contact for every member that does not have one yet."
msgstr "Legt für jedes Mitglied ohne Vereinfacht-Kontakt einen Finanzkontakt an."
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Credit"
@ -2872,6 +2877,11 @@ msgstr "Weiterleitungs-URI"
msgid "Regenerate Cycles"
msgstr "Zyklen regenerieren"
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Regenerate membership fee cycles"
msgstr "Beitragszyklen neu generieren"
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Regenerating..."

View file

@ -792,6 +792,11 @@ msgstr ""
msgid "Created at:"
msgstr ""
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Creates a Vereinfacht finance contact for every member that does not have one yet."
msgstr ""
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Credit"
@ -2873,6 +2878,11 @@ msgstr ""
msgid "Regenerate Cycles"
msgstr ""
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Regenerate membership fee cycles"
msgstr ""
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Regenerating..."

View file

@ -792,6 +792,11 @@ msgstr ""
msgid "Created at:"
msgstr "Created at:"
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Creates a Vereinfacht finance contact for every member that does not have one yet."
msgstr ""
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Credit"
@ -2873,6 +2878,11 @@ msgstr ""
msgid "Regenerate Cycles"
msgstr ""
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Regenerate membership fee cycles"
msgstr ""
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format
msgid "Regenerating..."

View file

@ -300,4 +300,31 @@ defmodule MvWeb.GlobalSettingsLiveTest do
"Single Sign-On"
end
end
describe "Vereinfacht sync control tooltip (§1.9)" do
setup %{conn: conn} do
user = create_test_user(%{email: "admin@example.com"})
conn = conn_with_oidc_user(conn, user)
System.put_env("VEREINFACHT_API_URL", "https://example.test/api/v1")
System.put_env("VEREINFACHT_API_KEY", "test-key")
System.put_env("VEREINFACHT_CLUB_ID", "club-1")
on_exit(fn ->
System.delete_env("VEREINFACHT_API_URL")
System.delete_env("VEREINFACHT_API_KEY")
System.delete_env("VEREINFACHT_CLUB_ID")
end)
{:ok, conn: conn}
end
test "global Vereinfacht sync control carries a tooltip and accessible label", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/settings")
# The sync button is wrapped in a <.tooltip> (data-tip) and carries an aria-label
assert has_element?(view, ".tooltip[data-tip] button[phx-click=sync_vereinfacht_contacts]")
assert has_element?(view, "button[phx-click=sync_vereinfacht_contacts][aria-label]")
end
end
end

View file

@ -55,6 +55,22 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|> Ash.create!(actor: system_actor)
end
describe "cycle-regeneration control tooltip (§3.5 icon/tooltip audit)" do
test "the regenerate_cycles control carries a tooltip and accessible label", %{conn: conn} do
fee_type = create_fee_type(%{interval: :yearly})
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
{:ok, view, _html} = live(conn, "/members/#{member.id}")
view
|> element("button[phx-click='switch_tab'][phx-value-tab='membership_fees']")
|> render_click()
assert has_element?(view, ".tooltip[data-tip] button[phx-click=regenerate_cycles]")
assert has_element?(view, "button[phx-click=regenerate_cycles][aria-label]")
end
end
describe "cycles table display" do
test "displays all cycles for member", %{conn: conn} do
fee_type = create_fee_type(%{interval: :yearly})