feat(join): use join_description as the join-form field label

This commit is contained in:
Simon 2026-06-03 12:11:39 +02:00
parent cb5cb68483
commit aced57d0fd
2 changed files with 67 additions and 5 deletions

View file

@ -8,6 +8,7 @@ defmodule MvWeb.JoinLive do
alias Ash.Resource.Info alias Ash.Resource.Info
alias Mv.Membership alias Mv.Membership
alias Mv.Membership.CustomFieldLookup alias Mv.Membership.CustomFieldLookup
alias MvWeb.Helpers.JoinDescriptionRenderer
alias MvWeb.JoinRateLimit alias MvWeb.JoinRateLimit
alias MvWeb.Translations.MemberFields alias MvWeb.Translations.MemberFields
@ -96,14 +97,20 @@ defmodule MvWeb.JoinLive do
class="checkbox checkbox-sm" class="checkbox checkbox-sm"
/> />
<span class="label-text"> <span class="label-text">
{field.label}<span :if={field.required} aria-hidden="true"> *</span> {render_field_label(field)}<span
:if={field.required}
aria-hidden="true"
> *</span>
</span> </span>
</label> </label>
<% else %> <% else %>
<div> <div>
<label for={"join-field-#{field.id}"} class="label"> <label for={"join-field-#{field.id}"} class="label">
<span class="label-text"> <span class="label-text">
{field.label}<span :if={field.required} aria-hidden="true"> *</span> {render_field_label(field)}<span
:if={field.required}
aria-hidden="true"
> *</span>
</span> </span>
</label> </label>
<input <input
@ -237,6 +244,17 @@ defmodule MvWeb.JoinLive do
|> assign(:form, to_form(params, as: "join"))} |> assign(:form, to_form(params, as: "join"))}
end end
# Renders a join field's label. When a custom field has a join_description it is
# rendered with auto-linked URLs/Markdown; otherwise the plain field label is used.
# Safe: join_description is admin-set settings content, never end-user input, and
# JoinDescriptionRenderer escapes all non-link text (only emits <a href> tags).
defp render_field_label(%{join_description: join_description})
when is_binary(join_description) do
JoinDescriptionRenderer.render(join_description)
end
defp render_field_label(%{label: label}), do: label
defp build_join_fields_with_labels(allowlist) do defp build_join_fields_with_labels(allowlist) do
member_field_strings = Mv.Constants.member_fields() |> Enum.map(&Atom.to_string/1) member_field_strings = Mv.Constants.member_fields() |> Enum.map(&Atom.to_string/1)
custom_field_by_id = custom_field_map(allowlist, member_field_strings) custom_field_by_id = custom_field_map(allowlist, member_field_strings)
@ -249,20 +267,36 @@ defmodule MvWeb.JoinLive do
defp build_join_field(id, required, member_field_strings, custom_field_by_id) do defp build_join_field(id, required, member_field_strings, custom_field_by_id) do
if id in member_field_strings do if id in member_field_strings do
label = MemberFields.label(String.to_existing_atom(id)) label = MemberFields.label(String.to_existing_atom(id))
%{id: id, label: label, required: required, input_type: member_field_input_type(id)}
%{
id: id,
label: label,
required: required,
input_type: member_field_input_type(id),
join_description: nil
}
else else
custom_field = Map.get(custom_field_by_id, id) custom_field = Map.get(custom_field_by_id, id)
label = if custom_field, do: custom_field.name, else: gettext("Field") label = if custom_field, do: custom_field.name, else: gettext("Field")
input_type = custom_field_input_type(custom_field && custom_field.value_type) input_type = custom_field_input_type(custom_field && custom_field.value_type)
%{id: id, label: label, required: required, input_type: input_type} %{
id: id,
label: label,
required: required,
input_type: input_type,
join_description: custom_field && custom_field.join_description
}
end end
end end
defp custom_field_map(allowlist, _member_field_strings) do defp custom_field_map(allowlist, _member_field_strings) do
allowlist allowlist
|> Enum.map(& &1.id) |> Enum.map(& &1.id)
|> CustomFieldLookup.fetch_map_by_ids(authorize?: false, select: [:id, :name, :value_type]) |> CustomFieldLookup.fetch_map_by_ids(
authorize?: false,
select: [:id, :name, :value_type, :join_description]
)
end end
defp initial_form_params(join_fields) do defp initial_form_params(join_fields) do

View file

@ -165,6 +165,34 @@ defmodule MvWeb.JoinLiveTest do
custom_field.name custom_field.name
) )
end end
@tag role: :unauthenticated
test "renders join_description with rendered link as label when set", %{conn: conn} do
{:ok, settings} = Membership.get_settings()
system_actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, custom_field} =
Membership.create_custom_field(
%{
name: "DSGVO",
value_type: :boolean,
join_description: "Akzeptiere die [Datenschutzerklärung](https://example.com/dsgvo)"
},
actor: system_actor
)
{:ok, _} =
Membership.update_settings(settings, %{
join_form_enabled: true,
join_form_field_ids: ["email", custom_field.id],
join_form_field_required: %{"email" => true, custom_field.id => false}
})
{:ok, _view, html} = live(conn, "/join")
assert html =~ ~s(<a href="https://example.com/dsgvo">Datenschutzerklärung</a>)
assert html =~ "Akzeptiere die"
end
end end
describe "join field input types" do describe "join field input types" do