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:
parent
5343b78750
commit
376086ae0f
3 changed files with 117 additions and 2 deletions
|
|
@ -319,11 +319,40 @@ defmodule MvWeb.MemberLive.Form do
|
|||
socket =
|
||||
socket
|
||||
|> put_flash(:info, flash_message)
|
||||
|> maybe_put_vereinfacht_sync_flash(member.id)
|
||||
|> push_navigate(to: return_path(socket.assigns.return_to, member))
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
defp maybe_put_vereinfacht_sync_flash(socket, member_id) do
|
||||
case Mv.Vereinfacht.SyncFlash.take(to_string(member_id)) do
|
||||
{:warning, message} ->
|
||||
put_flash(socket, :warning, translate_vereinfacht_flash(message))
|
||||
|
||||
{:ok, _message} ->
|
||||
# Optionally show sync success; for now we keep only the main success message
|
||||
socket
|
||||
|
||||
nil ->
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
defp translate_vereinfacht_flash(message) when is_binary(message) do
|
||||
prefix = "Vereinfacht: "
|
||||
|
||||
if String.starts_with?(message, prefix) do
|
||||
detail = message |> String.trim_leading(prefix) |> String.trim()
|
||||
|
||||
Gettext.dgettext(MvWeb.Gettext, "default", "Vereinfacht: %{detail}",
|
||||
detail: Gettext.dgettext(MvWeb.Gettext, "default", detail)
|
||||
)
|
||||
else
|
||||
Gettext.dgettext(MvWeb.Gettext, "default", message)
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_save_error(socket, form) do
|
||||
# Always show a flash message when save fails
|
||||
# Field-level validation errors are displayed in form fields, but flash provides additional feedback
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ defmodule MvWeb.MemberLive.Show do
|
|||
id={"membership-fees-#{@member.id}"}
|
||||
member={@member}
|
||||
current_user={@current_user}
|
||||
vereinfacht_debug_response={@vereinfacht_debug_response}
|
||||
/>
|
||||
<% end %>
|
||||
</Layouts.app>
|
||||
|
|
@ -264,7 +265,10 @@ defmodule MvWeb.MemberLive.Show do
|
|||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, assign(socket, :active_tab, :contact)}
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(:active_tab, :contact)
|
||||
|> assign(:vereinfacht_debug_response, nil)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
@ -316,6 +320,16 @@ defmodule MvWeb.MemberLive.Show do
|
|||
{:noreply, assign(socket, :active_tab, :membership_fees)}
|
||||
end
|
||||
|
||||
def handle_event("load_vereinfacht_debug", %{"contact_id" => contact_id}, socket) do
|
||||
response =
|
||||
case Mv.Vereinfacht.Client.get_contact(contact_id) do
|
||||
{:ok, body} -> {:ok, body}
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, :vereinfacht_debug_response, response)}
|
||||
end
|
||||
|
||||
# Flash set in LiveComponent is not shown in parent layout; child sends this to display flash
|
||||
@impl true
|
||||
def handle_info({:put_flash, type, message}, socket) do
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue