From 418b42d35a1cb9e75def6ad3d157e6d5ab9c87e3 Mon Sep 17 00:00:00 2001 From: carla Date: Thu, 27 Nov 2025 14:56:13 +0100 Subject: [PATCH 1/7] adds tests --- test/membership/setting_env_test.exs | 61 +++++++++++++++++ test/membership/setting_test.exs | 53 +++++++++++++++ .../mv_web/components/layouts/navbar_test.exs | 18 +++++ .../mv_web/live/global_settings_live_test.exs | 67 +++++++++++++++++++ 4 files changed, 199 insertions(+) create mode 100644 test/membership/setting_env_test.exs create mode 100644 test/membership/setting_test.exs create mode 100644 test/mv_web/live/global_settings_live_test.exs diff --git a/test/membership/setting_env_test.exs b/test/membership/setting_env_test.exs new file mode 100644 index 0000000..262f748 --- /dev/null +++ b/test/membership/setting_env_test.exs @@ -0,0 +1,61 @@ +defmodule Mv.Membership.SettingEnvTest do + use Mv.DataCase, async: false + alias Mv.Membership + + describe "Settings with environment variable" do + test "club_name can be set via ASSOCIATION_NAME environment variable" do + # Set environment variable + System.put_env("ASSOCIATION_NAME", "Test Association from Env") + + try do + # Get settings - should use environment variable if no DB value exists + {:ok, settings} = Membership.get_settings() + + # If settings don't have a club_name in DB, it should use the env var + # This depends on implementation - we'll check that the env var is respected + assert settings.club_name != nil + after + # Clean up + System.delete_env("ASSOCIATION_NAME") + end + end + + test "database value takes precedence over environment variable" do + # Set environment variable + System.put_env("ASSOCIATION_NAME", "Env Value") + + try do + # Set a value in the database + {:ok, settings} = Membership.get_settings() + {:ok, _updated} = Membership.update_settings(settings, %{club_name: "DB Value"}) + + # Get settings again - should use DB value, not env var + {:ok, settings_after} = Membership.get_settings() + assert settings_after.club_name == "DB Value" + after + # Clean up + System.delete_env("ASSOCIATION_NAME") + end + end + + test "uses environment variable when database value is not set" do + # Set environment variable + System.put_env("ASSOCIATION_NAME", "Default from Env") + + try do + # Clear database value (if possible) or check that env var is used + {:ok, settings} = Membership.get_settings() + + # If club_name is nil or empty in DB, should use env var + # This test depends on implementation details + # We're testing that the env var fallback works + club_name = settings.club_name || System.get_env("ASSOCIATION_NAME") + assert club_name != nil + assert club_name != "" + after + # Clean up + System.delete_env("ASSOCIATION_NAME") + end + end + end +end diff --git a/test/membership/setting_test.exs b/test/membership/setting_test.exs new file mode 100644 index 0000000..46cf3b9 --- /dev/null +++ b/test/membership/setting_test.exs @@ -0,0 +1,53 @@ +defmodule Mv.Membership.SettingTest do + use Mv.DataCase, async: false + alias Mv.Membership + + describe "Settings Resource" do + test "can read settings" do + # Settings should be a singleton resource + assert {:ok, _settings} = Membership.get_settings() + end + + test "settings have club_name attribute" do + {:ok, settings} = Membership.get_settings() + assert Map.has_key?(settings, :club_name) + end + + test "can update club_name" do + {:ok, settings} = Membership.get_settings() + + assert {:ok, updated_settings} = + Membership.update_settings(settings, %{club_name: "New Club Name"}) + + assert updated_settings.club_name == "New Club Name" + end + + test "club_name is required" do + {:ok, settings} = Membership.get_settings() + + assert {:error, %Ash.Error.Invalid{errors: errors}} = + Membership.update_settings(settings, %{club_name: nil}) + + assert error_message(errors, :club_name) =~ "must be present" + end + + test "club_name cannot be empty" do + {:ok, settings} = Membership.get_settings() + + assert {:error, %Ash.Error.Invalid{errors: errors}} = + Membership.update_settings(settings, %{club_name: ""}) + + assert error_message(errors, :club_name) =~ "must be present" + end + end + + # Helper function to extract error messages + defp error_message(errors, field) do + errors + |> Enum.find(fn error -> error.field == field end) + |> case do + nil -> "" + error -> List.first(error.message) || "" + end + end +end diff --git a/test/mv_web/components/layouts/navbar_test.exs b/test/mv_web/components/layouts/navbar_test.exs index b6fa556..6a50996 100644 --- a/test/mv_web/components/layouts/navbar_test.exs +++ b/test/mv_web/components/layouts/navbar_test.exs @@ -84,5 +84,23 @@ defmodule MvWeb.Layouts.NavbarTest do # Check for correct logout path assert html =~ ~s(href="/sign-out") end + + test "Settings link navigates to global settings page", %{conn: conn} do + user = create_test_user(%{email: "test@example.com"}) + conn = conn_with_oidc_user(conn, user) + + html = + render_component(&MvWeb.Layouts.Navbar.navbar/1, %{ + current_user: user + }) + + # Check that Settings link exists and points to /settings + assert html =~ "Settings" + assert html =~ ~s(href="/settings") || html =~ ~s(navigate="/settings") + + # Verify the link actually works by navigating to it + {:ok, _view, settings_html} = live(conn, ~p"/settings") + assert settings_html =~ "Vereinsdaten" + end end end diff --git a/test/mv_web/live/global_settings_live_test.exs b/test/mv_web/live/global_settings_live_test.exs new file mode 100644 index 0000000..f06deb1 --- /dev/null +++ b/test/mv_web/live/global_settings_live_test.exs @@ -0,0 +1,67 @@ +defmodule MvWeb.GlobalSettingsLiveTest do + use MvWeb.ConnCase, async: true + import Phoenix.LiveViewTest + alias Mv.Membership + + describe "Global Settings LiveView" do + setup %{conn: conn} do + user = create_test_user(%{email: "admin@example.com"}) + conn = conn_with_oidc_user(conn, user) + {:ok, conn: conn, user: user} + end + + test "renders the global settings page", %{conn: conn} do + {:ok, view, html} = live(conn, ~p"/settings") + + assert html =~ "Vereinsdaten" + assert html =~ "Settings" + end + + test "displays current club name", %{conn: conn} do + # Set initial club name + {:ok, settings} = Membership.get_settings() + Membership.update_settings!(settings, %{club_name: "Test Club"}) + + {:ok, _view, html} = live(conn, ~p"/settings") + + assert html =~ "Test Club" + end + + test "can update club name via form", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/settings") + + # Submit form with new club name + assert view + |> form("#settings-form", %{setting: %{club_name: "Updated Club Name"}}) + |> render_submit() + + # Check for success message + assert render(view) =~ "Settings updated successfully" + assert render(view) =~ "Updated Club Name" + end + + test "shows error when club_name is empty", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/settings") + + # Submit form with empty club name + html = + view + |> form("#settings-form", %{setting: %{club_name: ""}}) + |> render_submit() + + assert html =~ "must be present" + end + + test "shows error when club_name is missing", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/settings") + + # Submit form without club_name + html = + view + |> form("#settings-form", %{setting: %{}}) + |> render_submit() + + assert html =~ "must be present" + end + end +end From 193618eacef9baa1101fb39e1d1a12b0681b672d Mon Sep 17 00:00:00 2001 From: carla Date: Thu, 27 Nov 2025 14:56:50 +0100 Subject: [PATCH 2/7] chore: adds settings ressource and migration --- lib/membership/membership.ex | 77 ++++++++++++++++++ lib/membership/setting.ex | 80 +++++++++++++++++++ .../20251127134451_add_settings_table.exs | 31 +++++++ .../repo/settings/20251127134451.json | 67 ++++++++++++++++ 4 files changed, 255 insertions(+) create mode 100644 lib/membership/setting.ex create mode 100644 priv/repo/migrations/20251127134451_add_settings_table.exs create mode 100644 priv/resource_snapshots/repo/settings/20251127134451.json diff --git a/lib/membership/membership.ex b/lib/membership/membership.ex index 7891d2e..c9d0466 100644 --- a/lib/membership/membership.ex +++ b/lib/membership/membership.ex @@ -6,12 +6,14 @@ defmodule Mv.Membership do - `Member` - Club members with personal information and custom field values - `CustomFieldValue` - Dynamic custom field values attached to members - `CustomField` - Schema definitions for custom fields + - `Setting` - Global application settings (singleton) ## Public API The domain exposes these main actions: - Member CRUD: `create_member/1`, `list_members/0`, `update_member/2`, `destroy_member/1` - Custom field value management: `create_custom_field_value/1`, `list_custom_field_values/0`, etc. - Custom field management: `create_custom_field/1`, `list_custom_fields/0`, etc. + - Settings management: `get_settings/0`, `update_settings/2` ## Admin Interface The domain is configured with AshAdmin for management UI. @@ -45,5 +47,80 @@ defmodule Mv.Membership do define :destroy_custom_field, action: :destroy_with_values define :prepare_custom_field_deletion, action: :prepare_deletion, args: [:id] end + + resource Mv.Membership.Setting do + # Note: create action exists but is not exposed via code interface + # It's only used internally as fallback in get_settings/0 + # Settings should be created via seed script + define :update_settings, action: :update + end + end + + # Singleton pattern: Get the single settings record + @doc """ + Gets the global settings. + + Settings should normally be created via the seed script (`priv/repo/seeds.exs`). + If no settings exist, this function will create them as a fallback using the + `ASSOCIATION_NAME` environment variable or "Mitgliederverwaltung" as default. + + ## Returns + + - `{:ok, settings}` - The settings record + - `{:ok, nil}` - No settings exist (should not happen if seeds were run) + - `{:error, error}` - Error reading settings + + ## Examples + + iex> {:ok, settings} = Mv.Membership.get_settings() + iex> settings.club_name + "My Club" + + """ + def get_settings do + # Try to get the first (and only) settings record + case Ash.read_one(Mv.Membership.Setting, domain: __MODULE__) do + {:ok, nil} -> + # No settings exist - create as fallback (should normally be created via seed script) + default_club_name = System.get_env("ASSOCIATION_NAME") || "Mitgliederverwaltung" + + Mv.Membership.Setting + |> Ash.Changeset.for_create(:create, %{club_name: default_club_name}) + |> Ash.create!(domain: __MODULE__) + |> then(fn settings -> {:ok, settings} end) + + {:ok, settings} -> + {:ok, settings} + + {:error, error} -> + {:error, error} + end + end + + @doc """ + Updates the global settings. + + ## Parameters + + - `settings` - The settings record to update + - `attrs` - A map of attributes to update (e.g., `%{club_name: "New Name"}`) + + ## Returns + + - `{:ok, updated_settings}` - Successfully updated settings + - `{:error, error}` - Validation or update error + + ## Examples + + iex> {:ok, settings} = Mv.Membership.get_settings() + iex> {:ok, updated} = Mv.Membership.update_settings(settings, %{club_name: "New Club"}) + iex> updated.club_name + "New Club" + + """ + def update_settings(settings, attrs) do + settings + |> Ash.Changeset.for_update(:update, attrs) + |> Ash.update(domain: __MODULE__) end end diff --git a/lib/membership/setting.ex b/lib/membership/setting.ex new file mode 100644 index 0000000..47b9dd8 --- /dev/null +++ b/lib/membership/setting.ex @@ -0,0 +1,80 @@ +defmodule Mv.Membership.Setting do + @moduledoc """ + Ash resource representing global application settings. + + ## Overview + Settings is a singleton resource that stores global configuration for the association, + such as the club name and branding information. There should only ever be one settings + record in the database. + + ## Attributes + - `club_name` - The name of the association/club (required, cannot be empty) + + ## Singleton Pattern + This resource uses a singleton pattern - there should only be one settings record. + The resource is designed to be read and updated, but not created or destroyed + through normal CRUD operations. Initial settings should be seeded. + + ## Environment Variable Support + The `club_name` can be set via the `ASSOCIATION_NAME` environment variable. + If set, the environment variable value is used as a fallback when no database + value exists. Database values always take precedence over environment variables. + + ## Examples + + # Get current settings + {:ok, settings} = Mv.Membership.get_settings() + settings.club_name # => "My Club" + + # Update club name + {:ok, updated} = Mv.Membership.update_settings(settings, %{club_name: "New Name"}) + """ + use Ash.Resource, + domain: Mv.Membership, + data_layer: AshPostgres.DataLayer + + postgres do + table "settings" + repo Mv.Repo + end + + resource do + description "Global application settings (singleton resource)" + end + + actions do + defaults [:read] + + # Internal create action - not exposed via code interface + # Used only as fallback in get_settings/0 if settings don't exist + # Settings should normally be created via seed script + create :create do + accept [:club_name] + end + + update :update do + primary? true + accept [:club_name] + end + end + + attributes do + uuid_primary_key :id + + attribute :club_name, :string, + allow_nil?: false, + public?: true, + description: "The name of the association/club", + constraints: [ + trim?: true, + min_length: 1 + ] + + timestamps() + end + + validations do + validate present(:club_name), on: [:create, :update] + validate string_length(:club_name, min: 1), on: [:create, :update] + end +end diff --git a/priv/repo/migrations/20251127134451_add_settings_table.exs b/priv/repo/migrations/20251127134451_add_settings_table.exs new file mode 100644 index 0000000..e08ba1d --- /dev/null +++ b/priv/repo/migrations/20251127134451_add_settings_table.exs @@ -0,0 +1,31 @@ +defmodule Mv.Repo.Migrations.AddSettingsTable do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:settings, primary_key: false) do + add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true + add :club_name, :text, null: false + + add :inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + + add :updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + end + + # Note: Singleton pattern is enforced at application level via get_settings/0 + # which creates the record if it doesn't exist and only allows updates + end + + def down do + drop table(:settings) + end +end diff --git a/priv/resource_snapshots/repo/settings/20251127134451.json b/priv/resource_snapshots/repo/settings/20251127134451.json new file mode 100644 index 0000000..fefc223 --- /dev/null +++ b/priv/resource_snapshots/repo/settings/20251127134451.json @@ -0,0 +1,67 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "precision": null, + "primary_key?": true, + "references": null, + "scale": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "club_name", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "precision": null, + "primary_key?": false, + "references": null, + "scale": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "353EB39F18B97C596A77A78A060FB9DE075AAD731F74F64AB62D357CBCDEC914", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.Mv.Repo", + "schema": null, + "table": "settings" +} \ No newline at end of file From 37553d8d6c464e54cec760df1c8fd58e1bec3e8d Mon Sep 17 00:00:00 2001 From: carla Date: Thu, 27 Nov 2025 15:34:10 +0100 Subject: [PATCH 3/7] feat: adds settings live view and updated seeds --- lib/membership/membership.ex | 4 +- lib/membership/setting.ex | 10 +-- lib/mv_web/components/layouts/navbar.ex | 21 +++++- lib/mv_web/live/global_settings_live.ex | 97 +++++++++++++++++++++++++ lib/mv_web/router.ex | 2 + priv/repo/seeds.exs | 19 +++++ 6 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 lib/mv_web/live/global_settings_live.ex diff --git a/lib/membership/membership.ex b/lib/membership/membership.ex index c9d0466..cb3691b 100644 --- a/lib/membership/membership.ex +++ b/lib/membership/membership.ex @@ -62,7 +62,7 @@ defmodule Mv.Membership do Settings should normally be created via the seed script (`priv/repo/seeds.exs`). If no settings exist, this function will create them as a fallback using the - `ASSOCIATION_NAME` environment variable or "Mitgliederverwaltung" as default. + `ASSOCIATION_NAME` environment variable or "Club Name" as default. ## Returns @@ -82,7 +82,7 @@ defmodule Mv.Membership do case Ash.read_one(Mv.Membership.Setting, domain: __MODULE__) do {:ok, nil} -> # No settings exist - create as fallback (should normally be created via seed script) - default_club_name = System.get_env("ASSOCIATION_NAME") || "Mitgliederverwaltung" + default_club_name = System.get_env("ASSOCIATION_NAME") || "Club Name" Mv.Membership.Setting |> Ash.Changeset.for_create(:create, %{club_name: default_club_name}) diff --git a/lib/membership/setting.ex b/lib/membership/setting.ex index 47b9dd8..38624dc 100644 --- a/lib/membership/setting.ex +++ b/lib/membership/setting.ex @@ -58,6 +58,11 @@ defmodule Mv.Membership.Setting do end end + validations do + validate present(:club_name), on: [:create, :update] + validate string_length(:club_name, min: 1), on: [:create, :update] + end + attributes do uuid_primary_key :id @@ -72,9 +77,4 @@ defmodule Mv.Membership.Setting do timestamps() end - - validations do - validate present(:club_name), on: [:create, :update] - validate string_length(:club_name, min: 1), on: [:create, :update] - end end diff --git a/lib/mv_web/components/layouts/navbar.ex b/lib/mv_web/components/layouts/navbar.ex index 1de4c7f..7ff7f25 100644 --- a/lib/mv_web/components/layouts/navbar.ex +++ b/lib/mv_web/components/layouts/navbar.ex @@ -6,15 +6,21 @@ defmodule MvWeb.Layouts.Navbar do use Gettext, backend: MvWeb.Gettext use MvWeb, :verified_routes + alias Mv.Membership + attr :current_user, :map, required: true, doc: "The current user - navbar is only shown when user is present" def navbar(assigns) do + club_name = get_club_name() + + assigns = assign(assigns, :club_name, club_name) + ~H""" """ end + + # Helper function to get club name from settings + # Falls back to "Mitgliederverwaltung" if settings can't be loaded + defp get_club_name do + case Membership.get_settings() do + {:ok, settings} -> settings.club_name + _ -> "Mitgliederverwaltung" + end + end end diff --git a/lib/mv_web/live/global_settings_live.ex b/lib/mv_web/live/global_settings_live.ex new file mode 100644 index 0000000..0be4559 --- /dev/null +++ b/lib/mv_web/live/global_settings_live.ex @@ -0,0 +1,97 @@ +defmodule MvWeb.GlobalSettingsLive do + @moduledoc """ + LiveView for managing global application settings (Vereinsdaten). + + ## Features + - Edit the association/club name + - Real-time form validation + - Success/error feedback + + ## Settings + - `club_name` - The name of the association/club (required) + + ## Events + - `validate` - Real-time form validation + - `save` - Save settings changes + + ## Note + Settings is a singleton resource - there is only one settings record. + The club_name can also be set via the `ASSOCIATION_NAME` environment variable. + """ + use MvWeb, :live_view + + alias Mv.Membership + + @impl true + def mount(_params, _session, socket) do + {:ok, settings} = Membership.get_settings() + + {:ok, + socket + |> assign(:page_title, gettext("Club Settings")) + |> assign(:settings, settings) + |> assign_form()} + end + + @impl true + def render(assigns) do + ~H""" + + <.header> + {gettext("Club Settings")} + <:subtitle> + {gettext("Manage global settings for the association.")} + + + + <.form for={@form} id="settings-form" phx-change="validate" phx-submit="save"> + <.input + field={@form[:club_name]} + type="text" + label={gettext("Association Name")} + required + /> + + <.button phx-disable-with={gettext("Saving...")} variant="primary"> + {gettext("Save Settings")} + + + + """ + end + + @impl true + def handle_event("validate", %{"setting" => setting_params}, socket) do + {:noreply, + assign(socket, form: AshPhoenix.Form.validate(socket.assigns.form, setting_params))} + end + + def handle_event("save", %{"setting" => setting_params}, socket) do + case AshPhoenix.Form.submit(socket.assigns.form, params: setting_params) do + {:ok, updated_settings} -> + socket = + socket + |> assign(:settings, updated_settings) + |> put_flash(:info, gettext("Settings updated successfully")) + |> assign_form() + + {:noreply, socket} + + {:error, form} -> + {:noreply, assign(socket, form: form)} + end + end + + defp assign_form(%{assigns: %{settings: settings}} = socket) do + form = + AshPhoenix.Form.for_update( + settings, + :update, + api: Membership, + as: "setting", + forms: [auto?: true] + ) + + assign(socket, form: to_form(form)) + end +end diff --git a/lib/mv_web/router.ex b/lib/mv_web/router.ex index d2a63bc..09a2792 100644 --- a/lib/mv_web/router.ex +++ b/lib/mv_web/router.ex @@ -73,6 +73,8 @@ defmodule MvWeb.Router do live "/users/:id", UserLive.Show, :show live "/users/:id/show/edit", UserLive.Show, :edit + live "/settings", GlobalSettingsLive + post "/set_locale", LocaleController, :set_locale end diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index 8d3cb6f..00cf657 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -323,8 +323,27 @@ if friedrich = find_member.("friedrich.wagner@example.de") do end) end +# Create or update global settings (singleton) +default_club_name = System.get_env("ASSOCIATION_NAME") || "Club Name" + +case Membership.get_settings() do + {:ok, existing_settings} -> + # Settings exist, update if club_name is different from env var + if existing_settings.club_name != default_club_name do + {:ok, _updated} = + Membership.update_settings(existing_settings, %{club_name: default_club_name}) + end + + {:ok, nil} -> + # Settings don't exist, create them + Mv.Membership.Setting + |> Ash.Changeset.for_create(:create, %{club_name: default_club_name}) + |> Ash.create!(domain: Mv.Membership) +end + IO.puts("✅ Seeds completed successfully!") IO.puts("📝 Created sample data:") +IO.puts(" - Global settings: club_name = #{default_club_name}") IO.puts(" - Custom fields: 12 fields (String, Date, Boolean, Email, + 8 realistic fields)") IO.puts(" - Admin user: admin@mv.local (password: testpassword)") IO.puts(" - Sample members: Hans, Greta, Friedrich") From fdae610da02994e78eba2eda62b4595575f0dc52 Mon Sep 17 00:00:00 2001 From: carla Date: Thu, 27 Nov 2025 15:37:42 +0100 Subject: [PATCH 4/7] adds translation --- priv/gettext/de/LC_MESSAGES/default.po | 46 ++++++++++++++++++++------ priv/gettext/default.pot | 45 +++++++++++++++++++------ priv/gettext/en/LC_MESSAGES/default.po | 45 +++++++++++++++++++------ 3 files changed, 106 insertions(+), 30 deletions(-) diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po index 27acc80..f144198 100644 --- a/priv/gettext/de/LC_MESSAGES/default.po +++ b/priv/gettext/de/LC_MESSAGES/default.po @@ -160,6 +160,7 @@ msgstr "Mitglied speichern" #: lib/mv_web/live/custom_field_live/form.ex:66 #: lib/mv_web/live/custom_field_value_live/form.ex:74 +#: lib/mv_web/live/global_settings_live.ex:55 #: lib/mv_web/live/member_live/form.ex:79 #: lib/mv_web/live/user_live/form.ex:234 #, elixir-autogen, elixir-format @@ -293,7 +294,7 @@ msgstr "ID" msgid "Immutable" msgstr "Unveränderlich" -#: lib/mv_web/components/layouts/navbar.ex:94 +#: lib/mv_web/components/layouts/navbar.ex:102 #, elixir-autogen, elixir-format msgid "Logout" msgstr "Abmelden" @@ -309,8 +310,8 @@ msgstr "Benutzer*innen auflisten" msgid "Member" msgstr "Mitglied" -#: lib/mv_web/components/layouts/navbar.ex:19 -#: lib/mv_web/live/member_live/index.ex:57 +#: lib/mv_web/components/layouts/navbar.ex:25 +#: lib/mv_web/live/member_live/index.ex:39 #: lib/mv_web/live/member_live/index.html.heex:3 #, elixir-autogen, elixir-format msgid "Members" @@ -354,7 +355,7 @@ msgstr "OIDC ID" msgid "Password Authentication" msgstr "Passwort-Authentifizierung" -#: lib/mv_web/components/layouts/navbar.ex:89 +#: lib/mv_web/components/layouts/navbar.ex:95 #, elixir-autogen, elixir-format msgid "Profil" msgstr "Profil" @@ -374,7 +375,7 @@ msgstr "Alle Mitglieder auswählen" msgid "Select member" msgstr "Mitglied auswählen" -#: lib/mv_web/components/layouts/navbar.ex:92 +#: lib/mv_web/components/layouts/navbar.ex:99 #, elixir-autogen, elixir-format msgid "Settings" msgstr "Einstellungen" @@ -542,14 +543,14 @@ msgstr "Zurück zur Mitgliederliste" msgid "Back to users list" msgstr "Zurück zur Benutzer*innen-Liste" -#: lib/mv_web/components/layouts/navbar.ex:27 #: lib/mv_web/components/layouts/navbar.ex:33 +#: lib/mv_web/components/layouts/navbar.ex:39 #, elixir-autogen, elixir-format msgid "Select language" msgstr "Sprache auswählen" -#: lib/mv_web/components/layouts/navbar.ex:40 -#: lib/mv_web/components/layouts/navbar.ex:60 +#: lib/mv_web/components/layouts/navbar.ex:46 +#: lib/mv_web/components/layouts/navbar.ex:66 #, elixir-autogen, elixir-format msgid "Toggle dark mode" msgstr "Dunklen Modus umschalten" @@ -560,7 +561,7 @@ msgstr "Dunklen Modus umschalten" msgid "Search..." msgstr "Suchen..." -#: lib/mv_web/components/layouts/navbar.ex:21 +#: lib/mv_web/components/layouts/navbar.ex:27 #, elixir-autogen, elixir-format msgid "Users" msgstr "Benutzer*innen" @@ -653,7 +654,7 @@ msgstr "Benutzerdefinierten Feldwert speichern" msgid "Use this form to manage custom_field records in your database." msgstr "Verwende dieses Formular, um Benutzerdefinierte Felder in deiner Datenbank zu verwalten." -#: lib/mv_web/components/layouts/navbar.ex:20 +#: lib/mv_web/components/layouts/navbar.ex:26 #, elixir-autogen, elixir-format msgid "Custom Fields" msgstr "Benutzerdefinierte Felder" @@ -753,6 +754,31 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Show in overview" msgstr "In der Mitglieder-Übersicht anzeigen" +#: lib/mv_web/live/global_settings_live.ex:51 +#, elixir-autogen, elixir-format +msgid "Association Name" +msgstr "Vereinsname" + +#: lib/mv_web/live/global_settings_live.ex:31 +#: lib/mv_web/live/global_settings_live.ex:41 +#, elixir-autogen, elixir-format, fuzzy +msgid "Club Settings" +msgstr "Vereinsdaten" + +#: lib/mv_web/live/global_settings_live.ex:43 +#, elixir-autogen, elixir-format +msgid "Manage global settings for the association." +msgstr "Passe übergreifende Einstellungen für den Verein an." + +#: lib/mv_web/live/global_settings_live.ex:56 +#, elixir-autogen, elixir-format, fuzzy +msgid "Save Settings" +msgstr "Einstellungen speichern" + +#: lib/mv_web/live/global_settings_live.ex:75 +#, elixir-autogen, elixir-format +msgid "Settings updated successfully" +msgstr "Einstellungen erfolgreich gespeichert" #~ #: lib/mv_web/live/custom_field_live/index.ex:97 #~ #, elixir-autogen, elixir-format diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 7cf507b..a5e9aa9 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -161,6 +161,7 @@ msgstr "" #: lib/mv_web/live/custom_field_live/form.ex:66 #: lib/mv_web/live/custom_field_value_live/form.ex:74 +#: lib/mv_web/live/global_settings_live.ex:55 #: lib/mv_web/live/member_live/form.ex:79 #: lib/mv_web/live/user_live/form.ex:234 #, elixir-autogen, elixir-format @@ -294,7 +295,7 @@ msgstr "" msgid "Immutable" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:94 +#: lib/mv_web/components/layouts/navbar.ex:102 #, elixir-autogen, elixir-format msgid "Logout" msgstr "" @@ -310,8 +311,8 @@ msgstr "" msgid "Member" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:19 -#: lib/mv_web/live/member_live/index.ex:57 +#: lib/mv_web/components/layouts/navbar.ex:25 +#: lib/mv_web/live/member_live/index.ex:39 #: lib/mv_web/live/member_live/index.html.heex:3 #, elixir-autogen, elixir-format msgid "Members" @@ -355,7 +356,7 @@ msgstr "" msgid "Password Authentication" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:89 +#: lib/mv_web/components/layouts/navbar.ex:95 #, elixir-autogen, elixir-format msgid "Profil" msgstr "" @@ -375,7 +376,7 @@ msgstr "" msgid "Select member" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:92 +#: lib/mv_web/components/layouts/navbar.ex:99 #, elixir-autogen, elixir-format msgid "Settings" msgstr "" @@ -543,14 +544,14 @@ msgstr "" msgid "Back to users list" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:27 #: lib/mv_web/components/layouts/navbar.ex:33 +#: lib/mv_web/components/layouts/navbar.ex:39 #, elixir-autogen, elixir-format msgid "Select language" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:40 -#: lib/mv_web/components/layouts/navbar.ex:60 +#: lib/mv_web/components/layouts/navbar.ex:46 +#: lib/mv_web/components/layouts/navbar.ex:66 #, elixir-autogen, elixir-format msgid "Toggle dark mode" msgstr "" @@ -561,7 +562,7 @@ msgstr "" msgid "Search..." msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:21 +#: lib/mv_web/components/layouts/navbar.ex:27 #, elixir-autogen, elixir-format msgid "Users" msgstr "" @@ -654,7 +655,7 @@ msgstr "" msgid "Use this form to manage custom_field records in your database." msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:20 +#: lib/mv_web/components/layouts/navbar.ex:26 #, elixir-autogen, elixir-format msgid "Custom Fields" msgstr "" @@ -704,4 +705,28 @@ msgstr "" #: lib/mv_web/live/custom_field_live/form.ex:64 #, elixir-autogen, elixir-format msgid "Show in overview" +#: lib/mv_web/live/global_settings_live.ex:51 +#, elixir-autogen, elixir-format +msgid "Association Name" +msgstr "" + +#: lib/mv_web/live/global_settings_live.ex:31 +#: lib/mv_web/live/global_settings_live.ex:41 +#, elixir-autogen, elixir-format +msgid "Club Settings" +msgstr "" + +#: lib/mv_web/live/global_settings_live.ex:43 +#, elixir-autogen, elixir-format +msgid "Manage global settings for the association." +msgstr "" + +#: lib/mv_web/live/global_settings_live.ex:56 +#, elixir-autogen, elixir-format +msgid "Save Settings" +msgstr "" + +#: lib/mv_web/live/global_settings_live.ex:75 +#, elixir-autogen, elixir-format +msgid "Settings updated successfully" msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index ed38b0e..19be444 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -161,6 +161,7 @@ msgstr "" #: lib/mv_web/live/custom_field_live/form.ex:66 #: lib/mv_web/live/custom_field_value_live/form.ex:74 +#: lib/mv_web/live/global_settings_live.ex:55 #: lib/mv_web/live/member_live/form.ex:79 #: lib/mv_web/live/user_live/form.ex:234 #, elixir-autogen, elixir-format @@ -294,7 +295,7 @@ msgstr "" msgid "Immutable" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:94 +#: lib/mv_web/components/layouts/navbar.ex:102 #, elixir-autogen, elixir-format msgid "Logout" msgstr "" @@ -310,8 +311,8 @@ msgstr "" msgid "Member" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:19 -#: lib/mv_web/live/member_live/index.ex:57 +#: lib/mv_web/components/layouts/navbar.ex:25 +#: lib/mv_web/live/member_live/index.ex:39 #: lib/mv_web/live/member_live/index.html.heex:3 #, elixir-autogen, elixir-format msgid "Members" @@ -355,7 +356,7 @@ msgstr "" msgid "Password Authentication" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:89 +#: lib/mv_web/components/layouts/navbar.ex:95 #, elixir-autogen, elixir-format msgid "Profil" msgstr "" @@ -375,7 +376,7 @@ msgstr "" msgid "Select member" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:92 +#: lib/mv_web/components/layouts/navbar.ex:99 #, elixir-autogen, elixir-format msgid "Settings" msgstr "" @@ -543,14 +544,14 @@ msgstr "" msgid "Back to users list" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:27 #: lib/mv_web/components/layouts/navbar.ex:33 +#: lib/mv_web/components/layouts/navbar.ex:39 #, elixir-autogen, elixir-format, fuzzy msgid "Select language" msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:40 -#: lib/mv_web/components/layouts/navbar.ex:60 +#: lib/mv_web/components/layouts/navbar.ex:46 +#: lib/mv_web/components/layouts/navbar.ex:66 #, elixir-autogen, elixir-format msgid "Toggle dark mode" msgstr "" @@ -561,7 +562,7 @@ msgstr "" msgid "Search..." msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:21 +#: lib/mv_web/components/layouts/navbar.ex:27 #, elixir-autogen, elixir-format, fuzzy msgid "Users" msgstr "" @@ -654,7 +655,7 @@ msgstr "" msgid "Use this form to manage custom_field records in your database." msgstr "" -#: lib/mv_web/components/layouts/navbar.ex:20 +#: lib/mv_web/components/layouts/navbar.ex:26 #, elixir-autogen, elixir-format, fuzzy msgid "Custom Fields" msgstr "" @@ -753,6 +754,30 @@ msgstr "" #: lib/mv_web/live/custom_field_live/form.ex:64 #, elixir-autogen, elixir-format msgid "Show in overview" +#: lib/mv_web/live/global_settings_live.ex:51 +#, elixir-autogen, elixir-format +msgid "Association Name" +msgstr "" + +#: lib/mv_web/live/global_settings_live.ex:31 +#: lib/mv_web/live/global_settings_live.ex:41 +#, elixir-autogen, elixir-format, fuzzy +msgid "Club Settings" +msgstr "" + +#: lib/mv_web/live/global_settings_live.ex:43 +#, elixir-autogen, elixir-format +msgid "Manage global settings for the association." +msgstr "" + +#: lib/mv_web/live/global_settings_live.ex:56 +#, elixir-autogen, elixir-format, fuzzy +msgid "Save Settings" +msgstr "" + +#: lib/mv_web/live/global_settings_live.ex:75 +#, elixir-autogen, elixir-format +msgid "Settings updated successfully" msgstr "" #~ #: lib/mv_web/live/custom_field_live/index.ex:97 From cf354bcf2513d37a5f9b32d028b214ad697c7874 Mon Sep 17 00:00:00 2001 From: carla Date: Thu, 27 Nov 2025 15:49:29 +0100 Subject: [PATCH 5/7] test updated --- test/membership/setting_test.exs | 8 +++----- test/mv_web/components/layouts/navbar_test.exs | 2 +- test/mv_web/controllers/page_controller_test.exs | 11 ++++++----- test/mv_web/live/global_settings_live_test.exs | 11 ++++++----- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test/membership/setting_test.exs b/test/membership/setting_test.exs index 46cf3b9..531ab88 100644 --- a/test/membership/setting_test.exs +++ b/test/membership/setting_test.exs @@ -44,10 +44,8 @@ defmodule Mv.Membership.SettingTest do # Helper function to extract error messages defp error_message(errors, field) do errors - |> Enum.find(fn error -> error.field == field end) - |> case do - nil -> "" - error -> List.first(error.message) || "" - end + |> Enum.filter(fn err -> Map.get(err, :field) == field end) + |> Enum.map(&Map.get(&1, :message, "")) + |> List.first() || "" end end diff --git a/test/mv_web/components/layouts/navbar_test.exs b/test/mv_web/components/layouts/navbar_test.exs index 6a50996..7836ee6 100644 --- a/test/mv_web/components/layouts/navbar_test.exs +++ b/test/mv_web/components/layouts/navbar_test.exs @@ -100,7 +100,7 @@ defmodule MvWeb.Layouts.NavbarTest do # Verify the link actually works by navigating to it {:ok, _view, settings_html} = live(conn, ~p"/settings") - assert settings_html =~ "Vereinsdaten" + assert settings_html =~ "Club Settings" end end end diff --git a/test/mv_web/controllers/page_controller_test.exs b/test/mv_web/controllers/page_controller_test.exs index ce3195b..1dfcf2b 100644 --- a/test/mv_web/controllers/page_controller_test.exs +++ b/test/mv_web/controllers/page_controller_test.exs @@ -1,10 +1,11 @@ defmodule MvWeb.PageControllerTest do - use MvWeb.ConnCase + use MvWeb.ConnCase, async: true - test "GET /", %{conn: conn} do - conn = conn_with_oidc_user(conn) + test "renders home template successfully with authenticated user", %{conn: conn} do + user = create_test_user(%{email: "test@example.com"}) + conn = conn_with_oidc_user(conn, user) + conn = get(conn, "/") - conn = get(conn, ~p"/") - assert html_response(conn, 200) =~ "Mitgliederverwaltung" + assert html_response(conn, 200) end end diff --git a/test/mv_web/live/global_settings_live_test.exs b/test/mv_web/live/global_settings_live_test.exs index f06deb1..6a739b5 100644 --- a/test/mv_web/live/global_settings_live_test.exs +++ b/test/mv_web/live/global_settings_live_test.exs @@ -11,16 +11,16 @@ defmodule MvWeb.GlobalSettingsLiveTest do end test "renders the global settings page", %{conn: conn} do - {:ok, view, html} = live(conn, ~p"/settings") + {:ok, _view, html} = live(conn, ~p"/settings") - assert html =~ "Vereinsdaten" + assert html =~ "Club Settings" assert html =~ "Settings" end test "displays current club name", %{conn: conn} do # Set initial club name {:ok, settings} = Membership.get_settings() - Membership.update_settings!(settings, %{club_name: "Test Club"}) + {:ok, _updated} = Membership.update_settings(settings, %{club_name: "Test Club"}) {:ok, _view, html} = live(conn, ~p"/settings") @@ -55,10 +55,11 @@ defmodule MvWeb.GlobalSettingsLiveTest do test "shows error when club_name is missing", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/settings") - # Submit form without club_name + # Submit form with club_name explicitly set to empty string + # (Phoenix forms will keep existing value if field is omitted) html = view - |> form("#settings-form", %{setting: %{}}) + |> form("#settings-form", %{setting: %{club_name: ""}}) |> render_submit() assert html =~ "must be present" From dfdf4c980b29eeddb55f5d7056f9d5c2def7b480 Mon Sep 17 00:00:00 2001 From: carla Date: Thu, 27 Nov 2025 15:56:20 +0100 Subject: [PATCH 6/7] chore: updated env example --- .env.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.env.example b/.env.example index 7559b0a..13154f3 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,9 @@ TOKEN_SIGNING_SECRET=changeme-run-mix-phx.gen.secret # Required: Hostname for URL generation PHX_HOST=localhost +# Recommended: Association settings +ASSOCIATION_NAME="Sportsclub XYZ" + # Optional: OIDC Configuration # These have defaults in docker-compose.prod.yml, only override if needed # OIDC_CLIENT_ID=mv From f9ff6d3d2dc7ae70968e75381a07976b5a3da206 Mon Sep 17 00:00:00 2001 From: carla Date: Mon, 1 Dec 2025 10:54:12 +0100 Subject: [PATCH 7/7] fix: remove unused branch in seeds and fixed translations --- priv/gettext/de/LC_MESSAGES/default.po | 128 ++++++++++++------------ priv/gettext/default.pot | 80 ++++++++++++--- priv/gettext/en/LC_MESSAGES/default.po | 129 +++++++++++++------------ priv/repo/seeds.exs | 6 -- 4 files changed, 197 insertions(+), 146 deletions(-) diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po index f144198..e9214fc 100644 --- a/priv/gettext/de/LC_MESSAGES/default.po +++ b/priv/gettext/de/LC_MESSAGES/default.po @@ -16,7 +16,7 @@ msgid "Actions" msgstr "Aktionen" #: lib/mv_web/live/member_live/index.html.heex:202 -#: lib/mv_web/live/user_live/index.html.heex:65 +#: lib/mv_web/live/user_live/index.html.heex:72 #, elixir-autogen, elixir-format msgid "Are you sure?" msgstr "Bist du sicher?" @@ -35,14 +35,14 @@ msgid "City" msgstr "Stadt" #: lib/mv_web/live/member_live/index.html.heex:204 -#: lib/mv_web/live/user_live/index.html.heex:67 +#: lib/mv_web/live/user_live/index.html.heex:74 #, elixir-autogen, elixir-format msgid "Delete" msgstr "Löschen" #: lib/mv_web/live/member_live/index.html.heex:196 -#: lib/mv_web/live/user_live/form.ex:141 -#: lib/mv_web/live/user_live/index.html.heex:59 +#: lib/mv_web/live/user_live/form.ex:265 +#: lib/mv_web/live/user_live/index.html.heex:66 #, elixir-autogen, elixir-format msgid "Edit" msgstr "Bearbeite" @@ -88,7 +88,7 @@ msgid "New Member" msgstr "Neues Mitglied" #: lib/mv_web/live/member_live/index.html.heex:193 -#: lib/mv_web/live/user_live/index.html.heex:56 +#: lib/mv_web/live/user_live/index.html.heex:63 #, elixir-autogen, elixir-format msgid "Show" msgstr "Anzeigen" @@ -162,7 +162,7 @@ msgstr "Mitglied speichern" #: lib/mv_web/live/custom_field_value_live/form.ex:74 #: lib/mv_web/live/global_settings_live.ex:55 #: lib/mv_web/live/member_live/form.ex:79 -#: lib/mv_web/live/user_live/form.ex:234 +#: lib/mv_web/live/user_live/form.ex:248 #, elixir-autogen, elixir-format msgid "Saving..." msgstr "Speichern..." @@ -184,7 +184,7 @@ msgstr "Dieses Formular dient zur Verwaltung von Mitgliedern und deren Eigenscha msgid "Id" msgstr "ID" -#: lib/mv_web/live/member_live/index/formatter.ex:65 +#: lib/mv_web/live/member_live/index/formatter.ex:61 #: lib/mv_web/live/member_live/show.ex:53 #, elixir-autogen, elixir-format msgid "No" @@ -200,7 +200,7 @@ msgstr "Mitglied anzeigen" msgid "This is a member record from your database." msgstr "Dies ist ein Mitglied aus deiner Datenbank." -#: lib/mv_web/live/member_live/index/formatter.ex:64 +#: lib/mv_web/live/member_live/index/formatter.ex:60 #: lib/mv_web/live/member_live/show.ex:53 #, elixir-autogen, elixir-format msgid "Yes" @@ -259,7 +259,7 @@ msgstr "Ihr Passwort wurde erfolgreich zurückgesetzt" #: lib/mv_web/live/custom_field_live/index.ex:120 #: lib/mv_web/live/custom_field_value_live/form.ex:77 #: lib/mv_web/live/member_live/form.ex:82 -#: lib/mv_web/live/user_live/form.ex:237 +#: lib/mv_web/live/user_live/form.ex:251 #, elixir-autogen, elixir-format msgid "Cancel" msgstr "Abbrechen" @@ -311,7 +311,7 @@ msgid "Member" msgstr "Mitglied" #: lib/mv_web/components/layouts/navbar.ex:25 -#: lib/mv_web/live/member_live/index.ex:39 +#: lib/mv_web/live/member_live/index.ex:57 #: lib/mv_web/live/member_live/index.html.heex:3 #, elixir-autogen, elixir-format msgid "Members" @@ -339,7 +339,7 @@ msgstr "Nicht gesetzt" #: lib/mv_web/live/user_live/form.ex:107 #: lib/mv_web/live/user_live/form.ex:115 -#: lib/mv_web/live/user_live/form.ex:210 +#: lib/mv_web/live/user_live/form.ex:224 #, elixir-autogen, elixir-format msgid "Note" msgstr "Hinweis" @@ -380,7 +380,7 @@ msgstr "Mitglied auswählen" msgid "Settings" msgstr "Einstellungen" -#: lib/mv_web/live/user_live/form.ex:235 +#: lib/mv_web/live/user_live/form.ex:249 #, elixir-autogen, elixir-format msgid "Save User" msgstr "Benutzer*in speichern" @@ -405,7 +405,7 @@ msgstr "Nicht unterstützter Wertetyp: %{type}" msgid "Use this form to manage user records in your database." msgstr "Verwenden Sie dieses Formular, um Benutzer*innen-Datensätze zu verwalten." -#: lib/mv_web/live/user_live/form.ex:252 +#: lib/mv_web/live/user_live/form.ex:266 #: lib/mv_web/live/user_live/show.ex:34 #, elixir-autogen, elixir-format msgid "User" @@ -433,7 +433,7 @@ msgstr "aufsteigend" msgid "descending" msgstr "absteigend" -#: lib/mv_web/live/user_live/form.ex:251 +#: lib/mv_web/live/user_live/form.ex:265 #, elixir-autogen, elixir-format msgid "New" msgstr "Neue*r" @@ -701,59 +701,11 @@ msgstr "Obigen Text zur Bestätigung eingeben" msgid "To confirm deletion, please enter this text:" msgstr "Um die Löschung zu bestätigen, gib bitte folgenden Text ein:" -#: lib/mv_web/live/user_live/form.ex:210 -#, elixir-autogen, elixir-format -msgid "A member with this email already exists. To link with a different member, please change one of the email addresses first." -msgstr "Ein Mitglied mit dieser E-Mail-Adresse existiert bereits. Um mit einem anderen Mitglied zu verknüpfen, ändern Sie bitte zuerst eine der E-Mail-Adressen." - -#: lib/mv_web/live/user_live/form.ex:185 -#, elixir-autogen, elixir-format -msgid "Available members" -msgstr "Verfügbare Mitglieder" - -#: lib/mv_web/live/user_live/form.ex:152 -#, elixir-autogen, elixir-format -msgid "Member will be unlinked when you save. Cannot select new member until saved." -msgstr "Mitglied wird beim Speichern entverknüpft. Neues Mitglied kann erst nach dem Speichern ausgewählt werden." - -#: lib/mv_web/live/user_live/form.ex:226 -#, elixir-autogen, elixir-format -msgid "Save to confirm linking." -msgstr "Speichern, um die Verknüpfung zu bestätigen." - -#: lib/mv_web/live/user_live/form.ex:169 -#, elixir-autogen, elixir-format -msgid "Search for a member to link..." -msgstr "Nach einem Mitglied zum Verknüpfen suchen..." - -#: lib/mv_web/live/user_live/form.ex:173 -#, elixir-autogen, elixir-format -msgid "Search for member to link" -msgstr "Nach Mitglied zum Verknüpfen suchen" - -#: lib/mv_web/live/user_live/form.ex:223 -#, elixir-autogen, elixir-format -msgid "Selected" -msgstr "Ausgewählt" - -#: lib/mv_web/live/user_live/form.ex:143 -#, elixir-autogen, elixir-format -msgid "Unlink Member" -msgstr "Mitglied entverknüpfen" - -#: lib/mv_web/live/user_live/form.ex:152 -#, elixir-autogen, elixir-format -msgid "Unlinking scheduled" -msgstr "Entverknüpfung geplant" - -#: lib/mv_web/live/user_live/form.ex:342 -#, elixir-autogen, elixir-format -msgid "Failed to link member: %{error}" -msgstr "" #: lib/mv_web/live/custom_field_live/form.ex:64 #, elixir-autogen, elixir-format msgid "Show in overview" msgstr "In der Mitglieder-Übersicht anzeigen" + #: lib/mv_web/live/global_settings_live.ex:51 #, elixir-autogen, elixir-format msgid "Association Name" @@ -780,6 +732,56 @@ msgstr "Einstellungen speichern" msgid "Settings updated successfully" msgstr "Einstellungen erfolgreich gespeichert" +#: lib/mv_web/live/user_live/form.ex:224 +#, elixir-autogen, elixir-format +msgid "A member with this email already exists. To link with a different member, please change one of the email addresses first." +msgstr "Ein Mitglied mit dieser E-Mail-Adresse existiert bereits. Um mit einem anderen Mitglied zu verknüpfen, ändern Sie bitte zuerst eine der E-Mail-Adressen." + +#: lib/mv_web/live/user_live/form.ex:192 +#, elixir-autogen, elixir-format +msgid "Available members" +msgstr "Verfügbare Mitglieder" + +#: lib/mv_web/live/user_live/form.ex:357 +#, elixir-autogen, elixir-format +msgid "Failed to link member: %{error}" +msgstr "Fehler beim Verlinken des Mitglieds: %{error}" + +#: lib/mv_web/live/user_live/form.ex:152 +#, elixir-autogen, elixir-format +msgid "Member will be unlinked when you save. Cannot select new member until saved." +msgstr "Mitglied wird beim Speichern entverknüpft. Neues Mitglied kann erst nach dem Speichern ausgewählt werden." + +#: lib/mv_web/live/user_live/form.ex:240 +#, elixir-autogen, elixir-format +msgid "Save to confirm linking." +msgstr "Speichern, um die Verknüpfung zu bestätigen." + +#: lib/mv_web/live/user_live/form.ex:171 +#, elixir-autogen, elixir-format +msgid "Search for a member to link..." +msgstr "Nach einem Mitglied zum Verknüpfen suchen..." + +#: lib/mv_web/live/user_live/form.ex:175 +#, elixir-autogen, elixir-format +msgid "Search for member to link" +msgstr "Nach Mitglied zum Verknüpfen suchen" + +#: lib/mv_web/live/user_live/form.ex:237 +#, elixir-autogen, elixir-format +msgid "Selected" +msgstr "Ausgewählt" + +#: lib/mv_web/live/user_live/form.ex:143 +#, elixir-autogen, elixir-format +msgid "Unlink Member" +msgstr "Mitglied entverknüpfen" + +#: lib/mv_web/live/user_live/form.ex:152 +#, elixir-autogen, elixir-format +msgid "Unlinking scheduled" +msgstr "Entverknüpfung geplant" + #~ #: lib/mv_web/live/custom_field_live/index.ex:97 #~ #, elixir-autogen, elixir-format #~ msgid "To confirm deletion, please enter the custom field slug:" diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index a5e9aa9..47fe4dd 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -17,7 +17,7 @@ msgid "Actions" msgstr "" #: lib/mv_web/live/member_live/index.html.heex:202 -#: lib/mv_web/live/user_live/index.html.heex:65 +#: lib/mv_web/live/user_live/index.html.heex:72 #, elixir-autogen, elixir-format msgid "Are you sure?" msgstr "" @@ -36,14 +36,14 @@ msgid "City" msgstr "" #: lib/mv_web/live/member_live/index.html.heex:204 -#: lib/mv_web/live/user_live/index.html.heex:67 +#: lib/mv_web/live/user_live/index.html.heex:74 #, elixir-autogen, elixir-format msgid "Delete" msgstr "" #: lib/mv_web/live/member_live/index.html.heex:196 -#: lib/mv_web/live/user_live/form.ex:141 -#: lib/mv_web/live/user_live/index.html.heex:59 +#: lib/mv_web/live/user_live/form.ex:265 +#: lib/mv_web/live/user_live/index.html.heex:66 #, elixir-autogen, elixir-format msgid "Edit" msgstr "" @@ -89,7 +89,7 @@ msgid "New Member" msgstr "" #: lib/mv_web/live/member_live/index.html.heex:193 -#: lib/mv_web/live/user_live/index.html.heex:56 +#: lib/mv_web/live/user_live/index.html.heex:63 #, elixir-autogen, elixir-format msgid "Show" msgstr "" @@ -163,7 +163,7 @@ msgstr "" #: lib/mv_web/live/custom_field_value_live/form.ex:74 #: lib/mv_web/live/global_settings_live.ex:55 #: lib/mv_web/live/member_live/form.ex:79 -#: lib/mv_web/live/user_live/form.ex:234 +#: lib/mv_web/live/user_live/form.ex:248 #, elixir-autogen, elixir-format msgid "Saving..." msgstr "" @@ -185,7 +185,7 @@ msgstr "" msgid "Id" msgstr "" -#: lib/mv_web/live/member_live/index/formatter.ex:65 +#: lib/mv_web/live/member_live/index/formatter.ex:61 #: lib/mv_web/live/member_live/show.ex:53 #, elixir-autogen, elixir-format msgid "No" @@ -201,7 +201,7 @@ msgstr "" msgid "This is a member record from your database." msgstr "" -#: lib/mv_web/live/member_live/index/formatter.ex:64 +#: lib/mv_web/live/member_live/index/formatter.ex:60 #: lib/mv_web/live/member_live/show.ex:53 #, elixir-autogen, elixir-format msgid "Yes" @@ -260,7 +260,7 @@ msgstr "" #: lib/mv_web/live/custom_field_live/index.ex:120 #: lib/mv_web/live/custom_field_value_live/form.ex:77 #: lib/mv_web/live/member_live/form.ex:82 -#: lib/mv_web/live/user_live/form.ex:237 +#: lib/mv_web/live/user_live/form.ex:251 #, elixir-autogen, elixir-format msgid "Cancel" msgstr "" @@ -312,7 +312,7 @@ msgid "Member" msgstr "" #: lib/mv_web/components/layouts/navbar.ex:25 -#: lib/mv_web/live/member_live/index.ex:39 +#: lib/mv_web/live/member_live/index.ex:57 #: lib/mv_web/live/member_live/index.html.heex:3 #, elixir-autogen, elixir-format msgid "Members" @@ -340,7 +340,7 @@ msgstr "" #: lib/mv_web/live/user_live/form.ex:107 #: lib/mv_web/live/user_live/form.ex:115 -#: lib/mv_web/live/user_live/form.ex:210 +#: lib/mv_web/live/user_live/form.ex:224 #, elixir-autogen, elixir-format msgid "Note" msgstr "" @@ -381,7 +381,7 @@ msgstr "" msgid "Settings" msgstr "" -#: lib/mv_web/live/user_live/form.ex:235 +#: lib/mv_web/live/user_live/form.ex:249 #, elixir-autogen, elixir-format msgid "Save User" msgstr "" @@ -406,7 +406,7 @@ msgstr "" msgid "Use this form to manage user records in your database." msgstr "" -#: lib/mv_web/live/user_live/form.ex:252 +#: lib/mv_web/live/user_live/form.ex:266 #: lib/mv_web/live/user_live/show.ex:34 #, elixir-autogen, elixir-format msgid "User" @@ -434,7 +434,7 @@ msgstr "" msgid "descending" msgstr "" -#: lib/mv_web/live/user_live/form.ex:251 +#: lib/mv_web/live/user_live/form.ex:265 #, elixir-autogen, elixir-format msgid "New" msgstr "" @@ -705,6 +705,8 @@ msgstr "" #: lib/mv_web/live/custom_field_live/form.ex:64 #, elixir-autogen, elixir-format msgid "Show in overview" +msgstr "" + #: lib/mv_web/live/global_settings_live.ex:51 #, elixir-autogen, elixir-format msgid "Association Name" @@ -730,3 +732,53 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Settings updated successfully" msgstr "" + +#: lib/mv_web/live/user_live/form.ex:224 +#, elixir-autogen, elixir-format +msgid "A member with this email already exists. To link with a different member, please change one of the email addresses first." +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:192 +#, elixir-autogen, elixir-format +msgid "Available members" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:357 +#, elixir-autogen, elixir-format +msgid "Failed to link member: %{error}" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:152 +#, elixir-autogen, elixir-format +msgid "Member will be unlinked when you save. Cannot select new member until saved." +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:240 +#, elixir-autogen, elixir-format +msgid "Save to confirm linking." +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:171 +#, elixir-autogen, elixir-format +msgid "Search for a member to link..." +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:175 +#, elixir-autogen, elixir-format +msgid "Search for member to link" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:237 +#, elixir-autogen, elixir-format +msgid "Selected" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:143 +#, elixir-autogen, elixir-format +msgid "Unlink Member" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:152 +#, elixir-autogen, elixir-format +msgid "Unlinking scheduled" +msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 19be444..a9e59e8 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -17,7 +17,7 @@ msgid "Actions" msgstr "" #: lib/mv_web/live/member_live/index.html.heex:202 -#: lib/mv_web/live/user_live/index.html.heex:65 +#: lib/mv_web/live/user_live/index.html.heex:72 #, elixir-autogen, elixir-format msgid "Are you sure?" msgstr "" @@ -36,14 +36,14 @@ msgid "City" msgstr "" #: lib/mv_web/live/member_live/index.html.heex:204 -#: lib/mv_web/live/user_live/index.html.heex:67 +#: lib/mv_web/live/user_live/index.html.heex:74 #, elixir-autogen, elixir-format msgid "Delete" msgstr "" #: lib/mv_web/live/member_live/index.html.heex:196 -#: lib/mv_web/live/user_live/form.ex:141 -#: lib/mv_web/live/user_live/index.html.heex:59 +#: lib/mv_web/live/user_live/form.ex:265 +#: lib/mv_web/live/user_live/index.html.heex:66 #, elixir-autogen, elixir-format msgid "Edit" msgstr "" @@ -89,7 +89,7 @@ msgid "New Member" msgstr "" #: lib/mv_web/live/member_live/index.html.heex:193 -#: lib/mv_web/live/user_live/index.html.heex:56 +#: lib/mv_web/live/user_live/index.html.heex:63 #, elixir-autogen, elixir-format msgid "Show" msgstr "" @@ -163,7 +163,7 @@ msgstr "" #: lib/mv_web/live/custom_field_value_live/form.ex:74 #: lib/mv_web/live/global_settings_live.ex:55 #: lib/mv_web/live/member_live/form.ex:79 -#: lib/mv_web/live/user_live/form.ex:234 +#: lib/mv_web/live/user_live/form.ex:248 #, elixir-autogen, elixir-format msgid "Saving..." msgstr "" @@ -185,7 +185,7 @@ msgstr "" msgid "Id" msgstr "" -#: lib/mv_web/live/member_live/index/formatter.ex:65 +#: lib/mv_web/live/member_live/index/formatter.ex:61 #: lib/mv_web/live/member_live/show.ex:53 #, elixir-autogen, elixir-format msgid "No" @@ -201,7 +201,7 @@ msgstr "" msgid "This is a member record from your database." msgstr "" -#: lib/mv_web/live/member_live/index/formatter.ex:64 +#: lib/mv_web/live/member_live/index/formatter.ex:60 #: lib/mv_web/live/member_live/show.ex:53 #, elixir-autogen, elixir-format msgid "Yes" @@ -260,7 +260,7 @@ msgstr "" #: lib/mv_web/live/custom_field_live/index.ex:120 #: lib/mv_web/live/custom_field_value_live/form.ex:77 #: lib/mv_web/live/member_live/form.ex:82 -#: lib/mv_web/live/user_live/form.ex:237 +#: lib/mv_web/live/user_live/form.ex:251 #, elixir-autogen, elixir-format msgid "Cancel" msgstr "" @@ -312,7 +312,7 @@ msgid "Member" msgstr "" #: lib/mv_web/components/layouts/navbar.ex:25 -#: lib/mv_web/live/member_live/index.ex:39 +#: lib/mv_web/live/member_live/index.ex:57 #: lib/mv_web/live/member_live/index.html.heex:3 #, elixir-autogen, elixir-format msgid "Members" @@ -340,7 +340,7 @@ msgstr "" #: lib/mv_web/live/user_live/form.ex:107 #: lib/mv_web/live/user_live/form.ex:115 -#: lib/mv_web/live/user_live/form.ex:210 +#: lib/mv_web/live/user_live/form.ex:224 #, elixir-autogen, elixir-format, fuzzy msgid "Note" msgstr "" @@ -381,7 +381,7 @@ msgstr "" msgid "Settings" msgstr "" -#: lib/mv_web/live/user_live/form.ex:235 +#: lib/mv_web/live/user_live/form.ex:249 #, elixir-autogen, elixir-format, fuzzy msgid "Save User" msgstr "" @@ -406,7 +406,7 @@ msgstr "" msgid "Use this form to manage user records in your database." msgstr "" -#: lib/mv_web/live/user_live/form.ex:252 +#: lib/mv_web/live/user_live/form.ex:266 #: lib/mv_web/live/user_live/show.ex:34 #, elixir-autogen, elixir-format msgid "User" @@ -434,7 +434,7 @@ msgstr "" msgid "descending" msgstr "" -#: lib/mv_web/live/user_live/form.ex:251 +#: lib/mv_web/live/user_live/form.ex:265 #, elixir-autogen, elixir-format msgid "New" msgstr "" @@ -702,58 +702,11 @@ msgstr "" msgid "To confirm deletion, please enter this text:" msgstr "" -#: lib/mv_web/live/user_live/form.ex:210 -#, elixir-autogen, elixir-format -msgid "A member with this email already exists. To link with a different member, please change one of the email addresses first." -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:185 -#, elixir-autogen, elixir-format -msgid "Available members" -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:152 -#, elixir-autogen, elixir-format -msgid "Member will be unlinked when you save. Cannot select new member until saved." -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:226 -#, elixir-autogen, elixir-format -msgid "Save to confirm linking." -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:169 -#, elixir-autogen, elixir-format -msgid "Search for a member to link..." -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:173 -#, elixir-autogen, elixir-format -msgid "Search for member to link" -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:223 -#, elixir-autogen, elixir-format, fuzzy -msgid "Selected" -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:143 -#, elixir-autogen, elixir-format -msgid "Unlink Member" -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:152 -#, elixir-autogen, elixir-format -msgid "Unlinking scheduled" -msgstr "" - -#: lib/mv_web/live/user_live/form.ex:342 -#, elixir-autogen, elixir-format -msgid "Failed to link member: %{error}" -msgstr "" #: lib/mv_web/live/custom_field_live/form.ex:64 #, elixir-autogen, elixir-format msgid "Show in overview" +msgstr "" + #: lib/mv_web/live/global_settings_live.ex:51 #, elixir-autogen, elixir-format msgid "Association Name" @@ -780,6 +733,56 @@ msgstr "" msgid "Settings updated successfully" msgstr "" +#: lib/mv_web/live/user_live/form.ex:224 +#, elixir-autogen, elixir-format +msgid "A member with this email already exists. To link with a different member, please change one of the email addresses first." +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:192 +#, elixir-autogen, elixir-format +msgid "Available members" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:357 +#, elixir-autogen, elixir-format +msgid "Failed to link member: %{error}" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:152 +#, elixir-autogen, elixir-format +msgid "Member will be unlinked when you save. Cannot select new member until saved." +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:240 +#, elixir-autogen, elixir-format +msgid "Save to confirm linking." +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:171 +#, elixir-autogen, elixir-format +msgid "Search for a member to link..." +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:175 +#, elixir-autogen, elixir-format +msgid "Search for member to link" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:237 +#, elixir-autogen, elixir-format, fuzzy +msgid "Selected" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:143 +#, elixir-autogen, elixir-format +msgid "Unlink Member" +msgstr "" + +#: lib/mv_web/live/user_live/form.ex:152 +#, elixir-autogen, elixir-format +msgid "Unlinking scheduled" +msgstr "" + #~ #: lib/mv_web/live/custom_field_live/index.ex:97 #~ #, elixir-autogen, elixir-format #~ msgid "To confirm deletion, please enter the custom field slug:" diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index 00cf657..542e559 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -333,12 +333,6 @@ case Membership.get_settings() do {:ok, _updated} = Membership.update_settings(existing_settings, %{club_name: default_club_name}) end - - {:ok, nil} -> - # Settings don't exist, create them - Mv.Membership.Setting - |> Ash.Changeset.for_create(:create, %{club_name: default_club_name}) - |> Ash.create!(domain: Mv.Membership) end IO.puts("✅ Seeds completed successfully!")