defmodule Mv.Membership.CustomFieldValueFormatter do @moduledoc """ Neutral formatter for custom field values (e.g. CSV export). Same logic as the member overview Formatter but without Gettext or web helpers, so it can be used from the Membership context. For boolean: "Yes"/"No"; for date: European format (dd.mm.yyyy). """ @doc """ Formats a custom field value for plain text (e.g. CSV). Handles nil, Ash.Union, JSONB map, and direct values. Uses custom_field.value_type for typing. Boolean -> "Yes"/"No", Date -> dd.mm.yyyy. """ def format_custom_field_value(nil, _custom_field), do: "" def format_custom_field_value(%Ash.Union{value: value, type: type}, custom_field) do format_value_by_type(value, type, custom_field) end def format_custom_field_value(value, custom_field) when is_map(value) do type = Map.get(value, "type") || Map.get(value, "_union_type") val = Map.get(value, "value") || Map.get(value, "_union_value") format_value_by_type(val, type, custom_field) end def format_custom_field_value(value, custom_field) do format_value_by_type(value, custom_field.value_type, custom_field) end defp format_value_by_type(value, :string, _), do: to_string(value) defp format_value_by_type(value, :integer, _), do: to_string(value) defp format_value_by_type(value, type, _) when type in [:string, :email] and is_binary(value) do if String.trim(value) == "", do: "", else: value end defp format_value_by_type(value, :email, _), do: to_string(value) defp format_value_by_type(value, :boolean, _) when value == true, do: "Yes" defp format_value_by_type(value, :boolean, _) when value == false, do: "No" defp format_value_by_type(value, :boolean, _), do: to_string(value) defp format_value_by_type(%Date{} = date, :date, _) do Calendar.strftime(date, "%d.%m.%Y") end defp format_value_by_type(value, :date, _) when is_binary(value) do case Date.from_iso8601(value) do {:ok, date} -> Calendar.strftime(date, "%d.%m.%Y") _ -> value end end defp format_value_by_type(value, _type, _), do: to_string(value) end