Refactor: Implement emergency system plan
This commit is contained in:
@@ -21,18 +21,11 @@ import { Input } from '@/components/ui/input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { toast } from 'sonner';
|
||||
import { toast } from '@/hooks/use-toast';
|
||||
import { useEmergencyData } from '@/hooks/useEmergencyData';
|
||||
import { Incident } from '@/services/emergencyApi';
|
||||
|
||||
interface EmergencyTabProps {
|
||||
incidents: any[];
|
||||
stats: any;
|
||||
isAdmin: boolean;
|
||||
isSuperAdmin: boolean;
|
||||
}
|
||||
|
||||
const EmergencyTab: React.FC<EmergencyTabProps> = () => {
|
||||
const EmergencyTab: React.FC = () => {
|
||||
const {
|
||||
stats,
|
||||
incidents,
|
||||
@@ -69,13 +62,24 @@ const EmergencyTab: React.FC<EmergencyTabProps> = () => {
|
||||
try {
|
||||
const result = await activatePanicButton('panic');
|
||||
if (result.success) {
|
||||
toast.success('¡Alerta de pánico enviada! POLITUR ha sido notificado.');
|
||||
toast({
|
||||
title: "¡Alerta de pánico enviada!",
|
||||
description: "POLITUR ha sido notificado.",
|
||||
});
|
||||
} else {
|
||||
toast.error(result.error || 'Error activando alerta de pánico');
|
||||
toast({
|
||||
title: "Error",
|
||||
description: result.error || 'Error activando alerta de pánico',
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error activating panic button:', error);
|
||||
toast.error('Error activando alerta de pánico');
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Error activando alerta de pánico",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -187,37 +191,168 @@ const EmergencyTab: React.FC<EmergencyTabProps> = () => {
|
||||
<SelectItem value="resolved">Resuelto</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select value={typeFilter} onValueChange={setTypeFilter}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Tipo" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Todos los tipos</SelectItem>
|
||||
<SelectItem value="theft">Robo</SelectItem>
|
||||
<SelectItem value="assault">Asalto</SelectItem>
|
||||
<SelectItem value="accident">Accidente</SelectItem>
|
||||
<SelectItem value="medical">Médico</SelectItem>
|
||||
<SelectItem value="other">Otro</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="text-center py-8">
|
||||
<Shield className="w-16 h-16 text-blue-500 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold mb-2">Sistema de Emergencias Implementado</h3>
|
||||
<p className="text-gray-600 mb-4">
|
||||
✅ Panel de emergencias en tiempo real<br/>
|
||||
✅ Gestión de incidentes<br/>
|
||||
✅ Comunicación con POLITUR<br/>
|
||||
✅ Geolocalización de emergencias<br/>
|
||||
✅ Botón de pánico integrado
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
Mostrando {filteredIncidents.length} incidentes | {emergencyAlerts.length} alertas activas
|
||||
</p>
|
||||
<div className="space-y-4">
|
||||
{filteredIncidents.length > 0 ? (
|
||||
filteredIncidents.map((incident) => (
|
||||
<Card key={incident.id} className="cursor-pointer hover:shadow-md transition-shadow">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<h4 className="font-semibold text-lg">{incident.title}</h4>
|
||||
<div className="flex gap-2">
|
||||
<Badge variant={incident.priority === 'critical' ? 'destructive' :
|
||||
incident.priority === 'high' ? 'secondary' : 'outline'}>
|
||||
{incident.priority}
|
||||
</Badge>
|
||||
<Badge variant={incident.status === 'resolved' ? 'default' : 'outline'}>
|
||||
{incident.status}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-gray-600 mb-3">{incident.description}</p>
|
||||
<div className="flex justify-between items-center text-sm text-gray-500">
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="flex items-center gap-1">
|
||||
<MapPin className="w-4 h-4" />
|
||||
{incident.location.address || `${incident.location.latitude}, ${incident.location.longitude}`}
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<Clock className="w-4 h-4" />
|
||||
{new Date(incident.createdAt).toLocaleTimeString()}
|
||||
</span>
|
||||
</div>
|
||||
{incident.assignedOfficer && (
|
||||
<span className="flex items-center gap-1">
|
||||
<UserCheck className="w-4 h-4" />
|
||||
{incident.assignedOfficer.name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))
|
||||
) : (
|
||||
<div className="text-center py-8">
|
||||
<Shield className="w-16 h-16 text-blue-500 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold mb-2">Sistema de Emergencias Activo</h3>
|
||||
<p className="text-gray-600 mb-4">
|
||||
✅ Panel de emergencias en tiempo real<br/>
|
||||
✅ Gestión de incidentes<br/>
|
||||
✅ Comunicación con POLITUR<br/>
|
||||
✅ Geolocalización de emergencias<br/>
|
||||
✅ Botón de pánico integrado
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
{error ? `Usando datos de demostración - ${error}` : 'No hay incidentes que mostrar'}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="alerts" className="space-y-4">
|
||||
<div className="text-center p-8">
|
||||
<AlertCircle className="w-16 h-16 text-red-500 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold mb-2">Alertas de Emergencia</h3>
|
||||
<p className="text-gray-600">{emergencyAlerts.length} alertas activas</p>
|
||||
<div className="space-y-4">
|
||||
{emergencyAlerts.length > 0 ? (
|
||||
emergencyAlerts.map((alert) => (
|
||||
<Card key={alert.id} className="border-red-200 bg-red-50">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<h4 className="font-semibold text-lg text-red-800">
|
||||
Alerta de {alert.type === 'panic' ? 'Pánico' : alert.type}
|
||||
</h4>
|
||||
<Badge variant="destructive">{alert.priority}</Badge>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<div className="flex items-center gap-4 text-red-700">
|
||||
<span className="flex items-center gap-1">
|
||||
<MapPin className="w-4 h-4" />
|
||||
{alert.location.address || `${alert.location.latitude}, ${alert.location.longitude}`}
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<Clock className="w-4 h-4" />
|
||||
{new Date(alert.createdAt).toLocaleTimeString()}
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => deactivateEmergencyAlert(alert.id)}
|
||||
className="bg-red-600 hover:bg-red-700"
|
||||
>
|
||||
Desactivar
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))
|
||||
) : (
|
||||
<div className="text-center p-8">
|
||||
<AlertCircle className="w-16 h-16 text-red-500 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold mb-2">Alertas de Emergencia</h3>
|
||||
<p className="text-gray-600">No hay alertas activas en este momento</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="officers" className="space-y-4">
|
||||
<div className="text-center p-8">
|
||||
<Shield className="w-16 h-16 text-blue-500 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold mb-2">Personal POLITUR</h3>
|
||||
<p className="text-gray-600">{officers.length} oficiales registrados</p>
|
||||
<div className="space-y-4">
|
||||
{officers.length > 0 ? (
|
||||
officers.map((officer) => (
|
||||
<Card key={officer.id}>
|
||||
<CardContent className="p-4">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<div>
|
||||
<h4 className="font-semibold text-lg">{officer.name}</h4>
|
||||
<p className="text-gray-600">{officer.rank} - Badge: {officer.badge}</p>
|
||||
</div>
|
||||
<Badge variant={officer.status === 'available' ? 'default' :
|
||||
officer.status === 'busy' ? 'secondary' : 'outline'}>
|
||||
{officer.status === 'available' ? 'Disponible' :
|
||||
officer.status === 'busy' ? 'Ocupado' : 'Fuera de servicio'}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-sm text-gray-500">
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="flex items-center gap-1">
|
||||
<Phone className="w-4 h-4" />
|
||||
{officer.phone}
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<Activity className="w-4 h-4" />
|
||||
{officer.assignedIncidents} incidentes asignados
|
||||
</span>
|
||||
</div>
|
||||
{officer.location && (
|
||||
<span className="flex items-center gap-1">
|
||||
<MapPin className="w-4 h-4" />
|
||||
Ubicación activa
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))
|
||||
) : (
|
||||
<div className="text-center p-8">
|
||||
<Shield className="w-16 h-16 text-blue-500 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold mb-2">Personal POLITUR</h3>
|
||||
<p className="text-gray-600">No hay oficiales registrados</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user