Show QR code by default and use map tiles based on self-hosted setting

This commit is contained in:
Eugene Burmakin 2025-09-13 11:58:50 +02:00
parent e583a8fb52
commit cc1fecfd22
9 changed files with 90 additions and 25 deletions

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-flower-icon lucide-flower"><circle cx="12" cy="12" r="3"/><path d="M12 16.5A4.5 4.5 0 1 1 7.5 12 4.5 4.5 0 1 1 12 7.5a4.5 4.5 0 1 1 4.5 4.5 4.5 4.5 0 1 1-4.5 4.5"/><path d="M12 7.5V9"/><path d="M7.5 12H9"/><path d="M16.5 12H15"/><path d="M12 16.5V15"/><path d="m8 8 1.88 1.88"/><path d="M14.12 9.88 16 8"/><path d="m8 16 1.88-1.88"/><path d="M14.12 14.12 16 16"/></svg>

After

Width:  |  Height:  |  Size: 572 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-leaf-icon lucide-leaf"><path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z"/><path d="M2 21c0-3 1.85-5.36 5.08-6C9.5 14.52 12 13 13 12"/></svg>

After

Width:  |  Height:  |  Size: 384 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tree-palm-icon lucide-tree-palm"><path d="M13 8c0-2.76-2.46-5-5.5-5S2 5.24 2 8h2l1-1 1 1h4"/><path d="M13 7.14A5.82 5.82 0 0 1 16.5 6c3.04 0 5.5 2.24 5.5 5h-3l-1-1-1 1h-3"/><path d="M5.89 9.71c-2.15 2.15-2.3 5.47-.35 7.43l4.24-4.25.7-.7.71-.71 2.12-2.12c-1.95-1.96-5.27-1.8-7.42.35"/><path d="M11 15.5c.5 2.5-.17 4.5-1 6.5h4c2-5.5-.5-12-1-14"/></svg>

After

Width:  |  Height:  |  Size: 553 B

View file

@ -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

View file

@ -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() {

View file

@ -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);
}
}

View file

@ -2,12 +2,10 @@
<p class='py-2'>Use this API key to authenticate your requests.</p>
<code><%= current_user.api_key %></code>
<% if ENV['QR_CODE_ENABLED'] == 'true' %>
<p class='py-2'>
Or you can scan it in your Dawarich iOS app:
<%= api_key_qr_code(current_user) %>
</p>
<% end %>
<p class='py-2'>
Or you can scan it in your Dawarich iOS app:
<%= api_key_qr_code(current_user) %>
</p>
<p class='py-2'>
<p>Docs: <%= link_to "API documentation", '/api-docs', class: 'underline hover:no-underline' %></p>

View file

@ -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 %>">
<div class="card-body">
<div class="flex justify-between items-center mb-4">
<h2 class="card-title">

View file

@ -19,6 +19,9 @@
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<!-- ProtomapsL for vector tiles -->
<script src="https://unpkg.com/protomaps-leaflet@5.0.0/dist/protomaps-leaflet.js"></script>
</head>
<body data-theme="dark">
<div class="min-h-screen bg-base-100 mx-auto">
@ -74,7 +77,8 @@
data-public-stat-map-year-value="<%= @year %>"
data-public-stat-map-month-value="<%= @month %>"
data-public-stat-map-uuid-value="<%= @stat.sharing_uuid %>"
data-public-stat-map-data-bounds-value="<%= @data_bounds.to_json if @data_bounds %>"></div>
data-public-stat-map-data-bounds-value="<%= @data_bounds.to_json if @data_bounds %>"
data-public-stat-map-self-hosted-value="<%= @self_hosted %>"></div>
<!-- Loading overlay -->
<div id="map-loading" class="absolute inset-0 bg-base-200 bg-opacity-80 flex items-center justify-center z-50">