Packages

phoenix_kit

1.7.22
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 edit.ex
Raw

lib/modules/tickets/web/edit.ex

defmodule PhoenixKit.Modules.Tickets.Web.Edit do
@moduledoc """
LiveView for creating and editing support tickets.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Modules.Storage
alias PhoenixKit.Modules.Tickets
alias PhoenixKit.Modules.Tickets.Ticket
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth
alias PhoenixKit.Users.Roles
alias PhoenixKit.Utils.Routes
@impl true
def mount(params, _session, socket) do
if Tickets.enabled?() do
current_user = socket.assigns[:phoenix_kit_current_user]
if can_access_tickets?(current_user) do
socket = load_ticket_or_new(socket, params, current_user)
{:ok, socket}
else
{:ok,
socket
|> put_flash(:error, "Access denied")
|> push_navigate(to: Routes.path("/admin"))}
end
else
{:ok,
socket
|> put_flash(:error, "Tickets module is not enabled")
|> push_navigate(to: Routes.path("/admin"))}
end
end
defp load_ticket_or_new(socket, %{"id" => id}, current_user) do
case Tickets.get_ticket(id, preload: [:user, :assigned_to]) do
nil ->
socket
|> put_flash(:error, "Ticket not found")
|> push_navigate(to: Routes.path("/admin/tickets"))
ticket ->
changeset = Ticket.changeset(ticket, %{})
project_title = Settings.get_setting("project_title", "PhoenixKit")
socket
|> assign(:page_title, "Edit Ticket")
|> assign(:project_title, project_title)
|> assign(:ticket, ticket)
|> assign(:changeset, changeset)
|> assign(:form, to_form(changeset))
|> assign(:current_user, current_user)
|> assign(:staff_users, list_support_staff())
|> assign(:action, :edit)
end
end
defp load_ticket_or_new(socket, _params, current_user) do
ticket = %Ticket{user_id: current_user.id}
changeset = Ticket.changeset(ticket, %{})
project_title = Settings.get_setting("project_title", "PhoenixKit")
socket
|> assign(:page_title, "New Ticket")
|> assign(:project_title, project_title)
|> assign(:ticket, ticket)
|> assign(:changeset, changeset)
|> assign(:form, to_form(changeset))
|> assign(:current_user, current_user)
|> assign(:all_users, list_all_users())
|> assign(:action, :new)
|> assign(:show_media_selector, false)
|> assign(:pending_file_ids, [])
|> assign(:pending_files, [])
|> assign(
:attachments_enabled,
Settings.get_boolean_setting("tickets_attachments_enabled", true)
)
end
@impl true
def handle_params(_params, uri, socket) do
{:noreply, assign(socket, :url_path, URI.parse(uri).path)}
end
@impl true
def handle_event("validate", %{"ticket" => params}, socket) do
changeset =
socket.assigns.ticket
|> Ticket.changeset(params)
|> Map.put(:action, :validate)
{:noreply, assign(socket, :form, to_form(changeset))}
end
@impl true
def handle_event("save", %{"ticket" => params}, socket) do
save_ticket(socket, socket.assigns.action, params)
end
@impl true
def handle_event("open_media_selector", _params, socket) do
{:noreply, assign(socket, :show_media_selector, true)}
end
@impl true
def handle_event("close_media_selector", _params, socket) do
{:noreply, assign(socket, :show_media_selector, false)}
end
@impl true
def handle_event("remove_pending_file", %{"id" => file_id}, socket) do
pending_file_ids = Enum.reject(socket.assigns.pending_file_ids, &(&1 == file_id))
pending_files = Enum.reject(socket.assigns.pending_files, &(&1.id == file_id))
{:noreply,
socket
|> assign(:pending_file_ids, pending_file_ids)
|> assign(:pending_files, pending_files)}
end
@impl true
def handle_info({:media_selected, file_ids}, socket) do
# Load file details for display
pending_files =
Enum.map(file_ids, fn file_id ->
Storage.get_file(file_id)
end)
|> Enum.reject(&is_nil/1)
{:noreply,
socket
|> assign(:show_media_selector, false)
|> assign(:pending_file_ids, file_ids)
|> assign(:pending_files, pending_files)}
end
defp save_ticket(socket, :new, params) do
current_user = socket.assigns.current_user
pending_file_ids = socket.assigns.pending_file_ids
# Use the selected user or default to current user
user_id =
case Map.get(params, "user_id") do
nil -> current_user.id
"" -> current_user.id
id -> String.to_integer(id)
end
case Tickets.create_ticket(user_id, params) do
{:ok, ticket} ->
# Add pending attachments to the newly created ticket
Enum.each(pending_file_ids, fn file_id ->
Tickets.add_attachment_to_ticket(ticket.id, file_id)
end)
{:noreply,
socket
|> put_flash(:info, "Ticket created successfully")
|> push_navigate(to: Routes.path("/admin/tickets/#{ticket.id}"))}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :form, to_form(changeset))}
end
end
defp save_ticket(socket, :edit, params) do
case Tickets.update_ticket(socket.assigns.ticket, params) do
{:ok, ticket} ->
{:noreply,
socket
|> put_flash(:info, "Ticket updated successfully")
|> push_navigate(to: Routes.path("/admin/tickets/#{ticket.id}"))}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :form, to_form(changeset))}
end
end
defp can_access_tickets?(nil), do: false
defp can_access_tickets?(user) do
Roles.user_has_role_owner?(user) or
Roles.user_has_role_admin?(user) or
Roles.user_has_role?(user, "SupportAgent")
end
defp list_all_users do
# Get all users for customer selection
%{users: users} = Auth.list_users_paginated(page: 1, page_size: 1000)
users
rescue
_ -> []
end
defp list_support_staff do
# Get users who can handle tickets (for assignment)
%{users: users} = Auth.list_users_paginated(page: 1, page_size: 1000)
Enum.filter(users, fn user ->
Roles.user_has_role_owner?(user) or
Roles.user_has_role_admin?(user) or
Roles.user_has_role?(user, "SupportAgent")
end)
rescue
_ -> []
end
end