Mise à jour

This commit is contained in:
2026-06-03 14:47:35 +02:00
parent 085cf33114
commit ad0d86e734
16 changed files with 669 additions and 889 deletions

View File

@@ -1,14 +1,3 @@
/**
* ============================================
* ADMIN.JS - Panel d'administration
* Smart Parking v3.0
* CORRIGÉ :
* - Suppression du graphique d'occupation
* - Historique affiche la date complète
* (jour + mois + année + heure + minute)
* ============================================
*/
document.addEventListener('DOMContentLoaded', () => {
console.log('⚙️ Initialisation du panel admin...');
if (!isAdmin()) return;
@@ -27,7 +16,6 @@ function initAdminPanel() {
loadReservationsTable();
loadHistoryLog();
// Rafraîchissement périodique toutes les 10 secondes
setInterval(() => {
loadAdminStats();
loadReservationsTable();
@@ -35,9 +23,6 @@ function initAdminPanel() {
}, 10000);
}
// ============================================
// STATISTIQUES ADMIN
// ============================================
function loadAdminStats() {
const users = JSON.parse(localStorage.getItem('smart_parking_users') || '[]');
@@ -62,21 +47,44 @@ function loadAdminStats() {
document.getElementById('adminOccupancyRate').textContent = occupancyRate + '%';
}
// ============================================
// GESTION DES PLACES
// ============================================
function initPlacesControl() {
const spots = JSON.parse(localStorage.getItem('smart_parking_spots') || '[]');
const spotsInput = document.getElementById('adminTotalSpots');
if (spotsInput) spotsInput.value = spots.length || 10;
document.getElementById('updateSpotsBtn')?.addEventListener('click', () => {
document.getElementById('updateSpotsBtn')?.addEventListener('click', async () => {
const newCount = parseInt(document.getElementById('adminTotalSpots').value);
if (newCount < 5 || newCount > 50) {
Dashboard.showToast('Le nombre de places doit être entre 5 et 50', 'error');
if (newCount < 1 || newCount > 20) {
Dashboard.showToast('Le nombre de places doit être entre 1 et 20', 'error');
return;
}
const token = localStorage.getItem('smart_parking_token');
if (token) {
try {
const response = await fetch('/api/spots/init', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify({ count: newCount })
});
const data = await response.json();
if (data.success) {
if (window.ParkingMap) await window.ParkingMap.refresh();
renderAdminPlacesList();
Dashboard.showToast('Nombre de places mis à jour', 'success');
return;
}
} catch (_err) { /* fallback local */ }
}
if (window.ParkingMap) {
window.ParkingMap.setTotalSpots(newCount);
renderAdminPlacesList();
@@ -104,27 +112,48 @@ function renderAdminPlacesList() {
`).join('');
}
function toggleSpotStatus(spotId) {
async function toggleSpotStatus(spotId) {
const spots = JSON.parse(localStorage.getItem('smart_parking_spots') || '[]');
const spot = spots.find(s => s.id === spotId);
if (!spot) return;
const cycle = ['free', 'occupied', 'reserved'];
const nextStatus = cycle[(cycle.indexOf(spot.status) + 1) % cycle.length];
spot.status = nextStatus;
spot.lastUpdate = new Date().toISOString();
const cycle = ['free', 'occupied', 'reserved'];
const nextStatus = cycle[(cycle.indexOf(spot.status) + 1) % cycle.length];
const token = localStorage.getItem('smart_parking_token');
if (token) {
try {
const response = await fetch(`/api/spots/${spot.id}/status`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify({ status: nextStatus })
});
const data = await response.json();
if (!data.success) {
Dashboard.showToast('Erreur : ' + data.message, 'error');
return;
}
} catch (_err) {
console.warn('⚠️ API indisponible, modification locale uniquement');
}
}
spot.status = nextStatus;
spot.lastUpdate = new Date().toISOString();
localStorage.setItem('smart_parking_spots', JSON.stringify(spots));
renderAdminPlacesList();
if (window.ParkingMap) window.ParkingMap.refresh();
loadAdminStats();
Dashboard.showToast(`Place ${spot.number} ${getStatusLabel(nextStatus)}`, 'success');
Dashboard.showToast(`Place ${spot.number} ${getStatusLabel(nextStatus)}`, 'success');
}
// ============================================
// TABLEAU UTILISATEURS
// ============================================
function loadUsersTable() {
const tbody = document.getElementById('adminUsersTable');
@@ -176,9 +205,7 @@ function deleteUser(userId) {
Dashboard.showToast('Utilisateur supprimé', 'success');
}
// ============================================
// TABLEAU RÉSERVATIONS
// ============================================
function loadReservationsTable() {
const tbody = document.getElementById('adminReservationsTable');
@@ -218,11 +245,22 @@ function loadReservationsTable() {
`).join('');
}
function completeReservation(reservationId) {
async function completeReservation(reservationId) {
let reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]');
const reservation = reservations.find(r => r.id === reservationId);
if (!reservation) return;
const token = localStorage.getItem('smart_parking_token');
if (token) {
try {
await fetch(`/api/reservations/${reservationId}/complete`, {
method: 'PUT',
headers: { 'Authorization': 'Bearer ' + token }
});
} catch (_err) { /* fallback local */ }
}
reservation.status = 'completed';
localStorage.setItem('smart_parking_reservations', JSON.stringify(reservations));
@@ -233,13 +271,24 @@ function completeReservation(reservationId) {
Dashboard.showToast('Réservation terminée', 'success');
}
function adminCancelReservation(reservationId) {
async function adminCancelReservation(reservationId) {
if (!confirm('Êtes-vous sûr de vouloir annuler cette réservation ?')) return;
let reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]');
const reservation = reservations.find(r => r.id === reservationId);
if (!reservation) return;
// Appeler l'API
const token = localStorage.getItem('smart_parking_token');
if (token) {
try {
await fetch(`/api/reservations/${reservationId}/cancel`, {
method: 'PUT',
headers: { 'Authorization': 'Bearer ' + token }
});
} catch (_err) { /* fallback local */ }
}
reservation.status = 'cancelled';
localStorage.setItem('smart_parking_reservations', JSON.stringify(reservations));
@@ -250,9 +299,6 @@ function adminCancelReservation(reservationId) {
Dashboard.showToast('Réservation annulée', 'success');
}
// ============================================
// HISTORIQUE — CORRIGÉ : date complète
// ============================================
function loadHistoryLog() {
const container = document.getElementById('adminLogContainer');
@@ -273,15 +319,8 @@ function loadHistoryLog() {
`).join('');
}
// ============================================
// FONCTIONS DE FORMAT DATE
// ============================================
/**
* CORRIGÉ — Affiche la date complète dans l'historique
* Avant : seulement "14:32"
* Après : "12/06/2025 à 14:32"
*/
function formatDateComplete(dateString) {
if (!dateString) return 'N/A';
const date = new Date(dateString);
@@ -312,9 +351,6 @@ function getStatusLabel(status) {
}[status] || status;
}
// ============================================
// EXPORT
// ============================================
window.AdminModule = {
refresh: () => {