mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
Add modal to show countries and cities visited in a year
This commit is contained in:
parent
4ab1636a94
commit
605ceee820
11 changed files with 347 additions and 26 deletions
|
|
@ -37,10 +37,11 @@ Also, after updating to this version, Dawarich will start a huge background job
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- Map page now has a button to go to the previous and next day. #296 #631 #904
|
- Map page now has a button to go to the previous and next day. #296 #631 #904
|
||||||
|
- Clicking on number of countries and cities in stats cards now opens a modal with a list of countries and cities visited in that year.
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
- Reverse geocoding is now working as on-demand job instead of storing the result in the database.
|
- Reverse geocoding is now working as on-demand job instead of storing the result in the database. #619
|
||||||
- Stats cards now show the last update time. #733
|
- Stats cards now show the last update time. #733
|
||||||
- Visit card now shows buttons to confirm or decline a visit only if it's not confirmed or declined yet.
|
- Visit card now shows buttons to confirm or decline a visit only if it's not confirmed or declined yet.
|
||||||
- Distance unit is now being stored in the user settings. You can choose between kilometers and miles, default is kilometers. The setting is accessible in the user settings -> Maps -> Distance Unit. You might want to recalculate your stats after changing the unit.
|
- Distance unit is now being stored in the user settings. You can choose between kilometers and miles, default is kilometers. The setting is accessible in the user settings -> Maps -> Distance Unit. You might want to recalculate your stats after changing the unit.
|
||||||
|
|
@ -53,6 +54,7 @@ Also, after updating to this version, Dawarich will start a huge background job
|
||||||
- `rake points:migrate_to_lonlat` should work properly now. #1083 #1161
|
- `rake points:migrate_to_lonlat` should work properly now. #1083 #1161
|
||||||
- PostGIS extension is now being enabled only if it's not already enabled. #1186
|
- PostGIS extension is now being enabled only if it's not already enabled. #1186
|
||||||
- Fixed a bug where visits were returning into Suggested state after being confirmed or declined. #848
|
- Fixed a bug where visits were returning into Suggested state after being confirmed or declined. #848
|
||||||
|
- If no points are found for a month during stats calculation, stats are now being deleted instead of being left empty. #1066 #406
|
||||||
|
|
||||||
## Removed
|
## Removed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,35 @@ module ApplicationHelper
|
||||||
data[:cities].flatten!.uniq!
|
data[:cities].flatten!.uniq!
|
||||||
data[:countries].flatten!.uniq!
|
data[:countries].flatten!.uniq!
|
||||||
|
|
||||||
"#{data[:countries].count} countries, #{data[:cities].count} cities"
|
# Group cities by country
|
||||||
|
grouped_by_country = {}
|
||||||
|
stats.select { _1.year == year }.each do |stat|
|
||||||
|
stat.toponyms.flatten.each do |toponym|
|
||||||
|
country = toponym['country']
|
||||||
|
next unless country.present?
|
||||||
|
|
||||||
|
grouped_by_country[country] ||= []
|
||||||
|
|
||||||
|
if toponym['cities'].present?
|
||||||
|
toponym['cities'].each do |city_data|
|
||||||
|
city = city_data['city']
|
||||||
|
grouped_by_country[country] << city if city.present?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deduplicate cities for each country
|
||||||
|
grouped_by_country.transform_values!(&:uniq)
|
||||||
|
|
||||||
|
# Return data for the template to use
|
||||||
|
{
|
||||||
|
countries_count: data[:countries].count,
|
||||||
|
cities_count: data[:cities].count,
|
||||||
|
grouped_by_country: grouped_by_country.transform_values(&:sort).sort.to_h,
|
||||||
|
year: year,
|
||||||
|
modal_id: "countries_cities_modal_#{year}"
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def countries_and_cities_stat_for_month(stat)
|
def countries_and_cities_stat_for_month(stat)
|
||||||
|
|
|
||||||
235
app/helpers/country_flag_helper.rb
Normal file
235
app/helpers/country_flag_helper.rb
Normal file
|
|
@ -0,0 +1,235 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module CountryFlagHelper
|
||||||
|
def country_flag(country_name)
|
||||||
|
country_code = country_to_code(country_name)
|
||||||
|
return "" unless country_code
|
||||||
|
|
||||||
|
# Convert country code to regional indicator symbols (flag emoji)
|
||||||
|
country_code.upcase.each_char.map { |c| (c.ord + 127397).chr(Encoding::UTF_8) }.join
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def country_to_code(country_name)
|
||||||
|
# Mapping of country names to ISO 3166-1 alpha-2 codes
|
||||||
|
# This is a basic mapping - you might want to expand it based on your data
|
||||||
|
mapping = {
|
||||||
|
"Afghanistan" => "AF",
|
||||||
|
"Albania" => "AL",
|
||||||
|
"Algeria" => "DZ",
|
||||||
|
"Andorra" => "AD",
|
||||||
|
"Angola" => "AO",
|
||||||
|
"Antigua and Barbuda" => "AG",
|
||||||
|
"Argentina" => "AR",
|
||||||
|
"Armenia" => "AM",
|
||||||
|
"Australia" => "AU",
|
||||||
|
"Austria" => "AT",
|
||||||
|
"Azerbaijan" => "AZ",
|
||||||
|
"Bahamas" => "BS",
|
||||||
|
"Bahrain" => "BH",
|
||||||
|
"Bangladesh" => "BD",
|
||||||
|
"Barbados" => "BB",
|
||||||
|
"Belarus" => "BY",
|
||||||
|
"Belgium" => "BE",
|
||||||
|
"Belize" => "BZ",
|
||||||
|
"Benin" => "BJ",
|
||||||
|
"Bhutan" => "BT",
|
||||||
|
"Bolivia" => "BO",
|
||||||
|
"Bosnia and Herzegovina" => "BA",
|
||||||
|
"Botswana" => "BW",
|
||||||
|
"Brazil" => "BR",
|
||||||
|
"Brunei" => "BN",
|
||||||
|
"Bulgaria" => "BG",
|
||||||
|
"Burkina Faso" => "BF",
|
||||||
|
"Burundi" => "BI",
|
||||||
|
"Cabo Verde" => "CV",
|
||||||
|
"Cambodia" => "KH",
|
||||||
|
"Cameroon" => "CM",
|
||||||
|
"Canada" => "CA",
|
||||||
|
"Central African Republic" => "CF",
|
||||||
|
"Chad" => "TD",
|
||||||
|
"Chile" => "CL",
|
||||||
|
"China" => "CN",
|
||||||
|
"Colombia" => "CO",
|
||||||
|
"Comoros" => "KM",
|
||||||
|
"Congo (Brazzaville)" => "CG",
|
||||||
|
"Congo (Kinshasa)" => "CD",
|
||||||
|
"Costa Rica" => "CR",
|
||||||
|
"Croatia" => "HR",
|
||||||
|
"Cuba" => "CU",
|
||||||
|
"Cyprus" => "CY",
|
||||||
|
"Czechia" => "CZ",
|
||||||
|
"Czech Republic" => "CZ",
|
||||||
|
"Denmark" => "DK",
|
||||||
|
"Djibouti" => "DJ",
|
||||||
|
"Dominica" => "DM",
|
||||||
|
"Dominican Republic" => "DO",
|
||||||
|
"Ecuador" => "EC",
|
||||||
|
"Egypt" => "EG",
|
||||||
|
"El Salvador" => "SV",
|
||||||
|
"Equatorial Guinea" => "GQ",
|
||||||
|
"Eritrea" => "ER",
|
||||||
|
"Estonia" => "EE",
|
||||||
|
"Eswatini" => "SZ",
|
||||||
|
"Swaziland" => "SZ",
|
||||||
|
"Ethiopia" => "ET",
|
||||||
|
"Fiji" => "FJ",
|
||||||
|
"Finland" => "FI",
|
||||||
|
"France" => "FR",
|
||||||
|
"Gabon" => "GA",
|
||||||
|
"Gambia" => "GM",
|
||||||
|
"Georgia" => "GE",
|
||||||
|
"Germany" => "DE",
|
||||||
|
"Ghana" => "GH",
|
||||||
|
"Greece" => "GR",
|
||||||
|
"Grenada" => "GD",
|
||||||
|
"Guatemala" => "GT",
|
||||||
|
"Guinea" => "GN",
|
||||||
|
"Guinea-Bissau" => "GW",
|
||||||
|
"Guyana" => "GY",
|
||||||
|
"Haiti" => "HT",
|
||||||
|
"Honduras" => "HN",
|
||||||
|
"Hungary" => "HU",
|
||||||
|
"Iceland" => "IS",
|
||||||
|
"India" => "IN",
|
||||||
|
"Indonesia" => "ID",
|
||||||
|
"Iran" => "IR",
|
||||||
|
"Iraq" => "IQ",
|
||||||
|
"Ireland" => "IE",
|
||||||
|
"Israel" => "IL",
|
||||||
|
"Italy" => "IT",
|
||||||
|
"Jamaica" => "JM",
|
||||||
|
"Japan" => "JP",
|
||||||
|
"Jordan" => "JO",
|
||||||
|
"Kazakhstan" => "KZ",
|
||||||
|
"Kenya" => "KE",
|
||||||
|
"Kiribati" => "KI",
|
||||||
|
"Kuwait" => "KW",
|
||||||
|
"Kyrgyzstan" => "KG",
|
||||||
|
"Laos" => "LA",
|
||||||
|
"Latvia" => "LV",
|
||||||
|
"Lebanon" => "LB",
|
||||||
|
"Lesotho" => "LS",
|
||||||
|
"Liberia" => "LR",
|
||||||
|
"Libya" => "LY",
|
||||||
|
"Liechtenstein" => "LI",
|
||||||
|
"Lithuania" => "LT",
|
||||||
|
"Luxembourg" => "LU",
|
||||||
|
"Madagascar" => "MG",
|
||||||
|
"Malawi" => "MW",
|
||||||
|
"Malaysia" => "MY",
|
||||||
|
"Maldives" => "MV",
|
||||||
|
"Mali" => "ML",
|
||||||
|
"Malta" => "MT",
|
||||||
|
"Marshall Islands" => "MH",
|
||||||
|
"Mauritania" => "MR",
|
||||||
|
"Mauritius" => "MU",
|
||||||
|
"Mexico" => "MX",
|
||||||
|
"Micronesia" => "FM",
|
||||||
|
"Moldova" => "MD",
|
||||||
|
"Monaco" => "MC",
|
||||||
|
"Mongolia" => "MN",
|
||||||
|
"Montenegro" => "ME",
|
||||||
|
"Morocco" => "MA",
|
||||||
|
"Mozambique" => "MZ",
|
||||||
|
"Myanmar" => "MM",
|
||||||
|
"Burma" => "MM",
|
||||||
|
"Namibia" => "NA",
|
||||||
|
"Nauru" => "NR",
|
||||||
|
"Nepal" => "NP",
|
||||||
|
"Netherlands" => "NL",
|
||||||
|
"New Zealand" => "NZ",
|
||||||
|
"Nicaragua" => "NI",
|
||||||
|
"Niger" => "NE",
|
||||||
|
"Nigeria" => "NG",
|
||||||
|
"North Korea" => "KP",
|
||||||
|
"North Macedonia" => "MK",
|
||||||
|
"Norway" => "NO",
|
||||||
|
"Oman" => "OM",
|
||||||
|
"Pakistan" => "PK",
|
||||||
|
"Palau" => "PW",
|
||||||
|
"Palestine" => "PS",
|
||||||
|
"Panama" => "PA",
|
||||||
|
"Papua New Guinea" => "PG",
|
||||||
|
"Paraguay" => "PY",
|
||||||
|
"Peru" => "PE",
|
||||||
|
"Philippines" => "PH",
|
||||||
|
"Poland" => "PL",
|
||||||
|
"Portugal" => "PT",
|
||||||
|
"Qatar" => "QA",
|
||||||
|
"Romania" => "RO",
|
||||||
|
"Russia" => "RU",
|
||||||
|
"Russian Federation" => "RU",
|
||||||
|
"Rwanda" => "RW",
|
||||||
|
"Saint Kitts and Nevis" => "KN",
|
||||||
|
"Saint Lucia" => "LC",
|
||||||
|
"Saint Vincent and the Grenadines" => "VC",
|
||||||
|
"Samoa" => "WS",
|
||||||
|
"San Marino" => "SM",
|
||||||
|
"Sao Tome and Principe" => "ST",
|
||||||
|
"Saudi Arabia" => "SA",
|
||||||
|
"Senegal" => "SN",
|
||||||
|
"Serbia" => "RS",
|
||||||
|
"Seychelles" => "SC",
|
||||||
|
"Sierra Leone" => "SL",
|
||||||
|
"Singapore" => "SG",
|
||||||
|
"Slovakia" => "SK",
|
||||||
|
"Slovenia" => "SI",
|
||||||
|
"Solomon Islands" => "SB",
|
||||||
|
"Somalia" => "SO",
|
||||||
|
"South Africa" => "ZA",
|
||||||
|
"South Korea" => "KR",
|
||||||
|
"South Sudan" => "SS",
|
||||||
|
"Spain" => "ES",
|
||||||
|
"Sri Lanka" => "LK",
|
||||||
|
"Sudan" => "SD",
|
||||||
|
"Suriname" => "SR",
|
||||||
|
"Sweden" => "SE",
|
||||||
|
"Switzerland" => "CH",
|
||||||
|
"Syria" => "SY",
|
||||||
|
"Taiwan" => "TW",
|
||||||
|
"Tajikistan" => "TJ",
|
||||||
|
"Tanzania" => "TZ",
|
||||||
|
"Thailand" => "TH",
|
||||||
|
"Timor-Leste" => "TL",
|
||||||
|
"Togo" => "TG",
|
||||||
|
"Tonga" => "TO",
|
||||||
|
"Trinidad and Tobago" => "TT",
|
||||||
|
"Tunisia" => "TN",
|
||||||
|
"Turkey" => "TR",
|
||||||
|
"Turkmenistan" => "TM",
|
||||||
|
"Tuvalu" => "TV",
|
||||||
|
"Uganda" => "UG",
|
||||||
|
"Ukraine" => "UA",
|
||||||
|
"United Arab Emirates" => "AE",
|
||||||
|
"United Kingdom" => "GB",
|
||||||
|
"UK" => "GB",
|
||||||
|
"Great Britain" => "GB",
|
||||||
|
"United States" => "US",
|
||||||
|
"USA" => "US",
|
||||||
|
"Uruguay" => "UY",
|
||||||
|
"Uzbekistan" => "UZ",
|
||||||
|
"Vanuatu" => "VU",
|
||||||
|
"Vatican City" => "VA",
|
||||||
|
"Venezuela" => "VE",
|
||||||
|
"Vietnam" => "VN",
|
||||||
|
"Yemen" => "YE",
|
||||||
|
"Zambia" => "ZM",
|
||||||
|
"Zimbabwe" => "ZW"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Try direct match first
|
||||||
|
return mapping[country_name] if mapping[country_name]
|
||||||
|
|
||||||
|
# Try case-insensitive match or partial match
|
||||||
|
mapping.each do |name, code|
|
||||||
|
return code if country_name.downcase == name.downcase
|
||||||
|
return code if country_name.downcase.include?(name.downcase) || name.downcase.include?(country_name.downcase)
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -16,8 +16,8 @@ module Distanceable
|
||||||
private
|
private
|
||||||
|
|
||||||
def calculate_distance_for_relation(unit)
|
def calculate_distance_for_relation(unit)
|
||||||
unless DISTANCE_UNITS.key?(unit.to_sym)
|
unless ::DISTANCE_UNITS.key?(unit.to_sym)
|
||||||
raise ArgumentError, "Invalid unit. Supported units are: #{DISTANCE_UNITS.keys.join(', ')}"
|
raise ArgumentError, "Invalid unit. Supported units are: #{::DISTANCE_UNITS.keys.join(', ')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
distance_in_meters = connection.select_value(<<-SQL.squish)
|
distance_in_meters = connection.select_value(<<-SQL.squish)
|
||||||
|
|
@ -40,12 +40,12 @@ module Distanceable
|
||||||
WHERE prev_lonlat IS NOT NULL
|
WHERE prev_lonlat IS NOT NULL
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
distance_in_meters.to_f / DISTANCE_UNITS[unit.to_sym]
|
distance_in_meters.to_f / ::DISTANCE_UNITS[unit.to_sym]
|
||||||
end
|
end
|
||||||
|
|
||||||
def calculate_distance_for_array(points, unit = :km)
|
def calculate_distance_for_array(points, unit = :km)
|
||||||
unless DISTANCE_UNITS.key?(unit.to_sym)
|
unless ::DISTANCE_UNITS.key?(unit.to_sym)
|
||||||
raise ArgumentError, "Invalid unit. Supported units are: #{DISTANCE_UNITS.keys.join(', ')}"
|
raise ArgumentError, "Invalid unit. Supported units are: #{::DISTANCE_UNITS.keys.join(', ')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
return 0 if points.length < 2
|
return 0 if points.length < 2
|
||||||
|
|
@ -58,13 +58,13 @@ module Distanceable
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
total_meters.to_f / DISTANCE_UNITS[unit.to_sym]
|
total_meters.to_f / ::DISTANCE_UNITS[unit.to_sym]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def distance_to(other_point, unit = :km)
|
def distance_to(other_point, unit = :km)
|
||||||
unless DISTANCE_UNITS.key?(unit.to_sym)
|
unless ::DISTANCE_UNITS.key?(unit.to_sym)
|
||||||
raise ArgumentError, "Invalid unit. Supported units are: #{DISTANCE_UNITS.keys.join(', ')}"
|
raise ArgumentError, "Invalid unit. Supported units are: #{::DISTANCE_UNITS.keys.join(', ')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Extract coordinates based on what type other_point is
|
# Extract coordinates based on what type other_point is
|
||||||
|
|
@ -80,7 +80,7 @@ module Distanceable
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
# Convert to requested unit
|
# Convert to requested unit
|
||||||
distance_in_meters.to_f / DISTANCE_UNITS[unit.to_sym]
|
distance_in_meters.to_f / ::DISTANCE_UNITS[unit.to_sym]
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@ module Nearable
|
||||||
def near(*args)
|
def near(*args)
|
||||||
latitude, longitude, radius, unit = extract_coordinates_and_options(*args)
|
latitude, longitude, radius, unit = extract_coordinates_and_options(*args)
|
||||||
|
|
||||||
unless DISTANCE_UNITS.key?(unit.to_sym)
|
unless ::DISTANCE_UNITS.key?(unit.to_sym)
|
||||||
raise ArgumentError, "Invalid unit. Supported units are: #{DISTANCE_UNITS.keys.join(', ')}"
|
raise ArgumentError, "Invalid unit. Supported units are: #{::DISTANCE_UNITS.keys.join(', ')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Convert radius to meters for ST_DWithin
|
# Convert radius to meters for ST_DWithin
|
||||||
radius_in_meters = radius * DISTANCE_UNITS[unit.to_sym]
|
radius_in_meters = radius * ::DISTANCE_UNITS[unit.to_sym]
|
||||||
|
|
||||||
# Create a point from the given coordinates
|
# Create a point from the given coordinates
|
||||||
point = "SRID=4326;POINT(#{longitude} #{latitude})"
|
point = "SRID=4326;POINT(#{longitude} #{latitude})"
|
||||||
|
|
@ -33,12 +33,12 @@ module Nearable
|
||||||
def with_distance(*args)
|
def with_distance(*args)
|
||||||
latitude, longitude, unit = extract_coordinates_and_options(*args)
|
latitude, longitude, unit = extract_coordinates_and_options(*args)
|
||||||
|
|
||||||
unless DISTANCE_UNITS.key?(unit.to_sym)
|
unless ::DISTANCE_UNITS.key?(unit.to_sym)
|
||||||
raise ArgumentError, "Invalid unit. Supported units are: #{DISTANCE_UNITS.keys.join(', ')}"
|
raise ArgumentError, "Invalid unit. Supported units are: #{::DISTANCE_UNITS.keys.join(', ')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
point = "SRID=4326;POINT(#{longitude} #{latitude})"
|
point = "SRID=4326;POINT(#{longitude} #{latitude})"
|
||||||
conversion_factor = 1.0 / DISTANCE_UNITS[unit.to_sym]
|
conversion_factor = 1.0 / ::DISTANCE_UNITS[unit.to_sym]
|
||||||
|
|
||||||
select(<<-SQL.squish)
|
select(<<-SQL.squish)
|
||||||
#{table_name}.*,
|
#{table_name}.*,
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@ class Areas::Visits::Create
|
||||||
def area_points(area)
|
def area_points(area)
|
||||||
area_radius =
|
area_radius =
|
||||||
if user.safe_settings.distance_unit == :km
|
if user.safe_settings.distance_unit == :km
|
||||||
area.radius / DISTANCE_UNITS[:km]
|
area.radius / ::DISTANCE_UNITS[:km]
|
||||||
else
|
else
|
||||||
area.radius / DISTANCE_UNITS[user.safe_settings.distance_unit.to_sym]
|
area.radius / ::DISTANCE_UNITS[user.safe_settings.distance_unit.to_sym]
|
||||||
end
|
end
|
||||||
|
|
||||||
points = Point.where(user_id: user.id)
|
points = Point.where(user_id: user.id)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,11 @@ class Stats::CalculateMonth
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def call
|
||||||
return if points.empty?
|
if points.empty?
|
||||||
|
destroy_month_stats(year, month)
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
update_month_stats(year, month)
|
update_month_stats(year, month)
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
|
|
@ -66,4 +70,8 @@ class Stats::CalculateMonth
|
||||||
content: "#{error.message}, stacktrace: #{error.backtrace.join("\n")}"
|
content: "#{error.message}, stacktrace: #{error.backtrace.join("\n")}"
|
||||||
).call
|
).call
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy_month_stats(year, month)
|
||||||
|
Stat.where(year:, month:, user:).destroy_all
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Imported points</th>
|
<th>Imported points</th>
|
||||||
<th>Reverse geocoded points</th>
|
<% if DawarichSettings.store_geodata? %>
|
||||||
|
<th>Reverse geocoded points</th>
|
||||||
|
<% end %>
|
||||||
<th>Created at</th>
|
<th>Created at</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -65,9 +67,11 @@
|
||||||
<td data-points-count>
|
<td data-points-count>
|
||||||
<%= number_with_delimiter import.processed %>
|
<%= number_with_delimiter import.processed %>
|
||||||
</td>
|
</td>
|
||||||
<td data-reverse-geocoded-points-count>
|
<% if DawarichSettings.store_geodata? %>
|
||||||
<%= number_with_delimiter import.reverse_geocoded_points_count %>
|
<td data-reverse-geocoded-points-count>
|
||||||
</td>
|
<%= number_with_delimiter import.reverse_geocoded_points_count %>
|
||||||
|
</td>
|
||||||
|
<% end %>
|
||||||
<td><%= human_datetime(import.created_at) %></td>
|
<td><%= human_datetime(import.created_at) %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,41 @@
|
||||||
</p>
|
</p>
|
||||||
<% if DawarichSettings.reverse_geocoding_enabled? %>
|
<% if DawarichSettings.reverse_geocoding_enabled? %>
|
||||||
<div class="card-actions justify-end">
|
<div class="card-actions justify-end">
|
||||||
<%= countries_and_cities_stat_for_year(year, stats) %>
|
<% location_data = countries_and_cities_stat_for_year(year, stats) %>
|
||||||
|
<%= link_to "#{location_data[:countries_count]} countries, #{location_data[:cities_count]} cities",
|
||||||
|
"##{location_data[:modal_id]}",
|
||||||
|
class: "link link-primary",
|
||||||
|
onclick: "document.getElementById('#{location_data[:modal_id]}').checked = true" %>
|
||||||
|
|
||||||
|
<!-- Modal structure -->
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" id="<%= location_data[:modal_id] %>" class="modal-toggle" />
|
||||||
|
<div class="modal" role="dialog">
|
||||||
|
<div class="modal-box max-w-3xl">
|
||||||
|
<h3 class="text-lg font-bold mb-4">Countries and Cities visited in <%= location_data[:year] %></h3>
|
||||||
|
<div class="max-h-96 overflow-y-auto">
|
||||||
|
<% location_data[:grouped_by_country].each do |country, cities| %>
|
||||||
|
<div class="mb-4">
|
||||||
|
<h4 class="font-bold">
|
||||||
|
<span class="mr-2"><%= country_flag(country) %></span>
|
||||||
|
<%= country %>
|
||||||
|
</h4>
|
||||||
|
<% if cities.any? %>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 pl-4">
|
||||||
|
<% cities.each do |city| %>
|
||||||
|
<div class="text-sm"><%= city %></div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<p class="text-sm text-gray-500 italic pl-4">No specific cities recorded</p>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<label class="modal-backdrop" for="<%= location_data[:modal_id] %>"></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= column_chart(
|
<%= column_chart(
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ SELF_HOSTED = ENV.fetch('SELF_HOSTED', 'true') == 'true'
|
||||||
|
|
||||||
MIN_MINUTES_SPENT_IN_CITY = ENV.fetch('MIN_MINUTES_SPENT_IN_CITY', 60).to_i
|
MIN_MINUTES_SPENT_IN_CITY = ENV.fetch('MIN_MINUTES_SPENT_IN_CITY', 60).to_i
|
||||||
|
|
||||||
DISTANCE_UNITS = {
|
::DISTANCE_UNITS = {
|
||||||
km: 1000, # to meters
|
km: 1000, # to meters
|
||||||
mi: 1609.34, # to meters
|
mi: 1609.34, # to meters
|
||||||
m: 1, # already in meters
|
m: 1, # already in meters
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,16 @@ RSpec.describe Stats::CalculateMonth do
|
||||||
it 'does not create stats' do
|
it 'does not create stats' do
|
||||||
expect { calculate_stats }.not_to(change { Stat.count })
|
expect { calculate_stats }.not_to(change { Stat.count })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when stats already exist for the month' do
|
||||||
|
before do
|
||||||
|
create(:stat, user: user, year: year, month: month)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deletes existing stats for that month' do
|
||||||
|
expect { calculate_stats }.to change { Stat.count }.by(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when there are points' do
|
context 'when there are points' do
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue