Files
ATLAS/frontend/src/store/mapaStore.ts
FlotillasGPS Developer 51d78bacf4 FlotillasGPS - Sistema completo de monitoreo de flotillas GPS
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.
2026-01-21 08:18:00 +00:00

266 lines
6.9 KiB
TypeScript

import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'
import {
Coordenadas,
MapaEstado,
Geocerca,
POI,
VehiculoEstado,
VehiculoMovimiento,
VehiculoTipo,
} from '@/types'
interface MapaStoreState {
// Map state
centro: Coordenadas
zoom: number
bounds: { north: number; south: number; east: number; west: number } | null
// Selection
vehiculoSeleccionado: string | null
geocercaSeleccionada: string | null
poiSeleccionado: string | null
// Filters
filtros: {
estados: VehiculoEstado[]
movimientos: VehiculoMovimiento[]
tipos: VehiculoTipo[]
grupos: string[]
}
// Layers visibility
capas: {
vehiculos: boolean
geocercas: boolean
pois: boolean
trafico: boolean
rutas: boolean
labels: boolean
}
// Drawing
herramienta: 'seleccionar' | 'medir' | 'dibujar_circulo' | 'dibujar_poligono' | null
dibujando: boolean
puntosDibujo: Coordenadas[]
// Data (cached for map display)
geocercas: Geocerca[]
pois: POI[]
// Map style
estilo: 'dark' | 'light' | 'satellite'
// Following vehicle
siguiendoVehiculo: string | null
// Actions
setCentro: (centro: Coordenadas) => void
setZoom: (zoom: number) => void
setBounds: (bounds: { north: number; south: number; east: number; west: number } | null) => void
setView: (centro: Coordenadas, zoom: number) => void
fitBounds: (bounds: { north: number; south: number; east: number; west: number }) => void
setVehiculoSeleccionado: (id: string | null) => void
setGeocercaSeleccionada: (id: string | null) => void
setPoiSeleccionado: (id: string | null) => void
setFiltros: (filtros: Partial<MapaStoreState['filtros']>) => void
toggleFiltro: <K extends keyof MapaStoreState['filtros']>(
key: K,
value: MapaStoreState['filtros'][K][number]
) => void
resetFiltros: () => void
setCapa: (capa: keyof MapaStoreState['capas'], visible: boolean) => void
toggleCapa: (capa: keyof MapaStoreState['capas']) => void
setHerramienta: (herramienta: MapaStoreState['herramienta']) => void
startDibujo: () => void
addPuntoDibujo: (punto: Coordenadas) => void
removePuntoDibujo: (index: number) => void
finishDibujo: () => void
cancelDibujo: () => void
setGeocercas: (geocercas: Geocerca[]) => void
setPois: (pois: POI[]) => void
setEstilo: (estilo: MapaStoreState['estilo']) => void
setSiguiendoVehiculo: (id: string | null) => void
// Utils
centrarEnVehiculo: (lat: number, lng: number) => void
centrarEnGeocerca: (geocerca: Geocerca) => void
}
const defaultFiltros = {
estados: [] as VehiculoEstado[],
movimientos: [] as VehiculoMovimiento[],
tipos: [] as VehiculoTipo[],
grupos: [] as string[],
}
const defaultCapas = {
vehiculos: true,
geocercas: true,
pois: true,
trafico: false,
rutas: false,
labels: true,
}
// Default center (Mexico City)
const defaultCentro: Coordenadas = { lat: 19.4326, lng: -99.1332 }
export const useMapaStore = create<MapaStoreState>()(
persist(
(set, get) => ({
centro: defaultCentro,
zoom: 12,
bounds: null,
vehiculoSeleccionado: null,
geocercaSeleccionada: null,
poiSeleccionado: null,
filtros: defaultFiltros,
capas: defaultCapas,
herramienta: null,
dibujando: false,
puntosDibujo: [],
geocercas: [],
pois: [],
estilo: 'dark',
siguiendoVehiculo: null,
setCentro: (centro) => set({ centro }),
setZoom: (zoom) => set({ zoom }),
setBounds: (bounds) => set({ bounds }),
setView: (centro, zoom) => set({ centro, zoom }),
fitBounds: (bounds) => set({ bounds }),
setVehiculoSeleccionado: (id) =>
set({
vehiculoSeleccionado: id,
geocercaSeleccionada: null,
poiSeleccionado: null,
}),
setGeocercaSeleccionada: (id) =>
set({
geocercaSeleccionada: id,
vehiculoSeleccionado: null,
poiSeleccionado: null,
}),
setPoiSeleccionado: (id) =>
set({
poiSeleccionado: id,
vehiculoSeleccionado: null,
geocercaSeleccionada: null,
}),
setFiltros: (filtros) =>
set((state) => ({
filtros: { ...state.filtros, ...filtros },
})),
toggleFiltro: (key, value) =>
set((state) => {
const current = state.filtros[key] as unknown[]
const newValues = current.includes(value)
? current.filter((v) => v !== value)
: [...current, value]
return {
filtros: { ...state.filtros, [key]: newValues },
}
}),
resetFiltros: () => set({ filtros: defaultFiltros }),
setCapa: (capa, visible) =>
set((state) => ({
capas: { ...state.capas, [capa]: visible },
})),
toggleCapa: (capa) =>
set((state) => ({
capas: { ...state.capas, [capa]: !state.capas[capa] },
})),
setHerramienta: (herramienta) =>
set({
herramienta,
dibujando: false,
puntosDibujo: [],
}),
startDibujo: () => set({ dibujando: true, puntosDibujo: [] }),
addPuntoDibujo: (punto) =>
set((state) => ({
puntosDibujo: [...state.puntosDibujo, punto],
})),
removePuntoDibujo: (index) =>
set((state) => ({
puntosDibujo: state.puntosDibujo.filter((_, i) => i !== index),
})),
finishDibujo: () =>
set({
dibujando: false,
herramienta: null,
}),
cancelDibujo: () =>
set({
dibujando: false,
puntosDibujo: [],
herramienta: null,
}),
setGeocercas: (geocercas) => set({ geocercas }),
setPois: (pois) => set({ pois }),
setEstilo: (estilo) => set({ estilo }),
setSiguiendoVehiculo: (id) => set({ siguiendoVehiculo: id }),
centrarEnVehiculo: (lat, lng) =>
set({
centro: { lat, lng },
zoom: 16,
}),
centrarEnGeocerca: (geocerca) => {
if (geocerca.tipo === 'circulo' && geocerca.centroLat && geocerca.centroLng) {
set({
centro: { lat: geocerca.centroLat, lng: geocerca.centroLng },
zoom: 14,
})
} else if (geocerca.vertices && geocerca.vertices.length > 0) {
// Calculate center of polygon
const lats = geocerca.vertices.map((v) => v.lat)
const lngs = geocerca.vertices.map((v) => v.lng)
const centerLat = (Math.max(...lats) + Math.min(...lats)) / 2
const centerLng = (Math.max(...lngs) + Math.min(...lngs)) / 2
set({
centro: { lat: centerLat, lng: centerLng },
zoom: 14,
})
}
},
}),
{
name: 'flotillas-mapa',
storage: createJSONStorage(() => localStorage),
partialize: (state) => ({
centro: state.centro,
zoom: state.zoom,
capas: state.capas,
estilo: state.estilo,
}),
}
)
)