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_new.ex
Raw

lib/modules/tickets/web/user_new.ex

defmodule PhoenixKit.Modules.Tickets.Web.UserNew do
@moduledoc """
LiveView for creating new support tickets with file attachments.
Users can create tickets with title, description and drag-and-drop file uploads.
Files are stored via Storage module and attached to the ticket after creation.
"""
use PhoenixKitWeb, :live_view
require Logger
alias PhoenixKit.Modules.Storage
alias PhoenixKit.Modules.Tickets
alias PhoenixKit.Modules.Tickets.Ticket
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth
alias PhoenixKit.Utils.Routes
@impl true
def mount(_params, _session, socket) do
if Tickets.enabled?() do
current_user = socket.assigns[:phoenix_kit_current_user]
ticket = %Ticket{user_id: current_user.id}
changeset = Ticket.changeset(ticket, %{})
attachments_enabled =
Settings.get_boolean_setting("tickets_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_ids, [])
|> 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("/dashboard"))}
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_ids = socket.assigns.pending_file_ids
case Tickets.create_ticket(current_user.id, params) do
{:ok, ticket} ->
# Attach pending files to the newly created ticket
Enum.each(pending_file_ids, fn file_id ->
Tickets.add_attachment_to_ticket(ticket.uuid, file_id)
end)
{:noreply,
socket
|> put_flash(:info, gettext("Ticket created successfully"))
|> push_navigate(to: Routes.path("/dashboard/tickets/#{ticket.uuid}"))}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :form, to_form(changeset))}
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", %{"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.uuid == file_id))
{:noreply,
socket
|> assign(:pending_file_ids, pending_file_ids)
|> 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_id = current_user.id
{:ok, _stat} = File.stat(path)
file_hash = Auth.calculate_file_hash(path)
case Storage.store_file_in_buckets(
path,
"document",
user_id,
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_ids = Enum.map(new_files, & &1.uuid)
socket
|> assign(:pending_file_ids, socket.assigns.pending_file_ids ++ new_file_ids)
|> assign(:pending_files, socket.assigns.pending_files ++ new_files)
end
end