feature/account_view closes #106 #109

Merged
moritz merged 10 commits from feature/account_view into main 2025-07-24 17:08:34 +02:00
3 changed files with 158 additions and 48 deletions
Showing only changes of commit 5959c9f545 - Show all commits

View file

@ -1,54 +1,19 @@
defmodule MvWeb.UserLive.Index do
use MvWeb, :live_view
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash}>
<.header>
{gettext("Listing Users")}
<:actions>
<.button variant="primary" navigate={~p"/users/new"}>
<.icon name="hero-plus" /> {gettext("New User")}
</.button>
</:actions>
</.header>
<.table
id="users"
rows={@streams.users}
row_click={fn {_id, user} -> JS.navigate(~p"/users/#{user}") end}
>
<:col :let={{_id, user}} label={gettext("Email")}>{user.email}</:col>
<:col :let={{_id, user}} label={gettext("OIDC ID")}>{user.oidc_id}</:col>
<:action :let={{_id, user}}>
<div class="sr-only">
<.link navigate={~p"/users/#{user}"}>{gettext("Show")}</.link>
</div>
<.link navigate={~p"/users/#{user}/edit"}>{gettext("Edit")}</.link>
</:action>
<:action :let={{id, user}}>
<.link
phx-click={JS.push("delete", value: %{id: user.id}) |> hide("##{id}")}
data-confirm={gettext("Are you sure?")}
>
{gettext("Delete")}
</.link>
</:action>
</.table>
</Layouts.app>
"""
end
import MvWeb.TableComponents
@impl true
def mount(_params, _session, socket) do
users = Ash.read!(Mv.Accounts.User, domain: Mv.Accounts)
sorted = Enum.sort_by(users, & &1.email)
{:ok,
socket
|> assign(:page_title, gettext("Listing Users"))
|> stream(:users, Ash.read!(Mv.Accounts.User, domain: Mv.Accounts))}
|> assign(:sort_field, :email)
|> assign(:sort_order, :asc)
|> assign(:users, sorted)
|> assign(:selected_users, [])}
end
@impl true
@ -56,6 +21,66 @@ defmodule MvWeb.UserLive.Index do
user = Ash.get!(Mv.Accounts.User, id, domain: Mv.Accounts)
Ash.destroy!(user, domain: Mv.Accounts)
{:noreply, stream_delete(socket, :users, user)}
updated_users = Enum.reject(socket.assigns.users, &(&1.id == id))
{:noreply, assign(socket, :users, updated_users)}
end
# Selects one user in the list of users
@impl true
def handle_event("select_user", %{"id" => id}, socket) do
selected =
if id in socket.assigns.selected_users do
List.delete(socket.assigns.selected_users, id)
else
[id | socket.assigns.selected_users]
end
{:noreply, assign(socket, :selected_users, selected)}
end
# Sorts the list of users according to a field, when you click on the column header
moritz marked this conversation as resolved Outdated

maybe at some point we can seperate the sort function as we use the same in members?

maybe at some point we can seperate the sort function as we use the same in members?

Yes I think we can do some refactoring like this in a few weeks to merge some duplicated functions. I created this issue to collect some refactor steps: #122

Yes I think we can do some refactoring like this in a few weeks to merge some duplicated functions. I created this issue to collect some refactor steps: https://git.local-it.org/local-it/mitgliederverwaltung/issues/122
@impl true
def handle_event("sort", %{"field" => field_str}, socket) do
users = socket.assigns.users
field = String.to_existing_atom(field_str)
new_order =
if socket.assigns.sort_field == field do
toggle_order(socket.assigns.sort_order)
else
:asc
end
sorted_users =
users
|> Enum.sort_by(&Map.get(&1, field), sort_fun(new_order))
{:noreply,
socket
|> assign(:sort_field, field)
|> assign(:sort_order, new_order)
|> assign(:users, sorted_users)}
end
# Selects all users in the list of users
@impl true
def handle_event("select_all", _params, socket) do
users = socket.assigns.users
all_ids = Enum.map(users, & &1.id)
selected =
if Enum.sort(socket.assigns.selected_users) == Enum.sort(all_ids) do
[]
else
all_ids
end
{:noreply, assign(socket, :selected_users, selected)}
end
defp toggle_order(:asc), do: :desc
defp toggle_order(:desc), do: :asc
defp sort_fun(:asc), do: &<=/2
defp sort_fun(:desc), do: &>=/2
end

View file

@ -0,0 +1,75 @@
<Layouts.app flash={@flash}>
<.header>
{gettext("Listing Users")}
<:actions>
<.button variant="primary" navigate={~p"/users/new"}>
<.icon name="hero-plus" /> {gettext("New User")}
</.button>
</:actions>
</.header>
<.table
id="users"
rows={@users}
row_click={fn user -> JS.navigate(~p"/users/#{user}") end}
>
<:col
:let={user}
label={
~H"""
<.input
type="checkbox"
name="select_all"
phx-click="select_all"
checked={Enum.sort(@selected_users) == Enum.map(@users, & &1.id) |> Enum.sort()}
aria-label={gettext("Select all users")}
role="checkbox"
/>
"""
}
>
<.input
type="checkbox"
name={user.id}
phx-click="select_user"
phx-value-id={user.id}
checked={user.id in @selected_users}
phx-capture-click
phx-stop-propagation
aria-label={gettext("Select user")}
role="checkbox"
/>
</:col>
<:col
:let={user}
label={
sort_button(%{
field: :email,
label: gettext("Email"),
sort_field: @sort_field,
sort_order: @sort_order
})
}
>
{user.email}
</:col>
<:col :let={user} label={gettext("OIDC ID")}>{user.oidc_id}</:col>
<:action :let={user}>
<div class="sr-only">
<.link navigate={~p"/users/#{user}"}>{gettext("Show")}</.link>
</div>
<.link navigate={~p"/users/#{user}/edit"}>{gettext("Edit")}</.link>
</:action>
<:action :let={user}>
<.link
phx-click={JS.push("delete", value: %{id: user.id}) |> hide("#row-#{user.id}")}
data-confirm={gettext("Are you sure?")}
>
{gettext("Delete")}
</.link>
</:action>
</.table>
</Layouts.app>

View file

@ -410,12 +410,12 @@ msgstr ""
#: lib/mv_web/live/member_live/index.html.heex:27
#, elixir-autogen, elixir-format
msgid "Select all members"
msgstr ""
msgstr "Alle Mitglieder auswählen"
#: lib/mv_web/live/member_live/index.html.heex:41
#, elixir-autogen, elixir-format
msgid "Select member"
msgstr ""
msgstr "Mitglied auswählen"
#: lib/mv_web/components/layouts/navbar.ex:72
#, elixir-autogen, elixir-format
@ -476,12 +476,12 @@ msgstr ""
#: lib/mv_web/components/table_components.ex:30
#, elixir-autogen, elixir-format
msgid "ascending"
msgstr ""
msgstr "aufsteigend"
#: lib/mv_web/components/table_components.ex:30
#, elixir-autogen, elixir-format
msgid "descending"
msgstr ""
msgstr "absteigend"
#: lib/mv_web/live/user_live/form.ex:51
#, elixir-autogen, elixir-format
@ -492,3 +492,13 @@ msgstr "Neuer"
#, elixir-autogen, elixir-format
msgid "Users created here will need to set their password through the authentication system."
msgstr "Hier erstellte Benutzer müssen ihr Passwort über das Authentifizierungssystem setzen."
#: lib/mv_web/live/user_live/index.html.heex:15
#, elixir-autogen, elixir-format
msgid "Select all users"
msgstr "Alle Benutzer auswählen"
#: lib/mv_web/live/user_live/index.html.heex:29
#, elixir-autogen, elixir-format
msgid "Select user"
msgstr "Benutzer auswählen"