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.
This commit is contained in:
265
frontend/src/store/mapaStore.ts
Normal file
265
frontend/src/store/mapaStore.ts
Normal file
@@ -0,0 +1,265 @@
|
||||
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,
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user