mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
Show visited cities on map page
This commit is contained in:
parent
cab70839b9
commit
e7c393a776
5 changed files with 125 additions and 3 deletions
|
|
@ -0,0 +1,30 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Countries::VisitedCitiesController < ApiController
|
||||||
|
before_action :validate_params
|
||||||
|
|
||||||
|
def index
|
||||||
|
start_at = DateTime.parse(params[:start_at]).to_i
|
||||||
|
end_at = DateTime.parse(params[:end_at]).to_i
|
||||||
|
|
||||||
|
points = current_api_user
|
||||||
|
.tracked_points
|
||||||
|
.where(timestamp: start_at..end_at)
|
||||||
|
|
||||||
|
render json: { data: CountriesAndCities.new(points).call }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def validate_params
|
||||||
|
missing_params = %i[start_at end_at].select { |param| params[param].blank? }
|
||||||
|
|
||||||
|
if missing_params.any?
|
||||||
|
render json: {
|
||||||
|
error: "Missing required parameters: #{missing_params.join(', ')}"
|
||||||
|
}, status: :bad_request and return
|
||||||
|
end
|
||||||
|
|
||||||
|
params.permit(:start_at, :end_at)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
module Api::V1::Points::TrackedMonthsHelper
|
|
||||||
end
|
|
||||||
|
|
@ -958,8 +958,9 @@ export default class extends Controller {
|
||||||
} else {
|
} else {
|
||||||
this.map.addControl(this.rightPanel);
|
this.map.addControl(this.rightPanel);
|
||||||
localStorage.setItem('mapPanelOpen', 'true');
|
localStorage.setItem('mapPanelOpen', 'true');
|
||||||
|
// Fetch visited cities when panel is opened
|
||||||
|
this.fetchAndDisplayVisitedCities();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1008,6 +1009,7 @@ export default class extends Controller {
|
||||||
`).join('')}
|
`).join('')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -1141,6 +1143,24 @@ export default class extends Controller {
|
||||||
|
|
||||||
L.DomEvent.disableClickPropagation(div);
|
L.DomEvent.disableClickPropagation(div);
|
||||||
|
|
||||||
|
// Add container for visited cities
|
||||||
|
div.innerHTML += `
|
||||||
|
<div id="visited-cities-container" class="mt-4">
|
||||||
|
<h3 class="text-lg font-bold mb-2">Visited cities</h3>
|
||||||
|
<div id="visited-cities-list" class="space-y-2"
|
||||||
|
style="max-height: 300px; overflow-y: auto; padding-right: 10px;">
|
||||||
|
<p class="text-gray-500">Loading visited places...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Prevent map zoom when scrolling the cities list
|
||||||
|
const citiesList = div.querySelector('#visited-cities-list');
|
||||||
|
L.DomEvent.disableScrollPropagation(citiesList);
|
||||||
|
|
||||||
|
// Fetch visited cities when panel is first created
|
||||||
|
this.fetchAndDisplayVisitedCities();
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1187,5 +1207,71 @@ export default class extends Controller {
|
||||||
const endDate = `${year}-12-31T23:59`;
|
const endDate = `${year}-12-31T23:59`;
|
||||||
return `map?end_at=${encodeURIComponent(endDate)}&start_at=${encodeURIComponent(startDate)}`;
|
return `map?end_at=${encodeURIComponent(endDate)}&start_at=${encodeURIComponent(startDate)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchAndDisplayVisitedCities() {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const startAt = urlParams.get('start_at') || new Date().toISOString();
|
||||||
|
const endAt = urlParams.get('end_at') || new Date().toISOString();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/v1/countries/visited_cities?api_key=${this.apiKey}&start_at=${startAt}&end_at=${endAt}`, {
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
this.displayVisitedCities(data.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching visited cities:', error);
|
||||||
|
const container = document.getElementById('visited-cities-list');
|
||||||
|
if (container) {
|
||||||
|
container.innerHTML = '<p class="text-red-500">Error loading visited places</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayVisitedCities(citiesData) {
|
||||||
|
const container = document.getElementById('visited-cities-list');
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
if (!citiesData || citiesData.length === 0) {
|
||||||
|
container.innerHTML = '<p class="text-gray-500">No places visited during this period</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = citiesData.map(country => `
|
||||||
|
<div class="mb-4">
|
||||||
|
<h4 class="font-bold text-md">${country.country}</h4>
|
||||||
|
<ul class="ml-4 space-y-1">
|
||||||
|
${country.cities.map(city => `
|
||||||
|
<li class="text-sm">
|
||||||
|
${city.city}
|
||||||
|
<span class="text-gray-500">
|
||||||
|
(${new Date(city.timestamp * 1000).toLocaleDateString()})
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
`).join('')}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
container.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatDuration(seconds) {
|
||||||
|
const days = Math.floor(seconds / (24 * 60 * 60));
|
||||||
|
const hours = Math.floor((seconds % (24 * 60 * 60)) / (60 * 60));
|
||||||
|
|
||||||
|
if (days > 0) {
|
||||||
|
return `${days}d ${hours}h`;
|
||||||
|
}
|
||||||
|
return `${hours}h`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
namespace :countries do
|
namespace :countries do
|
||||||
resources :borders, only: :index
|
resources :borders, only: :index
|
||||||
|
resources :visited_cities, only: :index
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :points do
|
namespace :points do
|
||||||
|
|
|
||||||
7
spec/requests/api/v1/countries/visited_cities_spec.rb
Normal file
7
spec/requests/api/v1/countries/visited_cities_spec.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe "Api::V1::Countries::VisitedCities", type: :request do
|
||||||
|
describe "GET /index" do
|
||||||
|
pending "add some examples (or delete) #{__FILE__}"
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue