205 lines
6.6 KiB
TypeScript
205 lines
6.6 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { FileText, Search, Filter, Download, Eye } from 'lucide-react';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Badge } from '@/components/ui/badge';
|
|
|
|
interface Report {
|
|
id: string;
|
|
reportNumber: string;
|
|
touristName: string;
|
|
type: string;
|
|
category: string;
|
|
date: string;
|
|
status: 'open' | 'under_review' | 'closed';
|
|
officer: string;
|
|
description: string;
|
|
}
|
|
|
|
const Reports = () => {
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
const [reports] = useState<Report[]>([
|
|
{
|
|
id: '1',
|
|
reportNumber: 'POL-2024-001',
|
|
touristName: 'John Smith',
|
|
type: 'Robo',
|
|
category: 'Seguridad',
|
|
date: '2024-01-15',
|
|
status: 'closed',
|
|
officer: 'Oficial Rodriguez',
|
|
description: 'Robo de cartera en Zona Colonial'
|
|
},
|
|
{
|
|
id: '2',
|
|
reportNumber: 'POL-2024-002',
|
|
touristName: 'Maria Garcia',
|
|
type: 'Accidente',
|
|
category: 'Tránsito',
|
|
date: '2024-01-16',
|
|
status: 'under_review',
|
|
officer: 'Oficial Martinez',
|
|
description: 'Accidente de tránsito menor en el Malecón'
|
|
},
|
|
{
|
|
id: '3',
|
|
reportNumber: 'POL-2024-003',
|
|
touristName: 'Robert Johnson',
|
|
type: 'Pérdida',
|
|
category: 'Documentos',
|
|
date: '2024-01-17',
|
|
status: 'open',
|
|
officer: 'Oficial Fernandez',
|
|
description: 'Pérdida de pasaporte en área hotelera'
|
|
}
|
|
]);
|
|
|
|
const getStatusBadge = (status: string) => {
|
|
switch (status) {
|
|
case 'open':
|
|
return <Badge variant="default">Abierto</Badge>;
|
|
case 'under_review':
|
|
return <Badge variant="secondary">En Revisión</Badge>;
|
|
case 'closed':
|
|
return <Badge variant="outline">Cerrado</Badge>;
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const filteredReports = reports.filter(report =>
|
|
report.touristName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
report.reportNumber.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
report.type.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<h2 className="text-2xl font-bold text-gray-900">Reportes y Denuncias</h2>
|
|
<Button>
|
|
<FileText className="w-4 h-4 mr-2" />
|
|
Nuevo Reporte
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Stats */}
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm font-medium text-gray-600">
|
|
Reportes Abiertos
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-3xl font-bold text-blue-600">
|
|
{reports.filter(r => r.status === 'open').length}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm font-medium text-gray-600">
|
|
En Revisión
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-3xl font-bold text-orange-600">
|
|
{reports.filter(r => r.status === 'under_review').length}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm font-medium text-gray-600">
|
|
Cerrados
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-3xl font-bold text-green-600">
|
|
{reports.filter(r => r.status === 'closed').length}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Search and Filters */}
|
|
<Card>
|
|
<CardHeader>
|
|
<div className="flex flex-col md:flex-row gap-4">
|
|
<div className="flex-1">
|
|
<div className="relative">
|
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
|
|
<Input
|
|
placeholder="Buscar por nombre, número o tipo..."
|
|
className="pl-10"
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<Button variant="outline">
|
|
<Filter className="w-4 h-4 mr-2" />
|
|
Filtros
|
|
</Button>
|
|
<Button variant="outline">
|
|
<Download className="w-4 h-4 mr-2" />
|
|
Exportar
|
|
</Button>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-3">
|
|
{filteredReports.map((report) => (
|
|
<div
|
|
key={report.id}
|
|
className="border rounded-lg p-4 hover:bg-gray-50 transition-colors"
|
|
>
|
|
<div className="flex items-start justify-between mb-2">
|
|
<div>
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<h3 className="font-semibold">{report.reportNumber}</h3>
|
|
{getStatusBadge(report.status)}
|
|
</div>
|
|
<p className="text-sm text-gray-600">{report.touristName}</p>
|
|
</div>
|
|
<Button size="sm" variant="outline">
|
|
<Eye className="w-4 h-4 mr-1" />
|
|
Ver
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm mb-2">
|
|
<div>
|
|
<span className="text-gray-500">Tipo:</span>
|
|
<p className="font-medium">{report.type}</p>
|
|
</div>
|
|
<div>
|
|
<span className="text-gray-500">Categoría:</span>
|
|
<p className="font-medium">{report.category}</p>
|
|
</div>
|
|
<div>
|
|
<span className="text-gray-500">Fecha:</span>
|
|
<p className="font-medium">{new Date(report.date).toLocaleDateString('es-ES')}</p>
|
|
</div>
|
|
<div>
|
|
<span className="text-gray-500">Oficial:</span>
|
|
<p className="font-medium">{report.officer}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<p className="text-sm text-gray-700">{report.description}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Reports;
|