/** * TicketsPage - Lista de tickets de postventa */ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Plus, Eye, Trash2, Ticket, Clock, AlertTriangle, User, } from 'lucide-react'; import { useTickets, useDeleteTicket, useTicketStats, } from '../../../hooks/useQuality'; import type { TicketCategory, TicketPriority, TicketStatus, TicketFilters, } from '../../../types/quality.types'; import { TICKET_CATEGORY_OPTIONS, TICKET_PRIORITY_OPTIONS, TICKET_STATUS_OPTIONS, } from '../../../types/quality.types'; import { PageHeader, PageHeaderAction, SearchInput, SelectField, StatusBadgeFromOptions, ConfirmDialog, LoadingOverlay, EmptyState, Pagination, StatsCard, } from '../../../components/common'; export function TicketsPage() { const navigate = useNavigate(); const [search, setSearch] = useState(''); const [categoryFilter, setCategoryFilter] = useState(''); const [priorityFilter, setPriorityFilter] = useState(''); const [statusFilter, setStatusFilter] = useState(''); const [page, setPage] = useState(1); const [deleteId, setDeleteId] = useState(null); const filters: TicketFilters = { search: search || undefined, category: categoryFilter || undefined, priority: priorityFilter || undefined, status: statusFilter || undefined, page, limit: 10, }; const { data, isLoading, error } = useTickets(filters); const { data: stats } = useTicketStats(); const deleteMutation = useDeleteTicket(); const tickets = data?.items || []; const total = data?.total || 0; const totalPages = Math.ceil(total / 10); const handleDelete = async () => { if (deleteId) { await deleteMutation.mutateAsync(deleteId); setDeleteId(null); } }; const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleDateString('es-MX', { year: 'numeric', month: 'short', day: 'numeric', }); }; if (isLoading) { return ; } if (error) { return ( ); } return (
navigate('/admin/calidad/tickets/nuevo')}> Nuevo Ticket } /> {/* Stats */} {stats && (
} color="blue" /> } color="yellow" /> } color="blue" /> } color="green" /> } color="red" /> } color="purple" />
)} {/* Filters */}
({ value: o.value, label: o.label })), ]} value={categoryFilter} onChange={(e) => setCategoryFilter(e.target.value as TicketCategory | '')} /> ({ value: o.value, label: o.label })), ]} value={priorityFilter} onChange={(e) => setPriorityFilter(e.target.value as TicketPriority | '')} /> ({ value: o.value, label: o.label })), ]} value={statusFilter} onChange={(e) => setStatusFilter(e.target.value as TicketStatus | '')} />
{/* Table */}
{tickets.length === 0 ? ( } title="No hay tickets" description="No se encontraron tickets con los filtros seleccionados." /> ) : ( <>
{tickets.map((ticket) => ( ))}
Ticket Categoria Prioridad Estado SLA Creado Acciones
{ticket.ticketNumber}
{ticket.title}
{ticket.slaBreached ? ( Incumplido ) : ( {ticket.slaHours}h )} {formatDate(ticket.createdAt)}
{totalPages > 1 && (
)} )}
{/* Delete Confirmation */} setDeleteId(null)} onConfirm={handleDelete} title="Eliminar Ticket" message="Esta seguro de eliminar este ticket? Esta accion no se puede deshacer." confirmLabel="Eliminar" variant="danger" isLoading={deleteMutation.isPending} />
); }