diff --git a/package-lock.json b/package-lock.json index fdf65f9..31f9990 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ }, "devDependencies": { "@types/leaflet": "^1.9.8", + "@types/node": "^25.2.0", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@typescript-eslint/eslint-plugin": "^6.12.0", @@ -1505,6 +1506,16 @@ "@types/geojson": "*" } }, + "node_modules/@types/node": { + "version": "25.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", + "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -6695,6 +6706,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", diff --git a/package.json b/package.json index a1c8634..c585641 100644 --- a/package.json +++ b/package.json @@ -15,37 +15,38 @@ "test:cov": "vitest run --coverage" }, "dependencies": { + "@hookform/resolvers": "^3.3.2", + "@tanstack/react-query": "^5.8.4", + "axios": "^1.7.7", + "clsx": "^2.0.0", + "date-fns": "^2.30.0", + "leaflet": "^1.9.4", + "lucide-react": "^0.460.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-router-dom": "^6.28.0", - "zustand": "^5.0.1", - "axios": "^1.7.7", - "@tanstack/react-query": "^5.8.4", - "lucide-react": "^0.460.0", - "date-fns": "^2.30.0", - "clsx": "^2.0.0", "react-hook-form": "^7.48.2", - "@hookform/resolvers": "^3.3.2", + "react-leaflet": "^4.2.1", + "react-router-dom": "^6.28.0", "zod": "^3.22.4", - "leaflet": "^1.9.4", - "react-leaflet": "^4.2.1" + "zustand": "^5.0.1" }, "devDependencies": { + "@types/leaflet": "^1.9.8", + "@types/node": "^25.2.0", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", - "@types/leaflet": "^1.9.8", + "@typescript-eslint/eslint-plugin": "^6.12.0", + "@typescript-eslint/parser": "^6.12.0", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.16", + "eslint": "^8.54.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", "postcss": "^8.4.32", "tailwindcss": "^3.4.15", "typescript": "^5.3.2", "vite": "^5.0.8", - "vitest": "^1.0.4", - "eslint": "^8.54.0", - "@typescript-eslint/eslint-plugin": "^6.12.0", - "@typescript-eslint/parser": "^6.12.0", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0" + "vitest": "^1.0.4" }, "engines": { "node": ">=20.0.0" diff --git a/src/features/ordenes-transporte/components/OTDetail.tsx b/src/features/ordenes-transporte/components/OTDetail.tsx index 4dc83be..dfb71ab 100644 --- a/src/features/ordenes-transporte/components/OTDetail.tsx +++ b/src/features/ordenes-transporte/components/OTDetail.tsx @@ -1,7 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { ordenesTransporteApi } from '../api/ordenes-transporte.api'; import { OTStatusBadge } from './OTStatusBadge'; -import type { OrdenTransporte, EstadoOrdenTransporte } from '../types'; +import type { OrdenTransporte } from '../types'; interface OTDetailProps { orden: OrdenTransporte; @@ -20,7 +20,7 @@ export function OTDetail({ orden, onClose, onEdit }: OTDetailProps) { }); const cancelarMutation = useMutation({ - mutationFn: () => ordenesTransporteApi.cancelar(orden.id), + mutationFn: (motivo: string) => ordenesTransporteApi.cancelar(orden.id, motivo), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['ordenes-transporte'] }); }, @@ -59,8 +59,9 @@ export function OTDetail({ orden, onClose, onEdit }: OTDetailProps) { }; const handleCancelar = async () => { - if (window.confirm('¿Cancelar esta orden de transporte?')) { - await cancelarMutation.mutateAsync(); + const motivo = window.prompt('Motivo de cancelación:'); + if (motivo) { + await cancelarMutation.mutateAsync(motivo); } }; diff --git a/src/features/ordenes-transporte/components/OTForm.tsx b/src/features/ordenes-transporte/components/OTForm.tsx index aa06c0d..c34788d 100644 --- a/src/features/ordenes-transporte/components/OTForm.tsx +++ b/src/features/ordenes-transporte/components/OTForm.tsx @@ -3,6 +3,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { ordenesTransporteApi } from '../api/ordenes-transporte.api'; +import { TipoCarga, ModalidadServicio, TipoEquipo } from '../types'; import type { OrdenTransporte, CreateOTDto, UpdateOTDto } from '../types'; const otSchema = z.object({ @@ -72,20 +73,20 @@ export function OTForm({ initialData, onSuccess, onCancel }: OTFormProps) { ? { clienteId: initialData.clienteId, referenciaCliente: initialData.referenciaCliente || '', - modalidad: initialData.modalidad, - tipoCarga: initialData.tipoCarga, - tipoEquipo: initialData.tipoEquipo, + modalidad: (initialData.modalidad || 'FTL') as 'FTL' | 'LTL' | 'DEDICADO' | 'EXPRESS' | 'CONSOLIDADO', + tipoCarga: initialData.tipoCarga as 'GENERAL' | 'REFRIGERADA' | 'PELIGROSA' | 'SOBREDIMENSIONADA' | 'FRAGIL' | 'GRANEL' | 'LIQUIDOS' | 'CONTENEDOR', + tipoEquipo: initialData.tipoEquipo as 'CAJA_SECA' | 'REFRIGERADO' | 'PLATAFORMA' | 'TANQUE' | 'LOWBOY' | 'PORTACONTENEDOR' | 'TOLVA' | 'GONDOLA' | undefined, origenDireccion: initialData.origenDireccion, - origenCiudad: initialData.origenCiudad, - origenEstado: initialData.origenEstado, + origenCiudad: initialData.origenCiudad || '', + origenEstado: initialData.origenEstado || '', origenCP: initialData.origenCP || '', origenPais: initialData.origenPais || 'MX', destinoDireccion: initialData.destinoDireccion, - destinoCiudad: initialData.destinoCiudad, - destinoEstado: initialData.destinoEstado, + destinoCiudad: initialData.destinoCiudad || '', + destinoEstado: initialData.destinoEstado || '', destinoCP: initialData.destinoCP || '', destinoPais: initialData.destinoPais || 'MX', - fechaRecoleccion: initialData.fechaRecoleccion?.split('T')[0], + fechaRecoleccion: initialData.fechaRecoleccion?.split('T')[0] || '', fechaEntregaEstimada: initialData.fechaEntregaEstimada?.split('T')[0], pesoBruto: initialData.pesoBruto, pesoNeto: initialData.pesoNeto, @@ -99,8 +100,16 @@ export function OTForm({ initialData, onSuccess, onCancel }: OTFormProps) { notas: initialData.notas || '', } : { - modalidad: 'FTL', - tipoCarga: 'GENERAL', + clienteId: '', + origenDireccion: '', + origenCiudad: '', + origenEstado: '', + destinoDireccion: '', + destinoCiudad: '', + destinoEstado: '', + fechaRecoleccion: '', + modalidad: 'FTL' as const, + tipoCarga: 'GENERAL' as const, origenPais: 'MX', destinoPais: 'MX', moneda: 'MXN', @@ -124,10 +133,17 @@ export function OTForm({ initialData, onSuccess, onCancel }: OTFormProps) { }); const onSubmit = async (data: OTFormData) => { + const dto = { + ...data, + tipoCarga: data.tipoCarga as TipoCarga, + modalidadServicio: data.modalidad as ModalidadServicio, + modalidad: data.modalidad as ModalidadServicio, + tipoEquipo: data.tipoEquipo as TipoEquipo | undefined, + }; if (isEditing) { - await updateMutation.mutateAsync(data as UpdateOTDto); + await updateMutation.mutateAsync(dto as UpdateOTDto); } else { - await createMutation.mutateAsync(data as CreateOTDto); + await createMutation.mutateAsync(dto as CreateOTDto); } }; diff --git a/src/features/ordenes-transporte/components/OTStatusBadge.tsx b/src/features/ordenes-transporte/components/OTStatusBadge.tsx index b2f087f..bf92e76 100644 --- a/src/features/ordenes-transporte/components/OTStatusBadge.tsx +++ b/src/features/ordenes-transporte/components/OTStatusBadge.tsx @@ -8,10 +8,13 @@ interface OTStatusBadgeProps { const estadoConfig: Record = { [EstadoOrdenTransporte.BORRADOR]: { label: 'Borrador', color: 'bg-gray-100 text-gray-800' }, [EstadoOrdenTransporte.PENDIENTE]: { label: 'Pendiente', color: 'bg-yellow-100 text-yellow-800' }, + [EstadoOrdenTransporte.SOLICITADA]: { label: 'Solicitada', color: 'bg-orange-100 text-orange-800' }, [EstadoOrdenTransporte.CONFIRMADA]: { label: 'Confirmada', color: 'bg-blue-100 text-blue-800' }, - [EstadoOrdenTransporte.PROGRAMADA]: { label: 'Programada', color: 'bg-indigo-100 text-indigo-800' }, + [EstadoOrdenTransporte.ASIGNADA]: { label: 'Asignada', color: 'bg-indigo-100 text-indigo-800' }, [EstadoOrdenTransporte.EN_PROCESO]: { label: 'En Proceso', color: 'bg-purple-100 text-purple-800' }, + [EstadoOrdenTransporte.EN_TRANSITO]: { label: 'En Tránsito', color: 'bg-cyan-100 text-cyan-800' }, [EstadoOrdenTransporte.COMPLETADA]: { label: 'Completada', color: 'bg-green-100 text-green-800' }, + [EstadoOrdenTransporte.ENTREGADA]: { label: 'Entregada', color: 'bg-emerald-100 text-emerald-800' }, [EstadoOrdenTransporte.FACTURADA]: { label: 'Facturada', color: 'bg-teal-100 text-teal-800' }, [EstadoOrdenTransporte.CANCELADA]: { label: 'Cancelada', color: 'bg-red-100 text-red-800' }, }; diff --git a/src/features/ordenes-transporte/types/index.ts b/src/features/ordenes-transporte/types/index.ts index 3181d71..a96fbb3 100644 --- a/src/features/ordenes-transporte/types/index.ts +++ b/src/features/ordenes-transporte/types/index.ts @@ -25,6 +25,7 @@ export enum TipoCarga { LIQUIDOS = 'LIQUIDOS', CONTENEDOR = 'CONTENEDOR', AUTOMOVILES = 'AUTOMOVILES', + FRAGIL = 'FRAGIL', } export enum ModalidadServicio { @@ -51,8 +52,10 @@ export interface OrdenTransporte { tenantId: string; codigo: string; numeroOt?: string; + numero?: string; // Alias for display referenciaCliente?: string; clienteId: string; + clienteNombre?: string; // For display shipperId?: string; shipperNombre: string; consigneeId: string; @@ -60,8 +63,10 @@ export interface OrdenTransporte { // Origen origenDireccion: string; origenCodigoPostal?: string; + origenCP?: string; // Alias origenCiudad?: string; origenEstado?: string; + origenPais?: string; origenLatitud?: number; origenLongitud?: number; origenContacto?: string; @@ -69,8 +74,10 @@ export interface OrdenTransporte { // Destino destinoDireccion: string; destinoCodigoPostal?: string; + destinoCP?: string; // Alias destinoCiudad?: string; destinoEstado?: string; + destinoPais?: string; destinoLatitud?: number; destinoLongitud?: number; destinoContacto?: string; @@ -79,14 +86,21 @@ export interface OrdenTransporte { fechaRecoleccion?: string; fechaRecoleccionProgramada?: string; fechaEntregaProgramada?: string; + fechaEntregaEstimada?: string; // Alias // Carga tipoCarga: TipoCarga; descripcionCarga?: string; + descripcionMercancia?: string; // Alias pesoKg?: number; + pesoBruto?: number; // Alias + pesoNeto?: number; volumenM3?: number; + volumen?: number; // Alias piezas?: number; pallets?: number; + cantidadBultos?: number; valorDeclarado?: number; + valorMercancia?: number; // Alias // Requisitos requiereTemperatura: boolean; temperaturaMin?: number; @@ -95,18 +109,24 @@ export interface OrdenTransporte { requiereEscolta: boolean; instruccionesEspeciales?: string; observaciones?: string; + notas?: string; // Alias // Servicio y tarifa modalidadServicio: ModalidadServicio; + modalidad?: ModalidadServicio; // Alias + tipoEquipo?: TipoEquipo; tarifaId?: string; tarifaBase?: number; + tarifaTotal?: number; recargos: number; descuentos: number; subtotal?: number; iva?: number; total?: number; + moneda?: string; // Estado y asignacion estado: EstadoOrdenTransporte; viajeId?: string; + viajeNumero?: string; embarqueId?: string; // Auditoria createdAt: string; @@ -136,13 +156,15 @@ export interface CreateOrdenTransporteDto { referenciaCliente?: string; clienteId: string; shipperId?: string; - shipperNombre: string; - consigneeId: string; - consigneeNombre: string; + shipperNombre?: string; + consigneeId?: string; + consigneeNombre?: string; origenDireccion: string; origenCodigoPostal?: string; origenCiudad?: string; origenEstado?: string; + origenPais?: string; + origenCP?: string; origenLatitud?: number; origenLongitud?: number; origenContacto?: string; @@ -151,19 +173,29 @@ export interface CreateOrdenTransporteDto { destinoCodigoPostal?: string; destinoCiudad?: string; destinoEstado?: string; + destinoPais?: string; + destinoCP?: string; destinoLatitud?: number; destinoLongitud?: number; destinoContacto?: string; destinoTelefono?: string; + fechaRecoleccion?: string; fechaRecoleccionProgramada?: string; fechaEntregaProgramada?: string; + fechaEntregaEstimada?: string; tipoCarga?: TipoCarga; descripcionCarga?: string; + descripcionMercancia?: string; pesoKg?: number; + pesoBruto?: number; + pesoNeto?: number; volumenM3?: number; + volumen?: number; piezas?: number; pallets?: number; + cantidadBultos?: number; valorDeclarado?: number; + valorMercancia?: number; requiereTemperatura?: boolean; temperaturaMin?: number; temperaturaMax?: number; @@ -171,9 +203,22 @@ export interface CreateOrdenTransporteDto { requiereEscolta?: boolean; instruccionesEspeciales?: string; modalidadServicio?: ModalidadServicio; + modalidad?: ModalidadServicio; + tipoEquipo?: TipoEquipo; + tarifaBase?: number; + tarifaTotal?: number; + moneda?: string; + notas?: string; } export interface UpdateOrdenTransporteDto extends Partial { estado?: EstadoOrdenTransporte; observaciones?: string; } + +// Type aliases for shorter names (used in components) +export type CreateOTDto = CreateOrdenTransporteDto; +export type UpdateOTDto = UpdateOrdenTransporteDto; +export type OTFilters = OrdenTransporteFilters & { + tipoCarga?: TipoCarga; +}; diff --git a/src/features/tracking/components/ETAProgressBar.tsx b/src/features/tracking/components/ETAProgressBar.tsx index a55b4f9..13b4281 100644 --- a/src/features/tracking/components/ETAProgressBar.tsx +++ b/src/features/tracking/components/ETAProgressBar.tsx @@ -105,7 +105,7 @@ export function ETAProgressBar({ {/* Milestone markers */}
- {milestones.map((milestone, index) => ( + {milestones.map((milestone) => (
= { @@ -100,7 +99,7 @@ const fuenteLabels: Record = { [FuenteEvento.GEOCERCA]: 'Geocerca', }; -export function EventTimeline({ eventos, loading = false, viajeId }: EventTimelineProps) { +export function EventTimeline({ eventos, loading = false }: EventTimelineProps) { // Filter out frequent GPS positions to show only meaningful events const eventosImportantes = eventos.filter( (e) => diff --git a/src/features/tracking/components/EventosList.tsx b/src/features/tracking/components/EventosList.tsx index e808ece..d217fe8 100644 --- a/src/features/tracking/components/EventosList.tsx +++ b/src/features/tracking/components/EventosList.tsx @@ -1,7 +1,8 @@ import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { trackingApi } from '../api/tracking.api'; -import type { EventoTracking, EventoTrackingFilters, TipoEventoTracking } from '../types'; +import { TipoEventoTracking } from '../types'; +import type { EventoTracking, EventoFilters } from '../types'; interface EventosListProps { viajeId?: string; @@ -10,33 +11,39 @@ interface EventosListProps { } const tipoEventoLabels: Record = { - POSICION: 'Posición', - ENCENDIDO: 'Encendido', - APAGADO: 'Apagado', - VELOCIDAD_EXCESIVA: 'Velocidad Excesiva', - ENTRADA_GEOCERCA: 'Entrada Geocerca', - SALIDA_GEOCERCA: 'Salida Geocerca', - PARADA_PROLONGADA: 'Parada Prolongada', - DESVIO_RUTA: 'Desvío de Ruta', - BOTON_PANICO: 'Botón de Pánico', - BATERIA_BAJA: 'Batería Baja', - DESCONEXION_GPS: 'Desconexión GPS', - RECONEXION_GPS: 'Reconexión GPS', + [TipoEventoTracking.POSICION]: 'Posición', + [TipoEventoTracking.SALIDA]: 'Salida', + [TipoEventoTracking.ARRIBO_ORIGEN]: 'Arribo a Origen', + [TipoEventoTracking.INICIO_CARGA]: 'Inicio de Carga', + [TipoEventoTracking.FIN_CARGA]: 'Fin de Carga', + [TipoEventoTracking.ARRIBO_DESTINO]: 'Arribo a Destino', + [TipoEventoTracking.INICIO_DESCARGA]: 'Inicio de Descarga', + [TipoEventoTracking.FIN_DESCARGA]: 'Fin de Descarga', + [TipoEventoTracking.ENTREGA_POD]: 'POD Entregado', + [TipoEventoTracking.DESVIO]: 'Desvío', + [TipoEventoTracking.PARADA]: 'Parada', + [TipoEventoTracking.INCIDENTE]: 'Incidente', + [TipoEventoTracking.GPS_POSICION]: 'Posición GPS', + [TipoEventoTracking.GEOCERCA_ENTRADA]: 'Entrada Geocerca', + [TipoEventoTracking.GEOCERCA_SALIDA]: 'Salida Geocerca', }; const tipoEventoColors: Record = { - POSICION: 'bg-gray-100 text-gray-800', - ENCENDIDO: 'bg-green-100 text-green-800', - APAGADO: 'bg-red-100 text-red-800', - VELOCIDAD_EXCESIVA: 'bg-orange-100 text-orange-800', - ENTRADA_GEOCERCA: 'bg-blue-100 text-blue-800', - SALIDA_GEOCERCA: 'bg-purple-100 text-purple-800', - PARADA_PROLONGADA: 'bg-yellow-100 text-yellow-800', - DESVIO_RUTA: 'bg-pink-100 text-pink-800', - BOTON_PANICO: 'bg-red-200 text-red-900', - BATERIA_BAJA: 'bg-amber-100 text-amber-800', - DESCONEXION_GPS: 'bg-gray-200 text-gray-900', - RECONEXION_GPS: 'bg-teal-100 text-teal-800', + [TipoEventoTracking.POSICION]: 'bg-gray-100 text-gray-800', + [TipoEventoTracking.SALIDA]: 'bg-green-100 text-green-800', + [TipoEventoTracking.ARRIBO_ORIGEN]: 'bg-blue-100 text-blue-800', + [TipoEventoTracking.INICIO_CARGA]: 'bg-blue-200 text-blue-900', + [TipoEventoTracking.FIN_CARGA]: 'bg-blue-100 text-blue-800', + [TipoEventoTracking.ARRIBO_DESTINO]: 'bg-purple-100 text-purple-800', + [TipoEventoTracking.INICIO_DESCARGA]: 'bg-purple-200 text-purple-900', + [TipoEventoTracking.FIN_DESCARGA]: 'bg-purple-100 text-purple-800', + [TipoEventoTracking.ENTREGA_POD]: 'bg-green-200 text-green-900', + [TipoEventoTracking.DESVIO]: 'bg-yellow-100 text-yellow-800', + [TipoEventoTracking.PARADA]: 'bg-orange-100 text-orange-800', + [TipoEventoTracking.INCIDENTE]: 'bg-red-100 text-red-800', + [TipoEventoTracking.GPS_POSICION]: 'bg-gray-200 text-gray-900', + [TipoEventoTracking.GEOCERCA_ENTRADA]: 'bg-cyan-100 text-cyan-800', + [TipoEventoTracking.GEOCERCA_SALIDA]: 'bg-cyan-200 text-cyan-900', }; export function EventosList({ viajeId, unidadId, onSelect }: EventosListProps) { @@ -44,10 +51,10 @@ export function EventosList({ viajeId, unidadId, onSelect }: EventosListProps) { const [tipoFilter, setTipoFilter] = useState(''); const limit = 20; - const filters: EventoTrackingFilters = { + const filters: EventoFilters = { viajeId, unidadId, - tipo: tipoFilter || undefined, + tipoEvento: tipoFilter || undefined, limit, offset: (page - 1) * limit, }; @@ -114,10 +121,10 @@ export function EventosList({ viajeId, unidadId, onSelect }: EventosListProps) {
- {tipoEventoLabels[evento.tipo] || evento.tipo} + {tipoEventoLabels[evento.tipoEvento] || evento.tipoEvento} {formatDateTime(evento.timestamp)} @@ -139,9 +146,9 @@ export function EventosList({ viajeId, unidadId, onSelect }: EventosListProps) { )} {/* Additional data */} - {evento.datosExtra && Object.keys(evento.datosExtra).length > 0 && ( + {evento.datosAdicionales && Object.keys(evento.datosAdicionales).length > 0 && (
- {Object.entries(evento.datosExtra) + {Object.entries(evento.datosAdicionales) .slice(0, 3) .map(([key, value]) => ( diff --git a/src/features/tracking/components/GeocercasList.tsx b/src/features/tracking/components/GeocercasList.tsx index 4278e58..7f41cba 100644 --- a/src/features/tracking/components/GeocercasList.tsx +++ b/src/features/tracking/components/GeocercasList.tsx @@ -1,7 +1,8 @@ import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { trackingApi } from '../api/tracking.api'; -import type { Geocerca, GeocercaFilters, TipoGeocerca } from '../types'; +import { TipoGeocerca } from '../types'; +import type { Geocerca, GeocercaFilters } from '../types'; interface GeocercasListProps { onSelect?: (geocerca: Geocerca) => void; @@ -9,29 +10,29 @@ interface GeocercasListProps { } const tipoGeocercaLabels: Record = { - CLIENTE: 'Cliente', - ALMACEN: 'Almacén', - GASOLINERA: 'Gasolinera', - CASETA: 'Caseta', - PUNTO_CONTROL: 'Punto de Control', - ZONA_RIESGO: 'Zona de Riesgo', - ZONA_DESCANSO: 'Zona de Descanso', - FRONTERA: 'Frontera', - ADUANA: 'Aduana', - PUERTO: 'Puerto', + [TipoGeocerca.CIRCULAR]: 'Circular', + [TipoGeocerca.POLIGONAL]: 'Poligonal', + [TipoGeocerca.CLIENTE]: 'Cliente', + [TipoGeocerca.PROVEEDOR]: 'Proveedor', + [TipoGeocerca.PATIO]: 'Patio', + [TipoGeocerca.ZONA_RIESGO]: 'Zona de Riesgo', + [TipoGeocerca.CASETA]: 'Caseta', + [TipoGeocerca.GASOLINERA]: 'Gasolinera', + [TipoGeocerca.PUNTO_CONTROL]: 'Punto de Control', + [TipoGeocerca.OTRO]: 'Otro', }; const tipoGeocercaIcons: Record = { - CLIENTE: '🏢', - ALMACEN: '📦', - GASOLINERA: '⛽', - CASETA: '🚧', - PUNTO_CONTROL: '✓', - ZONA_RIESGO: '⚠️', - ZONA_DESCANSO: '🅿️', - FRONTERA: '🚩', - ADUANA: '🛃', - PUERTO: '⚓', + [TipoGeocerca.CIRCULAR]: '⭕', + [TipoGeocerca.POLIGONAL]: '🔷', + [TipoGeocerca.CLIENTE]: '🏢', + [TipoGeocerca.PROVEEDOR]: '🏭', + [TipoGeocerca.PATIO]: '📦', + [TipoGeocerca.ZONA_RIESGO]: '⚠️', + [TipoGeocerca.CASETA]: '🚧', + [TipoGeocerca.GASOLINERA]: '⛽', + [TipoGeocerca.PUNTO_CONTROL]: '✓', + [TipoGeocerca.OTRO]: '📍', }; export function GeocercasList({ onSelect, onEdit }: GeocercasListProps) { @@ -44,8 +45,7 @@ export function GeocercasList({ onSelect, onEdit }: GeocercasListProps) { const filters: GeocercaFilters = { tipo: tipoFilter || undefined, - activo: activoFilter !== '' ? activoFilter : undefined, - search: searchTerm || undefined, + activa: activoFilter !== '' ? activoFilter : undefined, limit, offset: (page - 1) * limit, }; @@ -160,9 +160,9 @@ export function GeocercasList({ onSelect, onEdit }: GeocercasListProps) { >
{geocerca.nombre}
- {geocerca.descripcion && ( + {geocerca.direccion && (
- {geocerca.descripcion} + {geocerca.direccion}
)} @@ -176,12 +176,12 @@ export function GeocercasList({ onSelect, onEdit }: GeocercasListProps) { - {geocerca.activo ? 'Activa' : 'Inactiva'} + {geocerca.activa ? 'Activa' : 'Inactiva'} diff --git a/src/features/tracking/components/TrackingMap.tsx b/src/features/tracking/components/TrackingMap.tsx index ef5bbd6..016a4fa 100644 --- a/src/features/tracking/components/TrackingMap.tsx +++ b/src/features/tracking/components/TrackingMap.tsx @@ -1,7 +1,7 @@ -import { useEffect, useRef, useState } from 'react'; +import { useRef, useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { trackingApi } from '../api/tracking.api'; -import type { PosicionActual, EventoTracking } from '../types'; +import type { PosicionActual } from '../types'; interface TrackingMapProps { unidadIds?: string[]; @@ -38,7 +38,7 @@ export function TrackingMap({ const rutaData = ruta?.data || []; // Simple map rendering (placeholder - integrate with actual map library) - const renderPosition = (pos: PosicionActual, index: number) => { + const renderPosition = (pos: PosicionActual, _index: number) => { const isSelected = selectedUnidad === pos.unidadId; return (
void; } @@ -40,7 +39,6 @@ export function ViajeTrackingView({ folio, origen, destino, - fechaSalida, etaOriginal, onClose, }: ViajeTrackingViewProps) { @@ -254,7 +252,6 @@ export function ViajeTrackingView({
diff --git a/src/features/tracking/hooks/useTrackingWebSocket.ts b/src/features/tracking/hooks/useTrackingWebSocket.ts index 55bd7b7..1f1d8e2 100644 --- a/src/features/tracking/hooks/useTrackingWebSocket.ts +++ b/src/features/tracking/hooks/useTrackingWebSocket.ts @@ -48,7 +48,7 @@ export function useTrackingWebSocket({ const [error, setError] = useState(null); const wsRef = useRef(null); - const reconnectTimeoutRef = useRef(null); + const reconnectTimeoutRef = useRef | null>(null); const getWebSocketUrl = useCallback(() => { // Build WebSocket URL with subscription parameters diff --git a/src/features/viajes/components/ViajeDetail.tsx b/src/features/viajes/components/ViajeDetail.tsx index a8312b4..1105959 100644 --- a/src/features/viajes/components/ViajeDetail.tsx +++ b/src/features/viajes/components/ViajeDetail.tsx @@ -2,11 +2,12 @@ import { useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { viajesApi } from '../api/viajes.api'; import { ViajeStatusBadge } from './ViajeStatusBadge'; -import type { Viaje, EstadoViaje } from '../types'; +import type { Viaje } from '../types'; interface ViajeDetailProps { viaje: Viaje; onClose: () => void; + onEdit?: () => void; } export function ViajeDetail({ viaje, onClose }: ViajeDetailProps) { diff --git a/src/features/viajes/components/ViajeForm.tsx b/src/features/viajes/components/ViajeForm.tsx index d825af9..cb2d93d 100644 --- a/src/features/viajes/components/ViajeForm.tsx +++ b/src/features/viajes/components/ViajeForm.tsx @@ -22,12 +22,13 @@ type FormData = z.infer; interface ViajeFormProps { viaje?: Viaje; - onSubmit: (data: CreateViajeDto | UpdateViajeDto) => Promise; + onSubmit?: (data: CreateViajeDto | UpdateViajeDto) => Promise; + onSuccess?: () => void; onCancel: () => void; isLoading?: boolean; } -export function ViajeForm({ viaje, onSubmit, onCancel, isLoading }: ViajeFormProps) { +export function ViajeForm({ viaje, onSubmit, onSuccess, onCancel, isLoading }: ViajeFormProps) { const isEditing = !!viaje; const { @@ -80,7 +81,10 @@ export function ViajeForm({ viaje, onSubmit, onCancel, isLoading }: ViajeFormPro ...(data.distanciaEstimadaKm && { distanciaEstimadaKm: data.distanciaEstimadaKm }), ...(data.tiempoEstimadoHoras && { tiempoEstimadoHoras: data.tiempoEstimadoHoras }), }; - await onSubmit(cleanData); + if (onSubmit) { + await onSubmit(cleanData); + } + onSuccess?.(); }; return ( diff --git a/tsconfig.node.json b/tsconfig.node.json index 97ede7e..1a555ac 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -5,7 +5,8 @@ "module": "ESNext", "moduleResolution": "bundler", "allowSyntheticDefaultImports": true, - "strict": true + "strict": true, + "types": ["node"] }, "include": ["vite.config.ts"] }