diff --git a/app/assets/svg/icons/lucide/outline/flower.svg b/app/assets/svg/icons/lucide/outline/flower.svg new file mode 100644 index 00000000..81265ee8 --- /dev/null +++ b/app/assets/svg/icons/lucide/outline/flower.svg @@ -0,0 +1 @@ + diff --git a/app/assets/svg/icons/lucide/outline/leaf.svg b/app/assets/svg/icons/lucide/outline/leaf.svg new file mode 100644 index 00000000..af8901e4 --- /dev/null +++ b/app/assets/svg/icons/lucide/outline/leaf.svg @@ -0,0 +1 @@ + diff --git a/app/assets/svg/icons/lucide/outline/tree-palm.svg b/app/assets/svg/icons/lucide/outline/tree-palm.svg new file mode 100644 index 00000000..685a5ea7 --- /dev/null +++ b/app/assets/svg/icons/lucide/outline/tree-palm.svg @@ -0,0 +1 @@ + diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 500b9711..3b11ff47 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -3,6 +3,8 @@ class ApplicationController < ActionController::Base include Pundit::Authorization + rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized + before_action :unread_notifications, :set_self_hosted_status protected @@ -16,13 +18,13 @@ class ApplicationController < ActionController::Base def authenticate_admin! return if current_user&.admin? - redirect_to root_path, notice: 'You are not authorized to perform this action.', status: :see_other + user_not_authorized end def authenticate_self_hosted! return if DawarichSettings.self_hosted? - redirect_to root_path, notice: 'You are not authorized to perform this action.', status: :see_other + user_not_authorized end def authenticate_active_user! @@ -34,7 +36,7 @@ class ApplicationController < ActionController::Base def authenticate_non_self_hosted! return unless DawarichSettings.self_hosted? - redirect_to root_path, notice: 'You are not authorized to perform this action.', status: :see_other + user_not_authorized end private @@ -42,4 +44,10 @@ class ApplicationController < ActionController::Base def set_self_hosted_status @self_hosted = DawarichSettings.self_hosted? end + + def user_not_authorized + redirect_back_or_to root_path, + alert: 'You are not authorized to perform this action.', + status: :see_other + end end diff --git a/app/javascript/controllers/public_stat_map_controller.js b/app/javascript/controllers/public_stat_map_controller.js index 361223c1..a6a534fd 100644 --- a/app/javascript/controllers/public_stat_map_controller.js +++ b/app/javascript/controllers/public_stat_map_controller.js @@ -1,18 +1,22 @@ -import { Controller } from "@hotwired/stimulus"; import L from "leaflet"; import { createHexagonGrid } from "../maps/hexagon_grid"; +import { createAllMapLayers } from "../maps/layers"; +import BaseController from "./base_controller"; -export default class extends Controller { +export default class extends BaseController { static targets = ["container"]; static values = { year: Number, month: Number, uuid: String, - dataBounds: Object + dataBounds: Object, + selfHosted: String }; connect() { + super.connect(); console.log('🏁 Controller connected - loading overlay should be visible'); + this.selfHosted = this.selfHostedValue || 'false'; this.initializeMap(); this.loadHexagons(); } @@ -37,14 +41,36 @@ export default class extends Controller { keyboard: false }); - // Add tile layer + // Add dynamic tile layer based on self-hosted setting + this.addMapLayers(); + + // Default view + this.map.setView([40.0, -100.0], 4); + } + + addMapLayers() { + try { + // Use appropriate default layer based on self-hosted mode + const selectedLayerName = this.selfHosted === "true" ? "OpenStreetMap" : "Light"; + const maps = createAllMapLayers(this.map, selectedLayerName, this.selfHosted); + + // If no layers were created, fall back to OSM + if (Object.keys(maps).length === 0) { + console.warn('No map layers available, falling back to OSM'); + this.addFallbackOSMLayer(); + } + } catch (error) { + console.error('Error creating map layers:', error); + console.log('Falling back to OSM tile layer'); + this.addFallbackOSMLayer(); + } + } + + addFallbackOSMLayer() { L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors', maxZoom: 15 }).addTo(this.map); - - // Default view - this.map.setView([40.0, -100.0], 4); } async loadHexagons() { diff --git a/app/javascript/controllers/stat_page_controller.js b/app/javascript/controllers/stat_page_controller.js index fbcc14e5..97b54b24 100644 --- a/app/javascript/controllers/stat_page_controller.js +++ b/app/javascript/controllers/stat_page_controller.js @@ -1,17 +1,20 @@ -import { Controller } from "@hotwired/stimulus"; import L from "leaflet"; import "leaflet.heat"; +import { createAllMapLayers } from "../maps/layers"; +import BaseController from "./base_controller"; -export default class extends Controller { +export default class extends BaseController { static targets = ["map", "loading", "heatmapBtn", "pointsBtn"]; connect() { + super.connect(); console.log("StatPage controller connected"); // Get data attributes from the element (will be passed from the view) this.year = parseInt(this.element.dataset.year || new Date().getFullYear()); this.month = parseInt(this.element.dataset.month || new Date().getMonth() + 1); this.apiKey = this.element.dataset.apiKey; + this.selfHosted = this.element.dataset.selfHosted || this.selfHostedValue; console.log(`Loading data for ${this.month}/${this.year} with API key: ${this.apiKey ? 'present' : 'missing'}`); @@ -46,11 +49,8 @@ export default class extends Controller { touchZoom: true }).setView([52.520008, 13.404954], 10); // Default to Berlin - // Add tile layer - L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { - maxZoom: 19, - attribution: '© OpenStreetMap contributors' - }).addTo(this.map); + // Add dynamic tile layer based on self-hosted setting + this.addMapLayers(); // Add small scale control L.control.scale({ @@ -259,4 +259,29 @@ export default class extends Controller { this.loadingTarget.style.display = 'flex'; } } + + addMapLayers() { + try { + // Use appropriate default layer based on self-hosted mode + const selectedLayerName = this.selfHosted === "true" ? "OpenStreetMap" : "Light"; + const maps = createAllMapLayers(this.map, selectedLayerName, this.selfHosted); + + // If no layers were created, fall back to OSM + if (Object.keys(maps).length === 0) { + console.warn('No map layers available, falling back to OSM'); + this.addFallbackOSMLayer(); + } + } catch (error) { + console.error('Error creating map layers:', error); + console.log('Falling back to OSM tile layer'); + this.addFallbackOSMLayer(); + } + } + + addFallbackOSMLayer() { + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: '© OpenStreetMap contributors' + }).addTo(this.map); + } } diff --git a/app/views/devise/registrations/_api_key.html.erb b/app/views/devise/registrations/_api_key.html.erb index aeba5bfd..37daa7fd 100644 --- a/app/views/devise/registrations/_api_key.html.erb +++ b/app/views/devise/registrations/_api_key.html.erb @@ -2,12 +2,10 @@
Use this API key to authenticate your requests.
<%= current_user.api_key %>
- <% if ENV['QR_CODE_ENABLED'] == 'true' %>
- - Or you can scan it in your Dawarich iOS app: - <%= api_key_qr_code(current_user) %> -
- <% end %> ++ Or you can scan it in your Dawarich iOS app: + <%= api_key_qr_code(current_user) %> +
Docs: <%= link_to "API documentation", '/api-docs', class: 'underline hover:no-underline' %>
diff --git a/app/views/stats/_month.html.erb b/app/views/stats/_month.html.erb index 8c0760e7..006ae123 100644 --- a/app/views/stats/_month.html.erb +++ b/app/views/stats/_month.html.erb @@ -55,7 +55,8 @@ data-controller="stat-page" data-api-key="<%= current_user.api_key %>" data-year="<%= year %>" - data-month="<%= month %>"> + data-month="<%= month %>" + data-self-hosted="<%= @self_hosted %>">