diff --git a/Gemfile b/Gemfile index ceefd493..323acf81 100644 --- a/Gemfile +++ b/Gemfile @@ -17,6 +17,7 @@ gem 'turbo-rails' gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] gem "importmap-rails" gem "mapkick-rb" +gem "chartkick" gem 'geocoder' gem 'sidekiq' diff --git a/Gemfile.lock b/Gemfile.lock index 25805348..3af5afb6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,6 +83,7 @@ GEM msgpack (~> 1.2) builder (3.2.4) byebug (11.1.3) + chartkick (5.0.6) coderay (1.1.3) concurrent-ruby (1.2.3) connection_pool (2.4.1) @@ -323,6 +324,7 @@ PLATFORMS DEPENDENCIES bootsnap + chartkick debug devise dotenv-rails diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb index eebc62eb..a50f6d76 100644 --- a/app/controllers/imports_controller.rb +++ b/app/controllers/imports_controller.rb @@ -18,7 +18,7 @@ class ImportsController < ApplicationController files.each do |file| import = current_user.imports.create( name: file.original_filename, - source: params[:import][:source], + source: params[:import][:source] ) import.file.attach(file) @@ -27,7 +27,7 @@ class ImportsController < ApplicationController redirect_to imports_url, notice: "#{files.size} files are queued to be imported in background", status: :see_other rescue StandardError => e Import.where(user: current_user, name: files.map(&:original_filename)).destroy_all -Rails.logger.debug e.message + flash.now[:error] = e.message redirect_to new_import_path, notice: e.message, status: :unprocessable_entity diff --git a/app/controllers/points_controller.rb b/app/controllers/points_controller.rb index efd8d9ab..9c57fac5 100644 --- a/app/controllers/points_controller.rb +++ b/app/controllers/points_controller.rb @@ -6,12 +6,11 @@ class PointsController < ApplicationController @countries_and_cities = CountriesAndCities.new(@points).call @coordinates = - @points - .pluck(:latitude, :longitude, :battery, :altitude, :timestamp, :velocity, :id) - .map { [_1.to_f, _2.to_f, _3.to_s, _4.to_s, _5.to_s, _6.to_s, _7] } + @points.pluck(:latitude, :longitude, :battery, :altitude, :timestamp, :velocity, :id) + .map { [_1.to_f, _2.to_f, _3.to_s, _4.to_s, _5.to_s, _6.to_s, _7] } @distance = distance - @start_at = Time.at(start_at) - @end_at = Time.at(end_at) + @start_at = Time.zone.at(start_at) + @end_at = Time.zone.at(end_at) end private @@ -23,7 +22,7 @@ class PointsController < ApplicationController end def end_at - return Date.today.end_of_day.to_i if params[:end_at].nil? + return Time.zone.today.end_of_day.to_i if params[:end_at].nil? params[:end_at].to_datetime.to_i end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index df49c727..30ed41cc 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -22,4 +22,8 @@ module ApplicationHelper { start_at: start_at, end_at: end_at } end + + def header_colors + %w[info success warning error accent secondary primary] + end end diff --git a/app/javascript/application.js b/app/javascript/application.js index 8b283c93..c35271fe 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -7,3 +7,5 @@ import "@hotwired/turbo-rails" import "mapkick/bundle" import "leaflet" import "leaflet-providers" +import "chartkick" +import "Chart.bundle" diff --git a/app/models/stat.rb b/app/models/stat.rb index 7fd717d9..81a2f504 100644 --- a/app/models/stat.rb +++ b/app/models/stat.rb @@ -1,5 +1,33 @@ +# frozen_string_literal: true + class Stat < ApplicationRecord validates :year, :month, presence: true belongs_to :user + + def timespan + DateTime.new(year, month).beginning_of_month..DateTime.new(year, month).end_of_month + end + + def distance_by_day + timespan.to_a.map.with_index(1) do |day, index| + beginning_of_day = day.beginning_of_day.to_i + end_of_day = day.end_of_day.to_i + + data = { day: index, distance: 0 } + + # We have to filter by user as well + points = Point.where(timestamp: beginning_of_day..end_of_day) + + points.each_cons(2) do |point1, point2| + distance = Geocoder::Calculations.distance_between( + [point1.latitude, point1.longitude], [point2.latitude, point2.longitude] + ) + + data[:distance] += distance + end + + [data[:day], data[:distance].round(2)] + end + end end diff --git a/app/models/user.rb b/app/models/user.rb index 8372108a..122407a3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -29,4 +29,8 @@ class User < ApplicationRecord def total_cities Stat.where(user: self).pluck(:toponyms).flatten.size end + + def total_reverse_geocoded + points.where.not(country: nil, city: nil).count + end end diff --git a/app/services/create_stats.rb b/app/services/create_stats.rb index 5a18dcdb..4d1ee1d0 100644 --- a/app/services/create_stats.rb +++ b/app/services/create_stats.rb @@ -16,16 +16,13 @@ class CreateStats end_of_month_timestamp = DateTime.new(year, month).end_of_month.to_i points = points(beginning_of_month_timestamp, end_of_month_timestamp) - next if points.empty? - Stat.create( - year: year, - month: month, - distance: distance(points), - toponyms: toponyms(points), - user: user - ) + stat = Stat.create(year:, month:, user:, distance: distance(points), toponyms: toponyms(points)) + + stat.update(daily_distance: stat.distance_by_day) if stat.persisted? + + stat end end.compact end diff --git a/app/views/shared/_right_sidebar.html.erb b/app/views/shared/_right_sidebar.html.erb index 4d702d10..222d7dbf 100644 --- a/app/views/shared/_right_sidebar.html.erb +++ b/app/views/shared/_right_sidebar.html.erb @@ -7,7 +7,7 @@