fix(member): order member list chronologically by custom :date fields
This commit is contained in:
parent
1aaa0ece5d
commit
6d4629ef5b
2 changed files with 66 additions and 16 deletions
|
|
@ -32,6 +32,7 @@ defmodule MvWeb.MemberLive.Index do
|
|||
import MvWeb.LiveHelpers, only: [current_actor: 1]
|
||||
|
||||
alias Mv.Membership
|
||||
alias Mv.Membership.CustomFieldSort
|
||||
alias Mv.Membership.Member, as: MemberResource
|
||||
alias Mv.MembershipFees
|
||||
alias Mv.MembershipFees.MembershipFeeType
|
||||
|
|
@ -1414,8 +1415,7 @@ defmodule MvWeb.MemberLive.Index do
|
|||
false
|
||||
|
||||
cfv ->
|
||||
extracted = extract_sort_value(cfv.value, custom_field.value_type)
|
||||
not empty_value?(extracted, custom_field.value_type)
|
||||
not empty_value?(cfv.value, custom_field.value_type)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1423,29 +1423,22 @@ defmodule MvWeb.MemberLive.Index do
|
|||
sorted =
|
||||
Enum.sort_by(members_with_values, fn member ->
|
||||
cfv = get_custom_field_value(member, custom_field)
|
||||
extracted = extract_sort_value(cfv.value, custom_field.value_type)
|
||||
normalize_sort_value(extracted, order)
|
||||
CustomFieldSort.sort_key(cfv.value, custom_field.value_type)
|
||||
end)
|
||||
|
||||
if order == :desc, do: Enum.reverse(sorted), else: sorted
|
||||
end
|
||||
|
||||
defp extract_sort_value(%Ash.Union{value: value, type: type}, _expected_type),
|
||||
do: extract_sort_value(value, type)
|
||||
defp empty_value?(%Ash.Union{value: value, type: type}, _expected_type),
|
||||
do: empty_value?(value, type)
|
||||
|
||||
defp extract_sort_value(value, :string) when is_binary(value), do: value
|
||||
defp extract_sort_value(value, :integer) when is_integer(value), do: value
|
||||
defp extract_sort_value(value, :boolean) when is_boolean(value), do: value
|
||||
defp extract_sort_value(%Date{} = date, :date), do: date
|
||||
defp extract_sort_value(value, :email) when is_binary(value), do: value
|
||||
defp extract_sort_value(value, _type), do: to_string(value)
|
||||
defp empty_value?(nil, _type), do: true
|
||||
|
||||
defp empty_value?(value, type) when type in [:string, :email] and is_binary(value),
|
||||
do: String.trim(value) == ""
|
||||
|
||||
defp empty_value?(value, :string) when is_binary(value), do: String.trim(value) == ""
|
||||
defp empty_value?(value, :email) when is_binary(value), do: String.trim(value) == ""
|
||||
defp empty_value?(_value, _type), do: false
|
||||
|
||||
defp normalize_sort_value(value, _order), do: value
|
||||
|
||||
defp maybe_update_sort(socket, %{"sort_field" => sf, "sort_order" => so}) do
|
||||
field = determine_field(socket.assigns.sort_field, sf)
|
||||
order = determine_order(socket.assigns.sort_order, so)
|
||||
|
|
|
|||
|
|
@ -231,6 +231,63 @@ defmodule MvWeb.MemberLive.IndexCustomFieldsSortingTest do
|
|||
assert has_element?(view, "[data-testid='custom_field_#{field.id}'][aria-label='ascending']")
|
||||
end
|
||||
|
||||
test "sorts members chronologically by a :date custom field (ascending)", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
# Dates chosen to expose the day-first term-ordering trap: term order of the
|
||||
# %Date{} structs compares day, then month, then year, which would place
|
||||
# 02.07.1986 (day 02) before 29.01.1981 (day 29). Chronologically 1981 < 1982 < 1986.
|
||||
members_and_dates = [
|
||||
{"EightySix", ~D[1986-07-02]},
|
||||
{"EightyOne", ~D[1981-01-29]},
|
||||
{"EightyTwo", ~D[1982-03-01]}
|
||||
]
|
||||
|
||||
{:ok, field} =
|
||||
CustomField
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
name: "birth_date",
|
||||
value_type: :date,
|
||||
show_in_overview: true
|
||||
})
|
||||
|> Ash.create(actor: system_actor)
|
||||
|
||||
for {first_name, date} <- members_and_dates do
|
||||
{:ok, member} =
|
||||
Mv.Membership.create_member(
|
||||
%{
|
||||
first_name: first_name,
|
||||
last_name: "Test",
|
||||
email: "#{String.downcase(first_name)}@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, _cfv} =
|
||||
CustomFieldValue
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
member_id: member.id,
|
||||
custom_field_id: field.id,
|
||||
value: %{"_union_type" => "date", "_union_value" => Date.to_iso8601(date)}
|
||||
})
|
||||
|> Ash.create(actor: system_actor)
|
||||
end
|
||||
|
||||
conn = conn_with_oidc_user(conn)
|
||||
|
||||
{:ok, view, _html} =
|
||||
live(conn, "/members?query=&sort_field=custom_field_#{field.id}&sort_order=asc")
|
||||
|
||||
html = render(view)
|
||||
|
||||
{one_idx, _} = :binary.match(html, "EightyOne")
|
||||
{two_idx, _} = :binary.match(html, "EightyTwo")
|
||||
{six_idx, _} = :binary.match(html, "EightySix")
|
||||
|
||||
assert one_idx < two_idx, "29.01.1981 must come before 01.03.1982 in ascending order"
|
||||
assert two_idx < six_idx, "01.03.1982 must come before 02.07.1986 in ascending order"
|
||||
end
|
||||
|
||||
test "NULL values and empty strings are always sorted last (ASC)", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue