mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -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 {
|
||||
this.map.addControl(this.rightPanel);
|
||||
localStorage.setItem('mapPanelOpen', 'true');
|
||||
// Fetch visited cities when panel is opened
|
||||
this.fetchAndDisplayVisitedCities();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1008,6 +1009,7 @@ export default class extends Controller {
|
|||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
|
@ -1141,6 +1143,24 @@ export default class extends Controller {
|
|||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -1187,5 +1207,71 @@ export default class extends Controller {
|
|||
const endDate = `${year}-12-31T23:59`;
|
||||
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
|
||||
resources :borders, only: :index
|
||||
resources :visited_cities, only: :index
|
||||
end
|
||||
|
||||
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