Packages

phoenix_kit

1.7.89
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 customer_service web edit.ex
Raw

lib/modules/customer_service/web/edit.ex

defmodule PhoenixKit.Modules.CustomerService.Web.Edit do
@moduledoc """
LiveView for creating and editing support tickets.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Modules.CustomerService
alias PhoenixKit.Modules.CustomerService.Ticket
alias PhoenixKit.Modules.Storage
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth
alias PhoenixKit.Users.Roles
alias PhoenixKit.Utils.Routes
@impl true
def mount(params, _session, socket) do
if CustomerService.enabled?() do
current_user = socket.assigns[:phoenix_kit_current_user]
socket = load_ticket_or_new(socket, params, current_user)
{:ok, socket}
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 CustomerService.get_ticket(id, preload: [:user, :assigned_to]) do
nil ->
socket
|> put_flash(:error, "Ticket not found")
|> push_navigate(to: Routes.path("/admin/customer-service/tickets"))
ticket ->
changeset = Ticket.changeset(ticket, %{})
project_title = Settings.get_project_title()
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_uuid: current_user.uuid}
changeset = Ticket.changeset(ticket, %{})
project_title = Settings.get_project_title()
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_uuids, [])
|> assign(:pending_files, [])
|> assign(
:attachments_enabled,
Settings.get_boolean_setting("customer_service_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", %{"uuid" => file_uuid}, socket) do
pending_file_uuids = Enum.reject(socket.assigns.pending_file_uuids, &(&1 == file_uuid))
pending_files = Enum.reject(socket.assigns.pending_files, &(&1.uuid == file_uuid))
{:noreply,
socket
|> assign(:pending_file_uuids, pending_file_uuids)
|> assign(:pending_files, pending_files)}
end
@impl true
def handle_info({:media_selected, file_uuids}, socket) do
# Load file details for display
pending_files =
Enum.map(file_uuids, fn file_uuid ->
Storage.get_file(file_uuid)
end)
|> Enum.reject(&is_nil/1)
{:noreply,
socket
|> assign(:show_media_selector, false)
|> assign(:pending_file_uuids, file_uuids)
|> assign(:pending_files, pending_files)}
end
defp save_ticket(socket, :new, params) do
current_user = socket.assigns.current_user
pending_file_uuids = socket.assigns.pending_file_uuids
# Use the selected user or default to current user
user_uuid =
case Map.get(params, "user_uuid") do
nil -> current_user.uuid
"" -> current_user.uuid
uuid -> uuid
end
try do
case CustomerService.create_ticket(user_uuid, params) do
{:ok, ticket} ->
# Add pending attachments to the newly created ticket
Enum.each(pending_file_uuids, fn file_uuid ->
CustomerService.add_attachment_to_ticket(ticket.uuid, file_uuid)
end)
{:noreply,
socket
|> put_flash(:info, "Ticket created successfully")
|> push_navigate(to: Routes.path("/admin/customer-service/tickets/#{ticket.uuid}"))}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :form, to_form(changeset))}
end
rescue
e ->
require Logger
Logger.error("Ticket save failed: #{Exception.message(e)}")
{:noreply, put_flash(socket, :error, "Something went wrong. Please try again.")}
end
end
defp save_ticket(socket, :edit, params) do
case CustomerService.update_ticket(socket.assigns.ticket, params) do
{:ok, ticket} ->
{:noreply,
socket
|> put_flash(:info, "Ticket updated successfully")
|> push_navigate(to: Routes.path("/admin/customer-service/tickets/#{ticket.uuid}"))}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :form, to_form(changeset))}
end
rescue
e ->
require Logger
Logger.error("Ticket save failed: #{Exception.message(e)}")
{:noreply, put_flash(socket, :error, "Something went wrong. Please try again.")}
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