Membership Fee 6 - UI Components & LiveViews closes #280 #304

Merged
moritz merged 79 commits from feature/280_membership_fee_ui into main 2025-12-26 23:14:50 +01:00
Showing only changes of commit 3afc20c2e2 - Show all commits

View file

@ -26,30 +26,42 @@ defmodule MvWeb.Helpers.MembershipFeeHelpers do
@spec format_currency(Decimal.t()) :: String.t()
def format_currency(%Decimal{} = amount) do
# Use German format: comma as decimal separator, always 2 decimal places
# Normalize to 2 decimal places
normalized = Decimal.round(amount, 2)
normalized_str = Decimal.to_string(normalized, :normal)
normalized_str =
normalized
|> Decimal.to_string(:normal)
|> String.replace(".", ",")
format_currency_parts(normalized_str)
end
# Ensure 2 decimal places
case String.split(normalized_str, ",") do
[int_part, dec_part] when byte_size(dec_part) == 1 ->
"#{int_part},#{dec_part}0 €"
[int_part, dec_part] when byte_size(dec_part) == 2 ->
"#{int_part},#{dec_part}"
# Formats currency string with comma as decimal separator
defp format_currency_parts(normalized_str) do
case String.split(normalized_str, ".") do
[int_part, dec_part] ->
format_with_decimal_part(int_part, dec_part)
[int_part] ->
"#{int_part},00 €"
_ ->
"#{normalized_str}"
# Fallback for unexpected split results
"#{String.replace(normalized_str, ".", ",")}"
end
end
# Formats currency with decimal part, ensuring exactly 2 decimal places
defp format_with_decimal_part(int_part, dec_part) do
dec_size = byte_size(dec_part)
formatted_dec =
cond do
dec_size == 1 -> "#{dec_part}0"
dec_size == 2 -> dec_part
dec_size > 2 -> String.slice(dec_part, 0, 2)
true -> "00"
end
"#{int_part},#{formatted_dec}"
end
@doc """
Formats an interval atom as a translated string.
@ -179,6 +191,7 @@ defmodule MvWeb.Helpers.MembershipFeeHelpers do
|> Enum.filter(fn cycle ->
CalendarCycles.current_cycle?(cycle.cycle_start, fee_type.interval, today)
end)
|> Enum.sort_by(& &1.cycle_start, {:desc, Date})
|> List.first()
end
end