Keep popups open/refreshed, rename app
This commit is contained in:
parent
e5ba61c71c
commit
7b332f873a
@ -1,4 +1,4 @@
|
|||||||
# Water Station Tracker
|
# CoolingStations.org Water Station Tracker
|
||||||
|
|
||||||
A mobile-first web application for tracking water refill stations with social login, real-time status updates, and interactive mapping.
|
A mobile-first web application for tracking water refill stations with social login, real-time status updates, and interactive mapping.
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<title>Select City - Water Station Tracker</title>
|
<title>Select City - CoolingStations.org</title>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<title>Dashboard - Water Station Tracker</title>
|
<title>Dashboard - CoolingStations.org</title>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
@ -561,6 +561,38 @@
|
|||||||
window.openEditModal = openEditModal;
|
window.openEditModal = openEditModal;
|
||||||
window.deleteStation = deleteStation;
|
window.deleteStation = deleteStation;
|
||||||
|
|
||||||
|
// Consolidated station management functions
|
||||||
|
let activePopup = null;
|
||||||
|
let activeStationId = null;
|
||||||
|
let stationMarkers = new Map(); // Map station ID to marker
|
||||||
|
|
||||||
|
function clearMapMarkers() {
|
||||||
|
map.eachLayer(function (layer) {
|
||||||
|
if (layer instanceof L.CircleMarker) {
|
||||||
|
map.removeLayer(layer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stationMarkers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshStationsAndKeepPopup(keepPopupOpen = false) {
|
||||||
|
const stationIdToReopen = keepPopupOpen ? activeStationId : null;
|
||||||
|
clearMapMarkers();
|
||||||
|
loadStations().then(() => {
|
||||||
|
if (stationIdToReopen && stationMarkers.has(stationIdToReopen)) {
|
||||||
|
// Reopen the popup for the specific station
|
||||||
|
setTimeout(() => {
|
||||||
|
const marker = stationMarkers.get(stationIdToReopen);
|
||||||
|
if (marker) {
|
||||||
|
marker.openPopup();
|
||||||
|
activePopup = marker.getPopup();
|
||||||
|
activeStationId = stationIdToReopen;
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function loadStations() {
|
async function loadStations() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/cities/${currentCity}/stations`);
|
const response = await fetch(`/api/cities/${currentCity}/stations`);
|
||||||
@ -621,6 +653,22 @@
|
|||||||
|
|
||||||
const popupContent = createPopupContent(station);
|
const popupContent = createPopupContent(station);
|
||||||
marker.bindPopup(popupContent);
|
marker.bindPopup(popupContent);
|
||||||
|
|
||||||
|
// Store marker in the map with station ID as key
|
||||||
|
stationMarkers.set(station.id, marker);
|
||||||
|
|
||||||
|
// Track popup open/close events
|
||||||
|
marker.on('popupopen', function(e) {
|
||||||
|
activePopup = e.popup;
|
||||||
|
activeStationId = station.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
marker.on('popupclose', function(e) {
|
||||||
|
if (activePopup === e.popup) {
|
||||||
|
activePopup = null;
|
||||||
|
activeStationId = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,9 +681,9 @@
|
|||||||
<h3>${station.name}</h3>
|
<h3>${station.name}</h3>
|
||||||
<p style="color: #666; font-size: 0.9rem; margin-bottom: 10px;">${station.description || 'No description'}</p>
|
<p style="color: #666; font-size: 0.9rem; margin-bottom: 10px;">${station.description || 'No description'}</p>
|
||||||
<p><strong>Status:</strong> ${station.latest_description || 'No status update'}</p>
|
<p><strong>Status:</strong> ${station.latest_description || 'No status update'}</p>
|
||||||
<p><strong>Last Refill:</strong> ${refillTime}</p>
|
<p><strong>Status As Of:</strong> ${refillTime}</p>
|
||||||
<p><strong>Estimated Empty:</strong> ${estimatedEmpty}</p>
|
<p><strong>Estimated Empty:</strong> ${estimatedEmpty}</p>
|
||||||
<p><strong>Last Updated By:</strong> ${station.updated_by_name || 'Unknown'}</p>
|
<p><strong>Status Update By:</strong> ${station.updated_by_name || 'Unknown'}</p>
|
||||||
<div style="margin-top: 10px;">
|
<div style="margin-top: 10px;">
|
||||||
<button class="popup-btn" onclick="openEditModal(${station.id})">Edit Station</button>
|
<button class="popup-btn" onclick="openEditModal(${station.id})">Edit Station</button>
|
||||||
<button class="popup-btn" onclick="openUpdateModal(${station.id})">Update Status</button>
|
<button class="popup-btn" onclick="openUpdateModal(${station.id})">Update Status</button>
|
||||||
@ -650,6 +698,7 @@
|
|||||||
if (!station) return;
|
if (!station) return;
|
||||||
|
|
||||||
selectedStation = station;
|
selectedStation = station;
|
||||||
|
activeStationId = stationId; // Track which station we're updating
|
||||||
document.getElementById('updateModal').style.display = 'block';
|
document.getElementById('updateModal').style.display = 'block';
|
||||||
|
|
||||||
// Set current date/time as default
|
// Set current date/time as default
|
||||||
@ -695,6 +744,7 @@
|
|||||||
if (!station) return;
|
if (!station) return;
|
||||||
|
|
||||||
selectedStation = station;
|
selectedStation = station;
|
||||||
|
activeStationId = stationId; // Track which station we're editing
|
||||||
document.getElementById('editModal').style.display = 'block';
|
document.getElementById('editModal').style.display = 'block';
|
||||||
document.getElementById('editStationName').value = station.name;
|
document.getElementById('editStationName').value = station.name;
|
||||||
document.getElementById('editStationDescription').value = station.description || '';
|
document.getElementById('editStationDescription').value = station.description || '';
|
||||||
@ -727,7 +777,7 @@
|
|||||||
showMessage('edit-message', 'Station deleted successfully!');
|
showMessage('edit-message', 'Station deleted successfully!');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
closeEditModal();
|
closeEditModal();
|
||||||
loadStations();
|
refreshStationsAndKeepPopup(false);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
showMessage('edit-message', result.error || 'Failed to delete station', 'error');
|
showMessage('edit-message', result.error || 'Failed to delete station', 'error');
|
||||||
@ -822,7 +872,7 @@
|
|||||||
showMessage('add-message', 'Station added successfully!');
|
showMessage('add-message', 'Station added successfully!');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
closeAddModal();
|
closeAddModal();
|
||||||
loadStations();
|
refreshStationsAndKeepPopup(false);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
@ -861,7 +911,7 @@
|
|||||||
showMessage('update-message', 'Station updated successfully!');
|
showMessage('update-message', 'Station updated successfully!');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
closeUpdateModal();
|
closeUpdateModal();
|
||||||
loadStations();
|
refreshStationsAndKeepPopup(true);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
@ -899,7 +949,7 @@
|
|||||||
showMessage('edit-message', 'Station updated successfully!');
|
showMessage('edit-message', 'Station updated successfully!');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
closeEditModal();
|
closeEditModal();
|
||||||
loadStations();
|
refreshStationsAndKeepPopup(true);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<title>Water Station Tracker</title>
|
<title>CoolingStations.org</title>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
@ -132,7 +132,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>💧 Water Stations</h1>
|
<h1>💧 CoolingStations.org</h1>
|
||||||
<p id="cityName">Loading...</p>
|
<p id="cityName">Loading...</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -347,7 +347,7 @@
|
|||||||
<p style="color: #666; font-size: 0.9rem; margin-bottom: 10px;">${station.description || 'No description'}</p>
|
<p style="color: #666; font-size: 0.9rem; margin-bottom: 10px;">${station.description || 'No description'}</p>
|
||||||
<div class="station-info">
|
<div class="station-info">
|
||||||
<p><strong>Status:</strong> ${station.latest_description || 'No status update'}</p>
|
<p><strong>Status:</strong> ${station.latest_description || 'No status update'}</p>
|
||||||
<p><strong>Last Refill:</strong> ${refillTime}</p>
|
<p><strong>Status As Of:</strong> ${refillTime}</p>
|
||||||
<p><strong>Estimated Empty:</strong> ${estimatedEmpty}</p>
|
<p><strong>Estimated Empty:</strong> ${estimatedEmpty}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<title>Login - Water Station Tracker</title>
|
<title>Login - CoolingStations.org</title>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -190,8 +190,8 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="login-container">
|
<div class="login-container">
|
||||||
<div class="login-header">
|
<div class="login-header">
|
||||||
<h1>💧 Water Station Tracker</h1>
|
<h1>💧 CoolingStations.org</h1>
|
||||||
<p>Login to manage water stations</p>
|
<p>Login to manage water station status</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="login-form">
|
<div id="login-form">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user