Packages

phoenix_kit

1.7.49
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules tickets web user_list.ex
Raw

lib/modules/tickets/web/user_list.ex

defmodule PhoenixKit.Modules.Tickets.Web.UserList do
@moduledoc """
LiveView for displaying user's support tickets.
Users can view only their own tickets with status filtering and pagination.
This is the user-facing ticket portal, separate from admin ticket management.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Modules.Tickets
alias PhoenixKit.Modules.Tickets.Events
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
@impl true
def mount(_params, _session, socket) do
if Tickets.enabled?() do
current_user = socket.assigns[:phoenix_kit_current_user]
# Subscribe to user's ticket events for real-time updates
Events.subscribe_to_user_tickets(current_user.id)
socket =
socket
|> assign(:page_title, gettext("My Tickets"))
|> assign(:current_user, current_user)
|> assign(:tickets, [])
|> assign(:total_count, 0)
|> assign(:loading, true)
|> assign_filter_defaults()
|> assign_pagination_defaults()
{:ok, socket}
else
{:ok,
socket
|> put_flash(:error, gettext("Tickets module is not enabled"))
|> push_navigate(to: Routes.path("/dashboard"))}
end
end
@impl true
def handle_params(params, uri, socket) do
socket =
socket
|> assign(:url_path, URI.parse(uri).path)
|> apply_params(params)
|> load_user_tickets()
{:noreply, assign(socket, :loading, false)}
end
@impl true
def handle_event("filter", params, socket) do
filter_params = %{}
filter_params =
case Map.get(params, "filters") do
%{"status" => status} when status != "" ->
Map.put(filter_params, "status", status)
_ ->
filter_params
end
{:noreply,
push_patch(socket, to: Routes.path("/dashboard/tickets", map_to_keyword(filter_params)))}
end
@impl true
def handle_event("clear_filters", _params, socket) do
{:noreply, push_patch(socket, to: Routes.path("/dashboard/tickets"))}
end
@impl true
def handle_event("change_page", %{"page" => page}, socket) do
page = String.to_integer(page)
current_params = build_current_params(socket)
params = Map.put(current_params, "page", page)
{:noreply, push_patch(socket, to: Routes.path("/dashboard/tickets", map_to_keyword(params)))}
end
# Private functions
defp assign_filter_defaults(socket) do
assign(socket, :status_filter, nil)
end
defp assign_pagination_defaults(socket) do
per_page = Settings.get_setting("tickets_per_page", "20") |> String.to_integer()
socket
|> assign(:page, 1)
|> assign(:per_page, per_page)
|> assign(:total_pages, 1)
end
defp apply_params(socket, params) do
page = params |> Map.get("page", "1") |> String.to_integer() |> max(1)
status = Map.get(params, "status")
socket
|> assign(:page, page)
|> assign(:status_filter, status)
end
defp load_user_tickets(socket) do
user_id = socket.assigns.current_user.id
opts = build_query_opts(socket, user_id)
# Get all tickets for counting, then paginate
all_opts = Keyword.drop(opts, [:page, :per_page])
all_tickets = Tickets.list_tickets(all_opts)
total_count = length(all_tickets)
# Apply pagination manually
per_page = socket.assigns.per_page
page = socket.assigns.page
tickets = all_tickets |> Enum.drop((page - 1) * per_page) |> Enum.take(per_page)
total_pages = max(1, ceil(total_count / per_page))
socket
|> assign(:tickets, tickets)
|> assign(:total_count, total_count)
|> assign(:total_pages, total_pages)
end
defp build_query_opts(socket, user_id) do
opts = [
page: socket.assigns.page,
per_page: socket.assigns.per_page,
user_id: user_id,
preload: [:assigned_to]
]
case socket.assigns.status_filter do
nil -> opts
status -> Keyword.put(opts, :status, status)
end
end
defp build_current_params(socket) do
params = %{}
if socket.assigns.status_filter,
do: Map.put(params, "status", socket.assigns.status_filter),
else: params
end
defp map_to_keyword(map) when is_map(map) do
Enum.map(map, fn {k, v} -> {String.to_existing_atom(k), v} end)
end
@impl true
def handle_info({:ticket_created, ticket}, socket) do
# Only add if it belongs to current user and matches filters
current_user_id = socket.assigns.current_user.id
if ticket.user_id == current_user_id && ticket_matches_filters?(ticket, socket) do
tickets = [ticket | socket.assigns.tickets]
total_count = socket.assigns.total_count + 1
{:noreply,
socket
|> assign(:tickets, tickets)
|> assign(:total_count, total_count)}
else
{:noreply, socket}
end
end
@impl true
def handle_info({:ticket_updated, ticket}, socket) do
# Update ticket in list if present
tickets =
Enum.map(socket.assigns.tickets, fn t ->
if t.uuid == ticket.uuid, do: ticket, else: t
end)
{:noreply, assign(socket, :tickets, tickets)}
end
@impl true
def handle_info({:ticket_status_changed, ticket, _old_status, _new_status}, socket) do
# Update ticket status in list
tickets =
Enum.map(socket.assigns.tickets, fn t ->
if t.uuid == ticket.uuid, do: ticket, else: t
end)
{:noreply, assign(socket, :tickets, tickets)}
end
@impl true
def handle_info({:ticket_assigned, ticket, _old_assignee, _new_assignee}, socket) do
# Update ticket in list
tickets =
Enum.map(socket.assigns.tickets, fn t ->
if t.uuid == ticket.uuid, do: ticket, else: t
end)
{:noreply, assign(socket, :tickets, tickets)}
end
@impl true
def handle_info({:tickets_bulk_updated, _tickets, _changes}, socket) do
# Reload tickets on bulk update
{:noreply, load_user_tickets(socket)}
end
defp ticket_matches_filters?(ticket, socket) do
status_filter = socket.assigns.status_filter
case status_filter do
nil -> true
status -> ticket.status == status
end
end
end