Packages
phoenix_kit
1.7.21
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
Current section
Files
lib/modules/tickets/web/user_new.html.heex
<PhoenixKitWeb.Layouts.dashboard {assigns}>
<div class="max-w-2xl mx-auto">
<%!-- Back Button --%>
<div class="mb-6">
<.link
navigate={PhoenixKit.Utils.Routes.path("/dashboard/tickets")}
class="btn btn-ghost btn-sm gap-2"
>
<.icon name="hero-arrow-left" class="h-4 w-4" />
{gettext("Back to Tickets")}
</.link>
</div>
<div class="card bg-base-100 shadow">
<div class="card-body">
<h1 class="card-title text-2xl mb-6">{gettext("Create New Ticket")}</h1>
<.form for={@form} phx-change="validate" phx-submit="save" class="space-y-6">
<%!-- Title Field --%>
<div class="form-control">
<label class="label">
<span class="label-text font-medium">{gettext("Subject")} *</span>
</label>
<input
type="text"
name="ticket[title]"
value={@form[:title].value}
class={"input input-bordered w-full #{if @form[:title].errors != [], do: "input-error"}"}
placeholder={gettext("Brief description of your issue")}
required
/>
<.error :for={msg <- @form[:title].errors |> Enum.map(&elem(&1, 0))}>{msg}</.error>
</div>
<%!-- Description Field --%>
<div class="form-control">
<label class="label">
<span class="label-text font-medium">{gettext("Description")} *</span>
</label>
<textarea
name="ticket[description]"
class={"textarea textarea-bordered w-full h-40 #{if @form[:description].errors != [], do: "textarea-error"}"}
placeholder={gettext("Please describe your issue in detail...")}
required
>{@form[:description].value}</textarea>
<.error :for={msg <- @form[:description].errors |> Enum.map(&elem(&1, 0))}>
{msg}
</.error>
</div>
<%!-- Attachments Section --%>
<%= if @attachments_enabled do %>
<div class="form-control">
<label class="label">
<span class="label-text font-medium">{gettext("Attachments")}</span>
<span class="label-text-alt text-base-content/50">{gettext("Optional")}</span>
</label>
<%!-- Already Uploaded Files Preview --%>
<%= if Enum.any?(@pending_files) do %>
<div class="grid grid-cols-2 md:grid-cols-4 gap-3 mb-4">
<%= for file <- @pending_files do %>
<div class="relative group border border-base-300 rounded-lg overflow-hidden p-3 bg-base-200">
<div class="flex items-center gap-2">
<.icon
name="hero-document"
class="w-6 h-6 text-base-content/50 flex-shrink-0"
/>
<div class="text-xs truncate flex-1">{file.original_file_name}</div>
</div>
<button
type="button"
phx-click="remove_pending_file"
phx-value-id={file.id}
class="absolute top-1 right-1 btn btn-circle btn-xs btn-error opacity-0 group-hover:opacity-100 transition-opacity"
>
<.icon name="hero-x-mark" class="w-3 h-3" />
</button>
</div>
<% end %>
</div>
<% end %>
<%!-- Upload Progress --%>
<%= if Map.has_key?(assigns, :uploads) do %>
<%= for entry <- @uploads.attachments.entries do %>
<div class="flex items-center gap-3 mb-2 p-2 bg-base-200 rounded-lg">
<.icon name="hero-document" class="w-5 h-5 text-base-content/50" />
<div class="flex-1 min-w-0">
<div class="text-sm truncate">{entry.client_name}</div>
<progress
class="progress progress-primary w-full h-1"
value={entry.progress}
max="100"
>
</progress>
</div>
<button
type="button"
phx-click="cancel_upload"
phx-value-ref={entry.ref}
class="btn btn-ghost btn-xs"
>
<.icon name="hero-x-mark" class="w-4 h-4" />
</button>
</div>
<% end %>
<%!-- Upload Errors --%>
<%= for {_ref, msg} <- @uploads.attachments.errors do %>
<div class="alert alert-error mb-2">
<.icon name="hero-exclamation-circle" class="w-5 h-5" />
<span>
<%= case msg do %>
<% :too_large -> %>
{gettext("File is too large")}
<% :too_many_files -> %>
{gettext("Too many files")}
<% :not_accepted -> %>
{gettext("File type not accepted")}
<% _ -> %>
{inspect(msg)}
<% end %>
</span>
</div>
<% end %>
<% end %>
<%!-- Drag and Drop Zone --%>
<%= if Map.has_key?(assigns, :uploads) do %>
<div
class="border-2 border-dashed border-base-300 rounded-lg p-6 text-center transition-colors cursor-pointer hover:border-primary hover:bg-primary/5"
phx-drop-target={@uploads.attachments.ref}
>
<label for={@uploads.attachments.ref} class="cursor-pointer block">
<div class="flex flex-col items-center gap-2">
<.icon name="hero-cloud-arrow-up" class="w-8 h-8 text-primary" />
<span class="text-sm font-medium">
{gettext("Drop files here or click to upload")}
</span>
<span class="text-xs text-base-content/50">
{gettext("Images, PDFs, documents (max 10MB each, up to 5 files)")}
</span>
</div>
<.live_file_input upload={@uploads.attachments} class="hidden" />
</label>
</div>
<% end %>
</div>
<% end %>
<%!-- Form Actions --%>
<div class="flex justify-end gap-3 pt-4 border-t border-base-300">
<.link
navigate={PhoenixKit.Utils.Routes.path("/dashboard/tickets")}
class="btn btn-ghost"
>
{gettext("Cancel")}
</.link>
<button type="submit" class="btn btn-primary">
<.icon name="hero-paper-airplane" class="w-5 h-5" />
{gettext("Submit Ticket")}
</button>
</div>
</.form>
</div>
</div>
</div>
</PhoenixKitWeb.Layouts.dashboard>