fix: sorting and filter for export
This commit is contained in:
parent
e7d63b9b0a
commit
9b9e7ec995
10 changed files with 1013 additions and 714 deletions
|
|
@ -41,24 +41,29 @@ defmodule MvWeb.Components.FieldVisibilityDropdownComponent do
|
|||
# RENDER
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Export-only alias; must not appear in dropdown (canonical UI key is membership_fee_status).
|
||||
@payment_status_value "payment_status"
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
all_fields = assigns.all_fields || []
|
||||
custom_fields = assigns.custom_fields || []
|
||||
|
||||
all_items =
|
||||
Enum.map(extract_member_field_keys(all_fields), fn field ->
|
||||
%{
|
||||
value: field_to_string(field),
|
||||
label: format_field_label(field)
|
||||
}
|
||||
end) ++
|
||||
Enum.map(extract_custom_field_keys(all_fields), fn field ->
|
||||
%{
|
||||
value: field,
|
||||
label: format_custom_field_label(field, custom_fields)
|
||||
}
|
||||
end)
|
||||
(Enum.map(extract_member_field_keys(all_fields), fn field ->
|
||||
%{
|
||||
value: field_to_string(field),
|
||||
label: format_field_label(field)
|
||||
}
|
||||
end) ++
|
||||
Enum.map(extract_custom_field_keys(all_fields), fn field ->
|
||||
%{
|
||||
value: field,
|
||||
label: format_custom_field_label(field, custom_fields)
|
||||
}
|
||||
end))
|
||||
|> Enum.reject(fn item -> item.value == @payment_status_value end)
|
||||
|> Enum.uniq_by(fn item -> item.value end)
|
||||
|
||||
assigns = assign(assigns, :all_items, all_items)
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -293,6 +293,7 @@
|
|||
</:col>
|
||||
<:col
|
||||
:let={member}
|
||||
:if={:membership_fee_status in @member_fields_visible}
|
||||
label={gettext("Membership Fee Status")}
|
||||
>
|
||||
<%= if badge = MvWeb.MemberLive.Index.MembershipFeeStatus.format_cycle_status_badge(
|
||||
|
|
|
|||
|
|
@ -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