mise à jour
This commit is contained in:
190
js/dashboard.js
190
js/dashboard.js
@@ -2,70 +2,48 @@
|
||||
* ============================================
|
||||
* DASHBOARD.JS - Gestion du dashboard
|
||||
* Smart Parking - BTS CIEL IR
|
||||
* CORRIGÉ : cancelReservation utilisait spotNumber
|
||||
* au lieu de spotId pour libérer la place
|
||||
* ============================================
|
||||
*/
|
||||
|
||||
// Configuration
|
||||
const API_URL = 'http://localhost:3000/api';
|
||||
|
||||
// État global
|
||||
let dashboardState = {
|
||||
user: null,
|
||||
user: null,
|
||||
currentPage: 'map'
|
||||
};
|
||||
|
||||
// Initialisation
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
console.log('🚗 Initialisation du dashboard...');
|
||||
|
||||
// Vérifier l'authentification
|
||||
checkAuthentication();
|
||||
|
||||
// Initialiser la navigation
|
||||
initNavigation();
|
||||
|
||||
// Initialiser la déconnexion
|
||||
initLogout();
|
||||
|
||||
// Charger les données utilisateur
|
||||
loadUserData();
|
||||
});
|
||||
|
||||
/**
|
||||
* Vérifie que l'utilisateur est authentifié
|
||||
*/
|
||||
function checkAuthentication() {
|
||||
const token = localStorage.getItem('smart_parking_token');
|
||||
const user = localStorage.getItem('smart_parking_user');
|
||||
|
||||
const user = localStorage.getItem('smart_parking_user');
|
||||
if (!token || !user) {
|
||||
// Rediriger vers la page de connexion
|
||||
window.location.href = '../index.html';
|
||||
return;
|
||||
}
|
||||
|
||||
dashboardState.user = JSON.parse(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise la navigation
|
||||
*/
|
||||
function initNavigation() {
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
|
||||
navLinks.forEach(link => {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
const page = link.getAttribute('data-page');
|
||||
navigateToPage(page);
|
||||
|
||||
// Mettre à jour la classe active
|
||||
navLinks.forEach(l => l.classList.remove('active'));
|
||||
link.classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// Afficher le lien admin si l'utilisateur est admin
|
||||
|
||||
if (dashboardState.user && dashboardState.user.role === 'admin') {
|
||||
const adminLink = document.querySelector('.admin-only');
|
||||
if (adminLink) {
|
||||
@@ -75,25 +53,18 @@ function initNavigation() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigation entre les pages
|
||||
*/
|
||||
function navigateToPage(page) {
|
||||
// Cacher toutes les pages
|
||||
const pages = document.querySelectorAll('.page');
|
||||
pages.forEach(p => {
|
||||
document.querySelectorAll('.page').forEach(p => {
|
||||
p.classList.add('hidden');
|
||||
p.classList.remove('active');
|
||||
});
|
||||
|
||||
// Afficher la page demandée
|
||||
|
||||
const targetPage = document.getElementById(page);
|
||||
if (targetPage) {
|
||||
targetPage.classList.remove('hidden');
|
||||
targetPage.classList.add('active');
|
||||
dashboardState.currentPage = page;
|
||||
|
||||
// Rafraîchir les données selon la page
|
||||
|
||||
if (page === 'map' && window.ParkingMap) {
|
||||
window.ParkingMap.refresh();
|
||||
} else if (page === 'my-reservations') {
|
||||
@@ -104,9 +75,6 @@ function navigateToPage(page) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise la déconnexion
|
||||
*/
|
||||
function initLogout() {
|
||||
const logoutBtn = document.getElementById('logoutBtn');
|
||||
if (logoutBtn) {
|
||||
@@ -118,78 +86,59 @@ function initLogout() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les données utilisateur
|
||||
*/
|
||||
function loadUserData() {
|
||||
const user = dashboardState.user;
|
||||
if (!user) return;
|
||||
|
||||
// Mettre à jour l'affichage
|
||||
|
||||
document.getElementById('userName').textContent = user.name;
|
||||
document.getElementById('userRole').textContent = user.role === 'admin' ? 'Administrateur' : 'Client';
|
||||
|
||||
// Page profil
|
||||
document.getElementById('profileName').textContent = user.name;
|
||||
document.getElementById('profileNameInput').value = user.name;
|
||||
document.getElementById('profileEmailInput').value = user.email;
|
||||
document.getElementById('profilePhoneInput').value = user.phone || '';
|
||||
|
||||
// Badge rôle
|
||||
|
||||
document.getElementById('profileName').textContent = user.name;
|
||||
document.getElementById('profileNameInput').value = user.name;
|
||||
document.getElementById('profileEmailInput').value = user.email;
|
||||
document.getElementById('profilePhoneInput').value = user.phone || '';
|
||||
|
||||
const roleBadge = document.getElementById('profileRole');
|
||||
if (roleBadge) {
|
||||
roleBadge.textContent = user.role === 'admin' ? 'Administrateur' : 'Client';
|
||||
roleBadge.className = 'role-badge ' + (user.role === 'admin' ? 'badge-admin' : 'badge-client');
|
||||
roleBadge.className = 'role-badge ' + (user.role === 'admin' ? 'badge-admin' : 'badge-client');
|
||||
}
|
||||
|
||||
// Charger les statistiques
|
||||
|
||||
loadUserStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les statistiques utilisateur
|
||||
*/
|
||||
function loadUserStats() {
|
||||
const reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]');
|
||||
const reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]');
|
||||
const userReservations = reservations.filter(r => r.userId === dashboardState.user.id);
|
||||
|
||||
const totalReservations = userReservations.length;
|
||||
const activeReservations = userReservations.filter(r => r.status === 'active').length;
|
||||
const totalSpent = userReservations.reduce((sum, r) => sum + (r.price || 0), 0);
|
||||
|
||||
document.getElementById('totalReservations').textContent = totalReservations;
|
||||
document.getElementById('activeReservations').textContent = activeReservations;
|
||||
document.getElementById('totalSpent').textContent = totalSpent + '€';
|
||||
|
||||
document.getElementById('totalReservations').textContent = userReservations.length;
|
||||
document.getElementById('activeReservations').textContent = userReservations.filter(r => r.status === 'active').length;
|
||||
document.getElementById('totalSpent').textContent = userReservations.reduce((s, r) => s + (r.price || 0), 0) + '€';
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les réservations de l'utilisateur
|
||||
*/
|
||||
function loadMyReservations() {
|
||||
const container = document.getElementById('myReservationsList');
|
||||
const container = document.getElementById('myReservationsList');
|
||||
const emptyState = document.getElementById('noReservations');
|
||||
|
||||
if (!container || !emptyState) return;
|
||||
|
||||
const reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]');
|
||||
|
||||
const reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]');
|
||||
const userReservations = reservations.filter(r => r.userId === dashboardState.user.id);
|
||||
|
||||
|
||||
if (userReservations.length === 0) {
|
||||
container.innerHTML = '';
|
||||
emptyState.classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
emptyState.classList.add('hidden');
|
||||
|
||||
container.innerHTML = userReservations.map(res => `
|
||||
container.innerHTML = userReservations.slice().reverse().map(res => `
|
||||
<div class="reservation-card">
|
||||
<div class="reservation-info">
|
||||
<h4>Place ${res.spotNumber}</h4>
|
||||
<div class="reservation-details">
|
||||
<span>📅 ${res.date}</span>
|
||||
<span>🕐 ${res.startTime}</span>
|
||||
<span>⏱️ ${res.duration} min</span>
|
||||
<span>⏱️ ${formatDurationLabel(res.duration)}</span>
|
||||
<span>🚗 ${res.vehicle || 'N/A'}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -207,94 +156,75 @@ function loadMyReservations() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Annule une réservation
|
||||
* CORRIGÉ : utilisait reservation.spotNumber (le numéro visible)
|
||||
* au lieu de reservation.spotId (l'id interne), ce qui empêchait
|
||||
* la place d'être libérée sur la carte.
|
||||
*/
|
||||
function cancelReservation(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) {
|
||||
// Mettre à jour le statut
|
||||
reservation.status = 'cancelled';
|
||||
localStorage.setItem('smart_parking_reservations', JSON.stringify(reservations));
|
||||
|
||||
// Libérer la place
|
||||
|
||||
// CORRIGÉ : spotId au lieu de spotNumber
|
||||
if (window.ParkingMap) {
|
||||
window.ParkingMap.setSpotStatus(reservation.spotNumber, 'free');
|
||||
window.ParkingMap.setSpotStatus(reservation.spotId, 'free');
|
||||
}
|
||||
|
||||
|
||||
showToast('Réservation annulée', 'success');
|
||||
loadMyReservations();
|
||||
loadUserStats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour le profil
|
||||
*/
|
||||
// Mise à jour du profil
|
||||
document.getElementById('profileForm')?.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const phone = document.getElementById('profilePhoneInput').value;
|
||||
const phone = document.getElementById('profilePhoneInput').value;
|
||||
const newPassword = document.getElementById('profileNewPassword').value;
|
||||
|
||||
// Mettre à jour l'utilisateur
|
||||
|
||||
let user = dashboardState.user;
|
||||
user.phone = phone;
|
||||
|
||||
if (newPassword) {
|
||||
user.password = newPassword;
|
||||
}
|
||||
|
||||
// Sauvegarder
|
||||
if (newPassword) user.password = newPassword;
|
||||
|
||||
localStorage.setItem('smart_parking_user', JSON.stringify(user));
|
||||
|
||||
// Mettre à jour aussi dans la liste des utilisateurs
|
||||
|
||||
let users = JSON.parse(localStorage.getItem('smart_parking_users') || '[]');
|
||||
const userIndex = users.findIndex(u => u.id === user.id);
|
||||
if (userIndex !== -1) {
|
||||
users[userIndex] = user;
|
||||
const idx = users.findIndex(u => u.id === user.id);
|
||||
if (idx !== -1) {
|
||||
users[idx] = user;
|
||||
localStorage.setItem('smart_parking_users', JSON.stringify(users));
|
||||
}
|
||||
|
||||
|
||||
showToast('Profil mis à jour', 'success');
|
||||
});
|
||||
|
||||
/**
|
||||
* Retourne le label du statut
|
||||
*/
|
||||
function getStatusLabel(status) {
|
||||
const labels = {
|
||||
'active': 'Active',
|
||||
'completed': 'Terminée',
|
||||
'cancelled': 'Annulée'
|
||||
};
|
||||
return labels[status] || status;
|
||||
return { active: 'Active', completed: 'Terminée', cancelled: 'Annulée' }[status] || status;
|
||||
}
|
||||
|
||||
function formatDurationLabel(minutes) {
|
||||
if (minutes >= 480) return 'Journée';
|
||||
if (minutes >= 60) return Math.floor(minutes / 60) + 'h' + (minutes % 60 ? (minutes % 60) + 'min' : '');
|
||||
return minutes + ' min';
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche une notification toast
|
||||
*/
|
||||
function showToast(message, type = 'info') {
|
||||
const container = document.getElementById('toastContainer');
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.remove();
|
||||
}, 3000);
|
||||
setTimeout(() => toast.remove(), 3000);
|
||||
}
|
||||
|
||||
// Exporter les fonctions
|
||||
window.Dashboard = {
|
||||
navigateToPage,
|
||||
showToast,
|
||||
getUser: () => dashboardState.user,
|
||||
getUser: () => dashboardState.user,
|
||||
refreshStats: loadUserStats
|
||||
};
|
||||
};
|
||||
@@ -2,6 +2,8 @@
|
||||
* ============================================
|
||||
* RESERVATION.JS - Système de réservation
|
||||
* Smart Parking - BTS CIEL IR
|
||||
* MODIFIÉ : Suppression du QR code, remplacement
|
||||
* par une confirmation simple avec badge
|
||||
* ============================================
|
||||
*/
|
||||
|
||||
@@ -33,7 +35,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
initDatePicker();
|
||||
initTimeSlots();
|
||||
initPricePreview();
|
||||
initPaymentModal();
|
||||
initConfirmationModal(); // MODIFIÉ : était initPaymentModal()
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -42,7 +44,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
function initReservationForm() {
|
||||
const form = document.getElementById('reservationForm');
|
||||
if (!form) return;
|
||||
|
||||
form.addEventListener('submit', handleReservationSubmit);
|
||||
}
|
||||
|
||||
@@ -52,8 +53,6 @@ function initReservationForm() {
|
||||
function initDatePicker() {
|
||||
const dateInput = document.getElementById('resDate');
|
||||
if (!dateInput) return;
|
||||
|
||||
// Date minimum = aujourd'hui
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
dateInput.min = today;
|
||||
dateInput.value = today;
|
||||
@@ -65,15 +64,15 @@ function initDatePicker() {
|
||||
function initTimeSlots() {
|
||||
const select = document.getElementById('resStartTime');
|
||||
if (!select) return;
|
||||
|
||||
|
||||
TIME_SLOTS.forEach(time => {
|
||||
const option = document.createElement('option');
|
||||
option.value = time;
|
||||
option.textContent = time;
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
// Sélectionner l'heure actuelle + 1h
|
||||
|
||||
// Sélectionner le prochain créneau disponible
|
||||
const now = new Date();
|
||||
const currentHour = now.getHours();
|
||||
const currentMinutes = now.getMinutes();
|
||||
@@ -81,10 +80,7 @@ function initTimeSlots() {
|
||||
const [h, m] = t.split(':').map(Number);
|
||||
return h > currentHour || (h === currentHour && m > currentMinutes);
|
||||
});
|
||||
|
||||
if (nextSlot) {
|
||||
select.value = nextSlot;
|
||||
}
|
||||
if (nextSlot) select.value = nextSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,10 +89,7 @@ function initTimeSlots() {
|
||||
function initPricePreview() {
|
||||
const durationSelect = document.getElementById('resDuration');
|
||||
if (!durationSelect) return;
|
||||
|
||||
durationSelect.addEventListener('change', updatePricePreview);
|
||||
|
||||
// Prix initial
|
||||
updatePricePreview();
|
||||
}
|
||||
|
||||
@@ -106,246 +99,192 @@ function initPricePreview() {
|
||||
function updatePricePreview() {
|
||||
const duration = parseInt(document.getElementById('resDuration').value);
|
||||
const price = PRICING[duration] || 0;
|
||||
|
||||
document.getElementById('previewPrice').textContent = price + '€';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère la soumission du formulaire
|
||||
* MODIFIÉ : la réservation est enregistrée ici directement,
|
||||
* puis le modal de confirmation s'affiche.
|
||||
*/
|
||||
function handleReservationSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
const user = JSON.parse(localStorage.getItem('smart_parking_user') || 'null');
|
||||
if (!user) {
|
||||
Dashboard.showToast('Veuillez vous connecter', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const spotId = parseInt(document.getElementById('resSpot').value);
|
||||
const date = document.getElementById('resDate').value;
|
||||
|
||||
const spotId = parseInt(document.getElementById('resSpot').value);
|
||||
const date = document.getElementById('resDate').value;
|
||||
const startTime = document.getElementById('resStartTime').value;
|
||||
const duration = parseInt(document.getElementById('resDuration').value);
|
||||
const vehicle = document.getElementById('resVehicle').value;
|
||||
|
||||
const duration = parseInt(document.getElementById('resDuration').value);
|
||||
const vehicle = document.getElementById('resVehicle').value;
|
||||
|
||||
if (!spotId || !date || !startTime || !vehicle) {
|
||||
Dashboard.showToast('Veuillez remplir tous les champs', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Vérifier que la place est toujours libre
|
||||
const spots = JSON.parse(localStorage.getItem('smart_parking_spots') || '[]');
|
||||
const spot = spots.find(s => s.id === spotId);
|
||||
|
||||
const spot = spots.find(s => s.id === spotId);
|
||||
|
||||
if (!spot || spot.status !== 'free') {
|
||||
Dashboard.showToast('Cette place n\'est plus disponible', 'error');
|
||||
// Rafraîchir la carte
|
||||
if (window.ParkingMap) {
|
||||
window.ParkingMap.refresh();
|
||||
}
|
||||
if (window.ParkingMap) window.ParkingMap.refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Calculer l'heure de fin
|
||||
const [hours, minutes] = startTime.split(':').map(Number);
|
||||
const endDate = new Date(date + 'T' + startTime);
|
||||
endDate.setMinutes(endDate.getMinutes() + duration);
|
||||
const endTime = endDate.toTimeString().slice(0, 5);
|
||||
|
||||
// Créer la réservation
|
||||
|
||||
// Construire l'objet réservation
|
||||
currentReservation = {
|
||||
id: Date.now(),
|
||||
userId: user.id,
|
||||
userName: user.name,
|
||||
spotId: spotId,
|
||||
spotNumber: spot.number,
|
||||
date: date,
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
duration: duration,
|
||||
vehicle: vehicle.toUpperCase(),
|
||||
price: PRICING[duration],
|
||||
status: 'pending',
|
||||
createdAt: new Date().toISOString()
|
||||
id: Date.now(),
|
||||
userId: user.id,
|
||||
userName: user.name,
|
||||
spotId: spotId,
|
||||
spotNumber: spot.number,
|
||||
date: date,
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
duration: duration,
|
||||
vehicle: vehicle.toUpperCase(),
|
||||
price: PRICING[duration],
|
||||
status: 'active',
|
||||
createdAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Afficher le modal de paiement
|
||||
showPaymentModal();
|
||||
|
||||
// ---- Enregistrement immédiat (plus de bouton "J'ai payé") ----
|
||||
|
||||
// Sauvegarder la réservation
|
||||
let reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]');
|
||||
reservations.push(currentReservation);
|
||||
localStorage.setItem('smart_parking_reservations', JSON.stringify(reservations));
|
||||
|
||||
// Mettre la place en "réservée" sur la carte
|
||||
if (window.ParkingMap) {
|
||||
window.ParkingMap.setSpotStatus(currentReservation.spotId, 'reserved');
|
||||
}
|
||||
|
||||
// Ajouter à l'historique admin
|
||||
addToHistory(
|
||||
'Réservation',
|
||||
`Place ${currentReservation.spotNumber} réservée par ${currentReservation.userName} - ${currentReservation.price}€`
|
||||
);
|
||||
|
||||
// Réinitialiser le formulaire
|
||||
document.getElementById('reservationForm').reset();
|
||||
initDatePicker();
|
||||
updatePricePreview();
|
||||
|
||||
// Afficher le modal de confirmation
|
||||
showConfirmationModal();
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// MODAL DE CONFIRMATION (remplace le QR code)
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Initialise les événements du modal de confirmation
|
||||
* REMPLACE : initPaymentModal()
|
||||
*/
|
||||
function initConfirmationModal() {
|
||||
document.getElementById('closeConfirmationModal')?.addEventListener('click', hideConfirmationModal);
|
||||
document.getElementById('closeConfirmationBtn')?.addEventListener('click', hideConfirmationModal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise le modal de paiement
|
||||
* Affiche le modal de confirmation
|
||||
* REMPLACE : showPaymentModal() + generateQRCode()
|
||||
*/
|
||||
function initPaymentModal() {
|
||||
// Fermer le modal
|
||||
document.getElementById('closePaymentModal')?.addEventListener('click', hidePaymentModal);
|
||||
document.getElementById('cancelPaymentBtn')?.addEventListener('click', hidePaymentModal);
|
||||
|
||||
// Confirmer le paiement
|
||||
document.getElementById('confirmPaymentBtn')?.addEventListener('click', confirmPayment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche le modal de paiement
|
||||
*/
|
||||
function showPaymentModal() {
|
||||
function showConfirmationModal() {
|
||||
if (!currentReservation) return;
|
||||
|
||||
const modal = document.getElementById('paymentModal');
|
||||
|
||||
|
||||
const modal = document.getElementById('confirmationModal');
|
||||
|
||||
// Remplir le récapitulatif
|
||||
document.getElementById('paySpot').textContent = 'Place ' + currentReservation.spotNumber;
|
||||
document.getElementById('payDate').textContent = formatDate(currentReservation.date);
|
||||
document.getElementById('payTime').textContent = currentReservation.startTime + ' - ' + currentReservation.endTime;
|
||||
document.getElementById('paySpot').textContent = 'Place ' + currentReservation.spotNumber;
|
||||
document.getElementById('payDate').textContent = formatDate(currentReservation.date);
|
||||
document.getElementById('payTime').textContent = currentReservation.startTime + ' - ' + currentReservation.endTime;
|
||||
document.getElementById('payDuration').textContent = formatDuration(currentReservation.duration);
|
||||
document.getElementById('payTotal').textContent = currentReservation.price + '€';
|
||||
|
||||
// Générer le QR code
|
||||
generateQRCode();
|
||||
|
||||
document.getElementById('payTotal').textContent = currentReservation.price + '€';
|
||||
|
||||
// Afficher le modal
|
||||
modal.classList.remove('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache le modal de paiement
|
||||
* Cache le modal de confirmation
|
||||
* REMPLACE : hidePaymentModal()
|
||||
*/
|
||||
function hidePaymentModal() {
|
||||
document.getElementById('paymentModal').classList.add('hidden');
|
||||
}
|
||||
function hideConfirmationModal() {
|
||||
document.getElementById('confirmationModal').classList.add('hidden');
|
||||
|
||||
/**
|
||||
* Génère le QR code
|
||||
*/
|
||||
function generateQRCode() {
|
||||
const container = document.getElementById('qrcode');
|
||||
container.innerHTML = '';
|
||||
|
||||
// Générer un code de paiement unique
|
||||
const paymentCode = 'PARK' + Date.now().toString().slice(-8);
|
||||
document.getElementById('paymentCode').textContent = paymentCode;
|
||||
|
||||
// Créer le QR code
|
||||
const qrData = JSON.stringify({
|
||||
type: 'parking_payment',
|
||||
reservationId: currentReservation.id,
|
||||
amount: currentReservation.price,
|
||||
code: paymentCode
|
||||
});
|
||||
|
||||
// Utiliser QRCode.js si disponible, sinon afficher un faux QR
|
||||
if (typeof QRCode !== 'undefined') {
|
||||
new QRCode(container, {
|
||||
text: qrData,
|
||||
width: 200,
|
||||
height: 200,
|
||||
colorDark: '#000000',
|
||||
colorLight: '#ffffff',
|
||||
correctLevel: QRCode.CorrectLevel.M
|
||||
});
|
||||
} else {
|
||||
// Fallback - afficher un QR code simulé
|
||||
container.innerHTML = `
|
||||
<div style="width: 200px; height: 200px; background: white; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-direction: column;">
|
||||
<div style="font-size: 80px;">📱</div>
|
||||
<div style="color: #333; font-size: 12px; margin-top: 10px;">QR Code de paiement</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirme le paiement
|
||||
*/
|
||||
function confirmPayment() {
|
||||
if (!currentReservation) return;
|
||||
|
||||
// Mettre à jour le statut
|
||||
currentReservation.status = 'active';
|
||||
|
||||
// Sauvegarder la réservation
|
||||
let reservations = JSON.parse(localStorage.getItem('smart_parking_reservations') || '[]');
|
||||
reservations.push(currentReservation);
|
||||
localStorage.setItem('smart_parking_reservations', JSON.stringify(reservations));
|
||||
|
||||
// Mettre à jour le statut de la place
|
||||
if (window.ParkingMap) {
|
||||
window.ParkingMap.setSpotStatus(currentReservation.spotId, 'reserved');
|
||||
}
|
||||
|
||||
// Ajouter à l'historique admin
|
||||
addToHistory('Réservation', `Place ${currentReservation.spotNumber} réservée par ${currentReservation.userName} - ${currentReservation.price}€`);
|
||||
|
||||
// Fermer le modal
|
||||
hidePaymentModal();
|
||||
|
||||
// Réinitialiser le formulaire
|
||||
document.getElementById('reservationForm').reset();
|
||||
initDatePicker();
|
||||
updatePricePreview();
|
||||
|
||||
// Afficher confirmation
|
||||
Dashboard.showToast('Réservation confirmée !', 'success');
|
||||
|
||||
// Rediriger vers mes réservations
|
||||
setTimeout(() => {
|
||||
// Rediriger vers "Mes réservations" après fermeture
|
||||
if (window.Dashboard) {
|
||||
Dashboard.navigateToPage('my-reservations');
|
||||
document.querySelector('[data-page="my-reservations"]').classList.add('active');
|
||||
document.querySelector('[data-page="reservation"]').classList.remove('active');
|
||||
}, 1500);
|
||||
document.querySelector('[data-page="my-reservations"]')?.classList.add('active');
|
||||
document.querySelector('[data-page="reservation"]')?.classList.remove('active');
|
||||
}
|
||||
|
||||
// Rafraîchir les stats du profil
|
||||
if (window.Dashboard) Dashboard.refreshStats();
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// FONCTIONS UTILITAIRES
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Ajoute à l'historique
|
||||
* Ajoute une entrée à l'historique
|
||||
*/
|
||||
function addToHistory(action, details) {
|
||||
let history = JSON.parse(localStorage.getItem('smart_parking_history') || '[]');
|
||||
history.unshift({
|
||||
id: Date.now(),
|
||||
action: action,
|
||||
details: details,
|
||||
id: Date.now(),
|
||||
action: action,
|
||||
details: details,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Garder seulement les 100 dernières entrées
|
||||
if (history.length > 100) {
|
||||
history = history.slice(0, 100);
|
||||
}
|
||||
|
||||
if (history.length > 100) history = history.slice(0, 100);
|
||||
localStorage.setItem('smart_parking_history', JSON.stringify(history));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate une date
|
||||
* Formate une date DD/MM/YYYY
|
||||
*/
|
||||
function formatDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('fr-FR', {
|
||||
day: '2-digit',
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric'
|
||||
year: 'numeric'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate une durée
|
||||
* Formate une durée en minutes vers texte lisible
|
||||
*/
|
||||
function formatDuration(minutes) {
|
||||
if (minutes >= 480) {
|
||||
return 'Journée (8h)';
|
||||
} else if (minutes >= 60) {
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const mins = minutes % 60;
|
||||
return mins > 0 ? `${hours}h ${mins}min` : `${hours}h`;
|
||||
} else {
|
||||
return `${minutes} min`;
|
||||
if (minutes >= 480) return 'Journée (8h)';
|
||||
if (minutes >= 60) {
|
||||
const h = Math.floor(minutes / 60);
|
||||
const m = minutes % 60;
|
||||
return m > 0 ? `${h}h ${m}min` : `${h}h`;
|
||||
}
|
||||
return `${minutes} min`;
|
||||
}
|
||||
|
||||
// Exporter les fonctions
|
||||
// Exporter les fonctions publiques
|
||||
window.Reservation = {
|
||||
PRICING,
|
||||
TIME_SLOTS,
|
||||
formatDuration,
|
||||
addToHistory
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user