<%= if @live_action in [:new, :edit] do %> <%= live_modal @socket, Shift73kWeb.UserManagement.FormComponent, id: @user.id || :new, title: @page_title, action: @live_action, user: @user, current_user: @current_user %> <% end %> <%= if @delete_user do %> <%= live_modal @socket, Shift73kWeb.UserManagement.DeleteComponent, id: @delete_user.id, title: "Delete User", delete_user: @delete_user %> <% end %> <h2 class="mb-3"> <i class="bi bi-people me-1"></i> Listing Users </h2> <%# filtering and new item creation %> <div class="row justify-content-between align-items-start align-items-md-end mb-3"> <div class="col-12 col-md-6 col-lg-4 col-xl-3"> <%= live_patch to: Routes.user_management_index_path(@socket, :new, Enum.into(@query, [])), class: "btn btn-primary mb-3 mb-md-0" do %> <i class="bi bi-person-plus me-1"></i> New User <% end %> </div> <div class="col-12 col-sm-5 d-block d-md-none"> <%= form_for :sort, "#", [phx_change: "sort-by-change"], fn srt -> %> <%= label srt, :sort_by, class: "visually-hidden" %> <div class="input-group inner-addon left-addon mb-3 mb-md-0"> <i class="bi bi-arrow-down-up icon is-left text-muted fs-5" style="z-index:1001;"></i> <%= Phoenix.HTML.Form.select srt, :sort_by, ["Email": "email", "Role": "role", "Created at": "inserted_at"], value: @query.sort_by, class: "form-select rounded-start" %> <button class="btn btn-primary" type="button" aria-label="Change sort order" phx-click="sort-order-change"> <i class={if @query.sort_order == "desc", do: "bi bi-sort-up-alt", else: "bi bi-sort-down-alt"}></i> </button> </div> <% end %> </div> <div class="col-12 col-sm-7 col-md-6 col-lg-4 col-xl-3"> <%= form_for :filter, "#", [phx_change: "filter-change"], fn flt -> %> <%= label flt, :filter, class: "visually-hidden" %> <div class="inner-addon left-addon right-addon"> <i class="bi bi-funnel icon is-left text-muted fs-5"></i> <%= if @query.filter != "" do %> <i class="bi bi-x-circle-fill icon is-right text-primary fs-5 cursor-pointer pe-auto" role="img" aria-hidden="false" aria-label="Clear filter" phx-click="filter-clear"></i> <% end %> <%= text_input flt, :filter, name: "filter", value: @query.filter, class: "form-control", placeholder: "Filter users", aria_label: "Filter users" %> </div> <% end %> </div> </div> <%# mobile data cards %> <div class="d-block d-md-none"> <div class="row justify-content-center"> <%= if !@page do %> <div class="card"> <div class="spinner-border text-primary my-5 mx-auto" role="status"> <span class="visually-hidden">Loading...</span> </div> </div> <% else %> <%= for user <- @page.entries do %> <div class="col-12 col-sm-10"> <div class="card mb-3"> <div class="card-body"> <dl class="row"> <dt class="col-sm-3 text-sm-end">Email</dt> <dd class="col-sm-9"><%= user.email %></dd> <dt class="col-sm-3 text-sm-end">Role</dt> <dd class="col-sm-9"><%= user.role |> Atom.to_string() |> String.capitalize() %></dd> <dt class="col-sm-3 text-sm-end">Created at</dt> <dd class="col-sm-9"><%= dt_out(user.inserted_at) %></dd> <dt class="d-inline d-sm-block col-auto text-sm-end"> <span>Confirmed?</span> </dt> <dd class="d-inline d-sm-block col-auto"> <span class="visually-hidden"><%= user.confirmed_at && "Yes" || "No" %></span> <input type="checkbox" class="form-check-input" aria-hidden="true" checked={user.confirmed_at && :true || :false} disabled> </dd> </dl> <%= if Roles.can?(@current_user, user, :edit) do %> <%= live_patch to: Routes.user_management_index_path(@socket, :edit, user.id, Enum.into(@query, [])), class: "btn btn-primary btn-sm text-nowrap" do %> <i class="bi bi-pencil me-1"></i> Edit <% end %> <% end %> <%= if Roles.can?(@current_user, user, :delete) do %> <button class="btn btn-outline-danger btn-sm text-nowrap" phx-click="delete-modal" phx-value-id={user.id}> <i class="bi bi-trash me-1"></i> Delete </button> <% end %> </div> </div> </div> <% end %> <% end %> </div> </div> <%# non-mobile main data table %> <div class="table-responsive d-none d-md-block"> <table class="table"> <thead> <tr> <th scope="col" style="white-space: nowrap;" phx-click="sort-change" phx-value-sort_by="email" class="cursor-pointer"> Email <%= if @query.sort_by == "email" do %> <i class={@query.sort_order == "desc" && "bi bi-sort-up-alt ms-1" || "bi bi-sort-down-alt ms-1"}></i> <% end %> </th> <th scope="col" style="white-space: nowrap;" phx-click="sort-change" phx-value-sort_by="role" class="cursor-pointer"> Role <%= if @query.sort_by == "role" do %> <i class={@query.sort_order == "desc" && "bi bi-sort-up-alt ms-1" || "bi bi-sort-down-alt ms-1"}></i> <% end %> </th> <th scope="col" style="white-space: nowrap;" phx-click="sort-change" phx-value-sort_by="inserted_at" class="cursor-pointer"> Created at <%= if @query.sort_by == "inserted_at" do %> <i class={@query.sort_order == "desc" && "bi bi-sort-up-alt ms-1" || "bi bi-sort-down-alt ms-1"}></i> <% end %> </th> <th scope="col">Confirmed?</th> <th></th> </tr> </thead> <tbody id="users"> <%= if !@page do %> <tr> <td class="text-center" colspan="5"> <div class="spinner-border text-primary my-5" role="status"> <span class="visually-hidden">Loading...</span> </div> </td> </tr> <% else %> <%= for user <- @page.entries do %> <tr id={"user-#{user.id}"}> <td class="align-middle"><%= user.email %></td> <td class="align-middle"><%= user.role |> Atom.to_string() |> String.capitalize() %></td> <td class="align-middle" style="white-space: nowrap;"><%= dt_out(user.inserted_at) %></td> <td class="align-middle"> <span class="visually-hidden"><%= user.confirmed_at && "Confirmed" || "Not confirmed" %></span> <input type="checkbox" class="form-check-input" aria-hidden="true" checked={user.confirmed_at && :true || :false} disabled> </td> <td class="align-middle text-end text-nowrap"> <%= if Roles.can?(@current_user, user, :edit) do %> <%= live_patch to: Routes.user_management_index_path(@socket, :edit, user.id, Enum.into(@query, [])), class: "btn btn-outline-primary btn-sm text-nowrap" do %> <i class="bi bi-pencil me-1"></i> Edit <% end %> <% end %> <%= if Roles.can?(@current_user, user, :delete) do %> <button class="btn btn-outline-danger btn-sm text-nowrap" phx-click="delete-modal" phx-value-id={user.id}> <i class="bi bi-trash me-1"></i> Delete </button> <% end %> </td> </tr> <% end %> <% end %> </tbody> </table> </div> <%# pagination interface %> <%= if @page do %> <div class="d-flex flex-column flex-sm-row justify-content-between d-flex align-items-start my-3"> <%# <div class="d-flex justify-content-between d-flex align-items-start"> %> <%# items per page selector %> <div class="d-flex align-items-center mb-3 mb-sm-0"> <%= form_for :page_size, "#", [phx_change: "page-size-change"], fn pgsz -> %> <%= select pgsz, :page_size, [10, 15, 20, 30, 50, 100] |> Enum.map(fn n -> {"#{n} per page", n} end), value: @query.page_size, id: "table_page_size_page_size", name: "page_size", class: "form-select" %> <% end %> <span class="ms-2"><%= @page.total_entries %> total</span> </div> <%# main pagination %> <nav aria-label="User list page navigation"> <ul class="pagination mb-0"> <%# previous page button %> <%= if @page.page_number == 1 do %> <li class="page-item disabled"> <span class="page-link" aria-hidden="true"><i class="bi bi-chevron-left"></i></span> <span class="visually-hidden">Previous</span> </li> <% else %> <li class="page-item"> <a class="page-link" href="#" aria-label="Previous" phx-value-page_number={@page.page_number - 1} phx-click="page-change"><i class="bi bi-chevron-left"></i></a> </li> <% end %> <%# page buttons %> <%= for page_num <- generate_page_list(@page.page_number, @page.total_pages) do %> <%= cond do %> <%= page_num < 1 -> %> <li class="page-item disabled"> <span class="page-link" aria-hidden="true">…</span> <span class="visually-hidden" role="img" aria-label="ellipses">…</span> </li> <% page_num == @page.page_number -> %> <li class="page-item active" aria-current="page"> <span class="page-link"><%= page_num %></span> </li> <% true -> %> <li class="page-item"> <a class="page-link" href="#" phx-value-page_number={page_num} phx-click="page-change"><%= page_num %></a> </li> <% end %> <% end %> <%# next page button %> <%= if @page.page_number == @page.total_pages do %> <li class="page-item disabled"> <span class="page-link" aria-hidden="true"><i class="bi bi-chevron-right"></i></span> <span class="visually-hidden">Next</span> </li> <% else %> <li class="page-item"> <a class="page-link" href="#" aria-label="Next" phx-value-page_number={@page.page_number + 1} phx-click="page-change"><i class="bi bi-chevron-right"></i></a> </li> <% end %> </ul> </nav> </div> <% end %>