Packages

phoenix_kit

1.7.62
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 new.ex
Raw

lib/modules/customer_service/web/new.ex

defmodule PhoenixKit.Modules.CustomerService.Web.New do
@moduledoc """
LiveView for creating new support tickets from admin panel.
Admins can create tickets on behalf of users with title, description,
priority, and optional file attachments.
"""
use PhoenixKitWeb, :live_view
require Logger
alias PhoenixKit.Modules.CustomerService
alias PhoenixKit.Modules.CustomerService.Ticket
alias PhoenixKit.Modules.Storage
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth
alias PhoenixKit.Utils.Routes
@impl true
def mount(_params, _session, socket) do
if CustomerService.enabled?() do
current_user = socket.assigns[:phoenix_kit_current_user]
ticket = %Ticket{}
changeset = Ticket.changeset(ticket, %{})
attachments_enabled =
Settings.get_boolean_setting("customer_service_attachments_enabled", true)
socket =
socket
|> assign(:page_title, gettext("New Ticket"))
|> assign(:current_user, current_user)
|> assign(:ticket, ticket)
|> assign(:form, to_form(changeset))
|> assign(:pending_file_uuids, [])
|> assign(:pending_files, [])
|> assign(:attachments_enabled, attachments_enabled)
|> assign(:upload_errors, [])
|> maybe_allow_upload(attachments_enabled)
{:ok, socket}
else
{:ok,
socket
|> put_flash(:error, gettext("Tickets module is not enabled"))
|> push_navigate(to: Routes.path("/admin"))}
end
end
defp maybe_allow_upload(socket, true) do
allow_upload(socket, :attachments,
accept: ~w(.jpg .jpeg .png .gif .webp .pdf .doc .docx .txt),
max_entries: 5,
max_file_size: 10_000_000,
auto_upload: true
)
end
defp maybe_allow_upload(socket, false), do: socket
@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("validate", _params, socket) do
# Handle file upload validation (when only files change)
{:noreply, socket}
end
@impl true
def handle_event("save", %{"ticket" => params}, socket) do
current_user = socket.assigns.current_user
# First, process any pending uploads
socket = process_pending_uploads(socket)
pending_file_uuids = socket.assigns.pending_file_uuids
# Determine the user for the ticket
# If admin is creating for a specific user, use that user_uuid
# Otherwise use admin's own uuid
user_uuid =
case params["user_uuid"] do
nil -> current_user.uuid
"" -> current_user.uuid
uuid -> uuid
end
# Merge the determined user_uuid into params
params = Map.put(params, "user_uuid", user_uuid)
try do
case CustomerService.create_ticket(user_uuid, params) do
{:ok, ticket} ->
# Attach pending files 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, gettext("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 ->
Logger.error("Ticket save failed: #{Exception.message(e)}")
{:noreply, put_flash(socket, :error, gettext("Something went wrong. Please try again."))}
end
end
@impl true
def handle_event("cancel_upload", %{"ref" => ref}, socket) do
{:noreply, cancel_upload(socket, :attachments, ref)}
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
defp process_pending_uploads(socket) do
if socket.assigns.attachments_enabled and
Map.has_key?(socket.assigns, :uploads) and
socket.assigns.uploads.attachments.entries != [] do
do_process_uploads(socket)
else
socket
end
end
defp do_process_uploads(socket) do
current_user = socket.assigns.current_user
uploaded_files =
consume_uploaded_entries(socket, :attachments, fn %{path: path}, entry ->
ext = Path.extname(entry.client_name) |> String.replace_leading(".", "")
user_uuid = current_user.uuid
{:ok, _stat} = File.stat(path)
file_hash = Auth.calculate_file_hash(path)
case Storage.store_file_in_buckets(
path,
"document",
user_uuid,
file_hash,
ext,
entry.client_name
) do
{:ok, file, :duplicate} ->
Logger.info("Ticket attachment is duplicate with ID: #{file.uuid}")
{:ok, file}
{:ok, file} ->
Logger.info("Ticket attachment stored with ID: #{file.uuid}")
{:ok, file}
{:error, reason} ->
Logger.error("Storage Error: #{inspect(reason)}")
{:error, reason}
end
end)
# Extract successful uploads
new_files =
uploaded_files
|> Enum.filter(&match?({:ok, _}, &1))
|> Enum.map(fn {:ok, file} -> file end)
new_file_uuids = Enum.map(new_files, & &1.uuid)
socket
|> assign(:pending_file_uuids, socket.assigns.pending_file_uuids ++ new_file_uuids)
|> assign(:pending_files, socket.assigns.pending_files ++ new_files)
end
end