From dd68d2efbc71e17c169db1bc85ddbe0fa2b06431 Mon Sep 17 00:00:00 2001 From: carla Date: Tue, 20 Jan 2026 14:23:27 +0100 Subject: [PATCH] refactor --- lib/mv/membership/import/header_mapper.ex | 39 ++++ lib/mv/membership/import/member_csv.ex | 15 +- lib/mv_web/live/global_settings_live.ex | 186 +++++++++++------- .../mv_web/live/global_settings_live_test.exs | 37 ++-- 4 files changed, 182 insertions(+), 95 deletions(-) diff --git a/lib/mv/membership/import/header_mapper.ex b/lib/mv/membership/import/header_mapper.ex index 4e4a77d..e224998 100644 --- a/lib/mv/membership/import/header_mapper.ex +++ b/lib/mv/membership/import/header_mapper.ex @@ -124,6 +124,45 @@ defmodule Mv.Membership.Import.HeaderMapper do end) end + @doc """ + Returns a MapSet of normalized member field names. + + This is the single source of truth for known member fields. + Used to distinguish between member fields and custom fields. + + ## Returns + + - `MapSet.t(String.t())` - Set of normalized member field names + + ## Examples + + iex> HeaderMapper.known_member_fields() + #MapSet<["email", "firstname", "lastname", "street", "postalcode", "city"]> + """ + @spec known_member_fields() :: MapSet.t(String.t()) + def known_member_fields do + cached = Process.get({__MODULE__, :known_member_fields}) + + if cached do + cached + else + fields = + @member_field_variants_raw + |> Map.keys() + |> Enum.map(fn canonical -> + # Normalize the canonical field name (e.g., :first_name -> "firstname") + canonical + |> Atom.to_string() + |> String.replace("_", "") + |> String.downcase() + end) + |> MapSet.new() + + Process.put({__MODULE__, :known_member_fields}, fields) + fields + end + end + @doc """ Normalizes a CSV header string for comparison. diff --git a/lib/mv/membership/import/member_csv.ex b/lib/mv/membership/import/member_csv.ex index 8e2783f..4222fc3 100644 --- a/lib/mv/membership/import/member_csv.ex +++ b/lib/mv/membership/import/member_csv.ex @@ -84,17 +84,6 @@ defmodule Mv.Membership.Import.MemberCSV do @default_chunk_size 200 @default_max_rows 1000 - # Known member field names (normalized) for efficient lookup - # These match the canonical fields in HeaderMapper - @known_member_fields [ - "email", - "firstname", - "lastname", - "street", - "postalcode", - "city" - ] - @doc """ Prepares CSV content for import by parsing, mapping headers, and validating limits. @@ -205,9 +194,9 @@ defmodule Mv.Membership.Import.MemberCSV do end # Checks if a normalized header matches a member field - # Uses direct lookup for better performance (avoids calling build_maps/2) + # Uses HeaderMapper.known_member_fields/0 as single source of truth defp member_field?(normalized) when is_binary(normalized) do - normalized in @known_member_fields + MapSet.member?(HeaderMapper.known_member_fields(), normalized) end defp member_field?(_), do: false diff --git a/lib/mv_web/live/global_settings_live.ex b/lib/mv_web/live/global_settings_live.ex index f8b6532..a11d84e 100644 --- a/lib/mv_web/live/global_settings_live.ex +++ b/lib/mv_web/live/global_settings_live.ex @@ -52,7 +52,8 @@ defmodule MvWeb.GlobalSettingsLive do on_mount {MvWeb.LiveHelpers, :ensure_user_role_loaded} # CSV Import configuration constants - @max_file_size_bytes 10_485_760 # 10 MB + # 10 MB + @max_file_size_bytes 10_485_760 @max_errors 50 @impl true @@ -182,6 +183,7 @@ defmodule MvWeb.GlobalSettingsLive do multipart={true} phx-change="validate_csv_upload" phx-submit="start_import" + data-testid="csv-upload-form" >