feat: respect field types in join requests
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
95b666f04f
commit
6327ea00eb
2 changed files with 115 additions and 31 deletions
|
|
@ -5,6 +5,7 @@ defmodule MvWeb.JoinLive do
|
|||
"""
|
||||
use MvWeb, :live_view
|
||||
|
||||
alias Ash.Resource.Info
|
||||
alias Mv.Membership
|
||||
alias MvWeb.JoinRateLimit
|
||||
alias MvWeb.Translations.MemberFields
|
||||
|
|
@ -54,10 +55,6 @@ defmodule MvWeb.JoinLive do
|
|||
{gettext("Become a member")}
|
||||
</.header>
|
||||
|
||||
<p class="text-base-content/80">
|
||||
{gettext("Please enter your details for the membership application here.")}
|
||||
</p>
|
||||
|
||||
<%= if @submitted do %>
|
||||
<div data-testid="join-success-message" class="alert alert-success">
|
||||
<p class="font-medium">
|
||||
|
|
@ -67,6 +64,9 @@ defmodule MvWeb.JoinLive do
|
|||
</p>
|
||||
</div>
|
||||
<% else %>
|
||||
<p class="text-base-content/80">
|
||||
{gettext("Please enter your details for the membership application here.")}
|
||||
</p>
|
||||
<.form
|
||||
for={@form}
|
||||
id="join-form"
|
||||
|
|
@ -80,18 +80,31 @@ defmodule MvWeb.JoinLive do
|
|||
<% end %>
|
||||
|
||||
<%= for field <- @join_fields do %>
|
||||
<div>
|
||||
<div class={
|
||||
if field.input_type == "checkbox", do: "flex items-end gap-3", else: ""
|
||||
}>
|
||||
<label for={"join-field-#{field.id}"} class="label">
|
||||
<span class="label-text">{field.label}{if field.required, do: " *"}</span>
|
||||
</label>
|
||||
<%= if field.input_type == "checkbox" do %>
|
||||
<input
|
||||
type={input_type(field.id)}
|
||||
type="checkbox"
|
||||
name={field.id}
|
||||
id={"join-field-#{field.id}"}
|
||||
checked={checkbox_checked?(@form.params[field.id])}
|
||||
required={field.required}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<% else %>
|
||||
<input
|
||||
type={field.input_type}
|
||||
name={field.id}
|
||||
id={"join-field-#{field.id}"}
|
||||
value={@form.params[field.id]}
|
||||
required={field.required}
|
||||
class="input input-bordered w-full"
|
||||
/>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
@ -216,21 +229,27 @@ defmodule MvWeb.JoinLive do
|
|||
|
||||
defp build_join_fields_with_labels(allowlist) do
|
||||
member_field_strings = Mv.Constants.member_fields() |> Enum.map(&Atom.to_string/1)
|
||||
custom_field_name_by_id = custom_field_name_map(allowlist, member_field_strings)
|
||||
custom_field_by_id = custom_field_map(allowlist, member_field_strings)
|
||||
|
||||
Enum.map(allowlist, fn %{id: id, required: required} ->
|
||||
label =
|
||||
if id in member_field_strings do
|
||||
MemberFields.label(String.to_existing_atom(id))
|
||||
else
|
||||
Map.get(custom_field_name_by_id, id, gettext("Field"))
|
||||
end
|
||||
|
||||
%{id: id, label: label, required: required}
|
||||
build_join_field(id, required, member_field_strings, custom_field_by_id)
|
||||
end)
|
||||
end
|
||||
|
||||
defp custom_field_name_map(allowlist, member_field_strings) do
|
||||
defp build_join_field(id, required, member_field_strings, custom_field_by_id) do
|
||||
if id in member_field_strings do
|
||||
label = MemberFields.label(String.to_existing_atom(id))
|
||||
%{id: id, label: label, required: required, input_type: member_field_input_type(id)}
|
||||
else
|
||||
custom_field = Map.get(custom_field_by_id, id)
|
||||
label = if custom_field, do: custom_field.name, else: gettext("Field")
|
||||
input_type = custom_field_input_type(custom_field && custom_field.value_type)
|
||||
|
||||
%{id: id, label: label, required: required, input_type: input_type}
|
||||
end
|
||||
end
|
||||
|
||||
defp custom_field_map(allowlist, member_field_strings) do
|
||||
custom_field_ids =
|
||||
allowlist
|
||||
|> Enum.map(& &1.id)
|
||||
|
|
@ -242,7 +261,7 @@ defmodule MvWeb.JoinLive do
|
|||
|
||||
ids ->
|
||||
Mv.Membership.CustomField
|
||||
|> Ash.Query.select([:id, :name])
|
||||
|> Ash.Query.select([:id, :name, :value_type])
|
||||
|> Ash.read(domain: Mv.Membership, authorize?: false)
|
||||
|> case do
|
||||
{:ok, fields} ->
|
||||
|
|
@ -250,7 +269,7 @@ defmodule MvWeb.JoinLive do
|
|||
|
||||
fields
|
||||
|> Enum.filter(&MapSet.member?(allowed_ids, &1.id))
|
||||
|> Map.new(&{&1.id, &1.name})
|
||||
|> Map.new(&{&1.id, &1})
|
||||
|
||||
{:error, _} ->
|
||||
%{}
|
||||
|
|
@ -265,8 +284,45 @@ defmodule MvWeb.JoinLive do
|
|||
|> Map.put(@honeypot_field, "")
|
||||
end
|
||||
|
||||
defp input_type("email"), do: "email"
|
||||
defp input_type(_), do: "text"
|
||||
defp member_field_input_type("email"), do: "email"
|
||||
|
||||
defp member_field_input_type(field_id) when is_binary(field_id) do
|
||||
case member_field_atom(field_id) do
|
||||
nil ->
|
||||
"text"
|
||||
|
||||
field_atom ->
|
||||
Mv.Membership.Member
|
||||
|> Info.attribute(field_atom)
|
||||
|> attribute_to_input_type()
|
||||
end
|
||||
end
|
||||
|
||||
defp member_field_input_type(_), do: "text"
|
||||
|
||||
defp member_field_atom(field_id) when is_binary(field_id) do
|
||||
Mv.Constants.member_fields()
|
||||
|> Enum.find(&(Atom.to_string(&1) == field_id))
|
||||
end
|
||||
|
||||
defp custom_field_input_type(type), do: attribute_to_input_type(%{type: type})
|
||||
|
||||
defp attribute_to_input_type(%{type: type}) when type in [:date, Ash.Type.Date], do: "date"
|
||||
|
||||
defp attribute_to_input_type(%{type: type}) when type in [:integer, Ash.Type.Integer],
|
||||
do: "number"
|
||||
|
||||
defp attribute_to_input_type(%{type: type}) when type in [:boolean, Ash.Type.Boolean],
|
||||
do: "checkbox"
|
||||
|
||||
defp attribute_to_input_type(%{type: type}) when type in [:email, Mv.Membership.Email],
|
||||
do: "email"
|
||||
|
||||
defp attribute_to_input_type(%{type: _}), do: "text"
|
||||
defp attribute_to_input_type(nil), do: "text"
|
||||
|
||||
defp checkbox_checked?(value) when value in [true, "true", "on", "1"], do: true
|
||||
defp checkbox_checked?(_), do: false
|
||||
|
||||
defp build_submit_attrs(params, join_fields) do
|
||||
allowlist_ids = MapSet.new(Enum.map(join_fields, & &1.id))
|
||||
|
|
|
|||
|
|
@ -192,7 +192,12 @@ defmodule MvWeb.JoinLiveTest do
|
|||
{:ok, view, _html} = live(conn, "/join")
|
||||
|
||||
assert has_element?(view, "#join-form")
|
||||
assert has_element?(view, "input#join-field-#{boolean_field.id}[name='#{boolean_field.id}']")
|
||||
|
||||
assert has_element?(
|
||||
view,
|
||||
"input#join-field-#{boolean_field.id}[name='#{boolean_field.id}']"
|
||||
)
|
||||
|
||||
assert has_element?(view, "input#join-field-#{boolean_field.id}[type='checkbox']")
|
||||
refute has_element?(view, "input#join-field-#{boolean_field.id}[type='text']")
|
||||
end
|
||||
|
|
@ -203,13 +208,19 @@ defmodule MvWeb.JoinLiveTest do
|
|||
{:ok, settings} = Membership.get_settings()
|
||||
|
||||
{:ok, integer_field} =
|
||||
Membership.create_custom_field(%{name: "Lucky number", value_type: :integer}, actor: system_actor)
|
||||
Membership.create_custom_field(%{name: "Lucky number", value_type: :integer},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, date_field} =
|
||||
Membership.create_custom_field(%{name: "Birth date", value_type: :date}, actor: system_actor)
|
||||
Membership.create_custom_field(%{name: "Birth date", value_type: :date},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, email_field} =
|
||||
Membership.create_custom_field(%{name: "Secondary email", value_type: :email}, actor: system_actor)
|
||||
Membership.create_custom_field(%{name: "Secondary email", value_type: :email},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, _} =
|
||||
Membership.update_settings(settings, %{
|
||||
|
|
@ -229,6 +240,23 @@ defmodule MvWeb.JoinLiveTest do
|
|||
assert has_element?(view, "input#join-field-#{date_field.id}[type='date']")
|
||||
assert has_element?(view, "input#join-field-#{email_field.id}[type='email']")
|
||||
end
|
||||
|
||||
@tag role: :unauthenticated
|
||||
test "renders standard date member fields with date input type", %{conn: conn} do
|
||||
{:ok, settings} = Membership.get_settings()
|
||||
|
||||
{:ok, _} =
|
||||
Membership.update_settings(settings, %{
|
||||
join_form_enabled: true,
|
||||
join_form_field_ids: ["email", "join_date"],
|
||||
join_form_field_required: %{"email" => true, "join_date" => false}
|
||||
})
|
||||
|
||||
{:ok, view, _html} = live(conn, "/join")
|
||||
|
||||
assert has_element?(view, "input#join-field-join_date[type='date']")
|
||||
refute has_element?(view, "input#join-field-join_date[type='text']")
|
||||
end
|
||||
end
|
||||
|
||||
describe "submit join form with typed custom fields" do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue