Merge pull request 'Fix UI issues' (#242) from ui-fixes into main
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #242 Reviewed-by: simon <s.thiessen@local-it.org>
This commit is contained in:
commit
422cf37a1e
14 changed files with 133 additions and 97 deletions
|
|
@ -79,7 +79,7 @@ defmodule MvWeb.CoreComponents do
|
||||||
<p>{msg}</p>
|
<p>{msg}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1" />
|
<div class="flex-1" />
|
||||||
<button type="button" class="group self-start cursor-pointer" aria-label={gettext("close")}>
|
<button type="button" class="self-start cursor-pointer group" aria-label={gettext("close")}>
|
||||||
<.icon name="hero-x-mark" class="size-5 opacity-40 group-hover:opacity-70" />
|
<.icon name="hero-x-mark" class="size-5 opacity-40 group-hover:opacity-70" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -368,61 +368,63 @@ defmodule MvWeb.CoreComponents do
|
||||||
end
|
end
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<table class="table table-zebra">
|
<div class="overflow-auto">
|
||||||
<thead>
|
<table class="table table-zebra">
|
||||||
<tr>
|
<thead>
|
||||||
<th :for={col <- @col}>{col[:label]}</th>
|
<tr>
|
||||||
<th :for={dyn_col <- @dynamic_cols}>
|
<th :for={col <- @col}>{col[:label]}</th>
|
||||||
<.live_component
|
<th :for={dyn_col <- @dynamic_cols}>
|
||||||
module={MvWeb.Components.SortHeaderComponent}
|
<.live_component
|
||||||
id={:"sort_custom_field_#{dyn_col[:custom_field].id}"}
|
module={MvWeb.Components.SortHeaderComponent}
|
||||||
field={"custom_field_#{dyn_col[:custom_field].id}"}
|
id={:"sort_custom_field_#{dyn_col[:custom_field].id}"}
|
||||||
label={dyn_col[:custom_field].name}
|
field={"custom_field_#{dyn_col[:custom_field].id}"}
|
||||||
sort_field={@sort_field}
|
label={dyn_col[:custom_field].name}
|
||||||
sort_order={@sort_order}
|
sort_field={@sort_field}
|
||||||
/>
|
sort_order={@sort_order}
|
||||||
</th>
|
/>
|
||||||
<th :if={@action != []}>
|
</th>
|
||||||
<span class="sr-only">{gettext("Actions")}</span>
|
<th :if={@action != []}>
|
||||||
</th>
|
<span class="sr-only">{gettext("Actions")}</span>
|
||||||
</tr>
|
</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody id={@id} phx-update={is_struct(@rows, Phoenix.LiveView.LiveStream) && "stream"}>
|
</thead>
|
||||||
<tr :for={row <- @rows} id={@row_id && @row_id.(row)}>
|
<tbody id={@id} phx-update={is_struct(@rows, Phoenix.LiveView.LiveStream) && "stream"}>
|
||||||
<td
|
<tr :for={row <- @rows} id={@row_id && @row_id.(row)}>
|
||||||
:for={col <- @col}
|
<td
|
||||||
phx-click={@row_click && @row_click.(row)}
|
:for={col <- @col}
|
||||||
class={@row_click && "hover:cursor-pointer"}
|
phx-click={@row_click && @row_click.(row)}
|
||||||
>
|
class={["max-w-xs truncate", @row_click && "hover:cursor-pointer"]}
|
||||||
{render_slot(col, @row_item.(row))}
|
>
|
||||||
</td>
|
{render_slot(col, @row_item.(row))}
|
||||||
<td
|
</td>
|
||||||
:for={dyn_col <- @dynamic_cols}
|
<td
|
||||||
phx-click={@row_click && @row_click.(row)}
|
:for={dyn_col <- @dynamic_cols}
|
||||||
class={@row_click && "hover:cursor-pointer"}
|
phx-click={@row_click && @row_click.(row)}
|
||||||
>
|
class={["max-w-xs truncate", @row_click && "hover:cursor-pointer"]}
|
||||||
{if dyn_col[:render] do
|
>
|
||||||
rendered = dyn_col[:render].(@row_item.(row))
|
{if dyn_col[:render] do
|
||||||
|
rendered = dyn_col[:render].(@row_item.(row))
|
||||||
|
|
||||||
if rendered == "" do
|
if rendered == "" do
|
||||||
""
|
""
|
||||||
|
else
|
||||||
|
rendered
|
||||||
|
end
|
||||||
else
|
else
|
||||||
rendered
|
""
|
||||||
end
|
end}
|
||||||
else
|
</td>
|
||||||
""
|
<td :if={@action != []} class="w-0 font-semibold">
|
||||||
end}
|
<div class="flex gap-4">
|
||||||
</td>
|
<%= for action <- @action do %>
|
||||||
<td :if={@action != []} class="w-0 font-semibold">
|
{render_slot(action, @row_item.(row))}
|
||||||
<div class="flex gap-4">
|
<% end %>
|
||||||
<%= for action <- @action do %>
|
</div>
|
||||||
{render_slot(action, @row_item.(row))}
|
</td>
|
||||||
<% end %>
|
</tr>
|
||||||
</div>
|
</tbody>
|
||||||
</td>
|
</table>
|
||||||
</tr>
|
</div>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
27
lib/mv_web/helpers/date_formatter.ex
Normal file
27
lib/mv_web/helpers/date_formatter.ex
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
defmodule MvWeb.Helpers.DateFormatter do
|
||||||
|
@moduledoc """
|
||||||
|
Centralized date formatting helper for the application.
|
||||||
|
Formats dates in European format (dd.mm.yyyy).
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Gettext, backend: MvWeb.Gettext
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Formats a Date struct to European format (dd.mm.yyyy).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> MvWeb.Helpers.DateFormatter.format_date(~D[2024-03-15])
|
||||||
|
"15.03.2024"
|
||||||
|
|
||||||
|
iex> MvWeb.Helpers.DateFormatter.format_date(nil)
|
||||||
|
""
|
||||||
|
"""
|
||||||
|
def format_date(%Date{} = date) do
|
||||||
|
Calendar.strftime(date, "%d.%m.%Y")
|
||||||
|
end
|
||||||
|
|
||||||
|
def format_date(nil), do: ""
|
||||||
|
|
||||||
|
def format_date(_), do: "Invalid date"
|
||||||
|
end
|
||||||
|
|
@ -19,7 +19,7 @@ defmodule MvWeb.Components.SortHeaderComponent do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="tooltip" data-tip={aria_sort(@field, @sort_field, @sort_order)}>
|
<div class="tooltip tooltip-bottom" data-tip={aria_sort(@field, @sort_field, @sort_order)}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={aria_sort(@field, @sort_field, @sort_order)}
|
aria-label={aria_sort(@field, @sort_field, @sort_order)}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
|
|
||||||
alias Mv.Membership
|
alias Mv.Membership
|
||||||
alias MvWeb.MemberLive.Index.Formatter
|
alias MvWeb.MemberLive.Index.Formatter
|
||||||
|
alias MvWeb.Helpers.DateFormatter
|
||||||
|
|
||||||
# Prefix used in sort field names for custom fields (e.g., "custom_field_<id>")
|
# Prefix used in sort field names for custom fields (e.g., "custom_field_<id>")
|
||||||
@custom_field_prefix "custom_field_"
|
@custom_field_prefix "custom_field_"
|
||||||
|
|
@ -937,4 +938,7 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
Map.get(visibility_config, Atom.to_string(field), true)
|
Map.get(visibility_config, Atom.to_string(field), true)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Public helper function to format dates for use in templates
|
||||||
|
def format_date(date), do: DateFormatter.format_date(date)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{member.join_date}
|
{MvWeb.MemberLive.Index.format_date(member.join_date)}
|
||||||
</:col>
|
</:col>
|
||||||
<:col :let={member} label={gettext("Paid")}>
|
<:col :let={member} label={gettext("Paid")}>
|
||||||
<span class={[
|
<span class={[
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ defmodule MvWeb.MemberLive.Index.Formatter do
|
||||||
formats them appropriately for display in the UI.
|
formats them appropriately for display in the UI.
|
||||||
"""
|
"""
|
||||||
use Gettext, backend: MvWeb.Gettext
|
use Gettext, backend: MvWeb.Gettext
|
||||||
|
alias MvWeb.Helpers.DateFormatter
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Formats a custom field value for display.
|
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, _) when value == false, do: gettext("No")
|
||||||
defp format_value_by_type(value, :boolean, _), do: to_string(value)
|
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
|
defp format_value_by_type(value, :date, _) when is_binary(value) do
|
||||||
case Date.from_iso8601(value) do
|
case Date.from_iso8601(value) do
|
||||||
{:ok, date} -> Date.to_string(date)
|
{:ok, date} -> DateFormatter.format_date(date)
|
||||||
_ -> value
|
_ -> value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ defmodule MvWeb.MemberLive.Show do
|
||||||
"""
|
"""
|
||||||
use MvWeb, :live_view
|
use MvWeb, :live_view
|
||||||
import Ash.Query
|
import Ash.Query
|
||||||
|
alias MvWeb.Helpers.DateFormatter
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
|
|
@ -52,8 +53,8 @@ defmodule MvWeb.MemberLive.Show do
|
||||||
{if @member.paid, do: gettext("Yes"), else: gettext("No")}
|
{if @member.paid, do: gettext("Yes"), else: gettext("No")}
|
||||||
</:item>
|
</:item>
|
||||||
<:item title={gettext("Phone Number")}>{@member.phone_number}</:item>
|
<:item title={gettext("Phone Number")}>{@member.phone_number}</:item>
|
||||||
<:item title={gettext("Join Date")}>{@member.join_date}</:item>
|
<:item title={gettext("Join Date")}>{DateFormatter.format_date(@member.join_date)}</:item>
|
||||||
<:item title={gettext("Exit Date")}>{@member.exit_date}</:item>
|
<:item title={gettext("Exit Date")}>{DateFormatter.format_date(@member.exit_date)}</:item>
|
||||||
<:item title={gettext("Notes")}>{@member.notes}</:item>
|
<:item title={gettext("Notes")}>{@member.notes}</:item>
|
||||||
<:item title={gettext("City")}>{@member.city}</:item>
|
<:item title={gettext("City")}>{@member.city}</:item>
|
||||||
<:item title={gettext("Street")}>{@member.street}</:item>
|
<:item title={gettext("Street")}>{@member.street}</:item>
|
||||||
|
|
@ -81,10 +82,7 @@ defmodule MvWeb.MemberLive.Show do
|
||||||
# name
|
# name
|
||||||
cfv.custom_field && cfv.custom_field.name,
|
cfv.custom_field && cfv.custom_field.name,
|
||||||
# value
|
# value
|
||||||
case cfv.value do
|
format_custom_field_value(cfv)
|
||||||
%{value: v} -> v
|
|
||||||
v -> v
|
|
||||||
end
|
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
} />
|
} />
|
||||||
|
|
@ -114,4 +112,17 @@ defmodule MvWeb.MemberLive.Show do
|
||||||
|
|
||||||
defp page_title(:show), do: gettext("Show Member")
|
defp page_title(:show), do: gettext("Show Member")
|
||||||
defp page_title(:edit), do: gettext("Edit 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
|
end
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
<:subtitle>{gettext("Use this form to manage user records in your database.")}</:subtitle>
|
<:subtitle>{gettext("Use this form to manage user records in your database.")}</:subtitle>
|
||||||
</.header>
|
</.header>
|
||||||
|
|
||||||
<.form for={@form} id="user-form" phx-change="validate" phx-submit="save">
|
<.form class="max-w-xl" for={@form} id="user-form" phx-change="validate" phx-submit="save">
|
||||||
<.input field={@form[:email]} label={gettext("Email")} required type="email" />
|
<.input field={@form[:email]} label={gettext("Email")} required type="email" />
|
||||||
|
|
||||||
<!-- Password Section -->
|
<!-- Password Section -->
|
||||||
|
|
@ -61,7 +61,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<%= if @show_password_fields do %>
|
<%= if @show_password_fields do %>
|
||||||
<div class="mt-4 space-y-4 p-4 bg-gray-50 rounded-lg">
|
<div class="p-4 mt-4 space-y-4 rounded-lg bg-gray-50">
|
||||||
<.input
|
<.input
|
||||||
field={@form[:password]}
|
field={@form[:password]}
|
||||||
label={gettext("Password")}
|
label={gettext("Password")}
|
||||||
|
|
@ -83,7 +83,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
|
|
||||||
<div class="text-sm text-gray-600">
|
<div class="text-sm text-gray-600">
|
||||||
<p><strong>{gettext("Password requirements")}:</strong></p>
|
<p><strong>{gettext("Password requirements")}:</strong></p>
|
||||||
<ul class="list-disc list-inside text-xs mt-1 space-y-1">
|
<ul class="mt-1 space-y-1 text-xs list-disc list-inside">
|
||||||
<li>{gettext("At least 8 characters")}</li>
|
<li>{gettext("At least 8 characters")}</li>
|
||||||
<li>{gettext("Include both letters and numbers")}</li>
|
<li>{gettext("Include both letters and numbers")}</li>
|
||||||
<li>{gettext("Consider using special characters")}</li>
|
<li>{gettext("Consider using special characters")}</li>
|
||||||
|
|
@ -91,7 +91,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= if @user do %>
|
<%= if @user do %>
|
||||||
<div class="mt-3 p-3 bg-orange-50 border border-orange-200 rounded">
|
<div class="p-3 mt-3 border border-orange-200 rounded bg-orange-50">
|
||||||
<p class="text-sm text-orange-800">
|
<p class="text-sm text-orange-800">
|
||||||
<strong>{gettext("Admin Note")}:</strong> {gettext(
|
<strong>{gettext("Admin Note")}:</strong> {gettext(
|
||||||
"As an administrator, you can directly set a new password for this user using the same secure Ash Authentication system."
|
"As an administrator, you can directly set a new password for this user using the same secure Ash Authentication system."
|
||||||
|
|
@ -102,7 +102,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= if @user do %>
|
<%= if @user do %>
|
||||||
<div class="mt-4 p-4 bg-blue-50 rounded-lg">
|
<div class="p-4 mt-4 rounded-lg bg-blue-50">
|
||||||
<p class="text-sm text-blue-800">
|
<p class="text-sm text-blue-800">
|
||||||
<strong>{gettext("Note")}:</strong> {gettext(
|
<strong>{gettext("Note")}:</strong> {gettext(
|
||||||
"Check 'Change Password' above to set a new password for this user."
|
"Check 'Change Password' above to set a new password for this user."
|
||||||
|
|
@ -110,7 +110,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
<div class="mt-4 p-4 bg-yellow-50 rounded-lg">
|
<div class="p-4 mt-4 rounded-lg bg-yellow-50">
|
||||||
<p class="text-sm text-yellow-800">
|
<p class="text-sm text-yellow-800">
|
||||||
<strong>{gettext("Note")}:</strong> {gettext(
|
<strong>{gettext("Note")}:</strong> {gettext(
|
||||||
"User will be created without a password. Check 'Set Password' to add one."
|
"User will be created without a password. Check 'Set Password' to add one."
|
||||||
|
|
@ -123,11 +123,11 @@ defmodule MvWeb.UserLive.Form do
|
||||||
|
|
||||||
<!-- Member Linking Section -->
|
<!-- Member Linking Section -->
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<h2 class="text-base font-semibold mb-3">{gettext("Linked Member")}</h2>
|
<h2 class="mb-3 text-base font-semibold">{gettext("Linked Member")}</h2>
|
||||||
|
|
||||||
<%= if @user && @user.member && !@unlink_member do %>
|
<%= if @user && @user.member && !@unlink_member do %>
|
||||||
<!-- Show linked member with unlink button -->
|
<!-- Show linked member with unlink button -->
|
||||||
<div class="p-4 bg-green-50 border border-green-200 rounded-lg">
|
<div class="p-4 border border-green-200 rounded-lg bg-green-50">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-green-900">
|
<p class="font-medium text-green-900">
|
||||||
|
|
@ -147,7 +147,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= if @unlink_member do %>
|
<%= if @unlink_member do %>
|
||||||
<!-- Show unlink pending message -->
|
<!-- Show unlink pending message -->
|
||||||
<div class="p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
|
<div class="p-4 border border-yellow-200 rounded-lg bg-yellow-50">
|
||||||
<p class="text-sm text-yellow-800">
|
<p class="text-sm text-yellow-800">
|
||||||
<strong>{gettext("Unlinking scheduled")}:</strong> {gettext(
|
<strong>{gettext("Unlinking scheduled")}:</strong> {gettext(
|
||||||
"Member will be unlinked when you save. Cannot select new member until saved."
|
"Member will be unlinked when you save. Cannot select new member until saved."
|
||||||
|
|
@ -219,7 +219,7 @@ defmodule MvWeb.UserLive.Form do
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= if @user && @user.email && @available_members != [] && Enum.all?(@available_members, &(&1.email == to_string(@user.email))) do %>
|
<%= if @user && @user.email && @available_members != [] && Enum.all?(@available_members, &(&1.email == to_string(@user.email))) do %>
|
||||||
<div class="p-3 bg-yellow-50 border border-yellow-200 rounded">
|
<div class="p-3 border border-yellow-200 rounded bg-yellow-50">
|
||||||
<p class="text-sm text-yellow-800">
|
<p class="text-sm text-yellow-800">
|
||||||
<strong>{gettext("Note")}:</strong> {gettext(
|
<strong>{gettext("Note")}:</strong> {gettext(
|
||||||
"A member with this email already exists. To link with a different member, please change one of the email addresses first."
|
"A member with this email already exists. To link with a different member, please change one of the email addresses first."
|
||||||
|
|
@ -231,12 +231,12 @@ defmodule MvWeb.UserLive.Form do
|
||||||
<%= if @selected_member_id && @selected_member_name do %>
|
<%= if @selected_member_id && @selected_member_name do %>
|
||||||
<div
|
<div
|
||||||
id="member-selected"
|
id="member-selected"
|
||||||
class="mt-2 p-3 bg-blue-50 border border-blue-200 rounded-lg"
|
class="p-3 mt-2 border border-blue-200 rounded-lg bg-blue-50"
|
||||||
>
|
>
|
||||||
<p class="text-sm text-blue-800">
|
<p class="text-sm text-blue-800">
|
||||||
<strong>{gettext("Selected")}:</strong> {@selected_member_name}
|
<strong>{gettext("Selected")}:</strong> {@selected_member_name}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-blue-600 mt-1">
|
<p class="mt-1 text-xs text-blue-600">
|
||||||
{gettext("Save to confirm linking.")}
|
{gettext("Save to confirm linking.")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -245,10 +245,12 @@ defmodule MvWeb.UserLive.Form do
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<.button phx-disable-with={gettext("Saving...")} variant="primary">
|
<div class="mt-4">
|
||||||
{gettext("Save User")}
|
<.button phx-disable-with={gettext("Saving...")} variant="primary">
|
||||||
</.button>
|
{gettext("Save User")}
|
||||||
<.button navigate={return_path(@return_to, @user)}>{gettext("Cancel")}</.button>
|
</.button>
|
||||||
|
<.button navigate={return_path(@return_to, @user)}>{gettext("Cancel")}</.button>
|
||||||
|
</div>
|
||||||
</.form>
|
</.form>
|
||||||
</Layouts.app>
|
</Layouts.app>
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@
|
||||||
>
|
>
|
||||||
{user.email}
|
{user.email}
|
||||||
</:col>
|
</:col>
|
||||||
<:col :let={user} label={gettext("OIDC ID")}>{user.oidc_id}</:col>
|
|
||||||
<:col :let={user} label={gettext("Linked Member")}>
|
<:col :let={user} label={gettext("Linked Member")}>
|
||||||
<%= if user.member do %>
|
<%= if user.member do %>
|
||||||
{user.member.first_name} {user.member.last_name}
|
{user.member.first_name} {user.member.last_name}
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,7 @@ defmodule MvWeb.UserLive.Show do
|
||||||
</.header>
|
</.header>
|
||||||
|
|
||||||
<.list>
|
<.list>
|
||||||
<:item title={gettext("ID")}>{@user.id}</:item>
|
|
||||||
<:item title={gettext("Email")}>{@user.email}</:item>
|
<:item title={gettext("Email")}>{@user.email}</:item>
|
||||||
<:item title={gettext("OIDC ID")}>{@user.oidc_id || gettext("Not set")}</:item>
|
|
||||||
<:item title={gettext("Password Authentication")}>
|
<:item title={gettext("Password Authentication")}>
|
||||||
{if @user.hashed_password, do: gettext("Enabled"), else: gettext("Not enabled")}
|
{if @user.hashed_password, do: gettext("Enabled"), else: gettext("Not enabled")}
|
||||||
</:item>
|
</:item>
|
||||||
|
|
@ -56,13 +54,13 @@ defmodule MvWeb.UserLive.Show do
|
||||||
<%= if @user.member do %>
|
<%= if @user.member do %>
|
||||||
<.link
|
<.link
|
||||||
navigate={~p"/members/#{@user.member}"}
|
navigate={~p"/members/#{@user.member}"}
|
||||||
class="text-blue-600 hover:text-blue-800 underline"
|
class="text-blue-600 underline hover:text-blue-800"
|
||||||
>
|
>
|
||||||
<.icon name="hero-users" class="h-4 w-4 inline mr-1" />
|
<.icon name="hero-users" class="inline w-4 h-4 mr-1" />
|
||||||
{@user.member.first_name} {@user.member.last_name}
|
{@user.member.first_name} {@user.member.last_name}
|
||||||
</.link>
|
</.link>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="text-gray-500 italic">{gettext("No member linked")}</span>
|
<span class="italic text-gray-500">{gettext("No member linked")}</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</:item>
|
</:item>
|
||||||
</.list>
|
</.list>
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ msgstr "Löschen"
|
||||||
#: lib/mv_web/live/user_live/index.html.heex:66
|
#: lib/mv_web/live/user_live/index.html.heex:66
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Bearbeite"
|
msgstr "Bearbeiten"
|
||||||
|
|
||||||
#: lib/mv_web/live/member_live/show.ex:41
|
#: lib/mv_web/live/member_live/show.ex:41
|
||||||
#: lib/mv_web/live/member_live/show.ex:116
|
#: lib/mv_web/live/member_live/show.ex:116
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,6 @@ defmodule MvWeb.ProfileNavigationTest do
|
||||||
# Verify we're on the correct profile page with OIDC specific information
|
# Verify we're on the correct profile page with OIDC specific information
|
||||||
{:ok, _profile_view, html} = live(conn, "/users/#{user.id}")
|
{:ok, _profile_view, html} = live(conn, "/users/#{user.id}")
|
||||||
assert html =~ to_string(user.email)
|
assert html =~ to_string(user.email)
|
||||||
# OIDC ID should be visible
|
|
||||||
assert html =~ "oidc_123"
|
|
||||||
# Password auth should be disabled for OIDC users
|
# Password auth should be disabled for OIDC users
|
||||||
assert html =~ "Not enabled"
|
assert html =~ "Not enabled"
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -231,8 +231,8 @@ defmodule MvWeb.MemberLive.IndexCustomFieldsDisplayTest do
|
||||||
conn = conn_with_oidc_user(conn)
|
conn = conn_with_oidc_user(conn)
|
||||||
{:ok, _view, html} = live(conn, "/members")
|
{:ok, _view, html} = live(conn, "/members")
|
||||||
|
|
||||||
# Date should be displayed in readable format
|
# Date should be displayed in European format (dd.mm.yyyy)
|
||||||
assert html =~ "1990" or html =~ "1990-05-15" or html =~ "15.05.1990"
|
assert html =~ "15.05.1990"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "formats email custom field values correctly", %{conn: conn, member1: _member1} do
|
test "formats email custom field values correctly", %{conn: conn, member1: _member1} do
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,6 @@ defmodule MvWeb.UserLive.IndexTest do
|
||||||
|
|
||||||
assert html =~ "alice@example.com"
|
assert html =~ "alice@example.com"
|
||||||
assert html =~ "bob@example.com"
|
assert html =~ "bob@example.com"
|
||||||
assert html =~ "alice123"
|
|
||||||
assert html =~ "bob456"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "shows correct action links", %{conn: conn} do
|
test "shows correct action links", %{conn: conn} do
|
||||||
|
|
@ -386,10 +384,6 @@ defmodule MvWeb.UserLive.IndexTest do
|
||||||
|
|
||||||
# Should still show the table structure
|
# Should still show the table structure
|
||||||
assert html =~ "Email"
|
assert html =~ "Email"
|
||||||
assert html =~ "OIDC ID"
|
|
||||||
# Should show the authenticated user at minimum
|
|
||||||
# Matches the generated email pattern oidc.user{unique_id}@example.com
|
|
||||||
assert html =~ "oidc.user"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "handles users with missing OIDC ID", %{conn: conn} do
|
test "handles users with missing OIDC ID", %{conn: conn} do
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue