formatting
This commit is contained in:
parent
e7c4a4f62f
commit
82bd573276
6 changed files with 148 additions and 68 deletions
|
|
@ -373,6 +373,7 @@ defmodule MvWeb.CoreComponents do
|
|||
>
|
||||
{if dyn_col[:render] do
|
||||
rendered = dyn_col[:render].(@row_item.(row))
|
||||
|
||||
if rendered == "" do
|
||||
""
|
||||
else
|
||||
|
|
|
|||
|
|
@ -205,7 +205,9 @@ defmodule MvWeb.MemberLive.Index do
|
|||
custom_field: custom_field,
|
||||
render: fn member ->
|
||||
case get_custom_field_value(member, custom_field) do
|
||||
nil -> ""
|
||||
nil ->
|
||||
""
|
||||
|
||||
cfv ->
|
||||
formatted = Formatter.format_custom_field_value(cfv.value, custom_field)
|
||||
if formatted == "", do: "", else: formatted
|
||||
|
|
@ -335,7 +337,13 @@ defmodule MvWeb.MemberLive.Index do
|
|||
|
||||
# Apply sorting based on current socket state
|
||||
# For custom fields, we sort after loading
|
||||
{query, sort_after_load} = maybe_sort(query, socket.assigns.sort_field, socket.assigns.sort_order, socket.assigns.custom_fields_visible)
|
||||
{query, sort_after_load} =
|
||||
maybe_sort(
|
||||
query,
|
||||
socket.assigns.sort_field,
|
||||
socket.assigns.sort_order,
|
||||
socket.assigns.custom_fields_visible
|
||||
)
|
||||
|
||||
# Note: Using Ash.read! - errors will be handled by Phoenix LiveView
|
||||
# This is appropriate for data loading in LiveViews
|
||||
|
|
@ -346,24 +354,21 @@ defmodule MvWeb.MemberLive.Index do
|
|||
# For large datasets (>1000 members), this could be optimized by filtering
|
||||
# at the database level, but requires more complex Ash queries.
|
||||
custom_field_ids = MapSet.new(Enum.map(socket.assigns.custom_fields_visible, & &1.id))
|
||||
members = Enum.map(members, fn member ->
|
||||
# Only filter if custom_field_values is loaded (is a list, not Ash.NotLoaded)
|
||||
if is_list(member.custom_field_values) do
|
||||
filtered_values = Enum.filter(member.custom_field_values, fn cfv ->
|
||||
cfv.custom_field_id in custom_field_ids
|
||||
end)
|
||||
%{member | custom_field_values: filtered_values}
|
||||
else
|
||||
member
|
||||
end
|
||||
end)
|
||||
|
||||
members = filter_member_custom_field_values(members, custom_field_ids)
|
||||
|
||||
# Sort in memory if needed (for custom fields)
|
||||
members = if sort_after_load do
|
||||
sort_members_in_memory(members, socket.assigns.sort_field, socket.assigns.sort_order, socket.assigns.custom_fields_visible)
|
||||
else
|
||||
members
|
||||
end
|
||||
members =
|
||||
if sort_after_load do
|
||||
sort_members_in_memory(
|
||||
members,
|
||||
socket.assigns.sort_field,
|
||||
socket.assigns.sort_order,
|
||||
socket.assigns.custom_fields_visible
|
||||
)
|
||||
else
|
||||
members
|
||||
end
|
||||
|
||||
assign(socket, :members, members)
|
||||
end
|
||||
|
|
@ -381,6 +386,28 @@ defmodule MvWeb.MemberLive.Index do
|
|||
|> Ash.Query.load(custom_field_values: [custom_field: [:id, :name, :value_type]])
|
||||
end
|
||||
|
||||
# Filters custom field values to only visible ones for all members
|
||||
defp filter_member_custom_field_values(members, custom_field_ids) do
|
||||
Enum.map(members, fn member ->
|
||||
filter_single_member_custom_field_values(member, custom_field_ids)
|
||||
end)
|
||||
end
|
||||
|
||||
# Filters custom field values for a single member
|
||||
defp filter_single_member_custom_field_values(member, _custom_field_ids)
|
||||
when not is_list(member.custom_field_values) do
|
||||
member
|
||||
end
|
||||
|
||||
defp filter_single_member_custom_field_values(member, custom_field_ids) do
|
||||
filtered_values =
|
||||
Enum.filter(member.custom_field_values, fn cfv ->
|
||||
cfv.custom_field_id in custom_field_ids
|
||||
end)
|
||||
|
||||
%{member | custom_field_values: filtered_values}
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Helper Functions
|
||||
# -------------------------------------------------------------
|
||||
|
|
@ -508,45 +535,76 @@ defmodule MvWeb.MemberLive.Index do
|
|||
members
|
||||
|
||||
id_str ->
|
||||
# Find the custom field by matching the ID string
|
||||
custom_field =
|
||||
Enum.find(custom_fields, fn cf ->
|
||||
to_string(cf.id) == id_str
|
||||
end)
|
||||
sort_members_by_custom_field(members, id_str, order, custom_fields)
|
||||
end
|
||||
end
|
||||
|
||||
case custom_field do
|
||||
nil ->
|
||||
members
|
||||
# Sorts members by a specific custom field ID
|
||||
defp sort_members_by_custom_field(members, id_str, order, custom_fields) do
|
||||
custom_field = find_custom_field_by_id(custom_fields, id_str)
|
||||
|
||||
cf ->
|
||||
# Split members into those with values and those without (NULL/empty)
|
||||
{members_with_values, members_without_values} =
|
||||
Enum.split_with(members, fn member ->
|
||||
case get_custom_field_value(member, cf) do
|
||||
nil -> false
|
||||
cfv ->
|
||||
extracted = extract_sort_value(cfv.value, cf.value_type)
|
||||
not is_empty_value(extracted, cf.value_type)
|
||||
end
|
||||
end)
|
||||
case custom_field do
|
||||
nil ->
|
||||
members
|
||||
|
||||
# Sort members with values
|
||||
sorted_with_values = Enum.sort_by(members_with_values, fn member ->
|
||||
cfv = get_custom_field_value(member, cf)
|
||||
extracted = extract_sort_value(cfv.value, cf.value_type)
|
||||
normalize_sort_value(extracted, order)
|
||||
end)
|
||||
cf ->
|
||||
sort_members_with_custom_field(members, cf, order)
|
||||
end
|
||||
end
|
||||
|
||||
# For DESC, reverse only the members with values
|
||||
sorted_with_values = if order == :desc do
|
||||
Enum.reverse(sorted_with_values)
|
||||
else
|
||||
sorted_with_values
|
||||
end
|
||||
# Finds a custom field by matching its ID string
|
||||
defp find_custom_field_by_id(custom_fields, id_str) do
|
||||
Enum.find(custom_fields, fn cf ->
|
||||
to_string(cf.id) == id_str
|
||||
end)
|
||||
end
|
||||
|
||||
# Combine: sorted values first, then NULL/empty values at the end
|
||||
sorted_with_values ++ members_without_values
|
||||
end
|
||||
# Sorts members that have a specific custom field
|
||||
defp sort_members_with_custom_field(members, custom_field, order) do
|
||||
# Split members into those with values and those without (NULL/empty)
|
||||
{members_with_values, members_without_values} =
|
||||
split_members_by_value_presence(members, custom_field)
|
||||
|
||||
# Sort members with values
|
||||
sorted_with_values = sort_members_with_values(members_with_values, custom_field, order)
|
||||
|
||||
# Combine: sorted values first, then NULL/empty values at the end
|
||||
sorted_with_values ++ members_without_values
|
||||
end
|
||||
|
||||
# Splits members into those with values and those without
|
||||
defp split_members_by_value_presence(members, custom_field) do
|
||||
Enum.split_with(members, fn member ->
|
||||
has_non_empty_value?(member, custom_field)
|
||||
end)
|
||||
end
|
||||
|
||||
# Checks if a member has a non-empty value for the custom field
|
||||
defp has_non_empty_value?(member, custom_field) do
|
||||
case get_custom_field_value(member, custom_field) do
|
||||
nil ->
|
||||
false
|
||||
|
||||
cfv ->
|
||||
extracted = extract_sort_value(cfv.value, custom_field.value_type)
|
||||
not empty_value?(extracted, custom_field.value_type)
|
||||
end
|
||||
end
|
||||
|
||||
# Sorts members that have values for the custom field
|
||||
defp sort_members_with_values(members_with_values, custom_field, order) 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)
|
||||
end)
|
||||
|
||||
# For DESC, reverse only the members with values
|
||||
if order == :desc do
|
||||
Enum.reverse(sorted)
|
||||
else
|
||||
sorted
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -569,20 +627,21 @@ defmodule MvWeb.MemberLive.Index do
|
|||
defp extract_sort_value(value, _type), do: to_string(value)
|
||||
|
||||
# Check if a value is considered empty (NULL or empty string)
|
||||
defp is_empty_value(value, :string) when is_binary(value) do
|
||||
defp empty_value?(value, :string) when is_binary(value) do
|
||||
String.trim(value) == ""
|
||||
end
|
||||
defp is_empty_value(value, :email) when is_binary(value) do
|
||||
|
||||
defp empty_value?(value, :email) when is_binary(value) do
|
||||
String.trim(value) == ""
|
||||
end
|
||||
defp is_empty_value(_value, _type), do: false
|
||||
|
||||
defp empty_value?(_value, _type), do: false
|
||||
|
||||
# Normalize sort value for DESC order
|
||||
# For DESC, we sort ascending first, then reverse the list
|
||||
# This function is kept for consistency but doesn't need to invert values
|
||||
defp normalize_sort_value(value, _order), do: value
|
||||
|
||||
|
||||
# Updates sort field and order from URL parameters if present.
|
||||
#
|
||||
# Validates the sort field and order, falling back to defaults if invalid.
|
||||
|
|
@ -678,13 +737,17 @@ defmodule MvWeb.MemberLive.Index do
|
|||
# get_custom_field_value(member, non_existent_field) -> nil
|
||||
def get_custom_field_value(member, custom_field) do
|
||||
case member.custom_field_values do
|
||||
nil -> nil
|
||||
nil ->
|
||||
nil
|
||||
|
||||
values when is_list(values) ->
|
||||
Enum.find(values, fn cfv ->
|
||||
cfv.custom_field_id == custom_field.id or
|
||||
(cfv.custom_field && cfv.custom_field.id == custom_field.id)
|
||||
end)
|
||||
_ -> nil
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue