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
phoenix_kit lib modules tickets web list.html.heex
Raw

lib/modules/tickets/web/list.html.heex

<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="Support Tickets"
current_path={@url_path}
project_title={@project_title}
>
<div class="container mx-auto px-4 py-6">
<%!-- Header --%>
<div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
<div>
<h1 class="text-2xl font-bold">Support Tickets</h1>
<p class="text-base-content/70 mt-1">Manage customer support requests</p>
</div>
<div class="mt-4 md:mt-0">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/tickets/new")}
class="btn btn-primary"
>
<.icon name="hero-plus" class="h-5 w-5" /> New Ticket
</.link>
</div>
</div>
<%!-- Stats Cards --%>
<div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6">
<div class="stat bg-base-200 rounded-lg p-4">
<div class="stat-title text-sm">Total</div>
<div class="stat-value text-2xl">{@stats.total}</div>
</div>
<div class="stat bg-info/20 rounded-lg p-4">
<div class="stat-title text-sm">Open</div>
<div class="stat-value text-2xl text-info">{@stats.open}</div>
</div>
<div class="stat bg-warning/20 rounded-lg p-4">
<div class="stat-title text-sm">In Progress</div>
<div class="stat-value text-2xl text-warning">{@stats.in_progress}</div>
</div>
<div class="stat bg-success/20 rounded-lg p-4">
<div class="stat-title text-sm">Resolved</div>
<div class="stat-value text-2xl text-success">{@stats.resolved}</div>
</div>
<div class="stat bg-base-300 rounded-lg p-4">
<div class="stat-title text-sm">Closed</div>
<div class="stat-value text-2xl">{@stats.closed}</div>
</div>
</div>
<%!-- Filters --%>
<div class="bg-base-200 rounded-lg p-4 mb-6">
<form phx-change="filter" phx-submit="filter" class="flex flex-col md:flex-row gap-4">
<%!-- Search --%>
<div class="flex-1">
<input
type="text"
name="search[query]"
value={@search_query}
placeholder="Search tickets..."
class="input input-bordered w-full"
phx-debounce="300"
/>
</div>
<%!-- Status Filter --%>
<div class="w-full md:w-48">
<select name="filters[status]" class="select select-bordered w-full">
<option value="">All Statuses</option>
<option value="open" selected={@status_filter == "open"}>Open</option>
<option value="in_progress" selected={@status_filter == "in_progress"}>
In Progress
</option>
<option value="resolved" selected={@status_filter == "resolved"}>Resolved</option>
<option value="closed" selected={@status_filter == "closed"}>Closed</option>
</select>
</div>
<%!-- Assignment Filter --%>
<div class="w-full md:w-48">
<select name="filters[assigned_to]" class="select select-bordered w-full">
<option value="">All Assigned</option>
<option value="unassigned" selected={@assigned_to_filter == "unassigned"}>
Unassigned
</option>
</select>
</div>
<%!-- Clear Filters --%>
<button type="button" phx-click="clear_filters" class="btn btn-ghost">
Clear
</button>
</form>
</div>
<%!-- Tickets Table --%>
<div class="bg-base-100 rounded-lg shadow">
<%= if @loading do %>
<div class="flex justify-center items-center py-12">
<span class="loading loading-spinner loading-lg"></span>
</div>
<% else %>
<%= if Enum.empty?(@tickets) do %>
<div class="text-center py-12">
<.icon name="hero-ticket" class="h-16 w-16 mx-auto text-base-content/30 mb-4" />
<h3 class="text-lg font-medium mb-2">No tickets found</h3>
<p class="text-base-content/70">
<%= if @status_filter || @search_query do %>
Try adjusting your filters or search query.
<% else %>
Create your first ticket to get started.
<% end %>
</p>
</div>
<% else %>
<.table_default variant="zebra" class="w-full">
<.table_default_header>
<.table_default_row>
<.table_default_header_cell>Ticket</.table_default_header_cell>
<.table_default_header_cell>Customer</.table_default_header_cell>
<.table_default_header_cell>Assigned To</.table_default_header_cell>
<.table_default_header_cell>Status</.table_default_header_cell>
<.table_default_header_cell>Created</.table_default_header_cell>
<.table_default_header_cell>Actions</.table_default_header_cell>
</.table_default_row>
</.table_default_header>
<.table_default_body>
<%= for ticket <- @tickets do %>
<.table_default_row>
<.table_default_cell>
<div class="font-medium">{ticket.title}</div>
<div class="text-sm text-base-content/70 truncate max-w-xs">
{String.slice(ticket.description, 0, 80)}{if String.length(
ticket.description
) >
80,
do: "..."}
</div>
</.table_default_cell>
<.table_default_cell>
<%= if ticket.user do %>
<div class="flex items-center gap-2">
<.user_avatar user={ticket.user} size="sm" />
<span class="text-sm">{ticket.user.email}</span>
</div>
<% else %>
<span class="text-base-content/50">Unknown</span>
<% end %>
</.table_default_cell>
<.table_default_cell>
<%= if ticket.assigned_to do %>
<span class="badge badge-outline">{ticket.assigned_to.email}</span>
<% else %>
<span class="badge badge-ghost">Unassigned</span>
<% end %>
</.table_default_cell>
<.table_default_cell>
<%= case ticket.status do %>
<% "open" -> %>
<span class="badge badge-info">Open</span>
<% "in_progress" -> %>
<span class="badge badge-warning">In Progress</span>
<% "resolved" -> %>
<span class="badge badge-success">Resolved</span>
<% "closed" -> %>
<span class="badge">Closed</span>
<% end %>
</.table_default_cell>
<.table_default_cell class="text-sm text-base-content/70">
{Calendar.strftime(ticket.inserted_at, "%b %d, %Y")}
</.table_default_cell>
<.table_default_cell>
<div class="flex items-center gap-1">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/tickets/#{ticket.id}")}
class="btn btn-ghost btn-xs"
title="View details"
>
<.icon name="hero-eye" class="w-4 h-4" />
</.link>
<.link
navigate={
PhoenixKit.Utils.Routes.path("/admin/tickets/#{ticket.id}/edit")
}
class="btn btn-ghost btn-xs"
title="Edit ticket"
>
<.icon name="hero-pencil" class="w-4 h-4" />
</.link>
</div>
</.table_default_cell>
</.table_default_row>
<% end %>
</.table_default_body>
</.table_default>
<%!-- Pagination --%>
<%= if @total_pages > 1 do %>
<div class="flex justify-center items-center gap-2 py-4 border-t">
<button
phx-click="change_page"
phx-value-page={max(1, @page - 1)}
class={"btn btn-sm #{if @page == 1, do: "btn-disabled"}"}
disabled={@page == 1}
>
Previous
</button>
<span class="text-sm">
Page {@page} of {@total_pages}
</span>
<button
phx-click="change_page"
phx-value-page={min(@total_pages, @page + 1)}
class={"btn btn-sm #{if @page == @total_pages, do: "btn-disabled"}"}
disabled={@page == @total_pages}
>
Next
</button>
</div>
<% end %>
<% end %>
<% end %>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>