diff --git a/package-lock.json b/package-lock.json index a0078a9..fe497d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,11 @@ "@vue-leaflet/vue-leaflet": "^0.10.1", "axios": "^1.2.1", "leaflet": "^1.9.4", + "leaflet-contextmenu": "^1.4.0", "leaflet-extra-markers": "^2.0.1", "leaflet-geosearch": "^4.2.2", "leaflet-routing-machine": "^3.2.12", + "openrouteservice-js": "^0.4.1", "pinia": "^3.0.4", "quasar": "^2.16.0", "socket.io-client": "^4.8.3", @@ -26,6 +28,7 @@ "@eslint/js": "^9.14.0", "@quasar/app-vite": "^2.1.0", "@types/leaflet": "^1.9.21", + "@types/leaflet-contextmenu": "^1.4.4", "@types/node": "^20.5.9", "@vue/eslint-config-prettier": "^10.1.0", "@vue/eslint-config-typescript": "^14.4.0", @@ -2097,11 +2100,20 @@ "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.21.tgz", "integrity": "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==", "devOptional": true, - "license": "MIT", "dependencies": { "@types/geojson": "*" } }, + "node_modules/@types/leaflet-contextmenu": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@types/leaflet-contextmenu/-/leaflet-contextmenu-1.4.4.tgz", + "integrity": "sha512-3BcUZceTEHDOu2kD6Is5cQB5z/DIVMPZoN/o5yXGrH0Y4CfWuSpP1Sm6ZHdBMQ+nVtEQXZnIV/GOE4ZEGX39HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/leaflet": "^1.9" + } + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -5748,6 +5760,11 @@ "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", "license": "BSD-2-Clause" }, + "node_modules/leaflet-contextmenu": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/leaflet-contextmenu/-/leaflet-contextmenu-1.4.0.tgz", + "integrity": "sha512-BXASCmJ5bLkuJGDCpWmvGqhZi5AzeOY0IbQalfkgBcMAMfAOFSvD4y0gIQxF/XzEyLkjXaRiUpibVj4+Cf3tUA==" + }, "node_modules/leaflet-extra-markers": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/leaflet-extra-markers/-/leaflet-extra-markers-2.0.1.tgz", @@ -6301,6 +6318,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openrouteservice-js": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/openrouteservice-js/-/openrouteservice-js-0.4.1.tgz", + "integrity": "sha512-Oeb/KgzaYXEtafSHB40KfZvHFfTSPhtt0/oEf0jv5o5Ljw3//+C63CFxbknOqDBrOkYLLQMMCjJGa54rUOBtLg==" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", diff --git a/package.json b/package.json index 814627e..4217d43 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,11 @@ "@vue-leaflet/vue-leaflet": "^0.10.1", "axios": "^1.2.1", "leaflet": "^1.9.4", + "leaflet-contextmenu": "^1.4.0", "leaflet-extra-markers": "^2.0.1", "leaflet-geosearch": "^4.2.2", "leaflet-routing-machine": "^3.2.12", + "openrouteservice-js": "^0.4.1", "pinia": "^3.0.4", "quasar": "^2.16.0", "socket.io-client": "^4.8.3", @@ -32,6 +34,7 @@ "@eslint/js": "^9.14.0", "@quasar/app-vite": "^2.1.0", "@types/leaflet": "^1.9.21", + "@types/leaflet-contextmenu": "^1.4.4", "@types/node": "^20.5.9", "@vue/eslint-config-prettier": "^10.1.0", "@vue/eslint-config-typescript": "^14.4.0", diff --git a/quasar.config.ts b/quasar.config.ts index 424e67f..c77270e 100644 --- a/quasar.config.ts +++ b/quasar.config.ts @@ -70,14 +70,30 @@ export default defineConfig((/* ctx */) => { extendViteConf() { return { + build: { + rollupOptions: { + output: { + manualChunks(id) { + if (id.includes('node_modules/leaflet')) return 'vendor-leaflet-core'; + if (id.includes('leaflet-routing-machine')) return 'vendor-leaflet-routing'; + if (id.includes('leaflet-geosearch')) return 'vendor-leaflet-geosearch'; + if (id.includes('leaflet-extra-markers')) return 'vendor-leaflet-markers'; + if (id.includes('openrouteservice-js')) return 'vendor-openrouteservice'; + if (id.includes('socket.io-client')) return 'vendor-socketio'; + if (id.includes('node_modules/quasar')) return 'vendor-quasar'; + if (id.includes('node_modules/vue') || id.includes('node_modules/pinia')) { + return 'vendor-vue-core'; + } + return undefined; + }, + }, + }, + }, server: { hmr: { -// overlay: false, + // overlay: false, }, - allowedHosts: [ - 'localhost', - 'strixx.famor.org' - ], + allowedHosts: ['localhost', 'strixx.famor.org', 'simloc.strixx.intrepidnet.org'], }, }; }, @@ -102,7 +118,7 @@ export default defineConfig((/* ctx */) => { devServer: { // https: true, open: false, // opens browser window automatically - // public: 'http://strixx.famor.org:9000', + // public: 'https://simloc.strixx.intrepidnet.org', proxy: { // proxy all requests starting with /api to jsonplaceholder '/api': { @@ -118,9 +134,27 @@ export default defineConfig((/* ctx */) => { changeOrigin: true, // rewrite: (path) => path.replace(/^\/socket.io/, ''), }, + '/osm': { + target: 'https://nominatim.openstreetmap.org', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/osm/, ''), + headers: { + Referer: 'https://nominatim.openstreetmap.org/', + 'User-Agent': 'map-sim-location/0.0.1 (iam@williambr.uno)', + }, + }, + '/ors': { +// target: 'https://router.project-osrm.org', + target: 'http://localhost:8080', + changeOrigin: true, +// rewrite: (path) => path.replace(/^\/osrm/, ''), +// headers: { +// Referer: 'https://router.project-osrm.org/', +// 'User-Agent': 'map-sim-location/0.0.1 (iam@williambr.uno)', +// }, + }, }, }, - // https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#framework framework: { config: { diff --git a/src/boot/axios.ts b/src/boot/axios.ts index a2b7d07..a36b1c5 100644 --- a/src/boot/axios.ts +++ b/src/boot/axios.ts @@ -5,16 +5,19 @@ declare module 'vue' { interface ComponentCustomProperties { $axios: AxiosInstance; $api: AxiosInstance; + $osm: AxiosInstance; } } const api = axios.create({ baseURL: '/api' }); +const osm = axios.create({ baseURL: '/osm' }); export default defineBoot(({ app }) => { app.config.globalProperties.$axios = axios app.config.globalProperties.$api = api + app.config.globalProperties.$osm = osm }) -export { axios, api }; +export { axios, api, osm }; diff --git a/src/components/ConfirmCommandDiaglog.vue b/src/components/ConfirmCommandDiaglog.vue index c24639c..607cbae 100644 --- a/src/components/ConfirmCommandDiaglog.vue +++ b/src/components/ConfirmCommandDiaglog.vue @@ -18,7 +18,7 @@ @@ -339,4 +500,8 @@ onMounted(() => { .q-item.q-router-link--active, .q-item--active background-color: $accent color: $primary + +.leafletDrawer + background-color: $dark + color: $dark diff --git a/src/components/LocationMark.vue b/src/components/LocationMark.vue index 416a869..a19215b 100644 --- a/src/components/LocationMark.vue +++ b/src/components/LocationMark.vue @@ -4,7 +4,7 @@ import { useSocketioStore } from 'stores/socketio'; import { computed, onMounted, onUnmounted, ref } from 'vue'; const socketStore = useSocketioStore(); -const { currentLocation, locationQueueOrder } = storeToRefs(socketStore); +const { currentLocation, locationQueueOrder, simulationRunning } = storeToRefs(socketStore); const props = defineProps({ address: { @@ -43,6 +43,10 @@ const props = defineProps({ type: String, required: true, }, + isLast: { + type: Boolean, + default: false, + }, }); // Define custom events that this component can emit @@ -100,6 +104,16 @@ const calculateDeltaT = computed(() => { return delta; }); +const secondsToTime = computed(() => { + const seconds = props.delay; + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const remainingSeconds = seconds % 60; + return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds + .toString() + .padStart(2, '0')}`; +}); + const humanReadableDateTime = (iso: string) => { return new Date(iso).toLocaleDateString('en-US', { // year: 'numeric', @@ -181,6 +195,24 @@ function formatAddress(input: string): string { return `${streetNumber} ${streetName}, ${city}, ${state} ${zip}`; } +const markerIndex = computed(() => { + const currentIndex = currentLocation.value + ? locationQueueOrder.value.indexOf(currentLocation.value.loc_id) + : 0; + const locationIndex = locationQueueOrder.value.indexOf(props.loc_id); + return props.active ? '*' : (locationIndex - currentIndex).toString(); +}); + +const itemClass = computed(() => { + const currentIndex = currentLocation.value + ? locationQueueOrder.value.indexOf(currentLocation.value.loc_id) + : 0; + const locationIndex = locationQueueOrder.value.indexOf(props.loc_id); + if (locationIndex - currentIndex > 0) return 'future'; + else if (locationIndex - currentIndex < 0) return 'past'; + else return 'active'; +}); + onMounted(() => { const update = () => { currentTime.value = new Date(); @@ -195,32 +227,35 @@ onUnmounted(() => { - + diff --git a/src/components/MenuBar.vue b/src/components/MenuBar.vue index 231ea5e..4d54ad2 100644 --- a/src/components/MenuBar.vue +++ b/src/components/MenuBar.vue @@ -1,6 +1,6 @@ + diff --git a/src/components/SimulationCommands.ts b/src/components/SimulationCommands.ts index 272c56b..cb0ff5c 100644 --- a/src/components/SimulationCommands.ts +++ b/src/components/SimulationCommands.ts @@ -1 +1 @@ -import { socket } from 'boot/socketio'; +export {}; diff --git a/src/components/SocketTest.vue b/src/components/SocketTest.vue index 5fd3ced..dc4dc6a 100644 --- a/src/components/SocketTest.vue +++ b/src/components/SocketTest.vue @@ -4,6 +4,7 @@ import { useQuasar } from 'quasar'; import { computed, ref, watch } from 'vue'; import { useSocketioStore } from 'stores/socketio'; import { storeToRefs } from 'pinia'; +import type { ClientToServerEvents } from 'components/models'; const socketioStore = useSocketioStore(); const $q = useQuasar(); @@ -30,18 +31,17 @@ function sendMessage() { function handleEmit() { const event = sockEvent.value; const jsonArgs = eventArgs.value; - socket.emit(event, jsonArgs, (resp) => { - console.log('Server Reponse: ' + resp); + socket.emit(event as keyof ClientToServerEvents, jsonArgs, (resp: unknown) => { + console.log('Server Reponse: ' + String(resp)); }); sockEvent.value = ''; eventArgs.value = ''; -}; +} watch( messageList, (newVal: string[], oldVal: string[]) => { - let newMsg: string; - newMsg = newVal[newVal.length - 1]; + const newMsg = newVal[newVal.length - 1] ?? ''; console.log('New message received: ', newMsg); console.log('Past List', oldVal); $q.notify(newMsg); diff --git a/src/components/StatusBar.vue b/src/components/StatusBar.vue index 058c1c7..a5abd52 100644 --- a/src/components/StatusBar.vue +++ b/src/components/StatusBar.vue @@ -9,8 +9,6 @@ const { tunnelConnected, simulationRunning, icloudMonitor, - currentLocation, - nextLocation, } = storeToRefs(socketioStore); function statusDevColor(state: string | boolean): string { if (typeof state === 'boolean') { @@ -56,7 +54,7 @@ function statusDevColor(state: string | boolean): string { void; } -interface SimulationStatus { +export interface SimulationStatus { + loc_id: string; status: boolean; - data: { - latitude: number; - longitude: number; - start: string; - end?: string; - next_move?: number; - }; + latitude: number; + longitude: number; + start: string; + end?: string; + next_move?: number; } export interface StatusUpdate { @@ -256,3 +255,36 @@ export interface NextLocation { } + +export interface NominatimReverseResponse { + place_id: number + licence: string + osm_type: string + osm_id: number + lat: string + lon: string + class: string + type: string + place_rank: number + importance: number + addresstype: string + name: string + display_name: string + address: NominatimAddress + boundingbox: string[] +} + +export interface NominatimAddress { + house_number: string; + road: string; + village?: string; + city? : string; + county: string; + state: string; + 'ISO3166-2-lvl4': string; + postcode: string; + country: string; + country_code: string; +} + + diff --git a/src/composables/useMarkerContextMenu.ts b/src/composables/useMarkerContextMenu.ts new file mode 100644 index 0000000..3e37b84 --- /dev/null +++ b/src/composables/useMarkerContextMenu.ts @@ -0,0 +1,45 @@ +import { ref, type Ref } from 'vue'; +import * as LeafLet from 'leaflet'; +import type { LeafletMouseEvent } from 'leaflet'; + +type RouteSet = { + start?: LeafLet.LatLng | null | undefined; + end?: LeafLet.LatLng | null | undefined; +}; + +type RouteSetLike = { + start?: unknown; + end?: unknown; + [key: string]: unknown; +}; + +export function useMarkerContextMenu(routeSet: Ref, updateRoute: () => void) { + const clickedLatLng = ref(null); + + const handleMarkerClick = (event: LeafletMouseEvent) => { + console.log('marker clicked', event); + clickedLatLng.value = event.latlng; + LeafLet.DomEvent.stopPropagation(event.originalEvent); + }; + + const setStartRoute = () => { + if (!clickedLatLng.value) return; + (routeSet.value as RouteSet).start = clickedLatLng.value; + console.log('setStartRoute: ', routeSet.value.start); + }; + + const setEndRoute = () => { + if (!clickedLatLng.value) return; + (routeSet.value as RouteSet).end = clickedLatLng.value; + console.log('setEndRoute: ', routeSet.value.end); + updateRoute(); + console.log('updating Route'); + }; + + return { + clickedLatLng, + handleMarkerClick, + setStartRoute, + setEndRoute, + }; +} diff --git a/src/composables/useRoutingEvents.ts b/src/composables/useRoutingEvents.ts new file mode 100644 index 0000000..a8b2ec4 --- /dev/null +++ b/src/composables/useRoutingEvents.ts @@ -0,0 +1,54 @@ +import { useLeafletStore } from 'stores/leaflet'; +import { storeToRefs } from 'pinia'; + +const leafletStore = useLeafletStore(); +const { routeSegments } = storeToRefs(leafletStore); + + +type RouteSummary = { + totalDistance: number; + totalTime: number; +}; + +type RouteWaypoint = { + latLng: { + lat: number; + lng: number; + }; +}; + +type RouteResult = { + summary?: RouteSummary; + segments?: RouteSummary[]; + inputWaypoints?: RouteWaypoint[]; +}; + +export function useRoutingEvents() { + const handleRoutesFound = (event: { routes?: RouteResult[] }) => { + const route = event.routes?.[0]; + console.log('routesfound event:', event); + if (!route) { + return; + } + + if (route.summary) { + console.log('Route summary:', route.summary); + } + + if (route.segments?.length) { + const segmentSummary = route.segments.map((segment, index) => ({ + fromWaypoint: index, + toWaypoint: index + 1, + distanceMeters: segment.totalDistance, + timeSeconds: segment.totalTime, + toCoordinates: route.inputWaypoints?.[index + 1]?.latLng ?? null, + })); + routeSegments.value = segmentSummary; + console.log('Waypoint segment summary:', segmentSummary); + } + }; + + return { + handleRoutesFound, + }; +} diff --git a/src/constants/controls.ts b/src/constants/controls.ts index 77caabd..db67bed 100644 --- a/src/constants/controls.ts +++ b/src/constants/controls.ts @@ -1,5 +1,3 @@ -import type { CtrlAttrs } from 'components/models'; - export const controls = { simulation: { start: { @@ -59,7 +57,7 @@ export const controls = { icon: 'restart_alt', cnfrm: true, delay: 5, - } + }, }, icloudmonitor: { start: { @@ -77,6 +75,6 @@ export const controls = { icon: 'stop', cnfrm: false, delay: 0, - } - } + }, + }, }; diff --git a/src/functions/reverseGeocode.ts b/src/functions/reverseGeocode.ts new file mode 100644 index 0000000..73d25d5 --- /dev/null +++ b/src/functions/reverseGeocode.ts @@ -0,0 +1,47 @@ +// services/nominatimService.ts +import { osm } from 'boot/axios'; + +// TypeScript Interface for Reverse Geocoding Response +export interface NominatimResponse { + place_id: number; + display_name: string; + address: { + road?: string; + city?: string; + country?: string; + [key: string]: unknown; + }; + lat: string; + lon: string; +} + +const API_URL = '/reverse'; + +// Simple debounce to respect 1s limit +let lastRequestTime = 0; + +export const reverseGeocodeRateLimited = async (lat: number, lon: number): Promise => { + const now = Date.now(); + const timeSinceLast = now - lastRequestTime; + + // Wait if less than 1000ms has passed + if (timeSinceLast < 1000) { + await new Promise((resolve) => setTimeout(resolve, 1000 - timeSinceLast)); + } + + const response = await osm.get(API_URL, { + params: { + lat, + lon, + format: 'jsonv2', + addressdetails: 1, + }, + headers: { + // It is mandatory to set a descriptive User-Agent + 'User-Agent': 'Vue3App/1.0 (your-email@example.com)', + }, + }); + + lastRequestTime = Date.now(); + return response.data; +}; diff --git a/src/functions/routingControl.ts b/src/functions/routingControl.ts index 5211671..41ac942 100644 --- a/src/functions/routingControl.ts +++ b/src/functions/routingControl.ts @@ -1,48 +1,46 @@ import { Utilities } from '@vue-leaflet/vue-leaflet'; -import type L from 'leaflet'; -import type { IRouter, IGeocoder, LineOptions } from 'leaflet-routing-machine'; +import type { PropType } from 'vue'; +import type { IRouter, LineOptions } from 'leaflet-routing-machine'; -// ---- Props typing ---- export interface RoutingControlProps { - waypoints: L.Routing.Waypoint[]; - router?: IRouter; - plan?: L.Routing.Plan; + waypoints: unknown[]; + router?: IRouter | undefined; + plan?: unknown; fitSelectedRoutes?: string | boolean; - lineOptions?: LineOptions; - routeLine?: (route: any) => L.Layer; + lineOptions?: LineOptions | undefined; + routeLine?: ((route: unknown) => unknown) | undefined; autoRoute?: boolean; routeWhileDragging?: boolean; routeDragInterval?: number; waypointMode?: string; useZoomParameter?: boolean; showAlternatives?: boolean; - altLineOptions?: LineOptions; + altLineOptions?: LineOptions | undefined; } -// ---- Vue-compatible prop definition ---- export const routingControlProps = { waypoints: { - type: Array as () => L.Routing.Waypoint[], + type: Array as PropType, default: () => [], }, router: { - type: Object as () => IRouter | undefined, + type: Object as PropType, default: undefined, }, plan: { - type: Object as () => L.Routing.Plan | undefined, + type: Object as PropType, default: undefined, }, fitSelectedRoutes: { - type: [String, Boolean] as unknown as () => string | boolean, + type: [String, Boolean] as PropType, default: 'smart', }, lineOptions: { - type: Object as () => LineOptions | undefined, + type: Object as PropType, default: undefined, }, routeLine: { - type: Function as unknown as () => ((route: any) => L.Layer) | undefined, + type: Function as PropType<((route: unknown) => unknown) | undefined>, default: undefined, }, autoRoute: { @@ -70,17 +68,13 @@ export const routingControlProps = { default: false, }, altLineOptions: { - type: Object as () => LineOptions | undefined, + type: Object as PropType, default: undefined, }, }; -// ---- Setup function ---- export const setupRoutingControl = (props: RoutingControlProps) => { - const options = Utilities.propsToLeafletOptions( - props, - routingControlProps, - ) as L.Routing.RoutingControlOptions; + const options = Utilities.propsToLeafletOptions(props, routingControlProps); return { options, diff --git a/src/functions/serviceURL.ts b/src/functions/serviceURL.ts new file mode 100644 index 0000000..052982b --- /dev/null +++ b/src/functions/serviceURL.ts @@ -0,0 +1,11 @@ +import { openrouteserviceV2 } from 'components/L.Routing.OpenRouteServiceV2'; + +export const customRouter = openrouteserviceV2({ + profile: 'driving-car', + geometry_simplify: true, + host: '/ors', +}); + +//export const customRouter = L.Routing.osrmv1({ +// serviceUrl: '/osrm/route/v1', // Replace with your URL +//}); diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index e263030..283c98e 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -6,6 +6,7 @@ + @@ -51,6 +53,7 @@ import StatusBar from 'components/StatusBar.vue'; const socketioStore = useSocketioStore(); const drawer = ref(false); +/* const route = useRoute(); const menuList = [ @@ -110,6 +113,7 @@ const menuList = [ route: 'ErrorNotFound', }, ]; +*/ onMounted(() => { socketioStore.bindEvents(); socketioStore.connect(); diff --git a/src/stores/leaflet.ts b/src/stores/leaflet.ts index 52b0abe..2024301 100644 --- a/src/stores/leaflet.ts +++ b/src/stores/leaflet.ts @@ -1,11 +1,42 @@ import { defineStore, acceptHMRUpdate } from 'pinia'; import { favorites } from 'constants/favorites' +interface RoutesSet { + [key: string]: RouteSet +} + +interface LatLng { + lat: number | null | undefined; + lng: number | null | undefined; +} + +interface routeSegments { + fromWaypoint: number; + toWaypoint: number; + distanceMeters: number; + timeSeconds: number; + toCoordinates: LatLng | null | undefined; +} + + +interface RouteSet { + start: [number, number] | [null, null] | [undefined, undefined] | null | undefined; + end: [number, number] | [null, null] | [undefined, undefined] | null | undefined; + wayPoints?: [number, number][] | [null, null] | [undefined, undefined] | null | undefined; +} + interface State { - zoom: number - center: [number, number] | [null, null] | null - markerLatLng: [number, number] | [null, null] | null - qLocDrawer: boolean + zoom: number; + center: [number, number] | [null, null] | null; + markerLatLng: [number, number] | [null, null] | null; + qLocDrawer: boolean; + routeSet: { + start: LatLng | null | undefined; + end: LatLng | null | undefined; + wayPoints?: LatLng[] | null | undefined; + }; + routesSet: RoutesSet[] | null; + routeSegments?: routeSegments[] | null; } export const useLeafletStore = defineStore('leaflet', { @@ -15,6 +46,15 @@ export const useLeafletStore = defineStore('leaflet', { center: [favorites.home.coords.lat, favorites.home.coords.lng], markerLatLng: null, qLocDrawer: false, + routeSet: + { + start: { lat: null, lng: null }, + end: { lat: null, lng: null}, + wayPoints: null, + }, + routesSet: null, + routeSegments: null, + } }, actions: { diff --git a/src/stores/socketio.ts b/src/stores/socketio.ts index 0e238c8..ca7cfb0 100644 --- a/src/stores/socketio.ts +++ b/src/stores/socketio.ts @@ -11,6 +11,7 @@ import type { StatusUpdate, FindMyUpdate, iCloudMonitorResponse, + SimulationStatus, } from 'components/models'; @@ -110,6 +111,20 @@ export const useSocketioStore = defineStore('socketio', { this.findMyUpdate = data; }); + socket.on('simulation_status', (data: SimulationStatus): void => { + if (debugLog) { + console.log('event: simulation_status received: ', data); + } + console.log('updating currentLocation', data) + this.currentLocation = { + loc_id: data.loc_id, + latitude: data.latitude, + longitude: data.longitude, + next_move: data.next_move, + }; + this.locationQueueData[data.loc_id]['start'] = data.start; + }); + socket.on('icloud_2fa_request', (callback) => { if (debugLog) { console.log('iCloud 2FA Request'); @@ -328,6 +343,24 @@ export const useSocketioStore = defineStore('socketio', { }, ); break; + case 'test-mode': + socket.emit( + 'simulation_control', + { command: 'test-mode' }, + (response: SimulationControlResponse) => { + if (response.status === 'error') { + throw new Error(response.message); + } else { + this.simulationState = response.status; + if (debugLog) { + console.log(response.message, response); + } + return response.message; + } + }, + ); + break; + case 'pause': if (this.simulationState !== 'RUNNING') { throw new Error('Simulation is not running'); @@ -368,9 +401,6 @@ export const useSocketioStore = defineStore('socketio', { if (this.simulationQueueLength == 0) { throw new Error('Simulation queue is empty'); } - if (this.simulationState == 'STOPPED ' || !this.simulationRunning) { - throw new Error('Simulation is not running'); - } socket.emit('simulation_control', { command: 'clear' }, (response) => { if (response.status == 'error') { throw new Error(response.message); @@ -417,15 +447,6 @@ export const useSocketioStore = defineStore('socketio', { if (debugLog) { console.log('response from simulate_control_add: ', response); } - const locMrk = { - [response.loc_id]: { - loc_id: response.loc_id, - latitude: response.latitude, - longitude: response.longitude, - delay: response.delay, - start_time: response.start_time, - }, - }; return response.message; } }, diff --git a/src/types/leaflet-esm.d.ts b/src/types/leaflet-esm.d.ts new file mode 100644 index 0000000..0bd4a27 --- /dev/null +++ b/src/types/leaflet-esm.d.ts @@ -0,0 +1 @@ +declare module 'leaflet/dist/leaflet-src.esm'; diff --git a/src/types/leaflet-routing-machine.d.ts b/src/types/leaflet-routing-machine.d.ts index 75c90a6..18a28f2 100644 --- a/src/types/leaflet-routing-machine.d.ts +++ b/src/types/leaflet-routing-machine.d.ts @@ -1,12 +1,12 @@ -declare module "leaflet-routing-machine" { - import * as L from "leaflet"; +declare module 'leaflet-routing-machine' { + import type * as L from 'leaflet'; - export interface IRouter {} - export interface IGeocoder {} - export interface LineOptions extends L.PolylineOptions {} + export type IRouter = Record; + export type IGeocoder = Record; + export type LineOptions = L.PolylineOptions; export namespace Routing { - function control(options: any): any; + function control(options: Record): Record; class Plan {} } diff --git a/src/types/openrouteservice-js.d.ts b/src/types/openrouteservice-js.d.ts new file mode 100644 index 0000000..32135af --- /dev/null +++ b/src/types/openrouteservice-js.d.ts @@ -0,0 +1 @@ +declare module 'openrouteservice-js';