Sistema completo para monitoreo y gestion de flotas de vehiculos con: - Backend FastAPI con PostgreSQL/TimescaleDB - Frontend React con TypeScript y TailwindCSS - App movil React Native con Expo - Soporte para dispositivos GPS, Meshtastic y celulares - Video streaming en vivo con MediaMTX - Geocercas, alertas, viajes y reportes - Autenticacion JWT y WebSockets en tiempo real Documentacion completa y guias de usuario incluidas.
113 lines
3.5 KiB
TypeScript
113 lines
3.5 KiB
TypeScript
import { Circle, Polygon, Polyline, Popup, Tooltip } from 'react-leaflet'
|
|
import { Geocerca } from '@/types'
|
|
|
|
interface GeocercaLayerProps {
|
|
geocerca: Geocerca
|
|
editable?: boolean
|
|
onClick?: () => void
|
|
}
|
|
|
|
export default function GeocercaLayer({
|
|
geocerca,
|
|
editable = false,
|
|
onClick,
|
|
}: GeocercaLayerProps) {
|
|
const pathOptions = {
|
|
color: geocerca.color,
|
|
fillColor: geocerca.color,
|
|
fillOpacity: 0.2,
|
|
weight: 2,
|
|
}
|
|
|
|
const eventHandlers = {
|
|
click: () => onClick?.(),
|
|
}
|
|
|
|
// Circle geocerca
|
|
if (geocerca.tipo === 'circulo' && geocerca.centroLat && geocerca.centroLng && geocerca.radio) {
|
|
return (
|
|
<Circle
|
|
center={[geocerca.centroLat, geocerca.centroLng]}
|
|
radius={geocerca.radio}
|
|
pathOptions={pathOptions}
|
|
eventHandlers={eventHandlers}
|
|
>
|
|
<Tooltip permanent={false} direction="top">
|
|
<span className="text-sm font-medium">{geocerca.nombre}</span>
|
|
</Tooltip>
|
|
<Popup>
|
|
<GeocercaPopup geocerca={geocerca} />
|
|
</Popup>
|
|
</Circle>
|
|
)
|
|
}
|
|
|
|
// Polygon geocerca
|
|
if (geocerca.tipo === 'poligono' && geocerca.vertices && geocerca.vertices.length > 2) {
|
|
const positions = geocerca.vertices.map((v) => [v.lat, v.lng] as [number, number])
|
|
|
|
return (
|
|
<Polygon positions={positions} pathOptions={pathOptions} eventHandlers={eventHandlers}>
|
|
<Tooltip permanent={false} direction="top">
|
|
<span className="text-sm font-medium">{geocerca.nombre}</span>
|
|
</Tooltip>
|
|
<Popup>
|
|
<GeocercaPopup geocerca={geocerca} />
|
|
</Popup>
|
|
</Polygon>
|
|
)
|
|
}
|
|
|
|
// Route geocerca
|
|
if (geocerca.tipo === 'ruta' && geocerca.vertices && geocerca.vertices.length > 1) {
|
|
const positions = geocerca.vertices.map((v) => [v.lat, v.lng] as [number, number])
|
|
|
|
return (
|
|
<Polyline positions={positions} pathOptions={{ ...pathOptions, fillOpacity: 0 }} eventHandlers={eventHandlers}>
|
|
<Tooltip permanent={false} direction="top">
|
|
<span className="text-sm font-medium">{geocerca.nombre}</span>
|
|
</Tooltip>
|
|
<Popup>
|
|
<GeocercaPopup geocerca={geocerca} />
|
|
</Popup>
|
|
</Polyline>
|
|
)
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
// Popup content
|
|
function GeocercaPopup({ geocerca }: { geocerca: Geocerca }) {
|
|
return (
|
|
<div className="p-1">
|
|
<h3 className="text-sm font-semibold text-white mb-1">{geocerca.nombre}</h3>
|
|
{geocerca.descripcion && (
|
|
<p className="text-xs text-slate-400 mb-2">{geocerca.descripcion}</p>
|
|
)}
|
|
<div className="space-y-1 text-xs">
|
|
<div className="flex justify-between">
|
|
<span className="text-slate-500">Tipo:</span>
|
|
<span className="text-slate-300 capitalize">{geocerca.tipo}</span>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<span className="text-slate-500">Accion:</span>
|
|
<span className="text-slate-300 capitalize">{geocerca.accion}</span>
|
|
</div>
|
|
{geocerca.velocidadMaxima && (
|
|
<div className="flex justify-between">
|
|
<span className="text-slate-500">Vel. max:</span>
|
|
<span className="text-slate-300">{geocerca.velocidadMaxima} km/h</span>
|
|
</div>
|
|
)}
|
|
{geocerca.tipo === 'circulo' && geocerca.radio && (
|
|
<div className="flex justify-between">
|
|
<span className="text-slate-500">Radio:</span>
|
|
<span className="text-slate-300">{geocerca.radio} m</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|