document.addEventListener('DOMContentLoaded', () => { console.log('⚙️ Initialisation du panel admin...'); if (!isAdmin()) return; initAdminPanel(); }); function isAdmin() { const user = JSON.parse(localStorage.getItem('smart_parking_user') || 'null'); return user && user.role === 'admin'; } function initAdminPanel() { loadAdminStats(); initPlacesControl(); loadUsersTable(); loadReservationsTable(); loadHistoryLog(); setInterval(() => { loadAdminStats(); loadReservationsTable(); loadHistoryLog(); }, 10000); } function loadAdminStats() { const users = JSON.parse(localStorage.getItem('smart_parking_users') || '[]'); const reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]'); const spots = JSON.parse(localStorage.getItem('smart_parking_spots') || '[]'); const totalUsers = users.length + 1; const totalReservations = reservations.length; const totalRevenue = reservations .filter(r => r.status === 'active' || r.status === 'completed') .reduce((sum, r) => sum + (r.price || 0), 0); const occupied = spots.filter(s => s.status === 'occupied').length; const reserved = spots.filter(s => s.status === 'reserved').length; const occupancyRate = spots.length > 0 ? Math.round(((occupied + reserved) / spots.length) * 100) : 0; document.getElementById('adminTotalUsers').textContent = totalUsers; document.getElementById('adminTotalReservations').textContent = totalReservations; document.getElementById('adminTotalRevenue').textContent = totalRevenue + '€'; document.getElementById('adminOccupancyRate').textContent = occupancyRate + '%'; } 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', async () => { const newCount = parseInt(document.getElementById('adminTotalSpots').value); 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(); Dashboard.showToast('Nombre de places mis à jour', 'success'); } }); renderAdminPlacesList(); } function renderAdminPlacesList() { const container = document.getElementById('adminPlacesList'); if (!container) return; const spots = JSON.parse(localStorage.getItem('smart_parking_spots') || '[]'); container.innerHTML = spots.map(spot => `
${spot.number}
`).join(''); } 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]; 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'); } function loadUsersTable() { const tbody = document.getElementById('adminUsersTable'); if (!tbody) return; const users = JSON.parse(localStorage.getItem('smart_parking_users') || '[]'); const allUsers = [ { id: 0, name: 'Administrateur', email: 'admin@smartparking.fr', phone: '01 23 45 67 89', role: 'admin' }, ...users ]; tbody.innerHTML = allUsers.map(user => ` #${user.id} ${user.name} ${user.email} ${user.phone || '-'} ${user.role === 'admin' ? 'Admin' : 'Client'}
${user.role !== 'admin' ? ` ` : '-'}
`).join(''); } function deleteUser(userId) { if (!confirm('Êtes-vous sûr de vouloir supprimer cet utilisateur ?')) return; let users = JSON.parse(localStorage.getItem('smart_parking_users') || '[]'); users = users.filter(u => u.id !== userId); localStorage.setItem('smart_parking_users', JSON.stringify(users)); let reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]'); reservations = reservations.filter(r => r.userId !== userId); localStorage.setItem('smart_parking_reservations', JSON.stringify(reservations)); loadUsersTable(); loadReservationsTable(); loadAdminStats(); Dashboard.showToast('Utilisateur supprimé', 'success'); } function loadReservationsTable() { const tbody = document.getElementById('adminReservationsTable'); if (!tbody) return; const reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]'); if (reservations.length === 0) { tbody.innerHTML = 'Aucune réservation'; return; } tbody.innerHTML = reservations.slice().reverse().map(res => ` #${res.id} ${res.userName} Place ${res.spotNumber} ${formatDateShort(res.date)} ${res.startTime} - ${res.endTime} ${res.price}€ ${getStatusLabel(res.status)}
${res.status === 'active' ? ` ` : '-'}
`).join(''); } 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)); if (window.ParkingMap) window.ParkingMap.setSpotStatus(reservation.spotId, 'free'); loadReservationsTable(); loadAdminStats(); Dashboard.showToast('Réservation terminée', 'success'); } 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)); if (window.ParkingMap) window.ParkingMap.setSpotStatus(reservation.spotId, 'free'); loadReservationsTable(); loadAdminStats(); Dashboard.showToast('Réservation annulée', 'success'); } function loadHistoryLog() { const container = document.getElementById('adminLogContainer'); if (!container) return; const history = JSON.parse(localStorage.getItem('smart_parking_history') || '[]'); if (history.length === 0) { container.innerHTML = '

Aucun historique

'; return; } container.innerHTML = history.slice(0, 50).map(item => `
${formatDateComplete(item.timestamp)} ${item.action} : ${item.details}
`).join(''); } function formatDateComplete(dateString) { if (!dateString) return 'N/A'; const date = new Date(dateString); const jour = String(date.getDate()).padStart(2, '0'); const mois = String(date.getMonth() + 1).padStart(2, '0'); const annee = date.getFullYear(); const heure = String(date.getHours()).padStart(2, '0'); const min = String(date.getMinutes()).padStart(2, '0'); return `${jour}/${mois}/${annee} à ${heure}:${min}`; } function formatDateShort(dateString) { if (!dateString) return 'N/A'; return new Date(dateString).toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit' }); } function getStatusLabel(status) { return { pending: 'En attente', active: 'Active', completed: 'Terminée', cancelled: 'Annulée', free: 'Libre', occupied: 'Occupée', reserved: 'Réservée' }[status] || status; } window.AdminModule = { refresh: () => { loadAdminStats(); renderAdminPlacesList(); loadUsersTable(); loadReservationsTable(); loadHistoryLog(); }, toggleSpotStatus, deleteUser, completeReservation, adminCancelReservation };