cover/Elixir.DaProductAppWeb.UsersLive.html

1
:-(
defmodule DaProductAppWeb.UsersLive do
2 @moduledoc """
3 LiveView for Users management with CRUD operations and role assignment.
4
5 Features:
6 - List all users with search and filtering
7 - Create, edit, delete users
8 - Role assignment and management
9 - Organization assignment
10 - Bulk operations
11 - Modern UI with DaisyUI components
12 """
13 use DaProductAppWeb, :live_view
14
15 alias DaProductApp.Accounts
16 alias DaProductApp.Accounts.User
17
18 @impl true
19
:-(
def mount(_params, session, socket) do
20
:-(
case get_current_user(session) do
21
:-(
nil ->
22 {:ok, redirect(socket, to: ~p"/login")}
23
24 user ->
25
:-(
if has_access?(user) do
26
:-(
if connected?(socket) do
27 # Subscribe to user events for real-time updates
28
:-(
Phoenix.PubSub.subscribe(DaProductApp.PubSub, "users")
29 end
30
31
:-(
socket =
32 socket
33 |> assign(:current_user, user)
34 |> assign(:page_title, "Users Management")
35 |> assign(:current_page, :users)
36 |> assign(:users, list_users())
37 |> assign(:organizations, Accounts.list_organizations())
38 |> assign(:roles, Accounts.list_roles())
39 |> assign(:search_term, "")
40 |> assign(:selected_org_filter, "")
41 |> assign(:selected_role_filter, "")
42 |> assign(:show_modal, false)
43 |> assign(:modal_action, :new)
44 |> assign(:selected_user, nil)
45 |> assign(:form, to_form(Accounts.change_user(%User{})))
46
47 {:ok, socket}
48 else
49 {:ok,
50 socket
51 |> put_flash(:error, "Access denied")
52 |> redirect(to: ~p"/login")}
53 end
54 end
55 end
56
57 @impl true
58
:-(
def handle_params(params, _url, socket) do
59
:-(
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
60 end
61
62 defp apply_action(socket, :index, _params) do
63 socket
64 |> assign(:page_title, "Users Management")
65
:-(
|> assign(:show_modal, false)
66 end
67
68 defp apply_action(socket, :new, _params) do
69 socket
70 |> assign(:page_title, "New User")
71 |> assign(:show_modal, true)
72 |> assign(:modal_action, :new)
73 |> assign(:selected_user, %User{})
74
:-(
|> assign(:form, to_form(Accounts.change_user(%User{})))
75 end
76
77 defp apply_action(socket, :edit, %{"id" => id}) do
78
:-(
user = Accounts.get_user!(id)
79
80 socket
81 |> assign(:page_title, "Edit User")
82 |> assign(:show_modal, true)
83 |> assign(:modal_action, :edit)
84 |> assign(:selected_user, user)
85
:-(
|> assign(:form, to_form(Accounts.change_user(user)))
86 end
87
88 @impl true
89
:-(
def handle_event("search", %{"search_term" => search_term}, socket) do
90
:-(
socket =
91 socket
92 |> assign(:search_term, search_term)
93
:-(
|> assign(:users, list_users(search_term, socket.assigns.selected_org_filter, socket.assigns.selected_role_filter))
94
95 {:noreply, socket}
96 end
97
98
:-(
def handle_event("filter_organization", %{"org_id" => org_id}, socket) do
99
:-(
socket =
100 socket
101 |> assign(:selected_org_filter, org_id)
102
:-(
|> assign(:users, list_users(socket.assigns.search_term, org_id, socket.assigns.selected_role_filter))
103
104 {:noreply, socket}
105 end
106
107
:-(
def handle_event("filter_role", %{"role_id" => role_id}, socket) do
108
:-(
socket =
109 socket
110 |> assign(:selected_role_filter, role_id)
111
:-(
|> assign(:users, list_users(socket.assigns.search_term, socket.assigns.selected_org_filter, role_id))
112
113 {:noreply, socket}
114 end
115
116
:-(
def handle_event("clear_filters", _params, socket) do
117
:-(
socket =
118 socket
119 |> assign(:search_term, "")
120 |> assign(:selected_org_filter, "")
121 |> assign(:selected_role_filter, "")
122 |> assign(:users, list_users("", "", ""))
123
124 {:noreply, socket}
125 end
126
127
:-(
def handle_event("clear_search", _params, socket) do
128
:-(
socket =
129 socket
130 |> assign(:search_term, "")
131
:-(
|> assign(:users, list_users("", socket.assigns.selected_org_filter, socket.assigns.selected_role_filter))
132
133 {:noreply, socket}
134 end
135
136
:-(
def handle_event("clear_org_filter", _params, socket) do
137
:-(
socket =
138 socket
139 |> assign(:selected_org_filter, "")
140
:-(
|> assign(:users, list_users(socket.assigns.search_term, "", socket.assigns.selected_role_filter))
141
142 {:noreply, socket}
143 end
144
145
:-(
def handle_event("clear_role_filter", _params, socket) do
146
:-(
socket =
147 socket
148 |> assign(:selected_role_filter, "")
149
:-(
|> assign(:users, list_users(socket.assigns.search_term, socket.assigns.selected_org_filter, ""))
150
151 {:noreply, socket}
152 end
153
154
:-(
def handle_event("close_modal", _params, socket) do
155 {:noreply, push_patch(socket, to: ~p"/users")}
156 end
157
158
:-(
def handle_event("delete_user", %{"id" => id}, socket) do
159
:-(
user = Accounts.get_user!(id)
160
161
:-(
case Accounts.delete_user(user) do
162 {:ok, _} ->
163 # Broadcast the deletion for real-time updates
164
:-(
Phoenix.PubSub.broadcast(DaProductApp.PubSub, "users", {:user_deleted, user})
165
166
:-(
socket =
167 socket
168 |> put_flash(:info, "User deleted successfully")
169 |> assign(:users, list_users())
170
171 {:noreply, socket}
172
173
:-(
{:error, _changeset} ->
174 {:noreply, put_flash(socket, :error, "Unable to delete user")}
175 end
176 end
177
178
:-(
def handle_event("toggle_user_status", %{"id" => id}, socket) do
179
:-(
user = Accounts.get_user!(id)
180
181
:-(
case Accounts.update_user(user, %{is_active: !user.is_active}) do
182 {:ok, updated_user} ->
183 # Broadcast the update for real-time updates
184
:-(
Phoenix.PubSub.broadcast(DaProductApp.PubSub, "users", {:user_updated, updated_user})
185
186
:-(
status = if updated_user.is_active, do: "activated", else: "deactivated"
187
188
:-(
socket =
189 socket
190
:-(
|> put_flash(:info, "User #{status} successfully")
191 |> assign(:users, list_users())
192
193 {:noreply, socket}
194
195
:-(
{:error, _changeset} ->
196 {:noreply, put_flash(socket, :error, "Unable to update user status")}
197 end
198 end
199
200
:-(
def handle_event("validate", %{"user" => user_params}, socket) do
201
:-(
changeset =
202
:-(
socket.assigns.selected_user
203 |> Accounts.change_user(user_params)
204 |> Map.put(:action, :validate)
205
206 {:noreply, assign(socket, form: to_form(changeset))}
207 end
208
209 def handle_event("save", %{"user" => user_params}, socket) do
210
:-(
save_user(socket, socket.assigns.modal_action, user_params)
211 end
212
213 # Handle real-time updates from PubSub
214 @impl true
215
:-(
def handle_info({:user_created, _user}, socket) do
216 {:noreply, assign(socket, :users, list_users())}
217 end
218
219
:-(
def handle_info({:user_updated, _user}, socket) do
220 {:noreply, assign(socket, :users, list_users())}
221 end
222
223
:-(
def handle_info({:user_deleted, _user}, socket) do
224 {:noreply, assign(socket, :users, list_users())}
225 end
226
227
:-(
defp save_user(socket, :new, user_params) do
228
:-(
case Accounts.create_user(user_params) do
229 {:ok, user} ->
230 # Broadcast the creation for real-time updates
231
:-(
Phoenix.PubSub.broadcast(DaProductApp.PubSub, "users", {:user_created, user})
232
233
:-(
socket =
234 socket
235 |> put_flash(:info, "User created successfully")
236 |> push_patch(to: ~p"/users")
237
238 {:noreply, socket}
239
240
:-(
{:error, %Ecto.Changeset{} = changeset} ->
241 {:noreply, assign(socket, form: to_form(changeset))}
242 end
243 end
244
245
:-(
defp save_user(socket, :edit, user_params) do
246
:-(
case Accounts.update_user(socket.assigns.selected_user, user_params) do
247 {:ok, user} ->
248 # Broadcast the update for real-time updates
249
:-(
Phoenix.PubSub.broadcast(DaProductApp.PubSub, "users", {:user_updated, user})
250
251
:-(
socket =
252 socket
253 |> put_flash(:info, "User updated successfully")
254 |> push_patch(to: ~p"/users")
255
256 {:noreply, socket}
257
258
:-(
{:error, %Ecto.Changeset{} = changeset} ->
259 {:noreply, assign(socket, form: to_form(changeset))}
260 end
261 end
262
263
:-(
defp list_users(search_term \\ "", org_filter \\ "", role_filter \\ "") do
264 import Ecto.Query
265
266
:-(
query = from u in User,
267 preload: [:organization, :role],
268 order_by: [desc: u.updated_at]
269
270
:-(
query =
271 if search_term != "" do
272
:-(
search_pattern = "%#{search_term}%"
273
:-(
from u in query,
274 where: ilike(u.name, ^search_pattern) or ilike(u.email, ^search_pattern)
275 else
276
:-(
query
277 end
278
279
:-(
query =
280 if org_filter != "" do
281
:-(
from u in query, where: u.organization_id == ^org_filter
282 else
283
:-(
query
284 end
285
286
:-(
query =
287 if role_filter != "" do
288
:-(
from u in query, where: u.role_id == ^role_filter
289 else
290
:-(
query
291 end
292
293
:-(
DaProductApp.Repo.all(query)
294 end
295
296 # Helper functions for authentication and access control
297
:-(
defp get_current_user(session) do
298
:-(
case session do
299 %{"user_id" => user_id} when is_binary(user_id) or is_integer(user_id) ->
300
:-(
Accounts.get_user!(user_id)
301
:-(
_ ->
302 nil
303 end
304 rescue
305
:-(
_ -> nil
306 end
307
308
:-(
defp has_access?(_user), do: true
309 end
Line Hits Source