feat(vereinfacht): member form flash and show page

- Form: show Vereinfacht sync warning after save via SyncFlash
- Show: load API debug response; MembershipFees: contact ID, link, no-contact warning
This commit is contained in:
Moritz 2026-02-18 22:28:55 +01:00
parent 81bcd2bc4d
commit d0fa3991f7
Signed by: moritz
GPG key ID: 1020A035E5DD0824
3 changed files with 117 additions and 2 deletions

View file

@ -50,6 +50,60 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
<% end %>
</div>
<%!-- Vereinfacht: contact info when synced, or warning when API is configured but no contact --%>
<%= if Mv.Config.vereinfacht_configured?() do %>
<%= if @member.vereinfacht_contact_id do %>
<div class="mb-4">
<label class="label">
<span class="label-text font-semibold">{gettext("Vereinfacht")}</span>
</label>
<div class="flex flex-col gap-1">
<span class="font-mono text-sm">
{gettext("Contact ID: %{id}", id: @member.vereinfacht_contact_id)}
</span>
<.link
:if={Mv.Config.vereinfacht_contact_view_url(@member.vereinfacht_contact_id)}
href={Mv.Config.vereinfacht_contact_view_url(@member.vereinfacht_contact_id)}
target="_blank"
rel="noopener noreferrer"
class="link link-primary inline-flex items-center gap-1"
>
{gettext("View contact in Vereinfacht")}
<.icon name="hero-arrow-top-right-on-square" class="inline-block size-4" />
</.link>
<div class="mt-2">
<span class="text-base-content/70 text-sm">{gettext("Debug:")}</span>
<button
type="button"
phx-click="load_vereinfacht_debug"
phx-value-contact_id={@member.vereinfacht_contact_id}
class="btn btn-sm btn-ghost ml-1"
>
{gettext("Load API response")}
</button>
</div>
<%= if @vereinfacht_debug_response do %>
<div class="mt-2 rounded border border-base-300 bg-base-200 p-3 overflow-x-auto max-h-96 overflow-y-auto">
<pre class="text-xs whitespace-pre-wrap font-mono"><%= format_vereinfacht_debug_response(@vereinfacht_debug_response) %></pre>
</div>
<% end %>
</div>
</div>
<% else %>
<div class="mb-4 rounded-lg border border-warning/50 bg-warning/10 p-3">
<p class="text-warning font-medium flex items-center gap-2">
<.icon name="hero-exclamation-triangle" class="size-5 shrink-0" />
{gettext("No Vereinfacht contact exists for this member.")}
</p>
<p class="text-sm text-base-content/70 mt-1">
{gettext(
"Sync this member from Settings (Vereinfacht section) or save the member again to create the contact."
)}
</p>
</div>
<% end %>
<% end %>
<%!-- Action Buttons (only when user has permission) --%>
<div class="flex gap-2 mb-4">
<.button
@ -439,7 +493,8 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|> assign_new(:creating_cycle, fn -> false end)
|> assign_new(:create_cycle_date, fn -> nil end)
|> assign_new(:create_cycle_error, fn -> nil end)
|> assign_new(:regenerating, fn -> false end)}
|> assign_new(:regenerating, fn -> false end)
|> assign_new(:vereinfacht_debug_response, fn -> nil end)}
end
@impl true
@ -997,6 +1052,23 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
defp format_create_cycle_period(_date, _interval), do: ""
defp format_vereinfacht_debug_response({:ok, body}) when is_map(body) do
Jason.encode!(body, pretty: true)
end
defp format_vereinfacht_debug_response({:error, {:http, status, detail}})
when is_binary(detail) do
"Error: HTTP #{status} #{detail}"
end
defp format_vereinfacht_debug_response({:error, {:http, status, _}}) do
"Error: HTTP #{status}"
end
defp format_vereinfacht_debug_response({:error, reason}) do
"Error: " <> inspect(reason)
end
# Helper component for section box
attr :title, :string, required: true
slot :inner_block, required: true