2021-03-04 22:03:27 -05:00
|
|
|
<%= if @live_action in [:new, :edit] do %>
|
2021-03-15 15:46:59 -04:00
|
|
|
<%= live_modal @socket, Shift73kWeb.UserManagement.FormComponent,
|
2021-03-04 22:03:27 -05:00
|
|
|
id: @user.id || :new,
|
|
|
|
title: @page_title,
|
|
|
|
action: @live_action,
|
|
|
|
user: @user,
|
|
|
|
current_user: @current_user %>
|
|
|
|
<% end %>
|
|
|
|
|
2021-03-05 15:32:01 -05:00
|
|
|
<%= if @delete_user do %>
|
2021-03-15 15:46:59 -04:00
|
|
|
<%= live_modal @socket, Shift73kWeb.UserManagement.DeleteComponent,
|
2021-03-05 15:32:01 -05:00
|
|
|
id: @delete_user.id,
|
|
|
|
title: "Delete User",
|
2021-03-19 16:38:52 -04:00
|
|
|
delete_user: @delete_user
|
|
|
|
%>
|
2021-03-05 15:32:01 -05:00
|
|
|
<% end %>
|
|
|
|
|
2021-03-04 22:03:27 -05:00
|
|
|
|
|
|
|
<h2 class="mb-3">
|
2022-08-13 07:32:36 -04:00
|
|
|
<i class="bi bi-people"></i> Listing Users
|
2021-03-04 22:03:27 -05:00
|
|
|
</h2>
|
|
|
|
|
|
|
|
<%# filtering and new item creation %>
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="row justify-content-between align-items-start align-items-md-end mb-3">
|
2021-03-04 22:03:27 -05:00
|
|
|
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="col-12 col-md-6 col-lg-4 col-xl-3">
|
2021-03-04 22:03:27 -05:00
|
|
|
<%= live_patch to: Routes.user_management_index_path(@socket, :new, Enum.into(@query, [])),
|
2021-03-10 09:27:24 -05:00
|
|
|
class: "btn btn-primary mb-3 mb-md-0" do %>
|
2022-08-13 07:32:36 -04:00
|
|
|
<i class="bi bi-person-plus"></i> New User
|
2021-03-04 22:03:27 -05:00
|
|
|
<% end %>
|
2021-03-09 10:22:05 -05:00
|
|
|
</div>
|
2021-03-04 22:03:27 -05:00
|
|
|
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="col-12 col-sm-5 d-block d-md-none">
|
2021-03-09 10:22:05 -05:00
|
|
|
<%= form_for :sort, "#", [phx_change: "sort-by-change"], fn srt -> %>
|
|
|
|
<%= label srt, :sort_by, class: "visually-hidden" %>
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="input-group inner-addon left-addon mb-3 mb-md-0">
|
2021-03-09 10:22:05 -05:00
|
|
|
<%= icon_div @socket, "bi-arrow-down-up", [class: "icon is-left text-muted fs-5", style: "z-index:1001;"], [style: "padding: 1px;"] %>
|
|
|
|
<%= Phoenix.HTML.Form.select srt, :sort_by, ["Email": "email", "Role": "role", "Created at": "inserted_at"], value: @query.sort_by, class: "form-select" %>
|
|
|
|
<button class="btn btn-primary" type="button" aria-label="Change sort order" phx-click="sort-order-change">
|
|
|
|
<%= icon_div @socket, (@query.sort_order == "desc" && "bi-sort-up-alt" || "bi-sort-down-alt"), [class: "icon baseline"] %>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<% end %>
|
|
|
|
</div>
|
2021-03-04 22:03:27 -05:00
|
|
|
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="col-12 col-sm-7 col-md-6 col-lg-4 col-xl-3">
|
2021-03-09 10:22:05 -05:00
|
|
|
<%= form_for :filter, "#", [phx_change: "filter-change"], fn flt -> %>
|
|
|
|
<%= label flt, :filter, class: "visually-hidden" %>
|
|
|
|
<div class="inner-addon left-addon right-addon">
|
2022-08-13 07:32:36 -04:00
|
|
|
<i class="bi bi-funnel is-left text-muted fs-5"></i>
|
2021-03-09 10:22:05 -05:00
|
|
|
<%= if @query.filter != "" do %>
|
|
|
|
<%= icon_div @socket, "bi-x-circle-fill", [class: "icon is-right text-primary fs-5"], [role: "img", aria_hidden: false, aria_label: "Clear filter", class: "cursor-pointer pe-auto", phx_click: "filter-clear"] %>
|
|
|
|
<% end %>
|
|
|
|
<%= text_input flt, :filter,
|
|
|
|
name: "filter",
|
|
|
|
value: @query.filter,
|
|
|
|
class: "form-control",
|
|
|
|
placeholder: "Filter users",
|
|
|
|
aria_label: "Filter users"
|
|
|
|
%>
|
|
|
|
</div>
|
|
|
|
<% end %>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-03-04 22:03:27 -05:00
|
|
|
|
2021-03-09 10:22:05 -05:00
|
|
|
<%# mobile data cards %>
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="d-block d-md-none">
|
2021-03-09 10:22:05 -05:00
|
|
|
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="row justify-content-center">
|
2021-03-09 10:22:05 -05:00
|
|
|
<%= 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 %>
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="col-12 col-sm-10">
|
2021-03-09 10:22:05 -05:00
|
|
|
<div class="card mb-3">
|
|
|
|
<div class="card-body">
|
|
|
|
<dl class="row">
|
2021-03-10 09:27:24 -05:00
|
|
|
<dt class="col-sm-3 text-sm-end">Email</dt>
|
2021-03-09 10:22:05 -05:00
|
|
|
<dd class="col-sm-9"><%= user.email %></dd>
|
2021-03-10 09:27:24 -05:00
|
|
|
<dt class="col-sm-3 text-sm-end">Role</dt>
|
2021-03-09 10:22:05 -05:00
|
|
|
<dd class="col-sm-9"><%= user.role |> Atom.to_string() |> String.capitalize() %></dd>
|
2021-03-10 09:27:24 -05:00
|
|
|
<dt class="col-sm-3 text-sm-end">Created at</dt>
|
2021-03-09 10:22:05 -05:00
|
|
|
<dd class="col-sm-9"><%= dt_out(user.inserted_at) %></dd>
|
2021-03-10 09:27:24 -05:00
|
|
|
<dt class="d-inline d-sm-block col-auto text-sm-end">
|
|
|
|
<span>Confirmed?</span>
|
2021-03-09 10:22:05 -05:00
|
|
|
</dt>
|
2021-03-10 09:27:24 -05:00
|
|
|
<dd class="d-inline d-sm-block col-auto">
|
|
|
|
<span class="visually-hidden"><%= user.confirmed_at && "Yes" || "No" %></span>
|
2021-03-21 10:47:53 -04:00
|
|
|
<input type="checkbox" class="form-check-input" aria-hidden="true" <%= user.confirmed_at && "checked" || "" %> disabled>
|
2021-03-10 09:27:24 -05:00
|
|
|
</dd>
|
2021-03-09 10:22:05 -05:00
|
|
|
</dl>
|
|
|
|
|
|
|
|
<%= if Roles.can?(@current_user, user, :edit) do %>
|
2021-03-09 20:55:59 -05:00
|
|
|
<%= live_patch to: Routes.user_management_index_path(@socket, :edit, user.id, Enum.into(@query, [])), class: "btn btn-primary btn-sm text-nowrap" do %>
|
2021-03-16 11:00:33 -04:00
|
|
|
<%= icon_div @socket, "bi-pencil", [class: "icon baseline"] %>
|
2021-03-09 10:22:05 -05:00
|
|
|
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 %>">
|
2021-03-16 11:00:33 -04:00
|
|
|
<%= icon_div @socket, "bi-trash", [class: "icon baseline"] %>
|
2021-03-09 10:22:05 -05:00
|
|
|
Delete
|
|
|
|
</button>
|
|
|
|
<% end %>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-03-10 09:27:24 -05:00
|
|
|
</div>
|
2021-03-04 22:03:27 -05:00
|
|
|
<% end %>
|
|
|
|
<% end %>
|
2021-03-10 09:27:24 -05:00
|
|
|
</div>
|
2021-03-04 22:03:27 -05:00
|
|
|
|
|
|
|
</div>
|
|
|
|
|
2021-03-09 10:22:05 -05:00
|
|
|
<%# non-mobile main data table %>
|
2021-03-10 09:27:24 -05:00
|
|
|
<div class="table-responsive d-none d-md-block">
|
2021-03-05 15:32:01 -05:00
|
|
|
<table class="table">
|
|
|
|
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
|
|
|
|
<th scope="col" phx-click="sort-change" phx-value-sort_by="email" class="cursor-pointer">
|
|
|
|
Email
|
|
|
|
<%= if @query.sort_by == "email", do: icon_div @socket,
|
|
|
|
(@query.sort_order == "desc" && "bi-sort-up-alt" || "bi-sort-down-alt"),
|
|
|
|
[class: "icon baseline ms-1"]
|
|
|
|
%>
|
|
|
|
</th>
|
|
|
|
|
|
|
|
<th scope="col" phx-click="sort-change" phx-value-sort_by="role" class="cursor-pointer">
|
|
|
|
Role
|
|
|
|
<%= if @query.sort_by == "role", do: icon_div @socket,
|
|
|
|
(@query.sort_order == "desc" && "bi-sort-up-alt" || "bi-sort-down-alt"),
|
|
|
|
[class: "icon baseline ms-1"]
|
|
|
|
%>
|
|
|
|
</th>
|
|
|
|
|
|
|
|
<th scope="col" phx-click="sort-change" phx-value-sort_by="inserted_at" class="cursor-pointer">
|
|
|
|
Created at
|
|
|
|
<%= if @query.sort_by == "inserted_at", do: icon_div @socket,
|
|
|
|
(@query.sort_order == "desc" && "bi-sort-up-alt" || "bi-sort-down-alt"),
|
|
|
|
[class: "icon baseline ms-1"]
|
|
|
|
%>
|
|
|
|
</th>
|
|
|
|
|
|
|
|
<th scope="col">Confirmed?</th>
|
|
|
|
|
|
|
|
<th></th>
|
2021-03-04 22:03:27 -05:00
|
|
|
|
|
|
|
</tr>
|
2021-03-05 15:32:01 -05:00
|
|
|
</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">
|
2021-03-09 10:22:05 -05:00
|
|
|
<span class="visually-hidden"><%= user.confirmed_at && "Confirmed" || "Not confirmed" %></span>
|
2021-03-21 10:47:53 -04:00
|
|
|
<input type="checkbox" class="form-check-input" aria-hidden="true" <%= user.confirmed_at && "checked" || "" %> disabled>
|
2021-03-05 15:32:01 -05:00
|
|
|
</td>
|
|
|
|
<td class="align-middle text-end text-nowrap">
|
|
|
|
|
2021-03-08 07:39:41 -05:00
|
|
|
<%= 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 %>
|
2021-03-16 11:00:33 -04:00
|
|
|
<%= icon_div @socket, "bi-pencil", [class: "icon baseline"] %>
|
2021-03-08 07:39:41 -05:00
|
|
|
Edit
|
|
|
|
<% end %>
|
2021-03-05 15:32:01 -05:00
|
|
|
<% 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 %>">
|
2021-03-16 11:00:33 -04:00
|
|
|
<%= icon_div @socket, "bi-trash", [class: "icon baseline"] %>
|
2021-03-05 15:32:01 -05:00
|
|
|
Delete
|
|
|
|
</button>
|
|
|
|
<% end %>
|
|
|
|
|
|
|
|
</td>
|
|
|
|
|
|
|
|
</tr>
|
|
|
|
<% end %>
|
|
|
|
<% end %>
|
|
|
|
</tbody>
|
2021-03-04 22:03:27 -05:00
|
|
|
|
2021-03-05 15:32:01 -05:00
|
|
|
</table>
|
|
|
|
</div>
|
2021-03-04 22:03:27 -05:00
|
|
|
|
|
|
|
<%# pagination interface %>
|
2021-03-05 15:32:01 -05:00
|
|
|
<%= 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"> %>
|
2021-03-04 22:03:27 -05:00
|
|
|
|
|
|
|
<%# items per page selector %>
|
2021-03-05 15:32:01 -05:00
|
|
|
<div class="d-flex align-items-center mb-3 mb-sm-0">
|
2021-03-04 22:03:27 -05:00
|
|
|
<%= 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 %>
|
2021-03-09 10:22:05 -05:00
|
|
|
<span class="ms-2"><%= @page.total_entries %> total</span>
|
2021-03-04 22:03:27 -05:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<%# main pagination %>
|
|
|
|
<nav aria-label="User list page navigation">
|
|
|
|
<ul class="pagination mb-0">
|
|
|
|
|
|
|
|
<%# previous page button %>
|
|
|
|
<% icon = icon_div @socket, "bi-chevron-left", [class: "icon baseline"] %>
|
|
|
|
<%= if @page.page_number == 1 do %>
|
|
|
|
<li class="page-item disabled">
|
|
|
|
<span class="page-link" aria-hidden="true"><%= icon %></span>
|
|
|
|
<span class="visually-hidden">Previous</span>
|
|
|
|
<% 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"><%= icon %></a>
|
|
|
|
<% end %>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
<%# 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>
|
2021-03-05 11:01:54 -05:00
|
|
|
<% page_num == @page.page_number -> %>
|
2021-03-04 22:03:27 -05:00
|
|
|
<li class="page-item active" aria-current="page">
|
|
|
|
<span class="page-link"><%= page_num %></a>
|
|
|
|
</li>
|
2021-03-05 11:01:54 -05:00
|
|
|
<% true -> %>
|
2021-03-04 22:03:27 -05:00
|
|
|
<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 %>
|
|
|
|
<% icon = icon_div @socket, "bi-chevron-right", [class: "icon baseline"] %>
|
|
|
|
<%= if @page.page_number == @page.total_pages do %>
|
|
|
|
<li class="page-item disabled">
|
|
|
|
<span class="page-link" aria-hidden="true"><%= icon %></span>
|
|
|
|
<span class="visually-hidden">Next</span>
|
|
|
|
<% 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"><%= icon %></a>
|
|
|
|
<% end %>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
</div>
|
2021-03-05 15:32:01 -05:00
|
|
|
<% end %>
|