diff --git a/.drone.yml b/.drone.yml index 483a08a..0615c71 100644 --- a/.drone.yml +++ b/.drone.yml @@ -166,7 +166,7 @@ environment: steps: - name: renovate - image: renovate/renovate:41.173 + image: renovate/renovate:42.33 environment: RENOVATE_CONFIG_FILE: "renovate_backend_config.js" RENOVATE_TOKEN: diff --git a/Justfile b/Justfile index 25fb35c..b835cf4 100644 --- a/Justfile +++ b/Justfile @@ -1,4 +1,7 @@ set dotenv-load := true +set export := true + +MIX_QUIET := "1" run: install-dependencies start-database migrate-database seed-database mix phx.server @@ -90,7 +93,7 @@ clean: remove-gettext-conflicts: #!/usr/bin/env bash set -euo pipefail - find priv/gettext -type f -exec sed -i '/^<<<<<<>>>>>>/d; /^%%%%%%%/d; /^++++++/d; s/^+//' {} \; + find priv/gettext -type f -exec sed -i '/^<<<<<<>>>>>>/d; /^%%%%%%%/d; /^++++++/d; s/^+//; s/^-//' {} \; # Production environment commands # ================================ diff --git a/lib/membership/member.ex b/lib/membership/member.ex index 8d271d7..b788dc9 100644 --- a/lib/membership/member.ex +++ b/lib/membership/member.ex @@ -401,6 +401,70 @@ defmodule Mv.Membership.Member do identity :unique_email, [:email] end + @doc """ + Checks if a member field should be shown in the overview. + + Reads the visibility configuration from Settings resource. If a field is not + configured in settings, it defaults to `true` (visible). + + ## Parameters + - `field` - Atom representing the member field name (e.g., `:email`, `:street`) + + ## Returns + - `true` if the field should be shown in overview (default) + - `false` if the field is configured as hidden in settings + + ## Examples + + iex> Member.show_in_overview?(:email) + true + + iex> Member.show_in_overview?(:street) + true # or false if configured in settings + + """ + @spec show_in_overview?(atom()) :: boolean() + def show_in_overview?(field) when is_atom(field) do + case Mv.Membership.get_settings() do + {:ok, settings} -> + visibility_config = settings.member_field_visibility || %{} + # Normalize map keys to atoms (JSONB may return string keys) + normalized_config = normalize_visibility_config(visibility_config) + + # Get value from normalized config, default to true + Map.get(normalized_config, field, true) + + {:error, _} -> + # If settings can't be loaded, default to visible + true + end + end + + def show_in_overview?(_), do: true + + # Normalizes visibility config map keys from strings to atoms. + # JSONB in PostgreSQL converts atom keys to string keys when storing. + defp normalize_visibility_config(config) when is_map(config) do + Enum.reduce(config, %{}, fn + {key, value}, acc when is_atom(key) -> + Map.put(acc, key, value) + + {key, value}, acc when is_binary(key) -> + try do + atom_key = String.to_existing_atom(key) + Map.put(acc, atom_key, value) + rescue + ArgumentError -> + acc + end + + _, acc -> + acc + end) + end + + defp normalize_visibility_config(_), do: %{} + @doc """ Performs fuzzy search on members using PostgreSQL trigram similarity. diff --git a/lib/mv/constants.ex b/lib/mv/constants.ex index 334bcc1..7bfb07b 100644 --- a/lib/mv/constants.ex +++ b/lib/mv/constants.ex @@ -18,5 +18,17 @@ defmodule Mv.Constants do :postal_code ] + @custom_field_prefix "custom_field_" + def member_fields, do: @member_fields + + @doc """ + Returns the prefix used for custom field keys in field visibility maps. + + ## Examples + + iex> Mv.Constants.custom_field_prefix() + "custom_field_" + """ + def custom_field_prefix, do: @custom_field_prefix end diff --git a/lib/mv_web/components/core_components.ex b/lib/mv_web/components/core_components.ex index 08133b5..be64655 100644 --- a/lib/mv_web/components/core_components.ex +++ b/lib/mv_web/components/core_components.ex @@ -119,6 +119,123 @@ defmodule MvWeb.CoreComponents do end end + @doc """ + Renders a dropdown menu. + + ## Examples + + <.dropdown_menu items={@items} open={@open} phx_target={@myself} /> + """ + attr :id, :string, default: "dropdown-menu" + attr :items, :list, required: true, doc: "List of %{label: string, value: any} maps" + attr :button_label, :string, default: "Dropdown" + attr :icon, :string, default: nil + attr :checkboxes, :boolean, default: false + attr :selected, :map, default: %{} + attr :open, :boolean, default: false, doc: "Whether the dropdown is open" + attr :show_select_buttons, :boolean, default: false, doc: "Show select all/none buttons" + attr :phx_target, :any, required: true, doc: "The LiveView/LiveComponent target for events" + + def dropdown_menu(assigns) do + ~H""" +
- {gettext("Auto-generated identifier (immutable)")} -
- - - <:item title="Name">{@custom_field.name} - - <:item title="Description">{@custom_field.description} - -