Merge branch 'main' into feature/209_hide_field_dropdown
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
carla 2025-12-03 14:57:56 +01:00
commit c17445975c
34 changed files with 3967 additions and 433 deletions

View file

@ -32,6 +32,7 @@ defmodule MvWeb.MemberLive.Index do
alias Mv.Membership
alias MvWeb.MemberLive.Index.Formatter
alias MvWeb.Helpers.DateFormatter
alias MvWeb.MemberLive.Index.FieldSelection
alias MvWeb.MemberLive.Index.FieldVisibility
@ -168,13 +169,7 @@ defmodule MvWeb.MemberLive.Index do
selected_ids = socket.assigns.selected_members
# Filter members that are in the selection and have email addresses
formatted_emails =
socket.assigns.members
|> Enum.filter(fn member ->
MapSet.member?(selected_ids, member.id) && member.email && member.email != ""
end)
|> Enum.map(&format_member_email/1)
formatted_emails = format_selected_member_emails(socket.assigns.members, selected_ids)
email_count = length(formatted_emails)
cond do
@ -1069,9 +1064,20 @@ defmodule MvWeb.MemberLive.Index do
end
end
# Filters selected members with email addresses and formats them.
# Returns a list of formatted email strings in the format "First Last <email>".
# Used by both copy_emails and mailto links.
def format_selected_member_emails(members, selected_members) do
members
|> Enum.filter(fn member ->
MapSet.member?(selected_members, member.id) && member.email && member.email != ""
end)
|> Enum.map(&format_member_email/1)
end
# Formats a member's email in the format "First Last <email>"
# Used for copy_emails feature to create email-client-friendly format.
defp format_member_email(member) do
# Used for copy_emails feature and mailto links to create email-client-friendly format.
def format_member_email(member) do
first_name = member.first_name || ""
last_name = member.last_name || ""
@ -1114,4 +1120,7 @@ defmodule MvWeb.MemberLive.Index do
Map.get(visibility_config, Atom.to_string(field), true)
end)
end
# Public helper function to format dates for use in templates
def format_date(date), do: DateFormatter.format_date(date)
end

View file

@ -14,7 +14,12 @@
</.button>
<.button
:if={Enum.any?(@members, &MapSet.member?(@selected_members, &1.id))}
href={"mailto:?bcc=#{@members |> Enum.filter(&(MapSet.member?(@selected_members, &1.id) && &1.email)) |> Enum.map(& &1.email) |> Enum.join(",")}"}
href={
"mailto:?bcc=" <>
(MvWeb.MemberLive.Index.format_selected_member_emails(@members, @selected_members)
|> Enum.join(", ")
|> URI.encode())
}
aria-label={gettext("Open email program with BCC recipients")}
>
<.icon name="hero-envelope" />
@ -245,7 +250,7 @@
"""
}
>
{member.join_date}
{MvWeb.MemberLive.Index.format_date(member.join_date)}
</:col>
<:col :let={member} :if={:paid in @member_fields_visible} label={gettext("Paid")}>
<span class={[

View file

@ -6,6 +6,7 @@ defmodule MvWeb.MemberLive.Index.Formatter do
formats them appropriately for display in the UI.
"""
use Gettext, backend: MvWeb.Gettext
alias MvWeb.Helpers.DateFormatter
@doc """
Formats a custom field value for display.
@ -61,11 +62,11 @@ defmodule MvWeb.MemberLive.Index.Formatter do
defp format_value_by_type(value, :boolean, _) when value == false, do: gettext("No")
defp format_value_by_type(value, :boolean, _), do: to_string(value)
defp format_value_by_type(%Date{} = date, :date, _), do: Date.to_string(date)
defp format_value_by_type(%Date{} = date, :date, _), do: DateFormatter.format_date(date)
defp format_value_by_type(value, :date, _) when is_binary(value) do
case Date.from_iso8601(value) do
{:ok, date} -> Date.to_string(date)
{:ok, date} -> DateFormatter.format_date(date)
_ -> value
end
end

View file

@ -23,6 +23,7 @@ defmodule MvWeb.MemberLive.Show do
"""
use MvWeb, :live_view
import Ash.Query
alias MvWeb.Helpers.DateFormatter
@impl true
def render(assigns) do
@ -52,8 +53,8 @@ defmodule MvWeb.MemberLive.Show do
{if @member.paid, do: gettext("Yes"), else: gettext("No")}
</:item>
<:item title={gettext("Phone Number")}>{@member.phone_number}</:item>
<:item title={gettext("Join Date")}>{@member.join_date}</:item>
<:item title={gettext("Exit Date")}>{@member.exit_date}</:item>
<:item title={gettext("Join Date")}>{DateFormatter.format_date(@member.join_date)}</:item>
<:item title={gettext("Exit Date")}>{DateFormatter.format_date(@member.exit_date)}</:item>
<:item title={gettext("Notes")}>{@member.notes}</:item>
<:item title={gettext("City")}>{@member.city}</:item>
<:item title={gettext("Street")}>{@member.street}</:item>
@ -81,10 +82,7 @@ defmodule MvWeb.MemberLive.Show do
# name
cfv.custom_field && cfv.custom_field.name,
# value
case cfv.value do
%{value: v} -> v
v -> v
end
format_custom_field_value(cfv)
}
end)
} />
@ -114,4 +112,17 @@ defmodule MvWeb.MemberLive.Show do
defp page_title(:show), do: gettext("Show Member")
defp page_title(:edit), do: gettext("Edit Member")
defp format_custom_field_value(cfv) do
value =
case cfv.value do
%{value: v} -> v
v -> v
end
case value do
%Date{} = date -> DateFormatter.format_date(date)
other -> other
end
end
end