SwapStation_WebApp/frontend/js/station_selection.js

370 lines
17 KiB
JavaScript

// document.addEventListener('DOMContentLoaded', () => {
// // --- DOM ELEMENTS ---
// const stationsGrid = document.getElementById('stations-grid');
// const stationTemplate = document.getElementById('stationCardTemplate');
// const errorMessage = document.getElementById('error-message');
// const stationCountEl = document.getElementById('station-count');
// // Note: SocketIO is not needed on this page anymore
// let allStations = []; // To store the master list of stations
// // --- AUTHENTICATION & USER INFO (Your existing code is perfect) ---
// const user = JSON.parse(localStorage.getItem('user'));
// if (!user) {
// window.location.href = 'index.html'; // Redirect if not logged in
// return;
// }
// // User info and logout button logic... (omitted for brevity, no changes needed)
// // --- ADMIN FEATURES (Your existing code is perfect) ---
// // Admin button and add station card logic... (omitted for brevity, no changes needed)
// // --- HELPER FUNCTIONS ---
// const getStatusAttributes = (status) => {
// switch (status) {
// case 'Online': return { color: 'text-green-500', bgColor: 'bg-green-100/60 dark:bg-green-500/10', icon: 'power' };
// case 'Offline': return { color: 'text-red-500', bgColor: 'bg-red-100/60 dark:bg-red-500/10', icon: 'power-off' };
// default: return { color: 'text-gray-500', bgColor: 'bg-gray-100/60 dark:bg-gray-500/10', icon: 'help-circle' };
// }
// };
// const handleStationSelect = (stationId) => {
// window.location.href = `dashboard.html?station_id=${stationId}`;
// };
// // This function now only renders the initial grid
// // const renderStations = (stations) => {
// // stationsGrid.innerHTML = '';
// // stationCountEl.textContent = `${stations.length} stations found. Select one to monitor.`;
// // stations.forEach(station => {
// // const status = getStatusAttributes(station.status);
// // const card = document.createElement('div');
// // card.className = "group bg-gray-900/60 backdrop-blur-xl rounded-2xl shadow-lg border border-gray-700 transition-transform duration-300 ease-out cursor-pointer flex flex-col justify-between hover:-translate-y-1.5 hover:border-emerald-400/60 hover:shadow-[0_0_0_1px_rgba(16,185,129,0.25),0_20px_40px_rgba(0,0,0,0.45)]";
// // card.id = `station-${station.id}`;
// // card.onclick = () => handleStationSelect(station.id);
// // card.innerHTML = `
// // <div class="p-5 flex-grow">
// // <div class="flex justify-between items-start">
// // <h3 class="text-lg font-bold text-white pr-2">${station.name}</h3>
// // <div class="status-badge flex items-center text-xs font-semibold px-3 py-1 rounded-full ${status.bgColor} ${status.color}">
// // <i data-lucide="${status.icon}" class="w-4 h-4 mr-1.5"></i>
// // <span class="status-text">${station.status}</span>
// // </div>
// // </div>
// // <p class="text-sm text-gray-400 mt-1">${station.id}</p>
// // </div>
// // <div class="border-t border-gray-700/50 px-5 py-2 flex justify-end">
// // <button
// // class="remove-btn text-xs font-semibold text-red-500 hover:text-red-400 transition"
// // data-id="${station.id}"
// // data-name="${station.name}"
// // >
// // Remove Station
// // </button>
// // </div>
// // `;
// // stationsGrid.appendChild(card);
// // });
// // lucide.createIcons();
// // };
// const renderStations = (stations) => {
// stationsGrid.innerHTML = '';
// stationCountEl.textContent = `${stations.length} stations found. Select one to monitor.`;
// stations.forEach(station => {
// const status = getStatusAttributes(station.status);
// const card = document.createElement('div');
// card.className = "group bg-gray-900/60 backdrop-blur-xl rounded-2xl shadow-lg border border-gray-700 transition-transform duration-300 ease-out flex flex-col justify-between hover:-translate-y-1.5 hover:border-emerald-400/60 hover:shadow-[0_0_0_1px_rgba(16,185,129,0.25),0_20px_40px_rgba(0,0,0,0.45)]";
// card.id = `station-${station.id}`;
// // --- Make the main card content clickable ---
// const mainContent = document.createElement('div');
// mainContent.className = "p-5 flex-grow cursor-pointer";
// mainContent.onclick = () => handleStationSelect(station.id);
// mainContent.innerHTML = `
// <div class="flex justify-between items-start">
// <h3 class="text-lg font-bold text-white pr-2">${station.name}</h3>
// <div class="status-badge flex items-center text-xs font-semibold px-3 py-1 rounded-full ${status.bgColor} ${status.color}">
// <i data-lucide="${status.icon}" class="w-4 h-4 mr-1.5"></i>
// <span class="status-text">${station.status}</span>
// </div>
// </div>
// <p class="text-sm text-gray-400 mt-1">${station.id}</p>
// `;
// // --- Create the footer with the remove button ---
// const footer = document.createElement('div');
// footer.className = "border-t border-gray-700/50 px-5 py-2 flex justify-end";
// footer.innerHTML = `
// <button
// class="remove-btn text-xs font-semibold text-red-500 hover:text-red-400 transition"
// data-id="${station.id}"
// data-name="${station.name}"
// >
// Remove Station
// </button>
// `;
// card.appendChild(mainContent);
// card.appendChild(footer);
// stationsGrid.appendChild(card);
// });
// lucide.createIcons();
// };
// // --- NEW: Function to update statuses without redrawing everything ---
// const updateStationStatuses = (stations) => {
// stations.forEach(station => {
// const card = document.getElementById(`station-${station.id}`);
// if (card) {
// const status = getStatusAttributes(station.status);
// const statusBadge = card.querySelector('.status-badge');
// const statusText = card.querySelector('.status-text');
// const statusIcon = card.querySelector('i[data-lucide]');
// if (statusBadge && statusText && statusIcon) {
// statusBadge.className = `status-badge flex items-center text-xs font-semibold px-3 py-1 rounded-full ${status.bgColor} ${status.color}`;
// statusText.textContent = station.status;
// statusIcon.setAttribute('data-lucide', status.icon);
// }
// }
// });
// lucide.createIcons(); // Re-render icons if any changed
// };
// // --- DATA FETCHING & STATUS POLLING ---
// const loadAndPollStations = async () => {
// try {
// const response = await fetch('http://192.168.1.12:5000/api/stations');
// if (!response.ok) throw new Error('Failed to fetch stations');
// const stations = await response.json();
// // Check if this is the first time loading data
// if (allStations.length === 0) {
// allStations = stations;
// renderStations(allStations); // Initial full render
// } else {
// allStations = stations;
// updateStationStatuses(allStations); // Subsequent, efficient updates
// }
// } catch (error) {
// console.error(error);
// stationCountEl.textContent = 'Could not load stations. Is the backend running?';
// // Stop polling on error
// if (pollingInterval) clearInterval(pollingInterval);
// }
// };
// // In station_selection.js
// stationsGrid.addEventListener('click', async (event) => {
// const removeButton = event.target.closest('.remove-btn');
// if (!removeButton) return;
// // Stop the click from triggering the card's navigation
// event.stopPropagation();
// const stationId = removeButton.dataset.id;
// const stationName = removeButton.dataset.name;
// if (!confirm(`Are you sure you want to permanently remove "${stationName}"?`)) {
// return;
// }
// try {
// const response = await fetch(`http://192.168.1.12:5000/api/stations/${stationId}`, {
// method: 'DELETE',
// });
// if (response.ok) {
// alert(`Station "${stationName}" removed successfully.`);
// allStations = [];
// loadAndPollStations();
// } else {
// const error = await response.json();
// alert(`Failed to remove station: ${error.message}`);
// }
// } catch (error) {
// console.error('Error removing station:', error);
// alert('An error occurred while trying to remove the station.');
// }
// });
// // --- INITIALIZATION ---
// loadAndPollStations(); // Load immediately on page start
// // Then, set an interval to refresh the statuses every 10 seconds
// const pollingInterval = setInterval(loadAndPollStations, 10000);
// });
document.addEventListener('DOMContentLoaded', () => {
// --- DOM ELEMENTS ---
const stationsGrid = document.getElementById('stations-grid');
const stationCountEl = document.getElementById('station-count'); // Make sure you have an element with this ID in your HTML
// --- CONFIG & STATE ---
const API_BASE = 'http://192.168.1.12:5000/api';
let allStations = []; // Master list of stations from the API
let pollingInterval = null;
// --- AUTHENTICATION ---
const user = JSON.parse(localStorage.getItem('user'));
if (!user) {
window.location.href = 'index.html'; // Redirect if not logged in
return;
}
// (Your other button listeners for logout, add user, etc., can go here)
// document.getElementById('logoutBtn').onclick = () => { ... };
// --- HELPER FUNCTIONS ---
const getStatusAttributes = (status) => {
switch (status) {
case 'Online': return { color: 'text-green-500', bgColor: 'bg-green-100/60 dark:bg-green-500/10', icon: 'power' };
case 'Offline': return { color: 'text-red-500', bgColor: 'bg-red-100/60 dark:bg-red-500/10', icon: 'power-off' };
default: return { color: 'text-gray-500', bgColor: 'bg-gray-100/60 dark:bg-gray-500/10', icon: 'help-circle' };
}
};
const handleStationSelect = (stationId) => {
window.location.href = `dashboard.html?station_id=${stationId}`;
};
// --- UI RENDERING ---
// This function's only job is to build the HTML. It does not add event listeners.
const renderStations = (stations) => {
stationsGrid.innerHTML = ''; // Clear the grid
stationCountEl.textContent = `${stations.length} stations found.`;
stations.forEach(station => {
const status = getStatusAttributes(station.status);
const card = document.createElement('div');
// Add station ID to the card's dataset for easy access
card.dataset.stationId = station.id;
card.dataset.stationName = station.name;
card.className = "group bg-gray-900/60 backdrop-blur-xl rounded-2xl shadow-lg border border-gray-700 transition-transform duration-300 ease-out flex flex-col justify-between hover:-translate-y-1.5 hover:border-emerald-400/60 hover:shadow-[0_0_0_1px_rgba(16,185,129,0.25),0_20px_40px_rgba(0,0,0,0.45)]";
card.innerHTML = `
<div class="main-content p-5 flex-grow cursor-pointer">
<div class="flex justify-between items-start">
<h3 class="text-lg font-bold text-white pr-2">${station.name}</h3>
<div class="status-badge flex items-center text-xs font-semibold px-3 py-1 rounded-full ${status.bgColor} ${status.color}">
<i data-lucide="${status.icon}" class="w-4 h-4 mr-1.5"></i>
<span class="status-text">${station.status}</span>
</div>
</div>
<p class="text-sm text-gray-400 mt-1">${station.id}</p>
</div>
<div class="border-t border-gray-700/50 px-5 py-2 flex justify-end">
<button
class="remove-btn text-xs font-semibold text-red-500 hover:text-red-400 transition"
>
Remove Station
</button>
</div>
`;
stationsGrid.appendChild(card);
});
if (window.lucide) {
lucide.createIcons();
}
};
const updateStationStatuses = (stations) => {
stations.forEach(station => {
const card = stationsGrid.querySelector(`[data-station-id="${station.id}"]`);
if (card) {
const status = getStatusAttributes(station.status);
const statusBadge = card.querySelector('.status-badge');
const statusText = card.querySelector('.status-text');
const statusIcon = card.querySelector('i[data-lucide]');
if (statusBadge && statusText && statusIcon) {
statusBadge.className = `status-badge flex items-center text-xs font-semibold px-3 py-1 rounded-full ${status.bgColor} ${status.color}`;
statusText.textContent = station.status;
statusIcon.setAttribute('data-lucide', status.icon);
}
}
});
if (window.lucide) {
lucide.createIcons();
}
};
// --- MAIN EVENT LISTENER ---
// This single listener handles all clicks on the grid for efficiency.
stationsGrid.addEventListener('click', async (event) => {
const mainContent = event.target.closest('.main-content');
const removeButton = event.target.closest('.remove-btn');
if (mainContent) {
const card = mainContent.closest('[data-station-id]');
if (card) {
handleStationSelect(card.dataset.stationId);
}
} else if (removeButton) {
event.stopPropagation(); // Prevent main content click
const card = removeButton.closest('[data-station-id]');
const stationId = card.dataset.stationId;
const stationName = card.dataset.stationName;
if (!confirm(`Are you sure you want to permanently remove "${stationName}"?`)) {
return;
}
try {
const response = await fetch(`${API_BASE}/stations/${stationId}`, { method: 'DELETE' });
if (response.ok) {
alert(`Station "${stationName}" removed successfully.`);
allStations = []; // Force a full refresh on next poll
loadAndPollStations();
} else {
const error = await response.json();
alert(`Failed to remove station: ${error.message}`);
}
} catch (error) {
console.error('Error removing station:', error);
alert('An error occurred while trying to remove the station.');
}
}
});
// --- DATA FETCHING & POLLING ---
const loadAndPollStations = async () => {
try {
const response = await fetch(`${API_BASE}/stations`);
if (!response.ok) throw new Error('Failed to fetch stations');
const newStationList = await response.json();
// If the number of stations has changed, we must do a full re-render.
if (newStationList.length !== allStations.length) {
allStations = newStationList;
renderStations(allStations);
} else {
// Otherwise, we can do a more efficient status-only update.
allStations = newStationList;
updateStationStatuses(allStations);
}
} catch (error) {
console.error(error);
stationCountEl.textContent = 'Could not load stations. Is the backend running?';
if (pollingInterval) clearInterval(pollingInterval);
}
};
// --- INITIALIZATION ---
loadAndPollStations(); // Load immediately on page start
pollingInterval = setInterval(loadAndPollStations, 10000);
});