feat: unify page titles
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing

This commit is contained in:
Simon 2026-03-13 19:01:50 +01:00
parent e8ec620d57
commit c933144920
Signed by: simon
GPG key ID: 40E7A58C4AA1EDB2
37 changed files with 309 additions and 200 deletions

View file

@ -13,6 +13,39 @@ defmodule MvWeb.Layouts do
embed_templates "layouts/*" embed_templates "layouts/*"
@doc """
Builds the full browser tab title: "Mila", "Mila · Page", or "Mila · Page · Club".
Order is always: Mila · page title · club name.
Uses assigns[:club_name] and the short page label from assigns[:content_title] or
assigns[:page_title]. LiveViews should set content_title (same gettext as sidebar)
and then assign page_title to the result of this function so the client receives
the full title.
"""
def page_title_string(assigns) do
club = assigns[:club_name]
page = assigns[:content_title] || assigns[:page_title]
parts =
[page, club]
|> Enum.filter(&(is_binary(&1) and String.trim(&1) != ""))
if parts == [] do
"Mila"
else
"Mila · " <> Enum.join(parts, " · ")
end
end
@doc """
Assigns content_title (short label for heading; same gettext as sidebar) and
page_title (full browser tab title). Call from LiveView mount after club_name
is set (e.g. from on_mount). Returns the socket.
"""
def assign_page_title(socket, content_title) do
socket = assign(socket, :content_title, content_title)
assign(socket, :page_title, page_title_string(socket.assigns))
end
@doc """ @doc """
Renders the public (unauthenticated) page layout: header with logo + "Mitgliederverwaltung" left, Renders the public (unauthenticated) page layout: header with logo + "Mitgliederverwaltung" left,
club name centered, language selector right; plus main content and flash group. Use for sign-in, join, and join-confirm pages so they club name centered, language selector right; plus main content and flash group. Use for sign-in, join, and join-confirm pages so they

View file

@ -7,8 +7,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="csrf-token" content={get_csrf_token()} /> <meta name="csrf-token" content={get_csrf_token()} />
<link phx-track-static rel="icon" type="image/svg+xml" href={~p"/images/mila.svg"} /> <link phx-track-static rel="icon" type="image/svg+xml" href={~p"/images/mila.svg"} />
<.live_title default="Mv" suffix=" · Phoenix Framework"> <.live_title default="Mila">
{assigns[:page_title]} {page_title_string(assigns)}
</.live_title> </.live_title>
<link phx-track-static rel="stylesheet" href={~p"/assets/css/app.css"} /> <link phx-track-static rel="stylesheet" href={~p"/assets/css/app.css"} />
<script defer phx-track-static type="text/javascript" src={~p"/assets/js/app.js"}> <script defer phx-track-static type="text/javascript" src={~p"/assets/js/app.js"}>

View file

@ -8,6 +8,8 @@ defmodule MvWeb.JoinConfirmController do
""" """
use MvWeb, :controller use MvWeb, :controller
use Gettext, backend: MvWeb.Gettext
def confirm(conn, %{"token" => token}) when is_binary(token) do def confirm(conn, %{"token" => token}) when is_binary(token) do
callback = Application.get_env(:mv, :join_confirm_callback, Mv.Membership) callback = Application.get_env(:mv, :join_confirm_callback, Mv.Membership)
@ -48,8 +50,15 @@ defmodule MvWeb.JoinConfirmController do
end end
defp assign_confirm_assigns(conn, result) do defp assign_confirm_assigns(conn, result) do
page_title = page_title_for_result(result)
conn conn
|> assign(:result, result) |> assign(:result, result)
|> assign(:page_title, page_title)
|> assign(:flash, conn.assigns[:flash] || conn.flash || %{}) |> assign(:flash, conn.assigns[:flash] || conn.flash || %{})
end end
defp page_title_for_result(:success), do: gettext("Join confirmation")
defp page_title_for_result(:expired), do: gettext("Link expired")
defp page_title_for_result(:invalid), do: gettext("Invalid link")
end end

View file

@ -7,7 +7,11 @@ defmodule MvWeb.PageController do
""" """
use MvWeb, :controller use MvWeb, :controller
use Gettext, backend: MvWeb.Gettext
def home(conn, _params) do def home(conn, _params) do
render(conn, :home) conn
|> assign(:page_title, gettext("Home"))
|> render(:home)
end end
end end

View file

@ -19,6 +19,7 @@ defmodule MvWeb.SignInLive do
alias AshAuthentication.Phoenix.Components alias AshAuthentication.Phoenix.Components
alias Mv.Config alias Mv.Config
alias Mv.Membership
alias MvWeb.{AuthOverridesDE, AuthOverridesRegistrationDisabled, Layouts} alias MvWeb.{AuthOverridesDE, AuthOverridesRegistrationDisabled, Layouts}
@impl true @impl true
@ -49,6 +50,13 @@ defmodule MvWeb.SignInLive do
register_path = register_path =
if session["registration_enabled"] == false, do: nil, else: session["register_path"] if session["registration_enabled"] == false, do: nil, else: session["register_path"]
# Club name and page title for browser tab (root layout: Mila · Club · Page)
club_name =
case Membership.get_settings() do
{:ok, settings} when is_binary(settings.club_name) -> settings.club_name
_ -> nil
end
socket = socket =
socket socket
|> assign(overrides: overrides) |> assign(overrides: overrides)
@ -66,6 +74,8 @@ defmodule MvWeb.SignInLive do
|> assign(:oidc_only, Config.oidc_only?()) |> assign(:oidc_only, Config.oidc_only?())
|> assign(:sign_in_id, "sign-in") |> assign(:sign_in_id, "sign-in")
|> assign(:locale, locale) |> assign(:locale, locale)
|> assign(:club_name, club_name)
|> Layouts.assign_page_title(gettext("Sign in"))
{:ok, socket} {:ok, socket}
end end

View file

@ -17,7 +17,7 @@ defmodule MvWeb.DatafieldsLive do
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Datafields")) |> Layouts.assign_page_title(gettext("Datafields"))
|> assign(:settings, settings) |> assign(:settings, settings)
|> assign(:active_editing_section, nil) |> assign(:active_editing_section, nil)
|> assign(:custom_field_delete_modal_open, false)} |> assign(:custom_field_delete_modal_open, false)}
@ -50,7 +50,7 @@ defmodule MvWeb.DatafieldsLive do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user} club_name={@settings.club_name}> <Layouts.app flash={@flash} current_user={@current_user} club_name={@settings.club_name}>
<.header> <.header>
{gettext("Datafields")} {@content_title}
<:subtitle> <:subtitle>
{gettext( {gettext(
"Configure which data you want to save for your members. Define individual datafields." "Configure which data you want to save for your members. Define individual datafields."

View file

@ -60,7 +60,7 @@ defmodule MvWeb.GlobalSettingsLive do
socket = socket =
socket socket
|> assign(:page_title, gettext("Settings")) |> Layouts.assign_page_title(gettext("Basic settings"))
|> assign(:settings, settings) |> assign(:settings, settings)
|> assign(:locale, locale) |> assign(:locale, locale)
|> assign(:environment, environment) |> assign(:environment, environment)
@ -112,7 +112,7 @@ defmodule MvWeb.GlobalSettingsLive do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user} club_name={@settings.club_name}> <Layouts.app flash={@flash} current_user={@current_user} club_name={@settings.club_name}>
<.header> <.header>
{gettext("Settings")} {gettext("Basic settings")}
<:subtitle> <:subtitle>
{gettext("Manage global settings for the association.")} {gettext("Manage global settings for the association.")}
</:subtitle> </:subtitle>

View file

@ -32,7 +32,7 @@ defmodule MvWeb.GroupLive.Form do
socket socket
|> assign(:actor, actor) |> assign(:actor, actor)
|> assign(:group, nil) |> assign(:group, nil)
|> assign(:page_title, page_title_for_params(params)) |> Layouts.assign_page_title(page_title_for_params(params))
|> assign(:return_to, return_to_for_params(params))} |> assign(:return_to, return_to_for_params(params))}
else else
{:ok, redirect(socket, to: ~p"/groups")} {:ok, redirect(socket, to: ~p"/groups")}
@ -56,7 +56,7 @@ defmodule MvWeb.GroupLive.Form do
{:noreply, {:noreply,
socket socket
|> assign(:group, group) |> assign(:group, group)
|> assign(:page_title, gettext("Edit Group")) |> Layouts.assign_page_title(gettext("Edit Group"))
|> assign(:return_to, :show) |> assign(:return_to, :show)
|> assign_form(actor)} |> assign_form(actor)}
@ -85,7 +85,7 @@ defmodule MvWeb.GroupLive.Form do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{@page_title} {@content_title}
<:actions> <:actions>
<.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit"> <.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
{gettext("Save")} {gettext("Save")}

View file

@ -28,7 +28,7 @@ defmodule MvWeb.GroupLive.Index do
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Groups")) |> Layouts.assign_page_title(gettext("Groups"))
|> assign(:groups, groups)} |> assign(:groups, groups)}
else else
{:ok, redirect(socket, to: ~p"/members")} {:ok, redirect(socket, to: ~p"/members")}
@ -40,7 +40,7 @@ defmodule MvWeb.GroupLive.Index do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Groups")} {@content_title}
<:actions> <:actions>
<%= if can?(@current_user, :create, Mv.Membership.Group) do %> <%= if can?(@current_user, :create, Mv.Membership.Group) do %>
<.button navigate={~p"/groups/new"} variant="primary"> <.button navigate={~p"/groups/new"} variant="primary">

View file

@ -70,9 +70,11 @@ defmodule MvWeb.GroupLive.Show do
{:ok, group} -> {:ok, group} ->
open_delete = params["confirm_delete"] == "1" && can?(actor, :destroy, group) open_delete = params["confirm_delete"] == "1" && can?(actor, :destroy, group)
content_title = gettext("Group %{name}", name: group.name)
socket = socket =
socket socket
|> assign(:page_title, group.name) |> Layouts.assign_page_title(content_title)
|> assign(:group, group) |> assign(:group, group)
|> assign(:show_delete_modal, open_delete) |> assign(:show_delete_modal, open_delete)
|> assign(:name_confirmation, "") |> assign(:name_confirmation, "")
@ -102,7 +104,7 @@ defmodule MvWeb.GroupLive.Show do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{@group.name} {@content_title}
<:actions> <:actions>
<%= if can?(@current_user, :update, @group) do %> <%= if can?(@current_user, :update, @group) do %>
<.button <.button

View file

@ -65,7 +65,7 @@ defmodule MvWeb.ImportLive do
socket = socket =
socket socket
|> assign(:page_title, gettext("Import")) |> Layouts.assign_page_title(gettext("Import"))
|> assign(:club_name, club_name) |> assign(:club_name, club_name)
|> assign(:import_state, nil) |> assign(:import_state, nil)
|> assign(:import_progress, nil) |> assign(:import_progress, nil)
@ -94,7 +94,7 @@ defmodule MvWeb.ImportLive do
<%!-- CSV Import Section --%> <%!-- CSV Import Section --%>
<div data-testid="import-page"> <div data-testid="import-page">
<.header> <.header>
{gettext("Import Members")} {@content_title}
<:subtitle> <:subtitle>
{gettext("Import members from CSV files.")} {gettext("Import members from CSV files.")}
</:subtitle> </:subtitle>

View file

@ -36,6 +36,7 @@ defmodule MvWeb.JoinLive do
|> assign(:client_ip, client_ip) |> assign(:client_ip, client_ip)
|> assign(:honeypot_field, @honeypot_field) |> assign(:honeypot_field, @honeypot_field)
|> assign(:club_name, club_name) |> assign(:club_name, club_name)
|> Layouts.assign_page_title(gettext("Join"))
|> assign(:form, to_form(initial_form_params(join_fields))) |> assign(:form, to_form(initial_form_params(join_fields)))
{:ok, socket} {:ok, socket}

View file

@ -43,7 +43,7 @@ defmodule MvWeb.JoinRequestLive.Index do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Join requests")} {@content_title}
</.header> </.header>
<div class="mt-6 space-y-8 max-w-4xl"> <div class="mt-6 space-y-8 max-w-4xl">
@ -159,7 +159,7 @@ defmodule MvWeb.JoinRequestLive.Index do
assign(socket, :join_requests_history, []) assign(socket, :join_requests_history, [])
end end
assign(socket, :page_title, gettext("Join requests")) Layouts.assign_page_title(socket, gettext("Join requests"))
end end
defp review_date(req, timezone) do defp review_date(req, timezone) do

View file

@ -32,7 +32,7 @@ defmodule MvWeb.JoinRequestLive.Show do
socket socket
|> assign(:join_request, nil) |> assign(:join_request, nil)
|> assign(:join_form_field_ids, []) |> assign(:join_form_field_ids, [])
|> assign(:page_title, gettext("Join request"))} |> Layouts.assign_page_title(gettext("Join request"))}
else else
{:ok, redirect(socket, to: ~p"/members")} {:ok, redirect(socket, to: ~p"/members")}
end end
@ -57,7 +57,7 @@ defmodule MvWeb.JoinRequestLive.Show do
socket socket
|> assign(:join_request, request) |> assign(:join_request, request)
|> assign(:join_form_field_ids, field_ids) |> assign(:join_form_field_ids, field_ids)
|> assign(:page_title, gettext("Join request %{email}", email: request.email))} |> Layouts.assign_page_title(gettext("Join request %{email}", email: request.email))}
{:error, _error} -> {:error, _error} ->
{:noreply, {:noreply,
@ -123,7 +123,7 @@ defmodule MvWeb.JoinRequestLive.Show do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{gettext("Join request")} {@content_title}
</.header> </.header>
<%= if @join_request do %> <%= if @join_request do %>

View file

@ -374,7 +374,7 @@ defmodule MvWeb.MemberLive.Form do
id -> Ash.get!(MemberResource, id, load: [:membership_fee_type], actor: actor) id -> Ash.get!(MemberResource, id, load: [:membership_fee_type], actor: actor)
end end
page_title = content_title =
if is_nil(member), do: gettext("Create Member"), else: gettext("Edit Member") if is_nil(member), do: gettext("Create Member"), else: gettext("Edit Member")
# Load available membership fee types # Load available membership fee types
@ -389,7 +389,7 @@ defmodule MvWeb.MemberLive.Form do
|> assign(:custom_fields, custom_fields) |> assign(:custom_fields, custom_fields)
|> assign(:initial_custom_field_values, initial_custom_field_values) |> assign(:initial_custom_field_values, initial_custom_field_values)
|> assign(member: member) |> assign(member: member)
|> assign(:page_title, page_title) |> Layouts.assign_page_title(content_title)
|> assign(:available_fee_types, available_fee_types) |> assign(:available_fee_types, available_fee_types)
|> assign(:interval_warning, nil) |> assign(:interval_warning, nil)
|> assign(:member_field_required_map, member_field_required_map) |> assign(:member_field_required_map, member_field_required_map)

View file

@ -127,7 +127,7 @@ defmodule MvWeb.MemberLive.Index do
socket = socket =
socket socket
|> assign(:page_title, gettext("Members")) |> Layouts.assign_page_title(gettext("Members"))
|> assign(:query, "") |> assign(:query, "")
|> assign_new(:sort_field, fn -> :first_name end) |> assign_new(:sort_field, fn -> :first_name end)
|> assign_new(:sort_order, fn -> :asc end) |> assign_new(:sort_order, fn -> :asc end)

View file

@ -1,6 +1,6 @@
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Members")} {@content_title}
<:actions> <:actions>
<.live_component <.live_component
module={MvWeb.Components.ExportDropdown} module={MvWeb.Components.ExportDropdown}

View file

@ -47,7 +47,7 @@ defmodule MvWeb.MemberLive.Show do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{MemberHelpers.display_name(@member)} {@content_title}
<:actions> <:actions>
<%= if can?(@current_user, :update, @member) do %> <%= if can?(@current_user, :update, @member) do %>
<.button <.button
@ -435,9 +435,12 @@ defmodule MvWeb.MemberLive.Show do
|> Map.put(:last_cycle_status, last_cycle_status) |> Map.put(:last_cycle_status, last_cycle_status)
|> Map.put(:current_cycle_status, current_cycle_status) |> Map.put(:current_cycle_status, current_cycle_status)
content_title =
gettext("Member %{name}", name: MemberHelpers.display_name(member))
{:noreply, {:noreply,
socket socket
|> assign(:page_title, page_title(socket.assigns.live_action)) |> Layouts.assign_page_title(content_title)
|> assign(:member, member)} |> assign(:member, member)}
end end
@ -565,9 +568,6 @@ defmodule MvWeb.MemberLive.Show do
{:noreply, assign(socket, :member, member)} {:noreply, assign(socket, :member, member)}
end end
defp page_title(:show), do: gettext("Show Member")
defp page_title(:edit), do: gettext("Edit Member")
defp format_error(%Ash.Error.Invalid{errors: errors}) do defp format_error(%Ash.Error.Invalid{errors: errors}) do
error_messages = error_messages =
Enum.map(errors, fn Enum.map(errors, fn

View file

@ -33,7 +33,7 @@ defmodule MvWeb.MembershipFeeSettingsLive do
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Membership Fee Settings")) |> Layouts.assign_page_title(gettext("Membership fee settings"))
|> assign(:settings, settings) |> assign(:settings, settings)
|> assign(:membership_fee_types, membership_fee_types) |> assign(:membership_fee_types, membership_fee_types)
|> assign(:member_counts, member_counts) |> assign(:member_counts, member_counts)
@ -140,7 +140,7 @@ defmodule MvWeb.MembershipFeeSettingsLive do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Membership Fee Settings")} {@content_title}
<:subtitle> <:subtitle>
{gettext("Configure fee types for membership fees.")} {gettext("Configure fee types for membership fees.")}
</:subtitle> </:subtitle>

View file

@ -33,7 +33,7 @@ defmodule MvWeb.MembershipFeeTypeLive.Form do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{@page_title} {@content_title}
<:actions> <:actions>
<.button <.button
form="membership-fee-type-form" form="membership-fee-type-form"
@ -221,7 +221,7 @@ defmodule MvWeb.MembershipFeeTypeLive.Form do
id -> Ash.get!(MembershipFeeType, id, domain: MembershipFees, actor: actor) id -> Ash.get!(MembershipFeeType, id, domain: MembershipFees, actor: actor)
end end
page_title = content_title =
if is_nil(membership_fee_type), if is_nil(membership_fee_type),
do: gettext("New Membership Fee Type"), do: gettext("New Membership Fee Type"),
else: gettext("Edit Membership Fee Type") else: gettext("Edit Membership Fee Type")
@ -230,7 +230,7 @@ defmodule MvWeb.MembershipFeeTypeLive.Form do
socket socket
|> assign(:return_to, return_to(params["return_to"])) |> assign(:return_to, return_to(params["return_to"]))
|> assign(:membership_fee_type, membership_fee_type) |> assign(:membership_fee_type, membership_fee_type)
|> assign(:page_title, page_title) |> Layouts.assign_page_title(content_title)
|> assign(:show_amount_warning, false) |> assign(:show_amount_warning, false)
|> assign(:old_amount, nil) |> assign(:old_amount, nil)
|> assign(:new_amount, nil) |> assign(:new_amount, nil)

View file

@ -32,7 +32,7 @@ defmodule MvWeb.MembershipFeeTypeLive.Index do
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Membership Fee Types")) |> Layouts.assign_page_title(gettext("Membership fee settings"))
|> assign(:membership_fee_types, fee_types) |> assign(:membership_fee_types, fee_types)
|> assign(:member_counts, member_counts)} |> assign(:member_counts, member_counts)}
end end
@ -42,7 +42,7 @@ defmodule MvWeb.MembershipFeeTypeLive.Index do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Membership Fee Types")} {@content_title}
<:subtitle> <:subtitle>
{gettext("Manage membership fee types for membership fees.")} {gettext("Manage membership fee types for membership fees.")}
</:subtitle> </:subtitle>

View file

@ -29,7 +29,7 @@ defmodule MvWeb.RoleLive.Form do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{@page_title} {@content_title}
<:actions> <:actions>
<.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit"> <.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
{gettext("Save")} {gettext("Save")}
@ -94,14 +94,13 @@ defmodule MvWeb.RoleLive.Form do
def mount(params, _session, socket) do def mount(params, _session, socket) do
case params["id"] do case params["id"] do
nil -> nil ->
action = gettext("New") content_title = gettext("New") <> " " <> gettext("Role")
page_title = action <> " " <> gettext("Role")
{:ok, {:ok,
socket socket
|> assign(:return_to, return_to(params["return_to"])) |> assign(:return_to, return_to(params["return_to"]))
|> assign(:role, nil) |> assign(:role, nil)
|> assign(:page_title, page_title) |> Layouts.assign_page_title(content_title)
|> assign_form()} |> assign_form()}
id -> id ->
@ -113,14 +112,13 @@ defmodule MvWeb.RoleLive.Form do
actor: socket.assigns[:current_user] actor: socket.assigns[:current_user]
) do ) do
{:ok, role} -> {:ok, role} ->
action = gettext("Edit") content_title = gettext("Edit") <> " " <> gettext("Role")
page_title = action <> " " <> gettext("Role")
{:ok, {:ok,
socket socket
|> assign(:return_to, return_to(params["return_to"])) |> assign(:return_to, return_to(params["return_to"]))
|> assign(:role, role) |> assign(:role, role)
|> assign(:page_title, page_title) |> Layouts.assign_page_title(content_title)
|> assign_form()} |> assign_form()}
{:error, %Ash.Error.Invalid{errors: [%Ash.Error.Query.NotFound{} | _]}} -> {:error, %Ash.Error.Invalid{errors: [%Ash.Error.Query.NotFound{} | _]}} ->

View file

@ -28,7 +28,7 @@ defmodule MvWeb.RoleLive.Index do
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Listing Roles")) |> Layouts.assign_page_title(gettext("Roles"))
|> assign(:roles, roles) |> assign(:roles, roles)
|> assign(:user_counts, user_counts)} |> assign(:user_counts, user_counts)}
end end

View file

@ -1,6 +1,6 @@
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Listing Roles")} {@content_title}
<:subtitle> <:subtitle>
{gettext("Manage roles and their permission sets.")} {gettext("Manage roles and their permission sets.")}
</:subtitle> </:subtitle>

View file

@ -30,9 +30,11 @@ defmodule MvWeb.RoleLive.Show do
{:ok, role} -> {:ok, role} ->
user_count = load_user_count(role, socket.assigns[:current_user]) user_count = load_user_count(role, socket.assigns[:current_user])
content_title = gettext("Role %{name}", name: role.name)
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Show Role")) |> Layouts.assign_page_title(content_title)
|> assign(:role, role) |> assign(:role, role)
|> assign(:user_count, user_count) |> assign(:user_count, user_count)
|> assign(:show_delete_modal, false)} |> assign(:show_delete_modal, false)}
@ -202,7 +204,7 @@ defmodule MvWeb.RoleLive.Show do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{gettext("Role")} {@role.name} {@content_title}
<:subtitle>{gettext("Role details and permissions.")}</:subtitle> <:subtitle>{gettext("Role details and permissions.")}</:subtitle>
<:actions> <:actions>

View file

@ -18,7 +18,7 @@ defmodule MvWeb.StatisticsLive do
# Only static assigns and fee types here; load_statistics runs once in handle_params # Only static assigns and fee types here; load_statistics runs once in handle_params
socket = socket =
socket socket
|> assign(:page_title, gettext("Statistics")) |> Layouts.assign_page_title(gettext("Statistics"))
|> assign(:selected_fee_type_id, nil) |> assign(:selected_fee_type_id, nil)
|> load_fee_types() |> load_fee_types()
@ -58,7 +58,7 @@ defmodule MvWeb.StatisticsLive do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Statistics")} {@content_title}
</.header> </.header>
<section class="mb-8" aria-labelledby="members-heading"> <section class="mb-8" aria-labelledby="members-heading">

View file

@ -59,7 +59,7 @@ defmodule MvWeb.UserLive.Form do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{@page_title} {@content_title}
<:actions> <:actions>
<.button <.button
form="user-form" form="user-form"
@ -423,8 +423,9 @@ defmodule MvWeb.UserLive.Form do
defp mount_continue(user, params, socket) do defp mount_continue(user, params, socket) do
actor = current_actor(socket) actor = current_actor(socket)
action = if is_nil(user), do: gettext("New"), else: gettext("Edit")
page_title = action <> " " <> gettext("User") content_title =
if(is_nil(user), do: gettext("New"), else: gettext("Edit")) <> " " <> gettext("User")
# Only admins can link/unlink users to members (permission docs; prevents privilege escalation). # Only admins can link/unlink users to members (permission docs; prevents privilege escalation).
can_manage_member_linking = can?(actor, :destroy, UserResource) can_manage_member_linking = can?(actor, :destroy, UserResource)
@ -436,7 +437,7 @@ defmodule MvWeb.UserLive.Form do
socket socket
|> assign(:return_to, return_to(params["return_to"])) |> assign(:return_to, return_to(params["return_to"]))
|> assign(user: user) |> assign(user: user)
|> assign(:page_title, page_title) |> Layouts.assign_page_title(content_title)
|> assign(:can_manage_member_linking, can_manage_member_linking) |> assign(:can_manage_member_linking, can_manage_member_linking)
|> assign(:can_assign_role, can_assign_role) |> assign(:can_assign_role, can_assign_role)
|> assign(:roles, roles) |> assign(:roles, roles)

View file

@ -38,7 +38,7 @@ defmodule MvWeb.UserLive.Index do
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Listing Users")) |> Layouts.assign_page_title(gettext("Users"))
|> assign(:sort_field, :email) |> assign(:sort_field, :email)
|> assign(:sort_order, :asc) |> assign(:sort_order, :asc)
|> assign(:users, sorted)} |> assign(:users, sorted)}

View file

@ -1,6 +1,6 @@
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Users")} {@content_title}
<:subtitle>{gettext("Manage users and their permissions.")}</:subtitle> <:subtitle>{gettext("Manage users and their permissions.")}</:subtitle>
<:actions> <:actions>
<%= if can?(@current_user, :create, Mv.Accounts.User) do %> <%= if can?(@current_user, :create, Mv.Accounts.User) do %>

View file

@ -48,7 +48,7 @@ defmodule MvWeb.UserLive.Show do
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading> </:leading>
{gettext("User")} {@user.email} {@content_title}
<:actions> <:actions>
<%= if can?(@current_user, :update, @user) do %> <%= if can?(@current_user, :update, @user) do %>
<.button <.button
@ -179,9 +179,11 @@ defmodule MvWeb.UserLive.Show do
|> put_flash(:error, gettext("This user cannot be viewed.")) |> put_flash(:error, gettext("This user cannot be viewed."))
|> push_navigate(to: ~p"/users")} |> push_navigate(to: ~p"/users")}
else else
content_title = gettext("User %{email}", email: user.email)
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Show User")) |> Layouts.assign_page_title(content_title)
|> assign(:user, user) |> assign(:user, user)
|> assign(:show_delete_modal, false)} |> assign(:show_delete_modal, false)}
end end

View file

@ -17,6 +17,7 @@ defmodule MvWeb.LiveHelpers do
""" """
import Phoenix.Component import Phoenix.Component
alias Mv.Authorization.Actor alias Mv.Authorization.Actor
alias Mv.Membership
alias MvWeb.Plugs.CheckPagePermission alias MvWeb.Plugs.CheckPagePermission
def on_mount(:default, _params, session, socket) do def on_mount(:default, _params, session, socket) do
@ -27,9 +28,17 @@ defmodule MvWeb.LiveHelpers do
connect_params = socket.private[:connect_params] || %{} connect_params = socket.private[:connect_params] || %{}
timezone = connect_params["timezone"] || connect_params[:timezone] timezone = connect_params["timezone"] || connect_params[:timezone]
# Club name for browser tab title (Mila · Club · Page)
club_name =
case Membership.get_settings() do
{:ok, settings} when is_binary(settings.club_name) -> settings.club_name
_ -> nil
end
socket = socket =
socket socket
|> assign(:browser_timezone, timezone) |> assign(:browser_timezone, timezone)
|> assign(:club_name, club_name)
{:cont, socket} {:cont, socket}
end end

View file

@ -0,0 +1,22 @@
defmodule MvWeb.Plugs.AssignClubName do
@moduledoc """
Assigns :club_name from settings for controller-rendered pages.
Used by the root layout to build the browser tab title (Mila · Club · Page).
LiveViews set club_name in on_mount instead.
"""
import Plug.Conn
alias Mv.Membership
def init(opts), do: opts
def call(conn, _opts) do
club_name =
case Membership.get_settings() do
{:ok, settings} when is_binary(settings.club_name) -> settings.club_name
_ -> nil
end
assign(conn, :club_name, club_name)
end
end

View file

@ -14,6 +14,7 @@ defmodule MvWeb.Router do
plug :put_secure_browser_headers plug :put_secure_browser_headers
plug :load_from_session plug :load_from_session
plug :set_locale plug :set_locale
plug MvWeb.Plugs.AssignClubName
plug MvWeb.Plugs.CheckPagePermission plug MvWeb.Plugs.CheckPagePermission
plug MvWeb.Plugs.JoinFormEnabled plug MvWeb.Plugs.JoinFormEnabled
plug MvWeb.Plugs.RegistrationEnabled plug MvWeb.Plugs.RegistrationEnabled

View file

@ -351,6 +351,7 @@ msgid "Base URL"
msgstr "Basis-URL" msgstr "Basis-URL"
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Basic settings" msgid "Basic settings"
msgstr "Grundeinstellungen" msgstr "Grundeinstellungen"
@ -1079,7 +1080,6 @@ msgid "Edit Group"
msgstr "Gruppe bearbeiten" msgstr "Gruppe bearbeiten"
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Edit Member" msgid "Edit Member"
msgstr "Mitglied bearbeiten" msgstr "Mitglied bearbeiten"
@ -1574,11 +1574,6 @@ msgstr "Wenn du diese Anfrage nicht gestellt hast, kannst du diese E-Mail ignori
msgid "Import" msgid "Import"
msgstr "Import" msgstr "Import"
#: lib/mv_web/live/import_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Import Members"
msgstr "Mitglieder importieren (CSV)"
#: lib/mv_web/live/import_live/components.ex #: lib/mv_web/live/import_live/components.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Import Results" msgid "Import Results"
@ -1828,17 +1823,6 @@ msgstr "Verknüpftes Mitglied"
msgid "Linked User" msgid "Linked User"
msgstr "Verknüpfte*r Benutzer*in" msgstr "Verknüpfte*r Benutzer*in"
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Listing Roles"
msgstr "Rollen auflisten"
#: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format
msgid "Listing Users"
msgstr "Benutzer*innen auflisten"
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Logout" msgid "Logout"
@ -1991,7 +1975,6 @@ msgstr "Die Verknüpfung des Mitglieds wird beim Speichern aufgehoben. Ein neues
#: lib/mv_web/live/group_live/index.ex #: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/index.ex #: lib/mv_web/live/member_live/index.ex
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/statistics_live.ex #: lib/mv_web/live/statistics_live.ex
@ -2010,11 +1993,6 @@ msgstr "Mitgliedertabelle"
msgid "Membership Fee" msgid "Membership Fee"
msgstr "Mitgliedsbeitrag" msgstr "Mitgliedsbeitrag"
#: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Membership Fee Settings"
msgstr "Mitgliedsbeitragseinstellungen"
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/translations/member_fields.ex #: lib/mv_web/translations/member_fields.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
@ -2034,7 +2012,6 @@ msgid "Membership Fee Type"
msgstr "Mitgliedsbeitragsart" msgstr "Mitgliedsbeitragsart"
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Membership Fee Types" msgid "Membership Fee Types"
msgstr "Mitgliedsbeitragsarten" msgstr "Mitgliedsbeitragsarten"
@ -2046,6 +2023,8 @@ msgid "Membership Fees"
msgstr "Mitgliedsbeiträge" msgstr "Mitgliedsbeiträge"
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Membership fee settings" msgid "Membership fee settings"
msgstr "Beitragseinstellungen" msgstr "Beitragseinstellungen"
@ -2705,7 +2684,6 @@ msgid "Reviewed at"
msgstr "Geprüft am" msgstr "Geprüft am"
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/index.html.heex #: lib/mv_web/live/user_live/index.html.heex
#: lib/mv_web/live/user_live/show.ex #: lib/mv_web/live/user_live/show.ex
@ -2735,6 +2713,7 @@ msgid "Role saved successfully."
msgstr "Rolle erfolgreich gespeichert." msgstr "Rolle erfolgreich gespeichert."
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/role_live/index.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Roles" msgid "Roles"
msgstr "Rollen" msgstr "Rollen"
@ -2971,11 +2950,6 @@ msgstr "Passwort setzen"
msgid "Sets whether the payment status filter and the membership fee status column use the last completed or the current payment cycle." msgid "Sets whether the payment status filter and the membership fee status column use the last completed or the current payment cycle."
msgstr "Legt fest, ob Bezahlstatusfilter und Mitgliedsbeitragsstatus-Spalte den letzten abgeschlossenen oder den aktuellen Zahlungszyklus verwenden." msgstr "Legt fest, ob Bezahlstatusfilter und Mitgliedsbeitragsstatus-Spalte den letzten abgeschlossenen oder den aktuellen Zahlungszyklus verwenden."
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Settings"
msgstr "Einstellungen"
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Settings saved successfully." msgid "Settings saved successfully."
@ -2991,21 +2965,6 @@ msgstr "Einstellungen erfolgreich gespeichert"
msgid "Show" msgid "Show"
msgstr "Anzeigen" msgstr "Anzeigen"
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Show Member"
msgstr "Mitglied anzeigen"
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Show Role"
msgstr "Rolle anzeigen"
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Show User"
msgstr "Benutzer*in anzeigen"
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Show bookings/receipts from Vereinfacht" msgid "Show bookings/receipts from Vereinfacht"
@ -3390,7 +3349,6 @@ msgid "Use the data field name as the CSV column header in your file. Data field
msgstr "Verwende die Namen der Datenfelder als Spaltennamen in der CSV-Datei. Datenfelder müssen in Mila bereits angelegt sein, da unbekannte Spaltennamen ignoriert werden. Gruppen und Beitragsstatus können nicht importiert werden." msgstr "Verwende die Namen der Datenfelder als Spaltennamen in der CSV-Datei. Datenfelder müssen in Mila bereits angelegt sein, da unbekannte Spaltennamen ignoriert werden. Gruppen und Beitragsstatus können nicht importiert werden."
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "User" msgid "User"
msgstr "Benutzer*in" msgstr "Benutzer*in"
@ -3429,7 +3387,7 @@ msgstr "Benutzername"
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/role_live/index.html.heex #: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex #: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Users" msgid "Users"
msgstr "Benutzer*innen" msgstr "Benutzer*innen"
@ -3847,6 +3805,7 @@ msgstr "Zum Antragsformular"
msgid "Invalid or expired link" msgid "Invalid or expired link"
msgstr "Ungültiger oder abgelaufener Link." msgstr "Ungültiger oder abgelaufener Link."
#: lib/mv_web/controllers/join_confirm_controller.ex
#: lib/mv_web/controllers/join_confirm_html/confirm.html.heex #: lib/mv_web/controllers/join_confirm_html/confirm.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Link expired" msgid "Link expired"
@ -3891,3 +3850,48 @@ msgstr "Einstellung konnte nicht gespeichert werden."
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "If disabled, users cannot sign up via /register; sign-in and the join form remain available." msgid "If disabled, users cannot sign up via /register; sign-in and the join form remain available."
msgstr "Wenn deaktiviert, können sich Nutzer*innen nicht über /register anmelden; Anmeldung und Beitrittsformular bleiben verfügbar." msgstr "Wenn deaktiviert, können sich Nutzer*innen nicht über /register anmelden; Anmeldung und Beitrittsformular bleiben verfügbar."
#: lib/mv_web/controllers/page_controller.ex
#, elixir-autogen, elixir-format
msgid "Home"
msgstr ""
#: lib/mv_web/controllers/join_confirm_controller.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Invalid link"
msgstr "Ungültiger oder abgelaufener Link."
#: lib/mv_web/live/join_live.ex
#, elixir-autogen, elixir-format
msgid "Join"
msgstr "Beitritt"
#: lib/mv_web/controllers/join_confirm_controller.ex
#, elixir-autogen, elixir-format
msgid "Join confirmation"
msgstr "Beitrittsbestätigung"
#: lib/mv_web/live/auth/sign_in_live.ex
#, elixir-autogen, elixir-format
msgid "Sign in"
msgstr "Anmelden"
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Group %{name}"
msgstr "Gruppe %{name}"
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member %{name}"
msgstr "Mitglied %{name}"
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Role %{name}"
msgstr "Rolle %{name}"
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "User %{email}"
msgstr "Benutzer*in %{email}"

View file

@ -352,6 +352,7 @@ msgid "Base URL"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Basic settings" msgid "Basic settings"
msgstr "" msgstr ""
@ -1080,7 +1081,6 @@ msgid "Edit Group"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Edit Member" msgid "Edit Member"
msgstr "" msgstr ""
@ -1575,11 +1575,6 @@ msgstr ""
msgid "Import" msgid "Import"
msgstr "" msgstr ""
#: lib/mv_web/live/import_live.ex
#, elixir-autogen, elixir-format
msgid "Import Members"
msgstr ""
#: lib/mv_web/live/import_live/components.ex #: lib/mv_web/live/import_live/components.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Import Results" msgid "Import Results"
@ -1829,17 +1824,6 @@ msgstr ""
msgid "Linked User" msgid "Linked User"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Listing Roles"
msgstr ""
#: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format
msgid "Listing Users"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Logout" msgid "Logout"
@ -1992,7 +1976,6 @@ msgstr ""
#: lib/mv_web/live/group_live/index.ex #: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/index.ex #: lib/mv_web/live/member_live/index.ex
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/statistics_live.ex #: lib/mv_web/live/statistics_live.ex
@ -2011,11 +1994,6 @@ msgstr ""
msgid "Membership Fee" msgid "Membership Fee"
msgstr "" msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Membership Fee Settings"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/translations/member_fields.ex #: lib/mv_web/translations/member_fields.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -2035,7 +2013,6 @@ msgid "Membership Fee Type"
msgstr "" msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Membership Fee Types" msgid "Membership Fee Types"
msgstr "" msgstr ""
@ -2047,6 +2024,8 @@ msgid "Membership Fees"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Membership fee settings" msgid "Membership fee settings"
msgstr "" msgstr ""
@ -2706,7 +2685,6 @@ msgid "Reviewed at"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/index.html.heex #: lib/mv_web/live/user_live/index.html.heex
#: lib/mv_web/live/user_live/show.ex #: lib/mv_web/live/user_live/show.ex
@ -2736,6 +2714,7 @@ msgid "Role saved successfully."
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/role_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Roles" msgid "Roles"
msgstr "" msgstr ""
@ -2972,11 +2951,6 @@ msgstr ""
msgid "Sets whether the payment status filter and the membership fee status column use the last completed or the current payment cycle." msgid "Sets whether the payment status filter and the membership fee status column use the last completed or the current payment cycle."
msgstr "" msgstr ""
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Settings"
msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Settings saved successfully." msgid "Settings saved successfully."
@ -2992,21 +2966,6 @@ msgstr ""
msgid "Show" msgid "Show"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Show Member"
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Show Role"
msgstr ""
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Show User"
msgstr ""
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Show bookings/receipts from Vereinfacht" msgid "Show bookings/receipts from Vereinfacht"
@ -3391,7 +3350,6 @@ msgid "Use the data field name as the CSV column header in your file. Data field
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "User" msgid "User"
msgstr "" msgstr ""
@ -3430,7 +3388,7 @@ msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/role_live/index.html.heex #: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex #: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Users" msgid "Users"
msgstr "" msgstr ""
@ -3847,6 +3805,7 @@ msgstr ""
msgid "Invalid or expired link" msgid "Invalid or expired link"
msgstr "" msgstr ""
#: lib/mv_web/controllers/join_confirm_controller.ex
#: lib/mv_web/controllers/join_confirm_html/confirm.html.heex #: lib/mv_web/controllers/join_confirm_html/confirm.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Link expired" msgid "Link expired"
@ -3891,3 +3850,48 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "If disabled, users cannot sign up via /register; sign-in and the join form remain available." msgid "If disabled, users cannot sign up via /register; sign-in and the join form remain available."
msgstr "" msgstr ""
#: lib/mv_web/controllers/page_controller.ex
#, elixir-autogen, elixir-format
msgid "Home"
msgstr ""
#: lib/mv_web/controllers/join_confirm_controller.ex
#, elixir-autogen, elixir-format
msgid "Invalid link"
msgstr ""
#: lib/mv_web/live/join_live.ex
#, elixir-autogen, elixir-format
msgid "Join"
msgstr ""
#: lib/mv_web/controllers/join_confirm_controller.ex
#, elixir-autogen, elixir-format
msgid "Join confirmation"
msgstr ""
#: lib/mv_web/live/auth/sign_in_live.ex
#, elixir-autogen, elixir-format
msgid "Sign in"
msgstr ""
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Group %{name}"
msgstr ""
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member %{name}"
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Role %{name}"
msgstr ""
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "User %{email}"
msgstr ""

View file

@ -352,6 +352,7 @@ msgid "Base URL"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Basic settings" msgid "Basic settings"
msgstr "" msgstr ""
@ -1080,7 +1081,6 @@ msgid "Edit Group"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Edit Member" msgid "Edit Member"
msgstr "" msgstr ""
@ -1575,11 +1575,6 @@ msgstr "If you did not submit this request, you can ignore this email."
msgid "Import" msgid "Import"
msgstr "" msgstr ""
#: lib/mv_web/live/import_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Import Members"
msgstr ""
#: lib/mv_web/live/import_live/components.ex #: lib/mv_web/live/import_live/components.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Import Results" msgid "Import Results"
@ -1829,17 +1824,6 @@ msgstr ""
msgid "Linked User" msgid "Linked User"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy
msgid "Listing Roles"
msgstr ""
#: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Listing Users"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Logout" msgid "Logout"
@ -1992,7 +1976,6 @@ msgstr ""
#: lib/mv_web/live/group_live/index.ex #: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/index.ex #: lib/mv_web/live/member_live/index.ex
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/statistics_live.ex #: lib/mv_web/live/statistics_live.ex
@ -2011,11 +1994,6 @@ msgstr ""
msgid "Membership Fee" msgid "Membership Fee"
msgstr "" msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Membership Fee Settings"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/translations/member_fields.ex #: lib/mv_web/translations/member_fields.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
@ -2035,7 +2013,6 @@ msgid "Membership Fee Type"
msgstr "" msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Membership Fee Types" msgid "Membership Fee Types"
msgstr "" msgstr ""
@ -2047,6 +2024,8 @@ msgid "Membership Fees"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Membership fee settings" msgid "Membership fee settings"
msgstr "" msgstr ""
@ -2706,7 +2685,6 @@ msgid "Reviewed at"
msgstr "Review date" msgstr "Review date"
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/index.html.heex #: lib/mv_web/live/user_live/index.html.heex
#: lib/mv_web/live/user_live/show.ex #: lib/mv_web/live/user_live/show.ex
@ -2736,6 +2714,7 @@ msgid "Role saved successfully."
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/role_live/index.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Roles" msgid "Roles"
msgstr "" msgstr ""
@ -2972,11 +2951,6 @@ msgstr ""
msgid "Sets whether the payment status filter and the membership fee status column use the last completed or the current payment cycle." msgid "Sets whether the payment status filter and the membership fee status column use the last completed or the current payment cycle."
msgstr "Sets whether the payment status filter and the membership fee status column use the last completed or the current payment cycle." msgstr "Sets whether the payment status filter and the membership fee status column use the last completed or the current payment cycle."
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Settings"
msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Settings saved successfully." msgid "Settings saved successfully."
@ -2992,21 +2966,6 @@ msgstr ""
msgid "Show" msgid "Show"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Show Member"
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Show Role"
msgstr ""
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Show User"
msgstr ""
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Show bookings/receipts from Vereinfacht" msgid "Show bookings/receipts from Vereinfacht"
@ -3391,7 +3350,6 @@ msgid "Use the data field name as the CSV column header in your file. Data field
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "User" msgid "User"
msgstr "" msgstr ""
@ -3430,7 +3388,7 @@ msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/role_live/index.html.heex #: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex #: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Users" msgid "Users"
msgstr "" msgstr ""
@ -3847,6 +3805,7 @@ msgstr "Go to join form"
msgid "Invalid or expired link" msgid "Invalid or expired link"
msgstr "Invalid or expired link." msgstr "Invalid or expired link."
#: lib/mv_web/controllers/join_confirm_controller.ex
#: lib/mv_web/controllers/join_confirm_html/confirm.html.heex #: lib/mv_web/controllers/join_confirm_html/confirm.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Link expired" msgid "Link expired"
@ -3891,3 +3850,48 @@ msgstr "Failed to update setting."
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "If disabled, users cannot sign up via /register; sign-in and the join form remain available." msgid "If disabled, users cannot sign up via /register; sign-in and the join form remain available."
msgstr "If disabled, users cannot sign up via /register; sign-in and the join form remain available." msgstr "If disabled, users cannot sign up via /register; sign-in and the join form remain available."
#: lib/mv_web/controllers/page_controller.ex
#, elixir-autogen, elixir-format
msgid "Home"
msgstr ""
#: lib/mv_web/controllers/join_confirm_controller.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Invalid link"
msgstr "Invalid or expired link."
#: lib/mv_web/live/join_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Join"
msgstr ""
#: lib/mv_web/controllers/join_confirm_controller.ex
#, elixir-autogen, elixir-format
msgid "Join confirmation"
msgstr ""
#: lib/mv_web/live/auth/sign_in_live.ex
#, elixir-autogen, elixir-format
msgid "Sign in"
msgstr ""
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Group %{name}"
msgstr "Group %{name}"
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
msgid "Member %{name}"
msgstr "Member %{name}"
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Role %{name}"
msgstr "Role %{name}"
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "User %{email}"
msgstr "User %{email}"

View file

@ -38,7 +38,10 @@ defmodule MvWeb.JoinLiveEmailFailureTest do
|> render_submit() |> render_submit()
html = render(view) html = render(view)
assert html =~ "could not send" or html =~ "confirmation email" # Error message is translated; accept English or German wording
assert html =~ "could not send" or html =~ "confirmation email" or
html =~ "konnte nicht" or html =~ "Bestätigungs-E-Mail"
refute view |> element("[data-testid='join-success-message']") |> has_element?() refute view |> element("[data-testid='join-success-message']") |> has_element?()
end end