From 9c2cff6307e2378c98d154ddb3f2e142b10a2cd5 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 15:38:06 +0100 Subject: [PATCH 1/9] docs: Update domain Public API documentation --- lib/accounts/accounts.ex | 9 +++++++++ lib/accounts/token.ex | 6 +++++- lib/membership/membership.ex | 4 ++-- lib/membership_fees/membership_fees.ex | 2 ++ lib/mv/authorization/authorization.ex | 2 +- lib/mv/membership/import/member_csv.ex | 12 ++++++++++-- lib/mv_web/controllers/page_controller.ex | 6 ++++++ lib/mv_web/live/member_live/form.ex | 2 +- 8 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lib/accounts/accounts.ex b/lib/accounts/accounts.ex index 7bc5073..13218e0 100644 --- a/lib/accounts/accounts.ex +++ b/lib/accounts/accounts.ex @@ -1,6 +1,15 @@ defmodule Mv.Accounts do @moduledoc """ AshAuthentication specific domain to handle Authentication for users. + + ## Resources + - `User` - User accounts with authentication methods (password, OIDC) + - `Token` - Session tokens for authentication + + ## Public API + The domain exposes these main actions: + - User CRUD: `create_user/1`, `list_users/0`, `update_user/2`, `destroy_user/1` + - Authentication: `create_register_with_rauthy/1`, `read_sign_in_with_rauthy/1` """ use Ash.Domain, extensions: [AshAdmin.Domain, AshPhoenix] diff --git a/lib/accounts/token.ex b/lib/accounts/token.ex index ab9c3a7..e76d8f1 100644 --- a/lib/accounts/token.ex +++ b/lib/accounts/token.ex @@ -1,6 +1,10 @@ defmodule Mv.Accounts.Token do @moduledoc """ - AshAuthentication specific ressource + AshAuthentication Token Resource for session management. + + This resource is used by AshAuthentication to manage authentication tokens + for user sessions. Tokens are automatically created and managed by the + authentication system. """ use Ash.Resource, data_layer: AshPostgres.DataLayer, diff --git a/lib/membership/membership.ex b/lib/membership/membership.ex index 982b837..97ac4be 100644 --- a/lib/membership/membership.ex +++ b/lib/membership/membership.ex @@ -12,8 +12,8 @@ defmodule Mv.Membership do 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` + - Custom field management: `create_custom_field/1`, `list_custom_fields/0`, `list_required_custom_fields/0`, etc. + - Settings management: `get_settings/0`, `update_settings/2`, `update_member_field_visibility/2`, `update_single_member_field_visibility/3` ## Admin Interface The domain is configured with AshAdmin for management UI. diff --git a/lib/membership_fees/membership_fees.ex b/lib/membership_fees/membership_fees.ex index 114f34c..37b4bc9 100644 --- a/lib/membership_fees/membership_fees.ex +++ b/lib/membership_fees/membership_fees.ex @@ -11,6 +11,8 @@ defmodule Mv.MembershipFees do - MembershipFeeType CRUD: `create_membership_fee_type/1`, `list_membership_fee_types/0`, `update_membership_fee_type/2`, `destroy_membership_fee_type/1` - MembershipFeeCycle CRUD: `create_membership_fee_cycle/1`, `list_membership_fee_cycles/0`, `update_membership_fee_cycle/2`, `destroy_membership_fee_cycle/1` + Note: LiveViews may use direct Ash calls instead of these domain functions for performance or flexibility. + ## Overview This domain handles the complete membership fee lifecycle including: - Fee type definitions (monthly, quarterly, half-yearly, yearly) diff --git a/lib/mv/authorization/authorization.ex b/lib/mv/authorization/authorization.ex index aac07a9..57942d1 100644 --- a/lib/mv/authorization/authorization.ex +++ b/lib/mv/authorization/authorization.ex @@ -7,7 +7,7 @@ defmodule Mv.Authorization do ## Public API The domain exposes these main actions: - - Role CRUD: `create_role/1`, `list_roles/0`, `update_role/2`, `destroy_role/1` + - Role CRUD: `create_role/1`, `list_roles/0`, `get_role/1`, `update_role/2`, `destroy_role/1` ## Admin Interface The domain is configured with AshAdmin for management UI. diff --git a/lib/mv/membership/import/member_csv.ex b/lib/mv/membership/import/member_csv.ex index 60cfadf..b4f4318 100644 --- a/lib/mv/membership/import/member_csv.ex +++ b/lib/mv/membership/import/member_csv.ex @@ -303,7 +303,9 @@ defmodule Mv.Membership.Import.MemberCSV do {inserted, failed, errors, _collected_error_count, truncated?} = Enum.reduce(chunk_rows_with_lines, {0, 0, [], 0, false}, fn {line_number, row_map}, - {acc_inserted, acc_failed, acc_errors, acc_error_count, acc_truncated?} -> + {acc_inserted, acc_failed, + acc_errors, acc_error_count, + acc_truncated?} -> current_error_count = existing_error_count + acc_error_count case process_row(row_map, line_number, custom_field_lookup) do @@ -325,7 +327,13 @@ defmodule Mv.Membership.Import.MemberCSV do end end) - {:ok, %{inserted: inserted, failed: failed, errors: Enum.reverse(errors), errors_truncated?: truncated?}} + {:ok, + %{ + inserted: inserted, + failed: failed, + errors: Enum.reverse(errors), + errors_truncated?: truncated? + }} end @doc """ diff --git a/lib/mv_web/controllers/page_controller.ex b/lib/mv_web/controllers/page_controller.ex index 6e1bc92..8cd38a6 100644 --- a/lib/mv_web/controllers/page_controller.ex +++ b/lib/mv_web/controllers/page_controller.ex @@ -1,4 +1,10 @@ defmodule MvWeb.PageController do + @moduledoc """ + Controller for rendering the homepage. + + This controller handles the root route and renders the application's + homepage view. + """ use MvWeb, :controller def home(conn, _params) do diff --git a/lib/mv_web/live/member_live/form.ex b/lib/mv_web/live/member_live/form.ex index b319fa1..c0b034e 100644 --- a/lib/mv_web/live/member_live/form.ex +++ b/lib/mv_web/live/member_live/form.ex @@ -13,7 +13,7 @@ defmodule MvWeb.MemberLive.Form do ## Form Sections - Personal Data: Name, address, contact information, membership dates, notes - Custom Fields: Dynamic fields in uniform grid layout (displayed sorted by name) - - Payment Data: Mockup section (not editable) + - Membership Fee: Selection of membership fee type with interval validation ## Events - `validate` - Real-time form validation -- 2.47.2 From cafd1d4ebc310d4741d241503a1dbbd31996eb7b Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 15:38:09 +0100 Subject: [PATCH 2/9] refactor: Remove deprecated LiveViews - Remove CustomFieldValueLive (Index, Form, Show) - Remove ContributionTypeLive.Index - Remove ContributionPeriodLive.Show - Remove corresponding routes from router - Remove references in CustomFieldValueLive.Index --- .../live/contribution_period_live/show.ex | 345 ------------------ .../live/contribution_type_live/index.ex | 205 ----------- .../live/custom_field_value_live/form.ex | 300 --------------- .../live/custom_field_value_live/index.ex | 157 -------- .../live/custom_field_value_live/show.ex | 67 ---- lib/mv_web/router.ex | 10 - test/mv_web/live/profile_navigation_test.exs | 2 - 7 files changed, 1086 deletions(-) delete mode 100644 lib/mv_web/live/contribution_period_live/show.ex delete mode 100644 lib/mv_web/live/contribution_type_live/index.ex delete mode 100644 lib/mv_web/live/custom_field_value_live/form.ex delete mode 100644 lib/mv_web/live/custom_field_value_live/index.ex delete mode 100644 lib/mv_web/live/custom_field_value_live/show.ex diff --git a/lib/mv_web/live/contribution_period_live/show.ex b/lib/mv_web/live/contribution_period_live/show.ex deleted file mode 100644 index b6a2574..0000000 --- a/lib/mv_web/live/contribution_period_live/show.ex +++ /dev/null @@ -1,345 +0,0 @@ -defmodule MvWeb.ContributionPeriodLive.Show do - @moduledoc """ - Mock-up LiveView for Member Contribution Periods (Admin/Treasurer View). - - This is a preview-only page that displays the planned UI for viewing - and managing contribution periods for a specific member. - It shows static mock data and is not functional. - - ## Planned Features (Future Implementation) - - Display all contribution periods for a member - - Show period dates, interval, amount, and status - - Quick status change (paid/unpaid/suspended) - - Bulk marking of multiple periods - - Notes per period - - ## Note - This page is intentionally non-functional and serves as a UI mockup - for the upcoming Membership Contributions feature. - """ - use MvWeb, :live_view - - @impl true - def mount(_params, _session, socket) do - {:ok, - socket - |> assign(:page_title, gettext("Member Contributions")) - |> assign(:member, mock_member()) - |> assign(:periods, mock_periods()) - |> assign(:selected_periods, MapSet.new())} - end - - @impl true - def render(assigns) do - ~H""" - - <.mockup_warning /> - - <.header> - {gettext("Contributions for %{name}", name: MvWeb.Helpers.MemberHelpers.display_name(@member))} - <:subtitle> - {gettext("Contribution type")}: - {@member.contribution_type} - · {gettext("Member since")}: {@member.joined_at} - - <:actions> - <.link navigate={~p"/membership_fee_settings"} class="btn btn-ghost btn-sm"> - <.icon name="hero-arrow-left" class="size-4" /> - {gettext("Back to Settings")} - - - - - <%!-- Member Info Card --%> -
-
-
-
- {gettext("Email")} -

{@member.email}

-
-
- {gettext("Contribution Start")} -

{@member.contribution_start}

-
-
- {gettext("Total Contributions")} -

{length(@periods)}

-
-
- {gettext("Open Contributions")} -

- {Enum.count(@periods, &(&1.status == :unpaid))} -

-
-
-
-
- - <%!-- Contribution Type Change --%> -
-
-
- {gettext("Change Contribution Type")}: - - - <.icon name="hero-question-mark-circle" class="inline size-4" /> - {gettext("Why are not all contribution types shown?")} - -
-
-
- - <%!-- Bulk Actions --%> -
- - {ngettext( - "%{count} period selected", - "%{count} periods selected", - MapSet.size(@selected_periods), - count: MapSet.size(@selected_periods) - )} - - - - -
- - <%!-- Periods Table --%> -
- - - - - - - - - - - - - - - - - - - - - - - -
- - {gettext("Time Period")}{gettext("Interval")}{gettext("Amount")}{gettext("Status")}{gettext("Notes")}{gettext("Actions")}
- - -
- {period.period_start} – {period.period_end} -
-
- {gettext("Current")} -
-
- {format_interval(period.interval)} - - {format_currency(period.amount)} - - <.status_badge status={period.status} /> - - - {period.notes} - - - -
- <.link - href="#" - class={[ - "cursor-not-allowed", - if(period.status == :paid, do: "invisible", else: "opacity-50") - ]} - > - {gettext("Paid")} - - <.link - href="#" - class={[ - "cursor-not-allowed", - if(period.status == :suspended, do: "invisible", else: "opacity-50") - ]} - > - {gettext("Suspend")} - - <.link - href="#" - class={[ - "cursor-not-allowed", - if(period.status != :paid, do: "invisible", else: "opacity-50") - ]} - > - {gettext("Reopen")} - - <.link href="#" class="opacity-50 cursor-not-allowed"> - {gettext("Note")} - -
-
-
-
- """ - end - - # Mock-up warning banner component - subtle orange style - defp mockup_warning(assigns) do - ~H""" -
- <.icon name="hero-exclamation-triangle" class="size-5 shrink-0" /> -
- {gettext("Preview Mockup")} - - – {gettext("This page is not functional and only displays the planned features.")} - -
-
- """ - end - - # Status badge component - attr :status, :atom, required: true - - defp status_badge(%{status: :paid} = assigns) do - ~H""" - - <.icon name="hero-check-circle-mini" class="size-3" /> - {gettext("Paid")} - - """ - end - - defp status_badge(%{status: :unpaid} = assigns) do - ~H""" - - <.icon name="hero-x-circle-mini" class="size-3" /> - {gettext("Unpaid")} - - """ - end - - defp status_badge(%{status: :suspended} = assigns) do - ~H""" - - <.icon name="hero-pause-circle-mini" class="size-3" /> - {gettext("Suspended")} - - """ - end - - defp period_row_class(:unpaid), do: "bg-error/5" - defp period_row_class(:suspended), do: "bg-base-200/50" - defp period_row_class(_), do: "" - - # Mock member data - defp mock_member do - %{ - id: "123", - first_name: "Maria", - last_name: "Weber", - email: "maria.weber@example.de", - contribution_type: gettext("Regular"), - joined_at: "15.03.2021", - contribution_start: "01.01.2021" - } - end - - # Mock periods data - defp mock_periods do - [ - %{ - id: "p1", - period_start: "01.01.2025", - period_end: "31.12.2025", - interval: :yearly, - amount: Decimal.new("60.00"), - status: :unpaid, - notes: nil, - is_current: true - }, - %{ - id: "p2", - period_start: "01.01.2024", - period_end: "31.12.2024", - interval: :yearly, - amount: Decimal.new("60.00"), - status: :paid, - notes: gettext("Paid via bank transfer"), - is_current: false - }, - %{ - id: "p3", - period_start: "01.01.2023", - period_end: "31.12.2023", - interval: :yearly, - amount: Decimal.new("50.00"), - status: :paid, - notes: nil, - is_current: false - }, - %{ - id: "p4", - period_start: "01.01.2022", - period_end: "31.12.2022", - interval: :yearly, - amount: Decimal.new("50.00"), - status: :paid, - notes: nil, - is_current: false - }, - %{ - id: "p5", - period_start: "01.01.2021", - period_end: "31.12.2021", - interval: :yearly, - amount: Decimal.new("50.00"), - status: :suspended, - notes: gettext("Joining year - reduced to 0"), - is_current: false - } - ] - end - - defp format_currency(%Decimal{} = amount) do - "#{Decimal.to_string(amount)} €" - end - - defp format_interval(:monthly), do: gettext("Monthly") - defp format_interval(:quarterly), do: gettext("Quarterly") - defp format_interval(:half_yearly), do: gettext("Half-yearly") - defp format_interval(:yearly), do: gettext("Yearly") -end diff --git a/lib/mv_web/live/contribution_type_live/index.ex b/lib/mv_web/live/contribution_type_live/index.ex deleted file mode 100644 index 3e2f04c..0000000 --- a/lib/mv_web/live/contribution_type_live/index.ex +++ /dev/null @@ -1,205 +0,0 @@ -defmodule MvWeb.ContributionTypeLive.Index do - @moduledoc """ - Mock-up LiveView for Contribution Types Management (Admin). - - This is a preview-only page that displays the planned UI for managing - contribution types. It shows static mock data and is not functional. - - ## Planned Features (Future Implementation) - - List all contribution types - - Display: Name, Amount, Interval, Member count - - Create new contribution types - - Edit existing contribution types (name, amount, description - NOT interval) - - Delete contribution types (if no members assigned) - - ## Note - This page is intentionally non-functional and serves as a UI mockup - for the upcoming Membership Contributions feature. - """ - use MvWeb, :live_view - - @impl true - def mount(_params, _session, socket) do - {:ok, - socket - |> assign(:page_title, gettext("Contribution Types")) - |> assign(:contribution_types, mock_contribution_types())} - end - - @impl true - def render(assigns) do - ~H""" - - <.mockup_warning /> - - <.header> - {gettext("Contribution Types")} - <:subtitle> - {gettext("Manage contribution types for membership fees.")} - - <:actions> - - - - - <.table id="contribution_types" rows={@contribution_types} row_id={fn ct -> "ct-#{ct.id}" end}> - <:col :let={ct} label={gettext("Name")}> - {ct.name} -

{ct.description}

- - - <:col :let={ct} label={gettext("Amount")}> - {format_currency(ct.amount)} - - - <:col :let={ct} label={gettext("Interval")}> - {format_interval(ct.interval)} - - - <:col :let={ct} label={gettext("Members")}> - {ct.member_count} - - - <:action :let={_ct}> - - - - <:action :let={ct}> - - - - - <.info_card /> -
- """ - end - - # Mock-up warning banner component - subtle orange style - defp mockup_warning(assigns) do - ~H""" -
- <.icon name="hero-exclamation-triangle" class="size-5 shrink-0" /> -
- {gettext("Preview Mockup")} - - – {gettext("This page is not functional and only displays the planned features.")} - -
-
- """ - end - - # Info card explaining the contribution type concept - defp info_card(assigns) do - ~H""" -
-
-

- <.icon name="hero-information-circle" class="size-5" /> - {gettext("About Contribution Types")} -

-
-

- {gettext( - "Contribution types define different membership fee structures. Each type has a fixed cycle (monthly, quarterly, half-yearly, yearly) that cannot be changed after creation." - )} -

-
    -
  • - {gettext("Name & Amount")} - - {gettext("Can be changed at any time. Amount changes affect future periods only.")} -
  • -
  • - {gettext("Interval")} - - {gettext( - "Fixed after creation. Members can only switch between types with the same interval." - )} -
  • -
  • - {gettext("Deletion")} - - {gettext("Only possible if no members are assigned to this type.")} -
  • -
-
-
-
- """ - end - - # Mock data for demonstration - defp mock_contribution_types do - [ - %{ - id: "1", - name: gettext("Regular"), - description: gettext("Standard membership fee for regular members"), - amount: Decimal.new("60.00"), - interval: :yearly, - member_count: 45 - }, - %{ - id: "2", - name: gettext("Reduced"), - description: gettext("Reduced fee for unemployed, pensioners, or low income"), - amount: Decimal.new("30.00"), - interval: :yearly, - member_count: 12 - }, - %{ - id: "3", - name: gettext("Student"), - description: gettext("Monthly fee for students and trainees"), - amount: Decimal.new("5.00"), - interval: :monthly, - member_count: 8 - }, - %{ - id: "4", - name: gettext("Family"), - description: gettext("Quarterly fee for family memberships"), - amount: Decimal.new("25.00"), - interval: :quarterly, - member_count: 15 - }, - %{ - id: "5", - name: gettext("Supporting Member"), - description: gettext("Half-yearly contribution for supporting members"), - amount: Decimal.new("100.00"), - interval: :half_yearly, - member_count: 3 - }, - %{ - id: "6", - name: gettext("Honorary"), - description: gettext("No fee for honorary members"), - amount: Decimal.new("0.00"), - interval: :yearly, - member_count: 2 - } - ] - end - - defp format_currency(%Decimal{} = amount) do - "#{Decimal.to_string(amount)} €" - end - - defp format_interval(:monthly), do: gettext("Monthly") - defp format_interval(:quarterly), do: gettext("Quarterly") - defp format_interval(:half_yearly), do: gettext("Half-yearly") - defp format_interval(:yearly), do: gettext("Yearly") -end diff --git a/lib/mv_web/live/custom_field_value_live/form.ex b/lib/mv_web/live/custom_field_value_live/form.ex deleted file mode 100644 index 599ce1d..0000000 --- a/lib/mv_web/live/custom_field_value_live/form.ex +++ /dev/null @@ -1,300 +0,0 @@ -defmodule MvWeb.CustomFieldValueLive.Form do - @moduledoc """ - LiveView form for creating and editing custom field values. - - ## Features - - Create new custom field values with member and type selection - - Edit existing custom field values - - Value input adapts to custom field type (string, integer, boolean, date, email) - - Real-time validation - - ## Form Fields - **Required:** - - member - Select which member owns this custom field value - - custom_field - Select the type (defines value type) - - value - The actual value (input type depends on custom field type) - - ## Value Types - The form dynamically renders appropriate inputs based on custom field type: - - String: text input - - Integer: number input - - Boolean: checkbox - - Date: date picker - - Email: email input with validation - - ## Events - - `validate` - Real-time form validation - - `save` - Submit form (create or update custom field value) - - ## Note - Custom field values are typically managed through the member edit form, - not through this standalone form. - """ - use MvWeb, :live_view - - on_mount {MvWeb.LiveHelpers, :ensure_user_role_loaded} - import MvWeb.LiveHelpers, only: [current_actor: 1, submit_form: 3] - - @impl true - def render(assigns) do - ~H""" - - <.header> - {@page_title} - <:subtitle> - {gettext("Use this form to manage Custom Field Value records in your database.")} - - - - <.form for={@form} id="custom_field_value-form" phx-change="validate" phx-submit="save"> - - <.input - field={@form[:custom_field_id]} - type="select" - label={gettext("Custom field")} - options={custom_field_options(@custom_fields)} - prompt={gettext("Choose a custom field")} - /> - - - <.input - field={@form[:member_id]} - type="select" - label={gettext("Member")} - options={member_options(@members)} - prompt={gettext("Choose a member")} - /> - - - <%= if @selected_custom_field do %> - <.union_value_input form={@form} custom_field={@selected_custom_field} /> - <% else %> -
- {gettext("Please select a custom field first")} -
- <% end %> - - <.button phx-disable-with={gettext("Saving...")} variant="primary"> - {gettext("Save Custom Field Value")} - - <.button navigate={return_path(@return_to, @custom_field_value)}>{gettext("Cancel")} - -
- """ - end - - # Helper function for Union-Value Input - defp union_value_input(assigns) do - # Extract the current value from the CustomFieldValue - current_value = extract_current_value(assigns.form.data, assigns.custom_field.value_type) - assigns = assign(assigns, :current_value, current_value) - - ~H""" -
- - - <%= case @custom_field.value_type do %> - <% :string -> %> - <.inputs_for :let={value_form} field={@form[:value]}> - <.input field={value_form[:value]} type="text" label="" value={@current_value} /> - - - <% :integer -> %> - <.inputs_for :let={value_form} field={@form[:value]}> - <.input field={value_form[:value]} type="number" label="" value={@current_value} /> - - - <% :boolean -> %> - <.inputs_for :let={value_form} field={@form[:value]}> - <.input field={value_form[:value]} type="checkbox" label="" checked={@current_value} /> - - - <% :date -> %> - <.inputs_for :let={value_form} field={@form[:value]}> - <.input - field={value_form[:value]} - type="date" - label="" - value={format_date_value(@current_value)} - /> - - - <% :email -> %> - <.inputs_for :let={value_form} field={@form[:value]}> - <.input field={value_form[:value]} type="email" label="" value={@current_value} /> - - - <% _ -> %> -
- {gettext("Unsupported value type: %{type}", type: @custom_field.value_type)} -
- <% end %> -
- """ - end - - # Helper function to extract the current value from the CustomFieldValue - defp extract_current_value( - %Mv.Membership.CustomFieldValue{value: %Ash.Union{value: value}}, - _value_type - ) do - value - end - - defp extract_current_value(_data, _value_type) do - nil - end - - # Helper function to format Date values for HTML input - defp format_date_value(%Date{} = date) do - Date.to_iso8601(date) - end - - defp format_date_value(nil), do: "" - - defp format_date_value(date) when is_binary(date) do - case Date.from_iso8601(date) do - {:ok, parsed_date} -> Date.to_iso8601(parsed_date) - _ -> "" - end - end - - defp format_date_value(_), do: "" - - @impl true - def mount(params, _session, socket) do - custom_field_value = - case params["id"] do - nil -> nil - id -> Ash.get!(Mv.Membership.CustomFieldValue, id) |> Ash.load!([:custom_field]) - end - - action = if is_nil(custom_field_value), do: "New", else: "Edit" - page_title = action <> " " <> "Custom field value" - - # Load all CustomFields and Members for the selection fields - actor = current_actor(socket) - custom_fields = Ash.read!(Mv.Membership.CustomField, actor: actor) - members = Ash.read!(Mv.Membership.Member, actor: actor) - - {:ok, - socket - |> assign(:return_to, return_to(params["return_to"])) - |> assign(custom_field_value: custom_field_value) - |> assign(:page_title, page_title) - |> assign(:custom_fields, custom_fields) - |> assign(:members, members) - |> assign(:selected_custom_field, custom_field_value && custom_field_value.custom_field) - |> assign_form()} - end - - defp return_to("show"), do: "show" - defp return_to(_), do: "index" - - @impl true - def handle_event("validate", %{"custom_field_value" => custom_field_value_params}, socket) do - # Find the selected CustomField - selected_custom_field = - case custom_field_value_params["custom_field_id"] do - "" -> nil - nil -> nil - id -> Enum.find(socket.assigns.custom_fields, &(&1.id == id)) - end - - # Set the Union type based on the selected CustomField - updated_params = - if selected_custom_field do - union_type = to_string(selected_custom_field.value_type) - put_in(custom_field_value_params, ["value", "_union_type"], union_type) - else - custom_field_value_params - end - - {:noreply, - socket - |> assign(:selected_custom_field, selected_custom_field) - |> assign(form: AshPhoenix.Form.validate(socket.assigns.form, updated_params))} - end - - def handle_event("save", %{"custom_field_value" => custom_field_value_params}, socket) do - # Set the Union type based on the selected CustomField - updated_params = - if socket.assigns.selected_custom_field do - union_type = to_string(socket.assigns.selected_custom_field.value_type) - put_in(custom_field_value_params, ["value", "_union_type"], union_type) - else - custom_field_value_params - end - - actor = current_actor(socket) - - case submit_form(socket.assigns.form, updated_params, actor) do - {:ok, custom_field_value} -> - notify_parent({:saved, custom_field_value}) - - action = - case socket.assigns.form.source.type do - :create -> gettext("create") - :update -> gettext("update") - other -> to_string(other) - end - - socket = - socket - |> put_flash( - :info, - gettext("Custom field value %{action} successfully", action: action) - ) - |> push_navigate(to: return_path(socket.assigns.return_to, custom_field_value)) - - {:noreply, socket} - - {:error, form} -> - {:noreply, assign(socket, form: form)} - end - end - - defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) - - defp assign_form(%{assigns: %{custom_field_value: custom_field_value}} = socket) do - form = - if custom_field_value do - # Determine the Union type based on the custom_field - union_type = custom_field_value.custom_field && custom_field_value.custom_field.value_type - - params = - if union_type do - %{"value" => %{"_union_type" => to_string(union_type)}} - else - %{} - end - - AshPhoenix.Form.for_update(custom_field_value, :update, - as: "custom_field_value", - params: params - ) - else - AshPhoenix.Form.for_create(Mv.Membership.CustomFieldValue, :create, - as: "custom_field_value" - ) - end - - assign(socket, form: to_form(form)) - end - - defp return_path("index", _custom_field_value), do: ~p"/custom_field_values" - - defp return_path("show", custom_field_value), - do: ~p"/custom_field_values/#{custom_field_value.id}" - - # Helper functions for selection options - defp custom_field_options(custom_fields) do - Enum.map(custom_fields, &{&1.name, &1.id}) - end - - defp member_options(members) do - Enum.map(members, &{MvWeb.Helpers.MemberHelpers.display_name(&1), &1.id}) - end -end diff --git a/lib/mv_web/live/custom_field_value_live/index.ex b/lib/mv_web/live/custom_field_value_live/index.ex deleted file mode 100644 index eea578e..0000000 --- a/lib/mv_web/live/custom_field_value_live/index.ex +++ /dev/null @@ -1,157 +0,0 @@ -defmodule MvWeb.CustomFieldValueLive.Index do - @moduledoc """ - LiveView for displaying and managing custom field values. - - ## Features - - List all custom field values with their values and types - - Show which member each custom field value belongs to - - Display custom field information - - Navigate to custom field value details and edit forms - - Delete custom field values - - ## Relationships - Each custom field value is linked to: - - A member (the custom field value owner) - - A custom field (defining value type and behavior) - - ## Events - - `delete` - Remove a custom field value from the database - - ## Note - Custom field values are typically managed through the member edit form. - This view provides a global overview of all custom field values. - """ - use MvWeb, :live_view - - on_mount {MvWeb.LiveHelpers, :ensure_user_role_loaded} - import MvWeb.LiveHelpers, only: [current_actor: 1] - - @impl true - def render(assigns) do - ~H""" - - <.header> - Listing Custom field values - <:actions> - <.button variant="primary" navigate={~p"/custom_field_values/new"}> - <.icon name="hero-plus" /> New Custom field value - - - - - <.table - id="custom_field_values" - rows={@streams.custom_field_values} - row_click={ - fn {_id, custom_field_value} -> - JS.navigate(~p"/custom_field_values/#{custom_field_value}") - end - } - > - <:col :let={{_id, custom_field_value}} label="Id">{custom_field_value.id} - - <:action :let={{_id, custom_field_value}}> -
- <.link navigate={~p"/custom_field_values/#{custom_field_value}"}>Show -
- - <.link navigate={~p"/custom_field_values/#{custom_field_value}/edit"}>Edit - - - <:action :let={{id, custom_field_value}}> - <.link - phx-click={JS.push("delete", value: %{id: custom_field_value.id}) |> hide("##{id}")} - data-confirm="Are you sure?" - > - Delete - - - -
- """ - end - - @impl true - def mount(_params, _session, socket) do - actor = current_actor(socket) - - # Early return if no actor (prevents exceptions in unauthenticated tests) - if is_nil(actor) do - {:ok, - socket - |> assign(:page_title, "Listing Custom field values") - |> stream(:custom_field_values, [])} - else - case Ash.read(Mv.Membership.CustomFieldValue, actor: actor) do - {:ok, custom_field_values} -> - {:ok, - socket - |> assign(:page_title, "Listing Custom field values") - |> stream(:custom_field_values, custom_field_values)} - - {:error, %Ash.Error.Forbidden{}} -> - {:ok, - socket - |> assign(:page_title, "Listing Custom field values") - |> stream(:custom_field_values, []) - |> put_flash(:error, gettext("You do not have permission to view custom field values"))} - - {:error, error} -> - {:ok, - socket - |> assign(:page_title, "Listing Custom field values") - |> stream(:custom_field_values, []) - |> put_flash(:error, format_error(error))} - end - end - end - - @impl true - def handle_event("delete", %{"id" => id}, socket) do - actor = MvWeb.LiveHelpers.current_actor(socket) - - case Ash.get(Mv.Membership.CustomFieldValue, id, actor: actor) do - {:ok, custom_field_value} -> - case Ash.destroy(custom_field_value, actor: actor) do - :ok -> - {:noreply, - socket - |> stream_delete(:custom_field_values, custom_field_value) - |> put_flash(:info, gettext("Custom field value deleted successfully"))} - - {:error, %Ash.Error.Forbidden{}} -> - {:noreply, - put_flash( - socket, - :error, - gettext("You do not have permission to delete this custom field value") - )} - - {:error, error} -> - {:noreply, put_flash(socket, :error, format_error(error))} - end - - {:error, %Ash.Error.Query.NotFound{}} -> - {:noreply, put_flash(socket, :error, gettext("Custom field value not found"))} - - {:error, %Ash.Error.Forbidden{} = _error} -> - {:noreply, - put_flash( - socket, - :error, - gettext("You do not have permission to access this custom field value") - )} - - {:error, error} -> - {:noreply, put_flash(socket, :error, format_error(error))} - end - end - - defp format_error(%Ash.Error.Invalid{errors: errors}) do - Enum.map_join(errors, ", ", fn %{message: message} -> message end) - end - - defp format_error(error) do - inspect(error) - end -end diff --git a/lib/mv_web/live/custom_field_value_live/show.ex b/lib/mv_web/live/custom_field_value_live/show.ex deleted file mode 100644 index 7a3f678..0000000 --- a/lib/mv_web/live/custom_field_value_live/show.ex +++ /dev/null @@ -1,67 +0,0 @@ -defmodule MvWeb.CustomFieldValueLive.Show do - @moduledoc """ - LiveView for displaying a single custom field value's details. - - ## Features - - Display custom field value and type - - Show linked member - - Show custom field definition - - Navigate to edit form - - Return to custom field value list - - ## Displayed Information - - Custom field value (formatted based on type) - - Custom field name and description - - Member information (who owns this custom field value) - - Custom field value metadata (ID, timestamps if added) - - ## Navigation - - Back to custom field value list - - Edit custom field value - """ - use MvWeb, :live_view - - @impl true - def render(assigns) do - ~H""" - - <.header> - Data field value {@custom_field_value.id} - <:subtitle>This is a custom_field_value record from your database. - - <:actions> - <.button navigate={~p"/custom_field_values"}> - <.icon name="hero-arrow-left" /> - - <.button - variant="primary" - navigate={~p"/custom_field_values/#{@custom_field_value}/edit?return_to=show"} - > - <.icon name="hero-pencil-square" /> Edit Custom field value - - - - - <.list> - <:item title="Id">{@custom_field_value.id} - - - """ - end - - @impl true - def mount(_params, _session, socket) do - {:ok, socket} - end - - @impl true - def handle_params(%{"id" => id}, _, socket) do - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:custom_field_value, Ash.get!(Mv.Membership.CustomFieldValue, id))} - end - - defp page_title(:show), do: "Show data field value" - defp page_title(:edit), do: "Edit data field value" -end diff --git a/lib/mv_web/router.ex b/lib/mv_web/router.ex index 682b672..79f4791 100644 --- a/lib/mv_web/router.ex +++ b/lib/mv_web/router.ex @@ -58,12 +58,6 @@ defmodule MvWeb.Router do live "/members/:id", MemberLive.Show, :show live "/members/:id/show/edit", MemberLive.Show, :edit - live "/custom_field_values", CustomFieldValueLive.Index, :index - live "/custom_field_values/new", CustomFieldValueLive.Form, :new - live "/custom_field_values/:id/edit", CustomFieldValueLive.Form, :edit - live "/custom_field_values/:id", CustomFieldValueLive.Show, :show - live "/custom_field_values/:id/show/edit", CustomFieldValueLive.Show, :edit - live "/users", UserLive.Index, :index live "/users/new", UserLive.Form, :new live "/users/:id/edit", UserLive.Form, :edit @@ -80,10 +74,6 @@ defmodule MvWeb.Router do live "/membership_fee_types/new", MembershipFeeTypeLive.Form, :new live "/membership_fee_types/:id/edit", MembershipFeeTypeLive.Form, :edit - # Contribution Management (Mock-ups) - live "/contribution_types", ContributionTypeLive.Index, :index - live "/contributions/member/:id", ContributionPeriodLive.Show, :show - # Role Management (Admin only) live "/admin/roles", RoleLive.Index, :index live "/admin/roles/new", RoleLive.Form, :new diff --git a/test/mv_web/live/profile_navigation_test.exs b/test/mv_web/live/profile_navigation_test.exs index 849d229..cac6802 100644 --- a/test/mv_web/live/profile_navigation_test.exs +++ b/test/mv_web/live/profile_navigation_test.exs @@ -146,8 +146,6 @@ defmodule MvWeb.ProfileNavigationTest do "/", "/members", "/members/new", - "/custom_field_values", - "/custom_field_values/new", "/users", "/users/new" ] -- 2.47.2 From 32e0adb6649b49e95c2fe86ae3530360485d89f6 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 15:38:11 +0100 Subject: [PATCH 3/9] test: Add tests for UserLive.Show and RoleLive.Show - Add comprehensive tests for UserLive.Show - Add comprehensive tests for RoleLive.Show - Cover mount, display, navigation, and error handling --- test/mv_web/live/role_live/show_test.exs | 274 +++++++++++++++++++++++ test/mv_web/live/user_live/show_test.exs | 155 +++++++++++++ 2 files changed, 429 insertions(+) create mode 100644 test/mv_web/live/role_live/show_test.exs create mode 100644 test/mv_web/live/user_live/show_test.exs diff --git a/test/mv_web/live/role_live/show_test.exs b/test/mv_web/live/role_live/show_test.exs new file mode 100644 index 0000000..2c56347 --- /dev/null +++ b/test/mv_web/live/role_live/show_test.exs @@ -0,0 +1,274 @@ +defmodule MvWeb.RoleLive.ShowTest do + @moduledoc """ + Tests for the role show page. + + Tests cover: + - Displaying role information + - System role badge display + - User count display + - Navigation + - Error handling + - Delete functionality + """ + use MvWeb.ConnCase, async: false + import Phoenix.LiveViewTest + require Ash.Query + use Gettext, backend: MvWeb.Gettext + + alias Mv.Authorization + alias Mv.Authorization.Role + + # Helper to create a role + defp create_role(attrs \\ %{}) do + default_attrs = %{ + name: "Test Role #{System.unique_integer([:positive])}", + description: "Test description", + permission_set_name: "read_only" + } + + attrs = Map.merge(default_attrs, attrs) + + case Authorization.create_role(attrs) do + {:ok, role} -> role + {:error, error} -> raise "Failed to create role: #{inspect(error)}" + end + end + + # Helper to create admin user with admin role + defp create_admin_user(conn) do + # Create admin role + admin_role = + case Authorization.list_roles() do + {:ok, roles} -> + case Enum.find(roles, &(&1.name == "Admin")) do + nil -> + # Create admin role if it doesn't exist + create_role(%{ + name: "Admin", + description: "Administrator with full access", + permission_set_name: "admin" + }) + + role -> + role + end + + _ -> + # Create admin role if list_roles fails + create_role(%{ + name: "Admin", + description: "Administrator with full access", + permission_set_name: "admin" + }) + end + + # Create user + {:ok, user} = + Mv.Accounts.User + |> Ash.Changeset.for_create(:register_with_password, %{ + email: "admin#{System.unique_integer([:positive])}@mv.local", + password: "testpassword123" + }) + |> Ash.create() + + # Assign admin role using manage_relationship + {:ok, user} = + user + |> Ash.Changeset.for_update(:update, %{}) + |> Ash.Changeset.manage_relationship(:role, admin_role, type: :append_and_remove) + |> Ash.update() + + # Load role for authorization checks (must be loaded for can?/3 to work) + user_with_role = Ash.load!(user, :role, domain: Mv.Accounts) + + # Store user with role in session for LiveView + conn = conn_with_password_user(conn, user_with_role) + {conn, user_with_role, admin_role} + end + + describe "mount and display" do + setup %{conn: conn} do + {conn, _user, _admin_role} = create_admin_user(conn) + %{conn: conn} + end + + test "mounts successfully with valid role ID", %{conn: conn} do + role = create_role() + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + assert html =~ role.name + end + + test "displays role name", %{conn: conn} do + role = create_role(%{name: "Test Role Name"}) + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + assert html =~ "Test Role Name" + assert html =~ gettext("Name") + end + + test "displays role description when present", %{conn: conn} do + role = create_role(%{description: "This is a test description"}) + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + assert html =~ "This is a test description" + assert html =~ gettext("Description") + end + + test "displays 'No description' when description is missing", %{conn: conn} do + role = create_role(%{description: nil}) + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + assert html =~ gettext("No description") + end + + test "displays permission set name", %{conn: conn} do + role = create_role(%{permission_set_name: "read_only"}) + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + assert html =~ "read_only" + assert html =~ gettext("Permission Set") + end + + test "displays system role badge when is_system_role is true", %{conn: conn} do + system_role = + Role + |> Ash.Changeset.for_create(:create_role, %{ + name: "System Role", + permission_set_name: "own_data" + }) + |> Ash.Changeset.force_change_attribute(:is_system_role, true) + |> Ash.create!() + + {:ok, _view, html} = live(conn, "/admin/roles/#{system_role.id}") + + assert html =~ gettext("System Role") + assert html =~ gettext("Yes") + end + + test "displays non-system role badge when is_system_role is false", %{conn: conn} do + role = create_role() + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + assert html =~ gettext("System Role") + assert html =~ gettext("No") + end + + test "displays user count", %{conn: conn} do + role = create_role() + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + # User count should be displayed (might be 0 or more) + assert html =~ gettext("User") || html =~ "0" || html =~ "users" + end + end + + describe "navigation" do + setup %{conn: conn} do + {conn, _user, _admin_role} = create_admin_user(conn) + %{conn: conn} + end + + test "back button navigates to role list", %{conn: conn} do + role = create_role() + + {:ok, view, _html} = live(conn, "/admin/roles/#{role.id}") + + assert {:error, {:live_redirect, %{to: to}}} = + view + |> element( + "a[aria-label='#{gettext("Back to roles list")}'], button[aria-label='#{gettext("Back to roles list")}']" + ) + |> render_click() + + assert to == "/admin/roles" + end + + test "edit button navigates to edit form", %{conn: conn} do + role = create_role() + + {:ok, view, _html} = live(conn, "/admin/roles/#{role.id}") + + assert {:error, {:live_redirect, %{to: to}}} = + view + |> element( + "a[href='/admin/roles/#{role.id}/edit'], button[href='/admin/roles/#{role.id}/edit']" + ) + |> render_click() + + assert to == "/admin/roles/#{role.id}/edit" + end + end + + describe "error handling" do + setup %{conn: conn} do + {conn, _user, _admin_role} = create_admin_user(conn) + %{conn: conn} + end + + test "redirects to role list with error for invalid role ID", %{conn: conn} do + invalid_id = Ecto.UUID.generate() + + # Should redirect to index with error message + result = live(conn, "/admin/roles/#{invalid_id}") + + assert match?({:error, {:redirect, %{to: "/admin/roles"}}}, result) or + match?({:error, {:live_redirect, %{to: "/admin/roles"}}}, result) + end + end + + describe "delete functionality" do + setup %{conn: conn} do + {conn, _user, _admin_role} = create_admin_user(conn) + %{conn: conn} + end + + test "delete button is not shown for system roles", %{conn: conn} do + system_role = + Role + |> Ash.Changeset.for_create(:create_role, %{ + name: "System Role", + permission_set_name: "own_data" + }) + |> Ash.Changeset.force_change_attribute(:is_system_role, true) + |> Ash.create!() + + {:ok, _view, html} = live(conn, "/admin/roles/#{system_role.id}") + + # Delete button should not be visible for system roles + refute html =~ ~r/Delete.*Role.*#{system_role.id}/i + end + + test "delete button is shown for non-system roles", %{conn: conn} do + role = create_role() + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + # Delete button should be visible for non-system roles + assert html =~ gettext("Delete Role") || html =~ "delete" + end + end + + describe "page title" do + setup %{conn: conn} do + {conn, _user, _admin_role} = create_admin_user(conn) + %{conn: conn} + end + + test "sets correct page title", %{conn: conn} do + role = create_role() + + {:ok, _view, html} = live(conn, "/admin/roles/#{role.id}") + + # Check that page title is set (might be in title tag or header) + assert html =~ gettext("Show Role") || html =~ role.name + end + end +end diff --git a/test/mv_web/live/user_live/show_test.exs b/test/mv_web/live/user_live/show_test.exs new file mode 100644 index 0000000..054640c --- /dev/null +++ b/test/mv_web/live/user_live/show_test.exs @@ -0,0 +1,155 @@ +defmodule MvWeb.UserLive.ShowTest do + @moduledoc """ + Tests for the user show page. + + Tests cover: + - Displaying user information + - Authentication status display + - Linked member display + - Navigation + - Error handling + """ + use MvWeb.ConnCase, async: true + import Phoenix.LiveViewTest + require Ash.Query + use Gettext, backend: MvWeb.Gettext + + alias Mv.Membership.Member + + setup do + # Create test user + user = create_test_user(%{email: "test@example.com", oidc_id: "test123"}) + %{user: user} + end + + describe "mount and display" do + test "mounts successfully with valid user ID", %{conn: conn, user: user} do + conn = conn_with_oidc_user(conn) + {:ok, _view, html} = live(conn, ~p"/users/#{user.id}") + + assert html =~ to_string(user.email) + end + + test "displays user email", %{conn: conn, user: user} do + conn = conn_with_oidc_user(conn) + {:ok, _view, html} = live(conn, ~p"/users/#{user.id}") + + assert html =~ to_string(user.email) + assert html =~ gettext("Email") + end + + test "displays password authentication status when enabled", %{conn: conn} do + user = create_test_user(%{email: "password-user@example.com", password: "test123"}) + conn = conn_with_oidc_user(conn) + {:ok, _view, html} = live(conn, ~p"/users/#{user.id}") + + assert html =~ gettext("Password Authentication") + assert html =~ gettext("Enabled") + end + + test "displays password authentication status when not enabled", %{conn: conn} do + # User without password (only OIDC) - create user with OIDC only + user = + create_test_user(%{ + email: "oidc-only#{System.unique_integer([:positive])}@example.com", + oidc_id: "oidc#{System.unique_integer([:positive])}", + hashed_password: nil + }) + + conn = conn_with_oidc_user(conn) + {:ok, _view, html} = live(conn, ~p"/users/#{user.id}") + + assert html =~ gettext("Password Authentication") + assert html =~ gettext("Not enabled") + end + + test "displays linked member when present", %{conn: conn} do + # Create member + {:ok, member} = + Member + |> Ash.Changeset.for_create(:create_member, %{ + first_name: "Alice", + last_name: "Smith", + email: "alice@example.com" + }) + |> Ash.create() + + # Create user and link to member + user = create_test_user(%{email: "user@example.com"}) + + {:ok, _updated_user} = + user + |> Ash.Changeset.for_update(:update, %{}) + |> Ash.Changeset.manage_relationship(:member, member, type: :append_and_remove) + |> Ash.update() + + conn = conn_with_oidc_user(conn) + {:ok, _view, html} = live(conn, ~p"/users/#{user.id}") + + assert html =~ gettext("Linked Member") + assert html =~ "Alice Smith" + assert html =~ ~r/href="[^"]*\/members\/#{member.id}"/ + end + + test "displays 'No member linked' when no member is linked", %{conn: conn, user: user} do + conn = conn_with_oidc_user(conn) + {:ok, _view, html} = live(conn, ~p"/users/#{user.id}") + + assert html =~ gettext("Linked Member") + assert html =~ gettext("No member linked") + end + end + + describe "navigation" do + test "back button navigates to user list", %{conn: conn, user: user} do + conn = conn_with_oidc_user(conn) + {:ok, view, _html} = live(conn, ~p"/users/#{user.id}") + + assert {:error, {:live_redirect, %{to: to}}} = + view + |> element( + "a[aria-label='#{gettext("Back to users list")}'], button[aria-label='#{gettext("Back to users list")}']" + ) + |> render_click() + + assert to == "/users" + end + + test "edit button navigates to edit form", %{conn: conn, user: user} do + conn = conn_with_oidc_user(conn) + {:ok, view, _html} = live(conn, ~p"/users/#{user.id}") + + assert {:error, {:live_redirect, %{to: to}}} = + view + |> element( + "a[href='/users/#{user.id}/edit?return_to=show'], button[href='/users/#{user.id}/edit?return_to=show']" + ) + |> render_click() + + assert to == "/users/#{user.id}/edit?return_to=show" + end + end + + describe "error handling" do + test "raises exception for invalid user ID", %{conn: conn} do + invalid_id = Ecto.UUID.generate() + conn = conn_with_oidc_user(conn) + + # The mount function uses Ash.get! which will raise an exception + # This is expected behavior - the LiveView doesn't handle this case + assert_raise Ash.Error.Invalid, fn -> + live(conn, ~p"/users/#{invalid_id}") + end + end + end + + describe "page title" do + test "sets correct page title", %{conn: conn, user: user} do + conn = conn_with_oidc_user(conn) + {:ok, _view, html} = live(conn, ~p"/users/#{user.id}") + + # Check that page title is set (might be in title tag or header) + assert html =~ gettext("Show User") || html =~ to_string(user.email) + end + end +end -- 2.47.2 From 0abcf540bb7c9696673b21cb1ce0d759a3c2dc72 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 15:58:15 +0100 Subject: [PATCH 4/9] refactor: Replace length/1 with empty list comparison Replace expensive length/1 calls with direct list comparison to fix Credo warnings about performance --- lib/mv_web/live/member_live/form.ex | 2 +- test/mv/membership/import/member_csv_test.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mv_web/live/member_live/form.ex b/lib/mv_web/live/member_live/form.ex index c0b034e..f07be75 100644 --- a/lib/mv_web/live/member_live/form.ex +++ b/lib/mv_web/live/member_live/form.ex @@ -403,7 +403,7 @@ defmodule MvWeb.MemberLive.Form do # Checks if form has any errors defp has_form_errors?(form) do case Map.get(form, :errors) do - errors when is_list(errors) and length(errors) > 0 -> true + errors when is_list(errors) and errors != [] -> true _ -> false end end diff --git a/test/mv/membership/import/member_csv_test.exs b/test/mv/membership/import/member_csv_test.exs index b5af238..98943d5 100644 --- a/test/mv/membership/import/member_csv_test.exs +++ b/test/mv/membership/import/member_csv_test.exs @@ -404,7 +404,7 @@ defmodule Mv.Membership.Import.MemberCSVTest do assert chunk_result.inserted == 0 assert chunk_result.failed == 10 - assert length(chunk_result.errors) == 0 + assert chunk_result.errors == [] end test "error capping with mixed success and failure" do -- 2.47.2 From 433f008af8340e287c6b20e4e020a419261eb72a Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 16:05:09 +0100 Subject: [PATCH 5/9] refactor: Reduce function complexity and nesting depth - Extract helper functions from process_chunk to reduce nesting - Extract format_error_message from extract_changeset_error - Split extract_error_message into smaller functions to reduce complexity - Fixes Credo refactoring opportunities --- lib/mv/membership/import/member_csv.ex | 79 +++++++++++++++++------- lib/mv_web/live/member_live/form.ex | 83 ++++++++++++++++---------- 2 files changed, 107 insertions(+), 55 deletions(-) diff --git a/lib/mv/membership/import/member_csv.ex b/lib/mv/membership/import/member_csv.ex index b4f4318..d56c56e 100644 --- a/lib/mv/membership/import/member_csv.ex +++ b/lib/mv/membership/import/member_csv.ex @@ -302,28 +302,15 @@ defmodule Mv.Membership.Import.MemberCSV do max_errors = Keyword.get(opts, :max_errors, 50) {inserted, failed, errors, _collected_error_count, truncated?} = - Enum.reduce(chunk_rows_with_lines, {0, 0, [], 0, false}, fn {line_number, row_map}, - {acc_inserted, acc_failed, - acc_errors, acc_error_count, - acc_truncated?} -> - current_error_count = existing_error_count + acc_error_count + Enum.reduce(chunk_rows_with_lines, {0, 0, [], 0, false}, fn {line_number, row_map}, acc -> + current_error_count = existing_error_count + elem(acc, 3) case process_row(row_map, line_number, custom_field_lookup) do {:ok, _member} -> - {acc_inserted + 1, acc_failed, acc_errors, acc_error_count, acc_truncated?} + update_inserted(acc) {:error, error} -> - new_acc_failed = acc_failed + 1 - - # Only collect errors if under limit - {new_acc_errors, new_error_count, new_truncated?} = - if current_error_count < max_errors do - {[error | acc_errors], acc_error_count + 1, acc_truncated?} - else - {acc_errors, acc_error_count, true} - end - - {acc_inserted, new_acc_failed, new_acc_errors, new_error_count, new_truncated?} + handle_row_error(acc, error, current_error_count, max_errors) end end) @@ -397,11 +384,9 @@ defmodule Mv.Membership.Import.MemberCSV do # Extracts the first error from a changeset and converts it to a MemberCSV.Error struct defp extract_changeset_error(changeset, csv_line_number) do - case Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> - Enum.reduce(opts, msg, fn {key, value}, acc -> - String.replace(acc, "%{#{key}}", to_string(value)) - end) - end) do + errors = Ecto.Changeset.traverse_errors(changeset, &format_error_message/1) + + case errors do %{email: [message | _]} -> # Email-specific error %Error{ @@ -430,6 +415,56 @@ defmodule Mv.Membership.Import.MemberCSV do end end + # Helper function to update accumulator when row is successfully inserted + defp update_inserted({acc_inserted, acc_failed, acc_errors, acc_error_count, acc_truncated?}) do + {acc_inserted + 1, acc_failed, acc_errors, acc_error_count, acc_truncated?} + end + + # Helper function to handle row error with error count limit checking + defp handle_row_error( + {acc_inserted, acc_failed, acc_errors, acc_error_count, acc_truncated?}, + error, + current_error_count, + max_errors + ) do + new_acc_failed = acc_failed + 1 + + {new_acc_errors, new_error_count, new_truncated?} = + collect_error_if_under_limit( + error, + acc_errors, + acc_error_count, + acc_truncated?, + current_error_count, + max_errors + ) + + {acc_inserted, new_acc_failed, new_acc_errors, new_error_count, new_truncated?} + end + + # Helper function to collect error only if under limit + defp collect_error_if_under_limit( + error, + acc_errors, + acc_error_count, + acc_truncated?, + current_error_count, + max_errors + ) do + if current_error_count < max_errors do + {[error | acc_errors], acc_error_count + 1, acc_truncated?} + else + {acc_errors, acc_error_count, true} + end + end + + # Formats error message by replacing placeholders + defp format_error_message({msg, opts}) do + Enum.reduce(opts, msg, fn {key, value}, acc -> + String.replace(acc, "%{#{key}}", to_string(value)) + end) + end + # Maps changeset error messages to appropriate Gettext messages defp gettext_error_message(message) when is_binary(message) do cond do diff --git a/lib/mv_web/live/member_live/form.ex b/lib/mv_web/live/member_live/form.ex index f07be75..395198a 100644 --- a/lib/mv_web/live/member_live/form.ex +++ b/lib/mv_web/live/member_live/form.ex @@ -355,48 +355,65 @@ defmodule MvWeb.MemberLive.Form do # Extracts a user-friendly error message from form errors defp extract_error_message(form) do - # Try to extract message from source errors first source_errors = get_source_errors(form) - case source_errors do - [%Ash.Error.Invalid{errors: errors} | _] when is_list(errors) -> - # Extract first error message - case List.first(errors) do - %{message: message} when is_binary(message) -> - gettext("Validation failed: %{message}", message: message) + cond do + has_invalid_error?(source_errors) -> + extract_invalid_error_message(source_errors) - %{field: field, message: message} when is_binary(message) -> - gettext("Validation failed: %{field} %{message}", field: field, message: message) + has_other_error?(source_errors) -> + extract_other_error_message(source_errors) - _ -> - gettext("Validation failed. Please check your input.") - end + has_form_errors?(form) -> + gettext("Please correct the errors in the form and try again.") - [error | _] -> - # Try to extract message from other error types - case error do - %{message: message} when is_binary(message) -> - message + true -> + gettext("Failed to save member. Please try again.") + end + end - error when is_struct(error) -> - # Try to use Ash.ErrorKind protocol if available - try do - Ash.ErrorKind.message(error) - rescue - Protocol.UndefinedError -> gettext("Failed to save member. Please try again.") - end + # Checks if source errors contain an Ash.Error.Invalid + defp has_invalid_error?([%Ash.Error.Invalid{errors: errors} | _]) when is_list(errors), do: true + defp has_invalid_error?(_), do: false - _ -> - gettext("Failed to save member. Please try again.") - end + # Extracts message from Ash.Error.Invalid + defp extract_invalid_error_message([%Ash.Error.Invalid{errors: errors} | _]) do + case List.first(errors) do + %{message: message} when is_binary(message) -> + gettext("Validation failed: %{message}", message: message) + + %{field: field, message: message} when is_binary(message) -> + gettext("Validation failed: %{field} %{message}", field: field, message: message) _ -> - # Check if there are any field errors in the form - if has_form_errors?(form) do - gettext("Please correct the errors in the form and try again.") - else - gettext("Failed to save member. Please try again.") - end + gettext("Validation failed. Please check your input.") + end + end + + # Checks if source errors contain other error types + defp has_other_error?([_ | _]), do: true + defp has_other_error?(_), do: false + + # Extracts message from other error types + defp extract_other_error_message([error | _]) do + cond do + Map.has_key?(error, :message) and is_binary(error.message) -> + error.message + + is_struct(error) -> + extract_struct_error_message(error) + + true -> + gettext("Failed to save member. Please try again.") + end + end + + # Extracts message from struct error using Ash.ErrorKind protocol + defp extract_struct_error_message(error) do + try do + Ash.ErrorKind.message(error) + rescue + Protocol.UndefinedError -> gettext("Failed to save member. Please try again.") end end -- 2.47.2 From 0d8141837e8be3e9aba7ebc930e9eed516d0d082 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 16:15:01 +0100 Subject: [PATCH 6/9] chore: update gettext --- priv/gettext/de/LC_MESSAGES/default.po | 628 ++++++++++++------------- priv/gettext/default.pot | 347 ++------------ priv/gettext/en/LC_MESSAGES/default.po | 628 ++++++++++++------------- 3 files changed, 655 insertions(+), 948 deletions(-) diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po index f386236..174a104 100644 --- a/priv/gettext/de/LC_MESSAGES/default.po +++ b/priv/gettext/de/LC_MESSAGES/default.po @@ -11,7 +11,6 @@ msgstr "" "Language: de\n" #: lib/mv_web/components/core_components.ex -#: lib/mv_web/live/contribution_period_live/show.ex #, elixir-autogen, elixir-format msgid "Actions" msgstr "Aktionen" @@ -37,7 +36,6 @@ msgstr "Verbindung wird wiederhergestellt" msgid "City" msgstr "Stadt" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show/membership_fees_component.ex @@ -47,7 +45,6 @@ msgstr "Stadt" msgid "Delete" msgstr "Löschen" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex @@ -65,7 +62,6 @@ msgstr "Bearbeiten" msgid "Edit Member" msgstr "Mitglied bearbeiten" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show.ex @@ -141,7 +137,6 @@ msgstr "Austrittsdatum" msgid "House Number" msgstr "Hausnummer" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/translations/member_fields.ex @@ -150,7 +145,6 @@ msgid "Notes" msgstr "Notizen" #: lib/mv_web/live/components/payment_filter_component.ex -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -171,7 +165,6 @@ msgid "Save Member" msgstr "Mitglied speichern" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/global_settings_live.ex #: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_live/form.ex @@ -214,14 +207,12 @@ msgid "Yes" msgstr "Ja" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "create" msgstr "erstellt" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "update" @@ -264,7 +255,6 @@ msgstr "Ihr Passwort wurde erfolgreich zurückgesetzt" #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex @@ -275,11 +265,6 @@ msgstr "Ihr Passwort wurde erfolgreich zurückgesetzt" msgid "Cancel" msgstr "Abbrechen" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Choose a member" -msgstr "Mitglied auswählen" - #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/form_component.ex @@ -313,13 +298,7 @@ msgstr "Abmelden" msgid "Listing Users" msgstr "Benutzer*innen auflisten" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Member" -msgstr "Mitglied" - #: lib/mv_web/components/layouts/sidebar.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/index.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -327,7 +306,6 @@ msgstr "Mitglied" msgid "Members" msgstr "Mitglieder" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/form_component.ex @@ -351,7 +329,6 @@ msgstr "Neue*r Benutzer*in" msgid "Not enabled" msgstr "Nicht aktiviert" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/user_live/form.ex #, elixir-autogen, elixir-format msgid "Note" @@ -401,11 +378,6 @@ msgstr "Benutzer*in anzeigen" msgid "This is a user record from your database." msgstr "Dies ist ein Benutzer*innen-Datensatz aus Ihrer Datenbank." -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Unsupported value type: %{type}" -msgstr "Nicht unterstützter Wertetyp: %{type}" - #: lib/mv_web/live/user_live/form.ex #, elixir-autogen, elixir-format msgid "Use this form to manage user records in your database." @@ -417,11 +389,6 @@ msgstr "Verwenden Sie dieses Formular, um Benutzer*innen-Datensätze zu verwalte msgid "User" msgstr "Benutzer*in" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Value" -msgstr "Wert" - #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format @@ -611,37 +578,12 @@ msgstr "E-Mail kann nicht aktualisiert werden: Diese E-Mail-Adresse ist bereits msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account." msgstr "Diese E-Mail-Adresse ist bereits mit einem anderen OIDC-Konto verknüpft. Es können nicht mehrere OIDC-Provider mit demselben Konto verknüpft werden." -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Choose a custom field" -msgstr "Wähle ein Benutzerdefiniertes Feld" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Custom field" -msgstr "Benutzerdefinierte Felder" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Custom field value %{action} successfully" -msgstr "Benutzerdefinierter Feldwert erfolgreich %{action}" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Please select a custom field first" -msgstr "Bitte wähle zuerst ein Benutzerdefiniertes Feld" - #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show.ex #, elixir-autogen, elixir-format msgid "Custom Fields" msgstr "Benutzerdefinierte Felder" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Use this form to manage Custom Field Value records in your database." -msgstr "Verwende dieses Formular, um Benutzerdefinierte Feldwerte in deiner Datenbank zu verwalten." - #: lib/mv_web/live/custom_field_live/index_component.ex #, elixir-autogen, elixir-format msgid "%{count} member has a value assigned for this custom field." @@ -866,20 +808,6 @@ msgstr "Speichern" msgid "Create Member" msgstr "Mitglied erstellen" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "%{count} period selected" -msgid_plural "%{count} periods selected" -msgstr[0] "%{count} Zyklus ausgewählt" -msgstr[1] "%{count} Zyklen ausgewählt" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "About Contribution Types" -msgstr "Über Beitragsarten" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -887,54 +815,16 @@ msgstr "Über Beitragsarten" msgid "Amount" msgstr "Betrag" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format msgid "Back to Settings" msgstr "Zurück zu den Einstellungen" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Can be changed at any time. Amount changes affect future periods only." msgstr "Kann jederzeit geändert werden. Änderungen des Betrags betreffen nur zukünftige Zyklen." -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Cannot delete - members assigned" -msgstr "Löschen nicht möglich – es sind Mitglieder zugewiesen" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Change Contribution Type" -msgstr "Beitragsart ändern" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Contribution Start" -msgstr "Beitragsbeginn" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Contribution Types" -msgstr "Beitragsarten" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Contribution type" -msgstr "Beitragsart" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Contributions for %{name}" -msgstr "Beiträge für %{name}" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Current" -msgstr "Aktuell" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format, fuzzy msgid "Deletion" @@ -945,12 +835,6 @@ msgstr "Löschen" msgid "Examples" msgstr "Beispiele" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Family" -msgstr "Familie" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Fixed after creation. Members can only switch between types with the same interval." @@ -962,27 +846,12 @@ msgid "Global Settings" msgstr "Globale Einstellungen" #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "Half-yearly" msgstr "Halbjährlich" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Half-yearly contribution for supporting members" -msgstr "Halbjährlicher Beitrag für Fördermitglieder" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Honorary" -msgstr "Ehrenamtlich" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -995,36 +864,6 @@ msgstr "Intervall" msgid "Joining date" msgstr "Beitrittsdatum" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Joining year - reduced to 0" -msgstr "Beitrittsjahr – auf 0 reduziert" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Manage contribution types for membership fees." -msgstr "Beitragsarten für Mitgliedsbeiträge verwalten." - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Paid" -msgstr "Als bezahlt markieren" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Suspended" -msgstr "Als pausiert markieren" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Unpaid" -msgstr "Als unbezahlt markieren" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Member Contributions" -msgstr "Mitgliedsbeiträge" - #: lib/mv_web/live/membership_fee_settings_live.ex #, elixir-autogen, elixir-format msgid "Member pays for the year they joined" @@ -1045,131 +884,35 @@ msgstr "Mitglied zahlt ab dem nächsten vollständigen Quartal" msgid "Member pays from the next full year" msgstr "Mitglied zahlt ab dem nächsten vollständigen Jahr" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Member since" -msgstr "Mitglied seit" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Members can only switch between contribution types with the same payment interval (e.g., yearly to yearly). This prevents complex period overlaps." -msgstr "Mitglieder können nur zwischen Beitragsarten mit demselben Zahlungszyklus wechseln (z. B. jährlich zu jährlich). Dadurch werden komplexe Überlappungen vermieden." - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format, fuzzy msgid "Monthly" msgstr "Monatlich" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Monthly fee for students and trainees" -msgstr "Monatlicher Beitrag für Studierende und Auszubildende" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Name & Amount" msgstr "Name & Betrag" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "New Contribution Type" -msgstr "Neue Beitragsart" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "No fee for honorary members" -msgstr "Kein Beitrag für ehrenamtliche Mitglieder" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Only possible if no members are assigned to this type." msgstr "Nur möglich, wenn diesem Typ keine Mitglieder zugewiesen sind." -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Open Contributions" -msgstr "Offene Beiträge" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Paid via bank transfer" -msgstr "Bezahlt durch Überweisung" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Preview Mockup" -msgstr "Vorschau" - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "Quarterly" msgstr "Vierteljährlich" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Quarterly fee for family memberships" -msgstr "Vierteljährlicher Beitrag für Familienmitgliedschaften" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Reduced" -msgstr "Reduziert" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Reduced fee for unemployed, pensioners, or low income" -msgstr "Ermäßigter Beitrag für Arbeitslose, Rentner*innen oder Geringverdienende" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Regular" -msgstr "Regulär" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Reopen" -msgstr "Wieder öffnen" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Standard membership fee for regular members" -msgstr "Regulärer Mitgliedsbeitrag für Vollmitglieder" - -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #, elixir-autogen, elixir-format msgid "Status" msgstr "Status" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Student" -msgstr "Student" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Supporting Member" -msgstr "Fördermitglied" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Suspend" -msgstr "Pausieren" - -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -1177,24 +920,7 @@ msgstr "Pausieren" msgid "Suspended" msgstr "Pausiert" -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "This page is not functional and only displays the planned features." -msgstr "Diese Seite ist nicht funktionsfähig und zeigt nur geplante Funktionen." - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Time Period" -msgstr "Zeitraum" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Total Contributions" -msgstr "Gesamtbeiträge" - #: lib/mv_web/live/components/payment_filter_component.ex -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -1202,14 +928,7 @@ msgstr "Gesamtbeiträge" msgid "Unpaid" msgstr "Unbezahlt" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Why are not all contribution types shown?" -msgstr "Warum werden nicht alle Beitragsarten angezeigt?" - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format, fuzzy @@ -1697,11 +1416,6 @@ msgstr "Zyklen regenerieren" msgid "Regenerating..." msgstr "Regeneriere..." -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Save Custom Field Value" -msgstr "Benutzerdefinierten Feldwert speichern" - #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format, fuzzy msgid "Save Field" @@ -1799,11 +1513,6 @@ msgstr "Jährliches Intervall – Beitrittszeitraum einbezogen" msgid "You are about to delete all %{count} cycles for this member." msgstr "Du bist dabei alle %{count} Zyklen für dieses Mitglied zu löschen." -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Contribution types define different membership fee structures. Each type has a fixed cycle (monthly, quarterly, half-yearly, yearly) that cannot be changed after creation." -msgstr "Beitragsarten definieren verschiedene Beitragsmodelle. Jede Art hat einen festen Zyklus (monatlich, vierteljährlich, halbjährlich, jährlich), der nach Erstellung nicht mehr geändert werden kann." - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format, fuzzy msgid "Delete Membership Fee Type" @@ -2072,16 +1781,6 @@ msgstr "Zyklus löschen" msgid "The cycle period will be calculated based on this date and the interval." msgstr "Der Zyklus wird basierend auf diesem Datum und dem Intervall berechnet." -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "Custom field value deleted successfully" -msgstr "Benutzerdefinierter Feldwert erfolgreich gelöscht" - -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "Custom field value not found" -msgstr "Benutzerdefinierter Feldwert nicht gefunden" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Membership fee type not found" @@ -2102,11 +1801,6 @@ msgstr "Benutzer*in erfolgreich gelöscht" msgid "User not found" msgstr "Benutzer*in nicht gefunden" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "You do not have permission to access this custom field value" -msgstr "Sie haben keine Berechtigung, auf diesen benutzerdefinierten Feldwert zuzugreifen" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "You do not have permission to access this membership fee type" @@ -2117,11 +1811,6 @@ msgstr "Sie haben keine Berechtigung, auf diese Mitgliedsbeitragsart zuzugreifen msgid "You do not have permission to access this user" msgstr "Sie haben keine Berechtigung, auf diese*n Benutzer*in zuzugreifen" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "You do not have permission to delete this custom field value" -msgstr "Sie haben keine Berechtigung, diesen benutzerdefinierten Feldwert zu löschen" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "You do not have permission to delete this membership fee type" @@ -2167,11 +1856,6 @@ msgstr "Sie haben keine Berechtigung, auf dieses Mitglied zuzugreifen" msgid "You do not have permission to delete this member" msgstr "Sie haben keine Berechtigung, dieses Mitglied zu löschen" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "You do not have permission to view custom field values" -msgstr "Sie haben keine Berechtigung, benutzerdefinierte Feldwerte anzuzeigen" - #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Member created successfully" @@ -2212,7 +1896,319 @@ msgstr "Beitragstypen" msgid "Administration" msgstr "Administration" +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Failed to %{action} member." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Failed to save member. Please try again." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Please correct the errors in the form and try again." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed. Please check your input." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed: %{field} %{message}" +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed: %{message}" +msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Use this form to manage Custom Field Value records in your database." +#~ msgstr "Verwende dieses Formular, um Benutzerdefinierte Feldwerte in deiner Datenbank zu verwalten." + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Member" +#~ msgstr "Mitglied" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Choose a custom field" +#~ msgstr "Wähle ein Benutzerdefiniertes Feld" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Joining year - reduced to 0" +#~ msgstr "Beitrittsjahr – auf 0 reduziert" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Regular" +#~ msgstr "Regulär" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Current" +#~ msgstr "Aktuell" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Paid via bank transfer" +#~ msgstr "Bezahlt durch Überweisung" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Mark as Unpaid" +#~ msgstr "Als unbezahlt markieren" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Half-yearly contribution for supporting members" +#~ msgstr "Halbjährlicher Beitrag für Fördermitglieder" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Reduced fee for unemployed, pensioners, or low income" +#~ msgstr "Ermäßigter Beitrag für Arbeitslose, Rentner*innen oder Geringverdienende" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Custom field value not found" +#~ msgstr "Benutzerdefinierter Feldwert nicht gefunden" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Supporting Member" +#~ msgstr "Fördermitglied" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Monthly fee for students and trainees" +#~ msgstr "Monatlicher Beitrag für Studierende und Auszubildende" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Custom field value %{action} successfully" +#~ msgstr "Benutzerdefinierter Feldwert erfolgreich %{action}" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Total Contributions" +#~ msgstr "Gesamtbeiträge" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Manage contribution types for membership fees." +#~ msgstr "Beitragsarten für Mitgliedsbeiträge verwalten." + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Change Contribution Type" +#~ msgstr "Beitragsart ändern" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "New Contribution Type" +#~ msgstr "Neue Beitragsart" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Time Period" +#~ msgstr "Zeitraum" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Custom field value deleted successfully" +#~ msgstr "Benutzerdefinierter Feldwert erfolgreich gelöscht" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "You do not have permission to access this custom field value" +#~ msgstr "Sie haben keine Berechtigung, auf diesen benutzerdefinierten Feldwert zuzugreifen" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Cannot delete - members assigned" +#~ msgstr "Löschen nicht möglich – es sind Mitglieder zugewiesen" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Preview Mockup" +#~ msgstr "Vorschau" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Contribution Types" +#~ msgstr "Beitragsarten" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "This page is not functional and only displays the planned features." +#~ msgstr "Diese Seite ist nicht funktionsfähig und zeigt nur geplante Funktionen." + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Member since" +#~ msgstr "Mitglied seit" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Unsupported value type: %{type}" +#~ msgstr "Nicht unterstützter Wertetyp: %{type}" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Custom field" +#~ msgstr "Benutzerdefinierte Felder" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Mark as Paid" +#~ msgstr "Als bezahlt markieren" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Contribution type" +#~ msgstr "Beitragsart" + #~ #: lib/mv_web/components/layouts/sidebar.ex #~ #, elixir-autogen, elixir-format, fuzzy #~ msgid "Contributions" #~ msgstr "Beiträge" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Reduced" +#~ msgstr "Reduziert" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "No fee for honorary members" +#~ msgstr "Kein Beitrag für ehrenamtliche Mitglieder" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "You do not have permission to delete this custom field value" +#~ msgstr "Sie haben keine Berechtigung, diesen benutzerdefinierten Feldwert zu löschen" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "%{count} period selected" +#~ msgid_plural "%{count} periods selected" +#~ msgstr[0] "%{count} Zyklus ausgewählt" +#~ msgstr[1] "%{count} Zyklen ausgewählt" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Mark as Suspended" +#~ msgstr "Als pausiert markieren" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Contribution types define different membership fee structures. Each type has a fixed cycle (monthly, quarterly, half-yearly, yearly) that cannot be changed after creation." +#~ msgstr "Beitragsarten definieren verschiedene Beitragsmodelle. Jede Art hat einen festen Zyklus (monatlich, vierteljährlich, halbjährlich, jährlich), der nach Erstellung nicht mehr geändert werden kann." + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Choose a member" +#~ msgstr "Mitglied auswählen" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Suspend" +#~ msgstr "Pausieren" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Reopen" +#~ msgstr "Wieder öffnen" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Value" +#~ msgstr "Wert" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Why are not all contribution types shown?" +#~ msgstr "Warum werden nicht alle Beitragsarten angezeigt?" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Contribution Start" +#~ msgstr "Beitragsbeginn" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Standard membership fee for regular members" +#~ msgstr "Regulärer Mitgliedsbeitrag für Vollmitglieder" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Save Custom Field Value" +#~ msgstr "Benutzerdefinierten Feldwert speichern" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Honorary" +#~ msgstr "Ehrenamtlich" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Contributions for %{name}" +#~ msgstr "Beiträge für %{name}" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Family" +#~ msgstr "Familie" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "You do not have permission to view custom field values" +#~ msgstr "Sie haben keine Berechtigung, benutzerdefinierte Feldwerte anzuzeigen" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Student" +#~ msgstr "Student" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Quarterly fee for family memberships" +#~ msgstr "Vierteljährlicher Beitrag für Familienmitgliedschaften" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Members can only switch between contribution types with the same payment interval (e.g., yearly to yearly). This prevents complex period overlaps." +#~ msgstr "Mitglieder können nur zwischen Beitragsarten mit demselben Zahlungszyklus wechseln (z. B. jährlich zu jährlich). Dadurch werden komplexe Überlappungen vermieden." + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Please select a custom field first" +#~ msgstr "Bitte wähle zuerst ein Benutzerdefiniertes Feld" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Open Contributions" +#~ msgstr "Offene Beiträge" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Member Contributions" +#~ msgstr "Mitgliedsbeiträge" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "About Contribution Types" +#~ msgstr "Über Beitragsarten" diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 9df03a5..d43c1a6 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -12,7 +12,6 @@ msgid "" msgstr "" #: lib/mv_web/components/core_components.ex -#: lib/mv_web/live/contribution_period_live/show.ex #, elixir-autogen, elixir-format msgid "Actions" msgstr "" @@ -38,7 +37,6 @@ msgstr "" msgid "City" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show/membership_fees_component.ex @@ -48,7 +46,6 @@ msgstr "" msgid "Delete" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex @@ -66,7 +63,6 @@ msgstr "" msgid "Edit Member" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show.ex @@ -142,7 +138,6 @@ msgstr "" msgid "House Number" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/translations/member_fields.ex @@ -151,7 +146,6 @@ msgid "Notes" msgstr "" #: lib/mv_web/live/components/payment_filter_component.ex -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -172,7 +166,6 @@ msgid "Save Member" msgstr "" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/global_settings_live.ex #: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_live/form.ex @@ -215,14 +208,12 @@ msgid "Yes" msgstr "" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "create" msgstr "" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "update" @@ -265,7 +256,6 @@ msgstr "" #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex @@ -276,11 +266,6 @@ msgstr "" msgid "Cancel" msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Choose a member" -msgstr "" - #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/form_component.ex @@ -314,13 +299,7 @@ msgstr "" msgid "Listing Users" msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Member" -msgstr "" - #: lib/mv_web/components/layouts/sidebar.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/index.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -328,7 +307,6 @@ msgstr "" msgid "Members" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/form_component.ex @@ -352,7 +330,6 @@ msgstr "" msgid "Not enabled" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/user_live/form.ex #, elixir-autogen, elixir-format msgid "Note" @@ -402,11 +379,6 @@ msgstr "" msgid "This is a user record from your database." msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Unsupported value type: %{type}" -msgstr "" - #: lib/mv_web/live/user_live/form.ex #, elixir-autogen, elixir-format msgid "Use this form to manage user records in your database." @@ -418,11 +390,6 @@ msgstr "" msgid "User" msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Value" -msgstr "" - #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format @@ -612,37 +579,12 @@ msgstr "" msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account." msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Choose a custom field" -msgstr "" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Custom field" -msgstr "" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Custom field value %{action} successfully" -msgstr "" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Please select a custom field first" -msgstr "" - #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show.ex #, elixir-autogen, elixir-format msgid "Custom Fields" msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Use this form to manage Custom Field Value records in your database." -msgstr "" - #: lib/mv_web/live/custom_field_live/index_component.ex #, elixir-autogen, elixir-format msgid "%{count} member has a value assigned for this custom field." @@ -867,20 +809,6 @@ msgstr "" msgid "Create Member" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "%{count} period selected" -msgid_plural "%{count} periods selected" -msgstr[0] "" -msgstr[1] "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "About Contribution Types" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -888,54 +816,16 @@ msgstr "" msgid "Amount" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format msgid "Back to Settings" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Can be changed at any time. Amount changes affect future periods only." msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Cannot delete - members assigned" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Change Contribution Type" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Contribution Start" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Contribution Types" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Contribution type" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Contributions for %{name}" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Current" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Deletion" @@ -946,12 +836,6 @@ msgstr "" msgid "Examples" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Family" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Fixed after creation. Members can only switch between types with the same interval." @@ -963,27 +847,12 @@ msgid "Global Settings" msgstr "" #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "Half-yearly" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Half-yearly contribution for supporting members" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Honorary" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -996,36 +865,6 @@ msgstr "" msgid "Joining date" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Joining year - reduced to 0" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Manage contribution types for membership fees." -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Paid" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Suspended" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Unpaid" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Member Contributions" -msgstr "" - #: lib/mv_web/live/membership_fee_settings_live.ex #, elixir-autogen, elixir-format msgid "Member pays for the year they joined" @@ -1046,131 +885,35 @@ msgstr "" msgid "Member pays from the next full year" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Member since" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Members can only switch between contribution types with the same payment interval (e.g., yearly to yearly). This prevents complex period overlaps." -msgstr "" - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "Monthly" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Monthly fee for students and trainees" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Name & Amount" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "New Contribution Type" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "No fee for honorary members" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Only possible if no members are assigned to this type." msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Open Contributions" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Paid via bank transfer" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Preview Mockup" -msgstr "" - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "Quarterly" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Quarterly fee for family memberships" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Reduced" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Reduced fee for unemployed, pensioners, or low income" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Regular" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Reopen" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Standard membership fee for regular members" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #, elixir-autogen, elixir-format msgid "Status" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Student" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Supporting Member" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Suspend" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -1178,24 +921,7 @@ msgstr "" msgid "Suspended" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "This page is not functional and only displays the planned features." -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Time Period" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Total Contributions" -msgstr "" - #: lib/mv_web/live/components/payment_filter_component.ex -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -1203,14 +929,7 @@ msgstr "" msgid "Unpaid" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Why are not all contribution types shown?" -msgstr "" - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format @@ -1698,11 +1417,6 @@ msgstr "" msgid "Regenerating..." msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Save Custom Field Value" -msgstr "" - #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format msgid "Save Field" @@ -1800,11 +1514,6 @@ msgstr "" msgid "You are about to delete all %{count} cycles for this member." msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Contribution types define different membership fee structures. Each type has a fixed cycle (monthly, quarterly, half-yearly, yearly) that cannot be changed after creation." -msgstr "" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Delete Membership Fee Type" @@ -2073,16 +1782,6 @@ msgstr "" msgid "The cycle period will be calculated based on this date and the interval." msgstr "" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "Custom field value deleted successfully" -msgstr "" - -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "Custom field value not found" -msgstr "" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Membership fee type not found" @@ -2103,11 +1802,6 @@ msgstr "" msgid "User not found" msgstr "" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "You do not have permission to access this custom field value" -msgstr "" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "You do not have permission to access this membership fee type" @@ -2118,11 +1812,6 @@ msgstr "" msgid "You do not have permission to access this user" msgstr "" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "You do not have permission to delete this custom field value" -msgstr "" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "You do not have permission to delete this membership fee type" @@ -2168,11 +1857,6 @@ msgstr "" msgid "You do not have permission to delete this member" msgstr "" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format -msgid "You do not have permission to view custom field values" -msgstr "" - #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Member created successfully" @@ -2191,6 +1875,7 @@ msgstr "" #: lib/mv/membership/import/member_csv.ex #, elixir-autogen, elixir-format msgid "Email is required." +msgstr "" #: lib/mv_web/components/layouts/sidebar.ex #, elixir-autogen, elixir-format @@ -2211,3 +1896,33 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Administration" msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Failed to %{action} member." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Failed to save member. Please try again." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Please correct the errors in the form and try again." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed. Please check your input." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed: %{field} %{message}" +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed: %{message}" +msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 6b4830b..a6d8fc2 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -12,7 +12,6 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: lib/mv_web/components/core_components.ex -#: lib/mv_web/live/contribution_period_live/show.ex #, elixir-autogen, elixir-format msgid "Actions" msgstr "" @@ -38,7 +37,6 @@ msgstr "" msgid "City" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show/membership_fees_component.ex @@ -48,7 +46,6 @@ msgstr "" msgid "Delete" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex @@ -66,7 +63,6 @@ msgstr "" msgid "Edit Member" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show.ex @@ -142,7 +138,6 @@ msgstr "" msgid "House Number" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/translations/member_fields.ex @@ -151,7 +146,6 @@ msgid "Notes" msgstr "" #: lib/mv_web/live/components/payment_filter_component.ex -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -172,7 +166,6 @@ msgid "Save Member" msgstr "" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/global_settings_live.ex #: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_live/form.ex @@ -215,14 +208,12 @@ msgid "Yes" msgstr "" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "create" msgstr "" #: lib/mv_web/live/custom_field_live/form_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "update" @@ -265,7 +256,6 @@ msgstr "" #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex -#: lib/mv_web/live/custom_field_value_live/form.ex #: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex @@ -276,11 +266,6 @@ msgstr "" msgid "Cancel" msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Choose a member" -msgstr "" - #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/form_component.ex @@ -314,13 +299,7 @@ msgstr "" msgid "Listing Users" msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Member" -msgstr "" - #: lib/mv_web/components/layouts/sidebar.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/index.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -328,7 +307,6 @@ msgstr "" msgid "Members" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_field_live/form_component.ex @@ -352,7 +330,6 @@ msgstr "" msgid "Not enabled" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/user_live/form.ex #, elixir-autogen, elixir-format, fuzzy msgid "Note" @@ -402,11 +379,6 @@ msgstr "" msgid "This is a user record from your database." msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Unsupported value type: %{type}" -msgstr "" - #: lib/mv_web/live/user_live/form.ex #, elixir-autogen, elixir-format, fuzzy msgid "Use this form to manage user records in your database." @@ -418,11 +390,6 @@ msgstr "" msgid "User" msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Value" -msgstr "" - #: lib/mv_web/live/custom_field_live/form_component.ex #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format @@ -612,37 +579,12 @@ msgstr "" msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account." msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Choose a custom field" -msgstr "" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Custom field" -msgstr "" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Custom field value %{action} successfully" -msgstr "" - -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format -msgid "Please select a custom field first" -msgstr "" - #: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/show.ex #, elixir-autogen, elixir-format, fuzzy msgid "Custom Fields" msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Use this form to manage Custom Field Value records in your database." -msgstr "" - #: lib/mv_web/live/custom_field_live/index_component.ex #, elixir-autogen, elixir-format msgid "%{count} member has a value assigned for this custom field." @@ -867,20 +809,6 @@ msgstr "" msgid "Create Member" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "%{count} period selected" -msgid_plural "%{count} periods selected" -msgstr[0] "" -msgstr[1] "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "About Contribution Types" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -888,54 +816,16 @@ msgstr "" msgid "Amount" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format msgid "Back to Settings" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Can be changed at any time. Amount changes affect future periods only." msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Cannot delete - members assigned" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Change Contribution Type" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Contribution Start" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Contribution Types" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Contribution type" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Contributions for %{name}" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Current" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format, fuzzy msgid "Deletion" @@ -946,12 +836,6 @@ msgstr "" msgid "Examples" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Family" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Fixed after creation. Members can only switch between types with the same interval." @@ -963,27 +847,12 @@ msgid "Global Settings" msgstr "" #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "Half-yearly" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Half-yearly contribution for supporting members" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Honorary" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #: lib/mv_web/live/membership_fee_type_live/index.ex @@ -996,36 +865,6 @@ msgstr "" msgid "Joining date" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Joining year - reduced to 0" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Manage contribution types for membership fees." -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Paid" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Suspended" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Mark as Unpaid" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Member Contributions" -msgstr "" - #: lib/mv_web/live/membership_fee_settings_live.ex #, elixir-autogen, elixir-format msgid "Member pays for the year they joined" @@ -1046,131 +885,35 @@ msgstr "" msgid "Member pays from the next full year" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Member since" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Members can only switch between contribution types with the same payment interval (e.g., yearly to yearly). This prevents complex period overlaps." -msgstr "" - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "Monthly" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Monthly fee for students and trainees" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Name & Amount" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "New Contribution Type" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "No fee for honorary members" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format msgid "Only possible if no members are assigned to this type." msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Open Contributions" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Paid via bank transfer" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Preview Mockup" -msgstr "" - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "Quarterly" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Quarterly fee for family memberships" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Reduced" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Reduced fee for unemployed, pensioners, or low income" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Regular" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Reopen" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Standard membership fee for regular members" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #, elixir-autogen, elixir-format msgid "Status" msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Student" -msgstr "" - -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "Supporting Member" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Suspend" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -1178,24 +921,7 @@ msgstr "" msgid "Suspended" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format -msgid "This page is not functional and only displays the planned features." -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Time Period" -msgstr "" - -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Total Contributions" -msgstr "" - #: lib/mv_web/live/components/payment_filter_component.ex -#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/member_live/index/membership_fee_status.ex @@ -1203,14 +929,7 @@ msgstr "" msgid "Unpaid" msgstr "" -#: lib/mv_web/live/contribution_period_live/show.ex -#, elixir-autogen, elixir-format -msgid "Why are not all contribution types shown?" -msgstr "" - #: lib/mv_web/helpers/membership_fee_helpers.ex -#: lib/mv_web/live/contribution_period_live/show.ex -#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format @@ -1698,11 +1417,6 @@ msgstr "" msgid "Regenerating..." msgstr "" -#: lib/mv_web/live/custom_field_value_live/form.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Save Custom Field Value" -msgstr "" - #: lib/mv_web/live/member_field_live/form_component.ex #, elixir-autogen, elixir-format, fuzzy msgid "Save Field" @@ -1800,11 +1514,6 @@ msgstr "" msgid "You are about to delete all %{count} cycles for this member." msgstr "" -#: lib/mv_web/live/contribution_type_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Contribution types define different membership fee structures. Each type has a fixed cycle (monthly, quarterly, half-yearly, yearly) that cannot be changed after creation." -msgstr "" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format, fuzzy msgid "Delete Membership Fee Type" @@ -2073,16 +1782,6 @@ msgstr "" msgid "The cycle period will be calculated based on this date and the interval." msgstr "" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Custom field value deleted successfully" -msgstr "" - -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "Custom field value not found" -msgstr "" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format, fuzzy msgid "Membership fee type not found" @@ -2103,11 +1802,6 @@ msgstr "" msgid "User not found" msgstr "" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "You do not have permission to access this custom field value" -msgstr "" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format, fuzzy msgid "You do not have permission to access this membership fee type" @@ -2118,11 +1812,6 @@ msgstr "" msgid "You do not have permission to access this user" msgstr "" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "You do not have permission to delete this custom field value" -msgstr "" - #: lib/mv_web/live/membership_fee_type_live/index.ex #, elixir-autogen, elixir-format, fuzzy msgid "You do not have permission to delete this membership fee type" @@ -2168,11 +1857,6 @@ msgstr "" msgid "You do not have permission to delete this member" msgstr "" -#: lib/mv_web/live/custom_field_value_live/index.ex -#, elixir-autogen, elixir-format, fuzzy -msgid "You do not have permission to view custom field values" -msgstr "" - #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Member created successfully" @@ -2213,12 +1897,324 @@ msgstr "" msgid "Administration" msgstr "" +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Failed to %{action} member." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Failed to save member. Please try again." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Please correct the errors in the form and try again." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed. Please check your input." +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed: %{field} %{message}" +msgstr "" + +#: lib/mv_web/live/member_live/form.ex +#, elixir-autogen, elixir-format +msgid "Validation failed: %{message}" +msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Use this form to manage Custom Field Value records in your database." +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Member" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Choose a custom field" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Joining year - reduced to 0" +#~ msgstr "" + #~ #: lib/mv_web/components/layouts/sidebar.ex #~ #, elixir-autogen, elixir-format, fuzzy #~ msgid "Admin" #~ msgstr "" +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Regular" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Current" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Paid via bank transfer" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Mark as Unpaid" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Half-yearly contribution for supporting members" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Reduced fee for unemployed, pensioners, or low income" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Custom field value not found" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Supporting Member" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Monthly fee for students and trainees" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Custom field value %{action} successfully" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Total Contributions" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Manage contribution types for membership fees." +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Change Contribution Type" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "New Contribution Type" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Time Period" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Custom field value deleted successfully" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "You do not have permission to access this custom field value" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Cannot delete - members assigned" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Preview Mockup" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Contribution Types" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "This page is not functional and only displays the planned features." +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Member since" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Unsupported value type: %{type}" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Custom field" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Mark as Paid" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Contribution type" +#~ msgstr "" + #~ #: lib/mv_web/components/layouts/sidebar.ex #~ #, elixir-autogen, elixir-format #~ msgid "Contributions" #~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Reduced" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "No fee for honorary members" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "You do not have permission to delete this custom field value" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "%{count} period selected" +#~ msgid_plural "%{count} periods selected" +#~ msgstr[0] "" +#~ msgstr[1] "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Mark as Suspended" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Contribution types define different membership fee structures. Each type has a fixed cycle (monthly, quarterly, half-yearly, yearly) that cannot be changed after creation." +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Choose a member" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Suspend" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Reopen" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Value" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Why are not all contribution types shown?" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Contribution Start" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Standard membership fee for regular members" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "Save Custom Field Value" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Honorary" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Contributions for %{name}" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Family" +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/index.ex +#~ #, elixir-autogen, elixir-format, fuzzy +#~ msgid "You do not have permission to view custom field values" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Student" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Quarterly fee for family memberships" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Members can only switch between contribution types with the same payment interval (e.g., yearly to yearly). This prevents complex period overlaps." +#~ msgstr "" + +#~ #: lib/mv_web/live/custom_field_value_live/form.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Please select a custom field first" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Open Contributions" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_period_live/show.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "Member Contributions" +#~ msgstr "" + +#~ #: lib/mv_web/live/contribution_type_live/index.ex +#~ #, elixir-autogen, elixir-format +#~ msgid "About Contribution Types" +#~ msgstr "" -- 2.47.2 From c6dd0cd09dd560d6429b51d6f3753996c96fabfa Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 16:30:43 +0100 Subject: [PATCH 7/9] i18n: Add missing German translations for member form errors - Add translations for validation error messages - Add translations for save failure messages --- priv/gettext/de/LC_MESSAGES/default.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po index 174a104..fa5cf54 100644 --- a/priv/gettext/de/LC_MESSAGES/default.po +++ b/priv/gettext/de/LC_MESSAGES/default.po @@ -1899,32 +1899,32 @@ msgstr "Administration" #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Failed to %{action} member." -msgstr "" +msgstr "Fehler beim %{action} des Mitglieds." #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Failed to save member. Please try again." -msgstr "" +msgstr "Fehler beim Speichern des Mitglieds. Bitte versuchen Sie es erneut." #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Please correct the errors in the form and try again." -msgstr "" +msgstr "Bitte korrigieren Sie die Fehler im Formular und versuchen Sie es erneut." #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Validation failed. Please check your input." -msgstr "" +msgstr "Validierung fehlgeschlagen. Bitte überprüfen Sie Ihre Eingabe." #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Validation failed: %{field} %{message}" -msgstr "" +msgstr "Validierung fehlgeschlagen: %{field} %{message}" #: lib/mv_web/live/member_live/form.ex #, elixir-autogen, elixir-format msgid "Validation failed: %{message}" -msgstr "" +msgstr "Validierung fehlgeschlagen: %{message}" #~ #: lib/mv_web/live/custom_field_value_live/form.ex #~ #, elixir-autogen, elixir-format, fuzzy -- 2.47.2 From 235154a102afc61c290ee01ffc33c07a24e144a2 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 16:33:50 +0100 Subject: [PATCH 8/9] test: Remove outdated TODO for auto-assignment feature Auto-assignment of default membership fee type is already implemented via SetDefaultMembershipFeeType change. Test assertion is now active. --- .../membership_fee_type_integration_test.exs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/membership_fees/membership_fee_type_integration_test.exs b/test/membership_fees/membership_fee_type_integration_test.exs index b70f47c..681bd02 100644 --- a/test/membership_fees/membership_fee_type_integration_test.exs +++ b/test/membership_fees/membership_fee_type_integration_test.exs @@ -158,10 +158,8 @@ defmodule Mv.MembershipFees.MembershipFeeTypeIntegrationTest do |> Ash.update!() # Create a member without explicitly setting membership_fee_type_id - # Note: This test assumes that the Member resource automatically assigns - # the default_membership_fee_type_id during creation. If this is not yet - # implemented, this test will fail initially (which is expected in TDD). - # For now, we skip this test as the auto-assignment feature is not yet implemented. + # The Member resource automatically assigns the default_membership_fee_type_id + # during creation via SetDefaultMembershipFeeType change. {:ok, member} = Ash.create(Member, %{ first_name: "Test", @@ -169,10 +167,8 @@ defmodule Mv.MembershipFees.MembershipFeeTypeIntegrationTest do email: "test.member.#{System.unique_integer([:positive])}@example.com" }) - # TODO: When auto-assignment is implemented, uncomment this assertion - # assert member.membership_fee_type_id == fee_type.id - # For now, we just verify the member was created successfully - assert %Member{} = member + # Verify that the default membership fee type was automatically assigned + assert member.membership_fee_type_id == fee_type.id end test "include_joining_cycle is used during cycle generation" do -- 2.47.2 From 2dc0bce8cb0bf846e9341a73337e686731dd7a94 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 20 Jan 2026 17:04:42 +0100 Subject: [PATCH 9/9] chore: rm todo list --- docs/documentation-sync-todos.md | 116 ------------------------------- 1 file changed, 116 deletions(-) delete mode 100644 docs/documentation-sync-todos.md diff --git a/docs/documentation-sync-todos.md b/docs/documentation-sync-todos.md deleted file mode 100644 index e4fb5a8..0000000 --- a/docs/documentation-sync-todos.md +++ /dev/null @@ -1,116 +0,0 @@ -# Documentation Sync - Code Adjustments Todo List - -**Created:** 2026-01-13 -**Purpose:** List of all code adjustments identified based on documentation synchronization - - -## Code Adjustments (Priority: Low) - -### 1. Domain Public API Documentation Incomplete - -**Problem:** The `@moduledoc` in domain modules does not list all public functions. - -**Affected Files:** -- `lib/membership/membership.ex` - Missing functions in Public API: - - `list_required_custom_fields/0` - - `update_member_field_visibility/2` - - `update_single_member_field_visibility/3` -- `lib/accounts/accounts.ex` - Very short Public API documentation, could be more detailed -- `lib/membership_fees/membership_fees.ex` - Public API is complete, but could more clearly document that LiveViews use direct Ash calls - -**Priority:** Low (Documentation, no functionality affected) - -**Recommendation:** Update Public API sections in all domain modules to list all public functions. - -### 2. Outdated Comments in MemberLive.Form - -**Problem:** `@moduledoc` in `lib/mv_web/live/member_live/form.ex` still mentions "Payment Data: Mockup section (not editable)", but Membership Fees are now fully implemented. - -**Affected File:** -- `lib/mv_web/live/member_live/form.ex` (Line 16) - -**Priority:** Low (Documentation, no functionality affected) - -**Recommendation:** Update `@moduledoc` to reflect the current status. - -### 3. Mv.Accounts Domain Public API Missing Completely - -**Problem:** The `@moduledoc` in `lib/accounts/accounts.ex` does not mention any Public API functions, although several are defined. - -**Affected File:** -- `lib/accounts/accounts.ex` - Missing Public API documentation for: - - `create_user/1` - - `list_users/0` - - `update_user/2` - - `destroy_user/1` - - `create_register_with_rauthy/1` - - `read_sign_in_with_rauthy/1` - -**Priority:** Low (Documentation, no functionality affected) - -**Recommendation:** Add Public API section to `@moduledoc`, similar to other domain modules. - -### 4. Mv.Authorization Domain Public API Missing get_role/1 - -**Problem:** The `@moduledoc` in `lib/mv/authorization/authorization.ex` does not list `get_role/1` in the Public API, although it is defined. - -**Affected File:** -- `lib/mv/authorization/authorization.ex` - Missing function in Public API: - - `get_role/1` (is defined, but not mentioned in Public API) - -**Priority:** Low (Documentation, no functionality affected) - -**Recommendation:** Add `get_role/1` to the Public API list. - -### 5. Remove Deprecated Implementations - -**Problem:** `lib/mv_web/live/custom_field_value_live/show.ex` `MvWeb.ContributionTypeLive.Index` and `MvWeb.ContributionPeriodLive.Show` are deprecated, they should be removed. - -### 6. Missing Tests for Some LiveViews - -**Problem:** Some LiveViews do not have corresponding test files. - -**Affected LiveViews:** -- `MvWeb.UserLive.Show` - No test present -- `MvWeb.RoleLive.Show` - No test present - -**Priority:** Medium (Test coverage could be improved) - -**Recommendation:** Add tests for the three Show LiveViews to ensure complete test coverage. - -### 7. Mv.Accounts.Token @moduledoc Too Short - -**Problem:** The `@moduledoc` in `lib/accounts/token.ex` is very short and not informative. - -**Affected File:** -- `lib/accounts/token.ex` - Currently only: "AshAuthentication specific ressource" - -**Priority:** Low (Documentation, no functionality affected) - -**Recommendation:** Expand @moduledoc to explain that this is an AshAuthentication Token Resource and is used for session management. - -### 8. PageController Missing @moduledoc - -**Problem:** The `@moduledoc` in `lib/mv_web/controllers/page_controller.ex` is completely missing. - -**Affected File:** -- `lib/mv_web/controllers/page_controller.ex` - No @moduledoc present - -**Priority:** Low (Documentation, no functionality affected) - -**Recommendation:** Add @moduledoc to explain that this controller renders the homepage. - -**Note:** Other controller modules (Router, Endpoint, Telemetry) also do not have @moduledoc, but this is common and acceptable for standard Phoenix modules. - -## Analysis Summary - -### Found Inconsistencies - -**1. Domain Public API Documentation Incomplete** (see Code Adjustments #1) -**2. Outdated Comments in MemberLive.Form** (see Code Adjustments #2) -**3. Mv.Accounts Domain Public API Missing Completely** (see Code Adjustments #3) -**4. Mv.Authorization Domain Public API Missing get_role/1** (see Code Adjustments #4) -**5. CustomFieldValueLive.Show is Deprecated** (see Code Adjustments #5) -**6. Missing Tests for Some LiveViews** (see Code Adjustments #6) -**7. Mv.Accounts.Token @moduledoc Too Short** (see Code Adjustments #7) -**8. PageController Missing @moduledoc** (see Code Adjustments #8) -- 2.47.2