86 lines
3 KiB
JavaScript
86 lines
3 KiB
JavaScript
|
|
import React, { useState, useMemo } from 'react';
|
|
import { Helmet } from 'react-helmet';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { Eye, Ticket, CheckCircle, Clock, AlertTriangle } from 'lucide-react';
|
|
import DataTable from '@/components/DataTable';
|
|
import StatusBadge from '@/components/StatusBadget';
|
|
import KPIBar from '@/components/KPIBar';
|
|
import { mockTickets, calculateKPIs } from '@/data/mockData';
|
|
|
|
const TicketsPage = () => {
|
|
const navigate = useNavigate();
|
|
const [period, setPeriod] = useState('month');
|
|
|
|
const kpis = useMemo(() => {
|
|
const stats = calculateKPIs(mockTickets, period, { dateField: 'openDate', amountField: 'id' });
|
|
const resolved = stats.items.filter(t => t.status === 'resolved' || t.status === 'closed');
|
|
const open = stats.items.filter(t => t.status === 'open' || t.status === 'in-progress');
|
|
|
|
return [
|
|
{ title: 'Tickets Ouverts', value: open.length, change: '+2', trend: 'up', icon: Ticket },
|
|
{ title: 'Tickets Résolus', value: resolved.length, change: '+5', trend: 'up', icon: CheckCircle },
|
|
{ title: 'SLA Moyen', value: '96%', change: '+1%', trend: 'up', icon: Clock },
|
|
{ title: 'Tickets Critiques', value: stats.items.filter(t => t.priority === 'critical').length, change: '-1', trend: 'down', icon: AlertTriangle },
|
|
];
|
|
}, [period]);
|
|
|
|
const columns = [
|
|
{ key: 'number', label: 'Numéro', sortable: true },
|
|
{ key: 'client', label: 'Client', sortable: true },
|
|
{ key: 'subject', label: 'Sujet', sortable: true },
|
|
{
|
|
key: 'priority',
|
|
label: 'Priorité',
|
|
sortable: true,
|
|
render: (value) => <StatusBadge status={value} />
|
|
},
|
|
{
|
|
key: 'status',
|
|
label: 'Statut',
|
|
sortable: true,
|
|
render: (value) => <StatusBadge status={value} />
|
|
},
|
|
{ key: 'assignedTo', label: 'Assigné à', sortable: true },
|
|
{ key: 'openDate', label: 'Date ouverture', sortable: true },
|
|
];
|
|
|
|
const actions = (row) => (
|
|
<button
|
|
onClick={() => navigate(`/tickets/${row.id}`)}
|
|
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors"
|
|
title="Voir"
|
|
>
|
|
<Eye className="w-4 h-4" />
|
|
</button>
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<Helmet>
|
|
<title>Tickets - Bijou ERP</title>
|
|
<meta name="description" content="Gestion des tickets support" />
|
|
</Helmet>
|
|
|
|
<div className="space-y-6">
|
|
<KPIBar kpis={kpis} period={period} onPeriodChange={setPeriod} />
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">Tickets Support</h1>
|
|
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">{mockTickets.length} tickets</p>
|
|
</div>
|
|
</div>
|
|
|
|
<DataTable
|
|
columns={columns}
|
|
data={mockTickets}
|
|
onRowClick={(row) => navigate(`/tickets/${row.id}`)}
|
|
actions={actions}
|
|
/>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default TicketsPage;
|