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
81bcd2bc4d
commit
d0fa3991f7
3 changed files with 117 additions and 2 deletions
|
|
@ -319,11 +319,40 @@ defmodule MvWeb.MemberLive.Form do
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> put_flash(:info, flash_message)
|
|> put_flash(:info, flash_message)
|
||||||
|
|> maybe_put_vereinfacht_sync_flash(member.id)
|
||||||
|> push_navigate(to: return_path(socket.assigns.return_to, member))
|
|> push_navigate(to: return_path(socket.assigns.return_to, member))
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
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
|
defp handle_save_error(socket, form) do
|
||||||
# Always show a flash message when save fails
|
# Always show a flash message when save fails
|
||||||
# Field-level validation errors are displayed in form fields, but flash provides additional feedback
|
# 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}"}
|
id={"membership-fees-#{@member.id}"}
|
||||||
member={@member}
|
member={@member}
|
||||||
current_user={@current_user}
|
current_user={@current_user}
|
||||||
|
vereinfacht_debug_response={@vereinfacht_debug_response}
|
||||||
/>
|
/>
|
||||||
<% end %>
|
<% end %>
|
||||||
</Layouts.app>
|
</Layouts.app>
|
||||||
|
|
@ -264,7 +265,10 @@ defmodule MvWeb.MemberLive.Show do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(_params, _session, socket) do
|
def mount(_params, _session, socket) do
|
||||||
{:ok, assign(socket, :active_tab, :contact)}
|
{:ok,
|
||||||
|
socket
|
||||||
|
|> assign(:active_tab, :contact)
|
||||||
|
|> assign(:vereinfacht_debug_response, nil)}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
@ -316,6 +320,16 @@ defmodule MvWeb.MemberLive.Show do
|
||||||
{:noreply, assign(socket, :active_tab, :membership_fees)}
|
{:noreply, assign(socket, :active_tab, :membership_fees)}
|
||||||
end
|
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
|
# Flash set in LiveComponent is not shown in parent layout; child sends this to display flash
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:put_flash, type, message}, socket) do
|
def handle_info({:put_flash, type, message}, socket) do
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,60 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</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) --%>
|
<%!-- Action Buttons (only when user has permission) --%>
|
||||||
<div class="flex gap-2 mb-4">
|
<div class="flex gap-2 mb-4">
|
||||||
<.button
|
<.button
|
||||||
|
|
@ -439,7 +493,8 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
|> assign_new(:creating_cycle, fn -> false end)
|
|> assign_new(:creating_cycle, fn -> false end)
|
||||||
|> assign_new(:create_cycle_date, fn -> nil end)
|
|> assign_new(:create_cycle_date, fn -> nil end)
|
||||||
|> assign_new(:create_cycle_error, 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
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
@ -997,6 +1052,23 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
|
||||||
|
|
||||||
defp format_create_cycle_period(_date, _interval), 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
|
# Helper component for section box
|
||||||
attr :title, :string, required: true
|
attr :title, :string, required: true
|
||||||
slot :inner_block, required: true
|
slot :inner_block, required: true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue