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(
- "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"""
-
- {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}}>
-