mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Implement rendering the route when the dates if the trip are changed
This commit is contained in:
parent
2cfc485f12
commit
e8842a9476
8 changed files with 189 additions and 47 deletions
File diff suppressed because one or more lines are too long
|
|
@ -3,9 +3,10 @@
|
|||
class TripsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_trip, only: %i[show edit update destroy]
|
||||
before_action :set_coordinates, only: %i[show edit]
|
||||
|
||||
def index
|
||||
@trips = current_user.trips
|
||||
@trips = current_user.trips.order(created_at: :desc).page(params[:page])
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
@ -54,6 +55,14 @@ class TripsController < ApplicationController
|
|||
@trip = current_user.trips.find(params[:id])
|
||||
end
|
||||
|
||||
|
||||
def set_coordinates
|
||||
@coordinates = @trip.points.pluck(
|
||||
:latitude, :longitude, :battery, :altitude, :timestamp, :velocity, :id,
|
||||
:country
|
||||
).map { [_1.to_f, _2.to_f, _3.to_s, _4.to_s, _5.to_s, _6.to_s, _7.to_s, _8.to_s] }
|
||||
end
|
||||
|
||||
def trip_params
|
||||
params.require(:trip).permit(:name, :started_at, :ended_at, :notes, :field_notes)
|
||||
end
|
||||
|
|
|
|||
69
app/javascript/controllers/datetime_controller.js
Normal file
69
app/javascript/controllers/datetime_controller.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["startedAt", "endedAt", "apiKey"]
|
||||
static values = { tripsId: String }
|
||||
|
||||
connect() {
|
||||
console.log("Datetime controller connected")
|
||||
this.debounceTimer = null;
|
||||
}
|
||||
|
||||
async updateCoordinates(event) {
|
||||
// Clear any existing timeout
|
||||
if (this.debounceTimer) {
|
||||
clearTimeout(this.debounceTimer);
|
||||
}
|
||||
|
||||
// Set new timeout
|
||||
this.debounceTimer = setTimeout(async () => {
|
||||
const startedAt = this.startedAtTarget.value
|
||||
const endedAt = this.endedAtTarget.value
|
||||
const apiKey = this.apiKeyTarget.value
|
||||
|
||||
if (startedAt && endedAt) {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
start_at: startedAt,
|
||||
end_at: endedAt,
|
||||
api_key: apiKey,
|
||||
slim: true
|
||||
})
|
||||
let allPoints = [];
|
||||
let currentPage = 1;
|
||||
const perPage = 1000;
|
||||
|
||||
do {
|
||||
const paginatedParams = `${params}&page=${currentPage}&per_page=${perPage}`;
|
||||
const response = await fetch(`/api/v1/points?${paginatedParams}`);
|
||||
const data = await response.json();
|
||||
|
||||
allPoints = [...allPoints, ...data];
|
||||
|
||||
const totalPages = parseInt(response.headers.get('X-Total-Pages'));
|
||||
currentPage++;
|
||||
|
||||
if (!totalPages || currentPage > totalPages) {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
const event = new CustomEvent('coordinates-updated', {
|
||||
detail: { coordinates: allPoints },
|
||||
bubbles: true,
|
||||
composed: true
|
||||
})
|
||||
|
||||
const tripsElement = document.querySelector('[data-controller="trips"]')
|
||||
if (tripsElement) {
|
||||
tripsElement.dispatchEvent(event)
|
||||
} else {
|
||||
console.error('Trips controller element not found')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error)
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,24 +13,43 @@ import { esriWorldGrayCanvasMapLayer } from "../maps/layers"
|
|||
import { fetchAndDisplayPhotos } from '../maps/helpers';
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["container"]
|
||||
static targets = ["container", "startedAt", "endedAt"]
|
||||
static values = { }
|
||||
|
||||
connect() {
|
||||
this.coordinates = JSON.parse(this.element.dataset.coordinates)
|
||||
this.apiKey = this.element.dataset.api_key
|
||||
this.userSettings = JSON.parse(this.element.dataset.user_settings)
|
||||
this.timezone = this.element.dataset.timezone
|
||||
this.distanceUnit = this.element.dataset.distance_unit
|
||||
console.log("Trips controller connected")
|
||||
this.coordinates = JSON.parse(this.containerTarget.dataset.coordinates)
|
||||
this.apiKey = this.containerTarget.dataset.api_key
|
||||
this.userSettings = JSON.parse(this.containerTarget.dataset.user_settings)
|
||||
this.timezone = this.containerTarget.dataset.timezone
|
||||
this.distanceUnit = this.containerTarget.dataset.distance_unit
|
||||
|
||||
// Initialize map and layers
|
||||
this.initializeMap()
|
||||
|
||||
// Add event listener for coordinates updates
|
||||
this.element.addEventListener('coordinates-updated', (event) => {
|
||||
console.log("Coordinates updated:", event.detail.coordinates)
|
||||
this.updateMapWithCoordinates(event.detail.coordinates)
|
||||
})
|
||||
}
|
||||
|
||||
// Move map initialization to separate method
|
||||
initializeMap() {
|
||||
// Initialize layer groups
|
||||
this.markersLayer = L.layerGroup()
|
||||
this.polylinesLayer = L.layerGroup()
|
||||
this.photoMarkers = L.layerGroup()
|
||||
|
||||
const center = [this.coordinates[0][0], this.coordinates[0][1]]
|
||||
// Set default center and zoom for world view
|
||||
const hasValidCoordinates = this.coordinates && Array.isArray(this.coordinates) && this.coordinates.length > 0
|
||||
const center = hasValidCoordinates
|
||||
? [this.coordinates[0][0], this.coordinates[0][1]]
|
||||
: [20, 0] // Roughly centers the world map
|
||||
const zoom = hasValidCoordinates ? 14 : 2
|
||||
|
||||
// Initialize map
|
||||
this.map = L.map(this.containerTarget).setView(center, 14)
|
||||
this.map = L.map(this.containerTarget).setView(center, zoom)
|
||||
|
||||
// Add base map layer
|
||||
osmMapLayer(this.map, "OpenStreetMap")
|
||||
|
|
@ -111,7 +130,7 @@ export default class extends Controller {
|
|||
marker.bindPopup(popupContent)
|
||||
|
||||
// Add to markers layer instead of directly to map
|
||||
this.markersLayer.addTo(this.map)
|
||||
|
||||
marker.addTo(this.markersLayer)
|
||||
})
|
||||
}
|
||||
|
|
@ -135,19 +154,25 @@ export default class extends Controller {
|
|||
this.map.fitBounds(bounds, { padding: [50, 50] })
|
||||
}
|
||||
|
||||
baseMaps() {
|
||||
let selectedLayerName = this.userSettings.preferred_map_layer || "OpenStreetMap";
|
||||
// Add this new method to update coordinates and refresh the map
|
||||
updateMapWithCoordinates(newCoordinates) {
|
||||
// Transform the coordinates to match the expected format
|
||||
this.coordinates = newCoordinates.map(point => [
|
||||
parseFloat(point.latitude),
|
||||
parseFloat(point.longitude),
|
||||
(point.timestamp).toString()
|
||||
])
|
||||
|
||||
return {
|
||||
OpenStreetMap: osmMapLayer(this.map, selectedLayerName),
|
||||
"OpenStreetMap.HOT": osmHotMapLayer(this.map, selectedLayerName),
|
||||
OPNV: OPNVMapLayer(this.map, selectedLayerName),
|
||||
openTopo: openTopoMapLayer(this.map, selectedLayerName),
|
||||
cyclOsm: cyclOsmMapLayer(this.map, selectedLayerName),
|
||||
esriWorldStreet: esriWorldStreetMapLayer(this.map, selectedLayerName),
|
||||
esriWorldTopo: esriWorldTopoMapLayer(this.map, selectedLayerName),
|
||||
esriWorldImagery: esriWorldImageryMapLayer(this.map, selectedLayerName),
|
||||
esriWorldGrayCanvas: esriWorldGrayCanvasMapLayer(this.map, selectedLayerName)
|
||||
};
|
||||
// Clear existing layers
|
||||
this.markersLayer.clearLayers()
|
||||
this.polylinesLayer.clearLayers()
|
||||
this.photoMarkers.clearLayers()
|
||||
|
||||
// Add new markers and route if coordinates exist
|
||||
if (this.coordinates?.length > 0) {
|
||||
this.addMarkers()
|
||||
this.addPolyline()
|
||||
this.fitMapToBounds()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
data-user_settings=<%= current_user.settings.to_json %>
|
||||
data-coordinates="<%= @coordinates %>"
|
||||
data-timezone="<%= Rails.configuration.time_zone %>">
|
||||
<div data-maps-target="container" class="h-[25rem] w-full min-h-screen">
|
||||
<div data-maps-target="container" class="h-[25rem] rounded-lg w-full min-h-screen">
|
||||
<div id="fog" class="fog"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,29 +11,63 @@
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="flex flex-col lg:flex-row gap-4 mt-4">
|
||||
<div class="form-control w-full lg:w-1/2">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, class: 'input input-bordered' %>
|
||||
</div>
|
||||
<div class="flex flex-col lg:flex-row lg:w-1/2 gap-4">
|
||||
<div class="form-control w-full lg:w-1/2">
|
||||
<%= form.label :started_at %>
|
||||
<%= form.datetime_field :started_at, include_seconds: false, class: 'input input-bordered', value: trip.started_at %>
|
||||
</div>
|
||||
<div class="form-control w-full lg:w-1/2">
|
||||
<%= form.label :ended_at %>
|
||||
<%= form.datetime_field :ended_at, include_seconds: false, class: 'input input-bordered', value: trip.ended_at %>
|
||||
<div class="flex flex-col lg:flex-row gap-4 my-4" data-controller="trips">
|
||||
<div class="w-full lg:w-1/2">
|
||||
<div
|
||||
id='map trips-container'
|
||||
class="w-full h-full rounded-lg"
|
||||
data-trips-target="container"
|
||||
data-distance_unit="<%= DISTANCE_UNIT %>"
|
||||
data-api_key="<%= current_user.api_key %>"
|
||||
data-user_settings="<%= current_user.settings.to_json %>"
|
||||
data-coordinates="<%= [].to_json %>"
|
||||
data-timezone="<%= Rails.configuration.time_zone %>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control w-full mt-4 mb-4">
|
||||
<%= form.label :field_notes %>
|
||||
<%= form.rich_text_area :field_notes %>
|
||||
</div>
|
||||
<div
|
||||
class="w-full lg:w-1/2 space-y-4"
|
||||
data-controller="datetime">
|
||||
|
||||
<div class="inline mb-4">
|
||||
<%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %>
|
||||
<div class="form-control">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, class: 'input input-bordered w-full' %>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-4">
|
||||
<div class="form-control w-full">
|
||||
<input type="hidden" data-datetime-target="apiKey" value="<%= current_user.api_key %>">
|
||||
<%= form.label :started_at %>
|
||||
<%= form.datetime_field :started_at,
|
||||
include_seconds: false,
|
||||
class: 'input input-bordered w-full',
|
||||
value: trip.started_at,
|
||||
data: {
|
||||
datetime_target: "startedAt",
|
||||
action: "change->datetime#updateCoordinates"
|
||||
} %>
|
||||
</div>
|
||||
<div class="form-control w-full">
|
||||
<%= form.label :ended_at %>
|
||||
<%= form.datetime_field :ended_at,
|
||||
include_seconds: false,
|
||||
class: 'input input-bordered w-full',
|
||||
value: trip.ended_at,
|
||||
data: {
|
||||
datetime_target: "endedAt",
|
||||
action: "change->datetime#updateCoordinates"
|
||||
} %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<%= form.label :field_notes %>
|
||||
<%= form.rich_text_area :field_notes %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
<div class="w-full">
|
||||
<div id="trips" class="min-w-full">
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="text-2xl font-bold">Trips</h1>
|
||||
<%= link_to 'New trip', new_trip_path, class: 'btn btn-primary' %>
|
||||
</div>
|
||||
|
||||
<% if @trips.empty? %>
|
||||
<div class="hero min-h-80 bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<div class="w-full">
|
||||
<div
|
||||
id='map'
|
||||
class="w-full h-full"
|
||||
class="w-full h-full rounded-lg"
|
||||
data-controller="trips"
|
||||
data-trips-target="container"
|
||||
data-distance_unit="<%= DISTANCE_UNIT %>"
|
||||
|
|
|
|||
Loading…
Reference in a new issue