fix: sorting and filter for export
This commit is contained in:
parent
e7d63b9b0a
commit
9b9e7ec995
10 changed files with 1013 additions and 714 deletions
|
|
@ -18,10 +18,25 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
|||
1. User-specific selection (from URL/Session/Cookie)
|
||||
2. Global settings (from database)
|
||||
3. Default (all fields visible)
|
||||
|
||||
## Pseudo Member Fields
|
||||
|
||||
Overview-only fields that are not in `Mv.Constants.member_fields()` (e.g. computed/UI-only).
|
||||
They appear in the field dropdown and in `member_fields_visible` but are not domain attributes.
|
||||
"""
|
||||
|
||||
alias Mv.Membership.Helpers.VisibilityConfig
|
||||
|
||||
# Single UI key for "Membership Fee Status"; only this appears in the dropdown.
|
||||
@pseudo_member_fields [:membership_fee_status]
|
||||
|
||||
# Export/API may accept this as alias; must not appear in the UI options list.
|
||||
@export_only_alias :payment_status
|
||||
|
||||
defp overview_member_fields do
|
||||
Mv.Constants.member_fields() ++ @pseudo_member_fields
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets all available fields for selection.
|
||||
|
||||
|
|
@ -39,7 +54,10 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
|||
"""
|
||||
@spec get_all_available_fields([struct()]) :: [atom() | String.t()]
|
||||
def get_all_available_fields(custom_fields) do
|
||||
member_fields = Mv.Constants.member_fields()
|
||||
member_fields =
|
||||
overview_member_fields()
|
||||
|> Enum.reject(fn field -> field == @export_only_alias end)
|
||||
|
||||
custom_field_names = Enum.map(custom_fields, &"custom_field_#{&1.id}")
|
||||
|
||||
member_fields ++ custom_field_names
|
||||
|
|
@ -115,6 +133,7 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
|||
field_selection
|
||||
|> Enum.filter(fn {_field, visible} -> visible end)
|
||||
|> Enum.map(fn {field_string, _visible} -> to_field_identifier(field_string) end)
|
||||
|> Enum.uniq()
|
||||
end
|
||||
|
||||
def get_visible_fields(_), do: []
|
||||
|
|
@ -132,7 +151,7 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
|||
"""
|
||||
@spec get_visible_member_fields(%{String.t() => boolean()}) :: [atom()]
|
||||
def get_visible_member_fields(field_selection) when is_map(field_selection) do
|
||||
member_fields = Mv.Constants.member_fields()
|
||||
member_fields = overview_member_fields()
|
||||
|
||||
field_selection
|
||||
|> Enum.filter(fn {field_string, visible} ->
|
||||
|
|
@ -140,10 +159,61 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
|||
visible && field_atom in member_fields
|
||||
end)
|
||||
|> Enum.map(fn {field_string, _visible} -> to_field_identifier(field_string) end)
|
||||
|> Enum.uniq()
|
||||
end
|
||||
|
||||
def get_visible_member_fields(_), do: []
|
||||
|
||||
@doc """
|
||||
Returns the list of computed (UI-only) member field atoms.
|
||||
|
||||
These fields are not in the database; they must not be used for Ash query
|
||||
select/sort. Use this to filter sort options and validate sort_field.
|
||||
"""
|
||||
@spec computed_member_fields() :: [atom()]
|
||||
def computed_member_fields, do: @pseudo_member_fields
|
||||
|
||||
@doc """
|
||||
Visible member fields that are real DB attributes (from `Mv.Constants.member_fields()`).
|
||||
|
||||
Use for query select/sort. Not for rendering column visibility (use
|
||||
`get_visible_member_fields/1` for that).
|
||||
"""
|
||||
@spec get_visible_member_fields_db(%{String.t() => boolean()}) :: [atom()]
|
||||
def get_visible_member_fields_db(field_selection) when is_map(field_selection) do
|
||||
db_fields = MapSet.new(Mv.Constants.member_fields())
|
||||
|
||||
field_selection
|
||||
|> Enum.filter(fn {field_string, visible} ->
|
||||
field_atom = to_field_identifier(field_string)
|
||||
visible && field_atom in db_fields
|
||||
end)
|
||||
|> Enum.map(fn {field_string, _visible} -> to_field_identifier(field_string) end)
|
||||
|> Enum.uniq()
|
||||
end
|
||||
|
||||
def get_visible_member_fields_db(_), do: []
|
||||
|
||||
@doc """
|
||||
Visible member fields that are computed/UI-only (e.g. membership_fee_status).
|
||||
|
||||
Use for rendering; do not use for query select or sort.
|
||||
"""
|
||||
@spec get_visible_member_fields_computed(%{String.t() => boolean()}) :: [atom()]
|
||||
def get_visible_member_fields_computed(field_selection) when is_map(field_selection) do
|
||||
computed_set = MapSet.new(@pseudo_member_fields)
|
||||
|
||||
field_selection
|
||||
|> Enum.filter(fn {field_string, visible} ->
|
||||
field_atom = to_field_identifier(field_string)
|
||||
visible && field_atom in computed_set
|
||||
end)
|
||||
|> Enum.map(fn {field_string, _visible} -> to_field_identifier(field_string) end)
|
||||
|> Enum.uniq()
|
||||
end
|
||||
|
||||
def get_visible_member_fields_computed(_), do: []
|
||||
|
||||
@doc """
|
||||
Gets visible custom fields from field selection.
|
||||
|
||||
|
|
@ -176,19 +246,23 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
|||
Map.merge(member_visibility, custom_field_visibility)
|
||||
end
|
||||
|
||||
# Gets member field visibility from settings
|
||||
# Gets member field visibility from settings (domain fields from settings, pseudo fields default true)
|
||||
defp get_member_field_visibility_from_settings(settings) do
|
||||
visibility_config =
|
||||
VisibilityConfig.normalize(Map.get(settings, :member_field_visibility, %{}))
|
||||
|
||||
member_fields = Mv.Constants.member_fields()
|
||||
domain_fields = Mv.Constants.member_fields()
|
||||
|
||||
Enum.reduce(member_fields, %{}, fn field, acc ->
|
||||
field_string = Atom.to_string(field)
|
||||
# exit_date defaults to false (hidden), all other fields default to true
|
||||
default_visibility = if field == :exit_date, do: false, else: true
|
||||
show_in_overview = Map.get(visibility_config, field, default_visibility)
|
||||
Map.put(acc, field_string, show_in_overview)
|
||||
domain_map =
|
||||
Enum.reduce(domain_fields, %{}, fn field, acc ->
|
||||
field_string = Atom.to_string(field)
|
||||
default_visibility = if field == :exit_date, do: false, else: true
|
||||
show_in_overview = Map.get(visibility_config, field, default_visibility)
|
||||
Map.put(acc, field_string, show_in_overview)
|
||||
end)
|
||||
|
||||
Enum.reduce(@pseudo_member_fields, domain_map, fn field, acc ->
|
||||
Map.put(acc, Atom.to_string(field), true)
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
@ -203,16 +277,20 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
|||
end)
|
||||
end
|
||||
|
||||
# Converts field string to atom (for member fields) or keeps as string (for custom fields)
|
||||
# Converts field string to atom (for member fields) or keeps as string (for custom fields).
|
||||
# Maps export-only alias to canonical UI key so only one option controls the column.
|
||||
defp to_field_identifier(field_string) when is_binary(field_string) do
|
||||
if String.starts_with?(field_string, Mv.Constants.custom_field_prefix()) do
|
||||
field_string
|
||||
else
|
||||
try do
|
||||
String.to_existing_atom(field_string)
|
||||
rescue
|
||||
ArgumentError -> field_string
|
||||
end
|
||||
atom =
|
||||
try do
|
||||
String.to_existing_atom(field_string)
|
||||
rescue
|
||||
ArgumentError -> field_string
|
||||
end
|
||||
|
||||
if atom == @export_only_alias, do: :membership_fee_status, else: atom
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue