Файловый менеджер - Редактировать - /home/gqdcvggs/peerkinton.com/reservation.php
Назад
<?php session_start(); if(!isset($_SESSION['user_id'])) { header("Location: login.php"); exit(); } require_once 'db.php'; $user_id = $_SESSION['user_id']; $sql = "SELECT * FROM users WHERE id = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("i", $user_id); $stmt->execute(); $result = $stmt->get_result(); $user = $result->fetch_assoc(); $sql = "SELECT solde FROM comptes_bancaires WHERE user_id = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("i", $user_id); $stmt->execute(); $result = $stmt->get_result(); $compte = $result->fetch_assoc(); $solde = $compte ? $compte['solde'] : 0; $sql = "SELECT nom, real_distance_between FROM aeroports WHERE statut = 'ouvert' ORDER BY nom"; $result_aeroports = $conn->query($sql); $aeroports_db = []; $aeroports_distances = []; while($row = $result_aeroports->fetch_assoc()) { $aeroports_db[] = $row['nom']; $aeroports_distances[$row['nom']] = floatval($row['real_distance_between']); } $sql = "SELECT nom, ligne, position, statut FROM gares_train ORDER BY ligne, position"; $result_gares = $conn->query($sql); $reseau_gares = []; $statuts_gares = []; $gares_par_nom = []; while($row = $result_gares->fetch_assoc()) { if(!isset($reseau_gares[$row['ligne']])) { $reseau_gares[$row['ligne']] = []; } $reseau_gares[$row['ligne']][] = [ 'nom' => $row['nom'], 'position' => intval($row['position']) ]; if(!isset($gares_par_nom[$row['nom']])) { $gares_par_nom[$row['nom']] = []; } $gares_par_nom[$row['nom']][] = $row['ligne']; $statuts_gares[$row['nom'] . '_' . $row['ligne']] = $row['statut']; } if(isset($_POST['action'])) { switch($_POST['action']) { case 'reserver_train': include 'includes/traitement_reservation_train.php'; break; case 'reserver_avion': include 'includes/traitement_reservation_avion.php'; break; } } $onglet = isset($_GET['tab']) ? $_GET['tab'] : 'train'; ?> <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Réservations - Peerkinton</title> <script src="https://cdn.tailwindcss.com"></script> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600&display=swap" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet"> <style> body { font-family: 'Poppins', sans-serif; } .tab-content { display: none; } .tab-content.active { display: block; } .creneau-card { transition: all 0.2s; } .creneau-card.selected { border-color: #0ea5e9; background-color: #f0f9ff; } .creneau-card.disabled { opacity: 0.5; cursor: not-allowed; } .success-overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.85); z-index: 9999; align-items: center; justify-content: center; animation: fadeIn 0.3s ease-in-out; } .success-overlay.show { display: flex; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes slideUp { from { transform: translateY(30px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes checkmark { 0% { stroke-dashoffset: 100; } 100% { stroke-dashoffset: 0; } } .success-content { animation: slideUp 0.5s ease-out; } .checkmark-circle { stroke-dasharray: 166; stroke-dashoffset: 166; animation: checkmark 0.6s 0.3s ease-out forwards; } .checkmark-check { stroke-dasharray: 48; stroke-dashoffset: 48; animation: checkmark 0.3s 0.6s ease-out forwards; } .gare-step { position: relative; padding-left: 32px; } .gare-step::before { content: ''; position: absolute; left: 11px; top: 24px; bottom: -8px; width: 2px; background: linear-gradient(to bottom, #0ea5e9, #3b82f6); } .gare-step:last-child::before { display: none; } .gare-dot { position: absolute; left: 0; top: 6px; width: 24px; height: 24px; border-radius: 50%; background: white; border: 3px solid #0ea5e9; display: flex; align-items: center; justify-content: center; z-index: 1; } .gare-dot.depart { background: #10b981; border-color: #10b981; } .gare-dot.arrivee { background: #ef4444; border-color: #ef4444; } .gare-dot.correspondance { background: #f59e0b; border-color: #f59e0b; width: 28px; height: 28px; top: 4px; } @media (max-width: 640px) { .gare-step { padding-left: 24px; } .gare-dot { width: 20px; height: 20px; border-width: 2px; } .gare-dot.correspondance { width: 24px; height: 24px; } .gare-step::before { left: 9px; } } </style> <script> tailwind.config = { theme: { extend: { fontFamily: { 'sans': ['Poppins', 'sans-serif'], }, colors: { primary: { 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', 300: '#7dd3fc', 400: '#38bdf8', 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1', 800: '#075985', 900: '#0c4a6e', } } } } } </script> </head> <body class="bg-gray-50 text-gray-900"> <div id="success-overlay" class="success-overlay"> <div class="success-content bg-white rounded-2xl p-8 max-w-md mx-4 text-center shadow-2xl"> <svg class="mx-auto mb-6" width="100" height="100" viewBox="0 0 100 100"> <circle class="checkmark-circle" cx="50" cy="50" r="45" fill="none" stroke="#10b981" stroke-width="4"/> <path class="checkmark-check" fill="none" stroke="#10b981" stroke-width="4" stroke-linecap="round" d="M30 50 L45 65 L70 35"/> </svg> <h2 class="text-2xl md:text-3xl font-bold text-gray-900 mb-3">Réservation confirmée !</h2> <p class="text-gray-600 mb-6 text-sm md:text-base" id="success-message">Ta réservation a été enregistrée avec succès.</p> <button onclick="closeSuccessOverlay()" class="px-6 py-3 bg-primary-600 text-white rounded-lg font-medium hover:bg-primary-700 transition-colors text-sm md:text-base"> Parfait ! </button> </div> </div> <div class="min-h-screen flex flex-col"> <nav class="bg-white shadow-sm"> <div class="max-w-7xl mx-auto px-4 lg:px-8"> <div class="flex justify-between h-16"> <div class="flex items-center gap-4"> <img src="logo.png" alt="Peerkinton Logo" class="h-7 md:h-8"> <a href="dashboard.php" class="flex items-center px-3 py-2 text-gray-700 hover:text-primary-600 transition-colors text-sm md:text-base"> <i class="fas fa-arrow-left mr-2"></i> Retour </a> </div> <div class="flex items-center gap-4"> <span class="text-sm font-medium hidden md:inline"><?php echo htmlspecialchars($user['email']); ?></span> <a href="logout.php" class="text-gray-500 hover:text-gray-700 p-2"> <i class="fas fa-sign-out-alt"></i> </a> </div> </div> </div> </nav> <div class="flex-grow py-6 md:py-8"> <div class="max-w-7xl mx-auto px-4 lg:px-8"> <div class="mb-6 md:mb-8"> <h1 class="text-2xl md:text-3xl font-extralight italic text-gray-900">Bienvenue dans ton centre de réservation.</h1> <p class="mt-2 text-sm md:text-base text-gray-600">Réserve tes billets de train et d'avion</p> </div> <div class="border-b border-gray-200 mb-6 md:mb-8"> <nav class="-mb-px flex gap-8"> <button onclick="showTab('train')" class="tab-link <?php echo $onglet == 'train' ? 'border-primary-500 text-primary-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'; ?> whitespace-nowrap py-4 border-b-2 font-medium text-sm md:text-base"> <i class="fas fa-train mr-2"></i>Train </button> <button onclick="showTab('avion')" class="tab-link <?php echo $onglet == 'avion' ? 'border-primary-500 text-primary-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'; ?> whitespace-nowrap py-4 border-b-2 font-medium text-sm md:text-base"> <i class="fas fa-plane mr-2"></i>Avion </button> <button onclick="showTab('historique')" class="tab-link <?php echo $onglet == 'historique' ? 'border-primary-500 text-primary-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'; ?> whitespace-nowrap py-4 border-b-2 font-medium text-sm md:text-base"> <i class="fas fa-history mr-2"></i>Historique </button> </nav> </div> <div class="tab-content <?php echo $onglet == 'train' ? 'active' : ''; ?>" id="tab-train"> <div class="bg-white shadow-lg rounded-xl border border-gray-100"> <div class="px-6 py-6 md:py-8 bg-gradient-to-br from-blue-500 via-blue-600 to-indigo-700"> <div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-4"> <div class="text-white"> <h3 class="text-xl md:text-2xl font-semibold flex items-center"> <i class="fas fa-train mr-2"></i>Réservation de billet de train </h3> <p class="mt-2 text-sm md:text-base opacity-90"> Ton billet est valable toute la journée jusqu'à minuit. </p> </div> <div class="text-white"> <div class="text-3xl md:text-4xl font-extralight" style="font-family: 'Poppins', sans-serif; font-weight: 200;">TNF</div> <p class="text-xs opacity-80 mt-1">Transport National Ferroviaire</p> </div> </div> </div> <div class="border-t border-gray-200 p-6 md:p-8"> <?php if(isset($train_message)): ?> <div class="mb-6 px-4 py-3 rounded-lg text-sm md:text-base <?php echo $train_success ? 'bg-green-50 text-green-800' : 'bg-red-50 text-red-800'; ?>"> <?php echo $train_message; ?> </div> <?php endif; ?> <form action="" method="POST" class="space-y-6"> <input type="hidden" name="action" value="reserver_train"> <input type="hidden" name="ligne_train" id="ligne_train_input"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div> <label for="gare_depart" class="block text-sm font-medium text-gray-700 mb-2">Gare de départ</label> <select name="gare_depart" id="gare_depart" onchange="calculerItineraire()" class="block w-full border-gray-300 rounded-lg shadow-sm focus:ring-primary-500 focus:border-primary-500 text-sm md:text-base py-3 px-4"> <option value="">Choisis une gare</option> <?php foreach($gares_par_nom as $nom => $lignes) { $lignes_text = implode(', ', $lignes); echo '<option value="' . htmlspecialchars($nom) . '">' . htmlspecialchars($nom) . ' (' . $lignes_text . ')</option>'; } ?> </select> </div> <div> <label for="gare_arrivee" class="block text-sm font-medium text-gray-700 mb-2">Gare d'arrivée</label> <select name="gare_arrivee" id="gare_arrivee" onchange="calculerItineraire()" class="block w-full border-gray-300 rounded-lg shadow-sm focus:ring-primary-500 focus:border-primary-500 text-sm md:text-base py-3 px-4"> <option value="">Choisis une gare</option> <?php foreach($gares_par_nom as $nom => $lignes) { $lignes_text = implode(', ', $lignes); echo '<option value="' . htmlspecialchars($nom) . '">' . htmlspecialchars($nom) . ' (' . $lignes_text . ')</option>'; } ?> </select> </div> </div> <div id="itineraire-section" style="display: none;"> <div class="bg-gradient-to-br from-blue-50 to-indigo-50 border-2 border-blue-200 rounded-xl p-6"> <h4 class="font-semibold text-gray-900 mb-6 flex items-center text-base md:text-lg"> <i class="fas fa-route mr-2 text-primary-600"></i> Ton itinéraire détaillé </h4> <div id="itineraire-details"></div> <div id="temps-trajet" class="mt-6 pt-6 border-t border-blue-200"></div> </div> </div> <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div> <label for="date_voyage_train" class="block text-sm font-medium text-gray-700 mb-2">Date de voyage</label> <input type="date" name="date_voyage_train" id="date_voyage_train" required min="<?php echo date('Y-m-d'); ?>" class="block w-full border-gray-300 rounded-lg shadow-sm focus:ring-primary-500 focus:border-primary-500 text-sm md:text-base py-3 px-4"> </div> <div id="prix-train-section" style="display: none;"> <div class="px-6 py-6 bg-gradient-to-br from-primary-50 to-blue-50 rounded-xl border-2 border-primary-200 h-full flex flex-col justify-center"> <p class="text-sm text-gray-600 font-medium">Prix du billet</p> <p class="text-3xl md:text-4xl font-bold text-primary-700 my-2" id="prix-train-display">0 F&</p> <p class="text-xs text-gray-500">Valable jusqu'à minuit</p> </div> </div> </div> <div> <button type="submit" class="w-full inline-flex justify-center py-4 px-6 border border-transparent shadow-lg text-base font-semibold rounded-lg text-white bg-gradient-to-r from-primary-600 to-blue-600 hover:from-primary-700 hover:to-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-all"> <i class="fas fa-ticket-alt mr-2"></i> Réserver le billet de train </button> </div> </form> </div> </div> </div> <div class="tab-content <?php echo $onglet == 'avion' ? 'active' : ''; ?>" id="tab-avion"> <div class="bg-white shadow-lg rounded-xl border border-gray-100"> <div class="px-6 py-6 md:py-8 bg-gradient-to-br from-sky-500 via-blue-500 to-indigo-600"> <div class="text-white"> <h3 class="text-xl md:text-2xl font-semibold flex items-center"> <i class="fas fa-plane mr-2"></i>Réservation de billet d'avion </h3> <p class="mt-2 text-sm md:text-base opacity-90"> Voyage rapidement entre nos aéroports. </p> </div> </div> <div class="border-t border-gray-200 p-6 md:p-8"> <?php if(isset($avion_message)): ?> <div class="mb-6 px-4 py-3 rounded-lg text-sm md:text-base <?php echo $avion_success ? 'bg-green-50 text-green-800' : 'bg-red-50 text-red-800'; ?>"> <?php echo $avion_message; ?> </div> <?php endif; ?> <form action="" method="POST" class="space-y-6"> <input type="hidden" name="action" value="reserver_avion"> <input type="hidden" name="heure_depart" id="heure_depart_input"> <input type="hidden" name="heure_arrivee" id="heure_arrivee_input"> <input type="hidden" name="prix_vol" id="prix_vol_input"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="relative"> <label for="aeroport_depart" class="block text-sm font-medium text-gray-700 mb-2">Aéroport de départ</label> <input type="text" name="aeroport_depart" id="aeroport_depart" required placeholder="Rechercher un aéroport..." oninput="searchAeroport('depart')" onclick="showSuggestions('depart')" class="block w-full border-gray-300 rounded-lg shadow-sm focus:ring-primary-500 focus:border-primary-500 text-sm md:text-base py-3 px-4" autocomplete="off"> <div id="suggestions-depart" class="absolute z-10 w-full bg-white border border-gray-300 rounded-lg shadow-lg hidden mt-1 max-h-48 overflow-y-auto"></div> </div> <div class="relative"> <label for="aeroport_arrivee" class="block text-sm font-medium text-gray-700 mb-2">Aéroport d'arrivée</label> <input type="text" name="aeroport_arrivee" id="aeroport_arrivee" required placeholder="Rechercher un aéroport..." oninput="searchAeroport('arrivee')" onclick="showSuggestions('arrivee')" class="block w-full border-gray-300 rounded-lg shadow-sm focus:ring-primary-500 focus:border-primary-500 text-sm md:text-base py-3 px-4" autocomplete="off"> <div id="suggestions-arrivee" class="absolute z-10 w-full bg-white border border-gray-300 rounded-lg shadow-lg hidden mt-1 max-h-48 overflow-y-auto"></div> </div> </div> <div> <label for="date_voyage_avion" class="block text-sm font-medium text-gray-700 mb-2">Date de voyage</label> <input type="date" name="date_voyage_avion" id="date_voyage_avion" required min="<?php echo date('Y-m-d'); ?>" onchange="calculerCreneauxAvion()" class="block w-full border-gray-300 rounded-lg shadow-sm focus:ring-primary-500 focus:border-primary-500 text-sm md:text-base py-3 px-4"> </div> <div id="creneaux-section" style="display: none;"> <label class="block text-sm font-medium text-gray-700 mb-4">Choisis ton créneau horaire</label> <div id="creneaux-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"></div> </div> <div> <button type="submit" id="btn-reserver-vol" disabled class="w-full inline-flex justify-center py-4 px-6 border border-transparent shadow-lg text-base font-semibold rounded-lg text-white bg-gray-400 cursor-not-allowed transition-all"> <i class="fas fa-plane mr-2"></i> Réserver le vol </button> </div> </form> </div> </div> </div> <div class="tab-content <?php echo $onglet == 'historique' ? 'active' : ''; ?>" id="tab-historique"> <div class="bg-white shadow-lg rounded-xl border border-gray-100"> <div class="px-6 py-6 md:py-8 bg-gradient-to-br from-gray-700 to-gray-900"> <div class="text-white"> <h3 class="text-xl md:text-2xl font-semibold flex items-center"> <i class="fas fa-history mr-2"></i>Mes réservations </h3> <p class="mt-2 text-sm md:text-base opacity-90"> Historique de toutes tes réservations de transport. </p> </div> </div> <div class="border-t border-gray-200"> <div class="overflow-x-auto"> <table class="min-w-full divide-y divide-gray-200"> <thead class="bg-gray-50"> <tr> <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">ID</th> <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Type</th> <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Trajet</th> <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Date</th> <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Prix</th> <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Statut</th> </tr> </thead> <tbody class="bg-white divide-y divide-gray-200"> <?php $sql = "SELECT * FROM reservations WHERE user_id = ? ORDER BY date_creation DESC"; $stmt = $conn->prepare($sql); $stmt->bind_param("i", $user_id); $stmt->execute(); $result = $stmt->get_result(); if($result->num_rows > 0) { while($reservation = $result->fetch_assoc()) { $type_icon = $reservation['type'] == 'train' ? 'fas fa-train text-blue-600' : 'fas fa-plane text-sky-600'; $type_bg = $reservation['type'] == 'train' ? 'bg-blue-100 text-blue-800' : 'bg-sky-100 text-sky-800'; $trajet = $reservation['type'] == 'train' ? $reservation['gare_depart'] . ' → ' . $reservation['gare_arrivee'] : $reservation['aeroport_depart'] . ' → ' . $reservation['aeroport_arrivee']; echo '<tr class="hover:bg-gray-50">'; echo '<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900">' . $reservation['id_reservation'] . '</td>'; echo '<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">'; echo '<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ' . $type_bg . '">'; echo '<i class="' . $type_icon . ' mr-1"></i>' . ucfirst($reservation['type']); echo '</span>'; echo '</td>'; echo '<td class="px-6 py-4 text-sm text-gray-500">' . $trajet . '</td>'; echo '<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">' . date('d/m/Y', strtotime($reservation['date_voyage'])) . '</td>'; echo '<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">' . number_format($reservation['prix'], 2, ',', ' ') . ' F&</td>'; echo '<td class="px-6 py-4 whitespace-nowrap text-sm">'; if($reservation['statut'] == 'confirme') { echo '<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">'; echo '<i class="fas fa-check mr-1"></i>Confirmé'; echo '</span>'; } else { echo '<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">'; echo '<i class="fas fa-clock mr-1"></i>Attente'; echo '</span>'; } echo '</td>'; echo '</tr>'; } } else { echo '<tr><td colspan="6" class="px-6 py-4 text-sm text-gray-500 text-center">Aucune réservation trouvée</td></tr>'; } ?> </tbody> </table> </div> </div> </div> </div> </div> </div> </div> <script> const reseauGares = <?php echo json_encode($reseau_gares); ?>; const statutsGares = <?php echo json_encode($statuts_gares); ?>; const garesParNom = <?php echo json_encode($gares_par_nom); ?>; const aeroports = <?php echo json_encode($aeroports_db); ?>; const aeroportsDistances = <?php echo json_encode($aeroports_distances); ?>; function showSuccessOverlay(message) { document.getElementById('success-message').textContent = message; document.getElementById('success-overlay').classList.add('show'); } function closeSuccessOverlay() { document.getElementById('success-overlay').classList.remove('show'); } <?php if(isset($train_success) && $train_success): ?> window.addEventListener('load', function() { showSuccessOverlay('Ta réservation de train a été confirmée avec succès !'); }); <?php endif; ?> <?php if(isset($avion_success) && $avion_success): ?> window.addEventListener('load', function() { showSuccessOverlay('Ton vol a été réservé avec succès !'); }); <?php endif; ?> function showTab(tabName) { document.querySelectorAll('.tab-content').forEach(content => { content.classList.remove('active'); }); document.querySelectorAll('.tab-link').forEach(link => { link.classList.remove('border-primary-500', 'text-primary-600'); link.classList.add('border-transparent', 'text-gray-500'); }); document.getElementById('tab-' + tabName).classList.add('active'); event.target.classList.remove('border-transparent', 'text-gray-500'); event.target.classList.add('border-primary-500', 'text-primary-600'); } function trouverGareDansLigne(nomGare, ligne = null) { if(ligne) { for(let gare of reseauGares[ligne]) { if(gare.nom === nomGare) { return {ligne: ligne, position: gare.position}; } } } else { for(let l in reseauGares) { for(let gare of reseauGares[l]) { if(gare.nom === nomGare) { return {ligne: l, position: gare.position}; } } } } return null; } function calculerTempsTrajet(itineraire) { let tempsTotal = 0; itineraire.forEach(segment => { const nbGares = segment.stations - 1; if(segment.ligne === 'GOne') { tempsTotal += nbGares * 15; } else { tempsTotal += nbGares * 5; } }); return tempsTotal; } function afficherTempsTrajet(minutes) { const heures = Math.floor(minutes / 60); const mins = minutes % 60; let texte = ''; if(heures > 0) { texte += heures + 'h'; if(mins > 0) texte += ' ' + mins + 'min'; } else { texte = mins + 'min'; } return texte; } function calculerItineraire() { const depart = document.getElementById('gare_depart').value; const arrivee = document.getElementById('gare_arrivee').value; if(!depart || !arrivee || depart === arrivee) { document.getElementById('itineraire-section').style.display = 'none'; document.getElementById('prix-train-section').style.display = 'none'; return; } const lignesDepart = garesParNom[depart]; const lignesArrivee = garesParNom[arrivee]; if(!lignesDepart || !lignesArrivee) { document.getElementById('itineraire-section').style.display = 'none'; document.getElementById('prix-train-section').style.display = 'none'; return; } let meilleurItineraire = null; let prixMin = Infinity; for(let ligneD of lignesDepart) { for(let ligneA of lignesArrivee) { const infoDepart = trouverGareDansLigne(depart, ligneD); const infoArrivee = trouverGareDansLigne(arrivee, ligneA); if(!infoDepart || !infoArrivee) continue; let itineraire = []; let prix = 0; if(ligneD === ligneA) { const distance = Math.abs(infoArrivee.position - infoDepart.position); prix = distance * 25; const garesLigne = reseauGares[ligneD]; const indexMin = Math.min(infoDepart.position, infoArrivee.position); const indexMax = Math.max(infoDepart.position, infoArrivee.position); let parcours = []; for(let i = indexMin; i <= indexMax; i++) { const gare = garesLigne.find(g => g.position === i); if(gare) { parcours.push(gare.nom); } } itineraire.push({ ligne: ligneD, parcours: parcours, stations: distance + 1, gareCorrespondance: null }); } else { const correspondances = trouverCorrespondance(ligneD, ligneA, depart, arrivee); if(correspondances) { for(let i = 0; i < correspondances.segments.length; i++) { const segment = correspondances.segments[i]; const distance = Math.abs(segment.fin - segment.debut); prix += distance * 25; const garesLigne = reseauGares[segment.ligne]; const indexMin = Math.min(segment.debut, segment.fin); const indexMax = Math.max(segment.debut, segment.fin); let parcours = []; for(let j = indexMin; j <= indexMax; j++) { const gare = garesLigne.find(g => g.position === j); if(gare) { parcours.push(gare.nom); } } itineraire.push({ ligne: segment.ligne, parcours: parcours, stations: distance + 1, gareCorrespondance: i < correspondances.segments.length - 1 ? correspondances.gareCorrespondance : null }); } } } if(itineraire.length > 0 && prix < prixMin) { prixMin = prix; meilleurItineraire = itineraire; } } } if(meilleurItineraire) { const lignesUtilisees = meilleurItineraire.map(seg => seg.ligne); document.getElementById('ligne_train_input').value = lignesUtilisees.join(','); const tempsTotal = calculerTempsTrajet(meilleurItineraire); afficherItineraire(meilleurItineraire, tempsTotal); document.getElementById('prix-train-display').textContent = prixMin.toLocaleString('fr-FR') + ' F&'; document.getElementById('prix-train-section').style.display = 'block'; document.getElementById('itineraire-section').style.display = 'block'; } else { document.getElementById('itineraire-section').style.display = 'none'; document.getElementById('prix-train-section').style.display = 'none'; } } function trouverCorrespondance(ligneDepart, ligneArrivee, gareDepart, gareArrivee) { const garesCommunes = []; for(let gareD of reseauGares[ligneDepart]) { for(let gareA of reseauGares[ligneArrivee]) { if(gareD.nom === gareA.nom) { garesCommunes.push({ nom: gareD.nom, positionDepart: gareD.position, positionArrivee: gareA.position }); } } } if(garesCommunes.length === 0) return null; const infoDepart = trouverGareDansLigne(gareDepart, ligneDepart); const infoArrivee = trouverGareDansLigne(gareArrivee, ligneArrivee); const correspondance = garesCommunes[0]; return { gareCorrespondance: correspondance.nom, segments: [ { ligne: ligneDepart, debut: infoDepart.position, fin: correspondance.positionDepart }, { ligne: ligneArrivee, debut: correspondance.positionArrivee, fin: infoArrivee.position } ] }; } function afficherItineraire(itineraire, tempsTotal) { const detailsDiv = document.getElementById('itineraire-details'); detailsDiv.innerHTML = ''; const lignesUtilisees = itineraire.map(seg => seg.ligne); const utiliseGOne = lignesUtilisees.includes('GOne'); if(utiliseGOne) { const goneAlert = document.createElement('div'); goneAlert.className = 'mb-6 p-4 md:p-5 bg-gradient-to-r from-purple-50 to-pink-50 border-2 border-purple-300 rounded-xl shadow-sm'; goneAlert.innerHTML = ` <div class="flex items-center"> <i class="fas fa-star text-purple-600 mr-2 text-lg"></i> <span class="text-sm md:text-base font-bold text-purple-900">Bienvenue dans la ligne GOne</span> </div> <p class="text-xs md:text-sm text-purple-700 mt-2">Ton trajet emprunte la ligne GOne, notre réseau à grande vitesse en ligne droite jusqu'à Costa Nera !</p> `; detailsDiv.appendChild(goneAlert); } const parcourDiv = document.createElement('div'); parcourDiv.className = 'space-y-4'; itineraire.forEach((segment, indexSegment) => { const ligneInfo = getLigneInfo(segment.ligne); segment.parcours.forEach((gare, indexGare) => { const stepDiv = document.createElement('div'); stepDiv.className = 'gare-step'; const statutKey = gare + '_' + segment.ligne; const statut = statutsGares[statutKey]; const estFermee = statut === 'fermee'; const estDepart = indexSegment === 0 && indexGare === 0; const estArrivee = indexSegment === itineraire.length - 1 && indexGare === segment.parcours.length - 1; const estCorrespondance = segment.gareCorrespondance && gare === segment.gareCorrespondance; let dotClass = 'gare-dot'; let dotContent = ''; if(estDepart) { dotClass += ' depart'; dotContent = '<i class="fas fa-play text-white text-xs"></i>'; } else if(estArrivee) { dotClass += ' arrivee'; dotContent = '<i class="fas fa-flag text-white text-xs"></i>'; } else if(estCorrespondance) { dotClass += ' correspondance'; dotContent = '<i class="fas fa-exchange-alt text-white text-xs"></i>'; } let gareHTML = ` <div class="${dotClass}">${dotContent}</div> <div class="pt-1"> <div class="flex items-center gap-2 flex-wrap"> <span class="inline-block px-2.5 py-1 ${ligneInfo.bgColor} text-white text-xs rounded-md font-semibold shadow-sm">${segment.ligne}</span> <span class="font-semibold text-sm md:text-base ${estFermee ? 'text-red-600 line-through' : 'text-gray-900'}">${gare}</span> ${estFermee ? '<span class="px-2 py-0.5 bg-red-100 text-red-700 rounded text-xs font-medium">❌ Fermée</span>' : ''} </div> `; if(estDepart) { gareHTML += '<p class="text-xs md:text-sm text-green-700 font-medium mt-1"><i class="fas fa-map-marker-alt mr-1"></i>Monte dans le train ici</p>'; } else if(estArrivee) { gareHTML += '<p class="text-xs md:text-sm text-red-700 font-medium mt-1"><i class="fas fa-flag-checkered mr-1"></i>Descends ici - Arrivée</p>'; } else if(estCorrespondance) { const prochaineLigne = itineraire[indexSegment + 1].ligne; const prochaineInfo = getLigneInfo(prochaineLigne); gareHTML += ` <div class="mt-2 p-3 bg-orange-50 border-l-4 border-orange-400 rounded"> <p class="text-xs md:text-sm text-orange-900 font-semibold"><i class="fas fa-exchange-alt mr-1"></i>Changement de train</p> <p class="text-xs text-orange-700 mt-1">Descends du train <span class="font-semibold">${segment.ligne}</span> et prends la <span class="font-semibold">${prochaineLigne}</span> sur le quai ${prochaineInfo.nom}</p> </div> `; } else { gareHTML += '<p class="text-xs text-gray-500 mt-1">Reste dans le train</p>'; } gareHTML += '</div>'; stepDiv.innerHTML = gareHTML; parcourDiv.appendChild(stepDiv); }); }); detailsDiv.appendChild(parcourDiv); const tempsDiv = document.getElementById('temps-trajet'); tempsDiv.innerHTML = ` <div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-4"> <div class="flex items-center"> <i class="fas fa-clock text-primary-600 mr-3 text-xl"></i> <span class="text-sm md:text-base font-medium text-gray-700">Temps de trajet estimé</span> </div> <span class="text-2xl md:text-3xl font-bold text-primary-700">${afficherTempsTrajet(tempsTotal)}</span> </div> `; } function getLigneInfo(ligne) { const infos = { 'A1': { nom: 'Ligne A1 - Thormion', bgColor: 'bg-blue-600' }, 'A2': { nom: 'Ligne A2 - Franklin', bgColor: 'bg-indigo-600' }, 'A3': { nom: 'Ligne A3 - Sakura', bgColor: 'bg-pink-600' }, 'GOne': { nom: 'Ligne GOne - Express Premium', bgColor: 'bg-purple-600' } }; return infos[ligne] || { nom: ligne, bgColor: 'bg-gray-600' }; } function showSuggestions(type) { const input = document.getElementById('aeroport_' + type); const suggestionsDiv = document.getElementById('suggestions-' + type); if(input.value.length === 0) { searchAeroport(type); } } function searchAeroport(type) { const input = document.getElementById('aeroport_' + type); const suggestionsDiv = document.getElementById('suggestions-' + type); const query = input.value.toLowerCase(); suggestionsDiv.innerHTML = ''; if(query.length === 0) { aeroports.forEach(aeroport => { addSuggestion(aeroport, type, suggestionsDiv); }); suggestionsDiv.classList.remove('hidden'); } else { const matches = aeroports.filter(aeroport => aeroport.toLowerCase().includes(query) ); if(matches.length > 0) { matches.forEach(aeroport => { addSuggestion(aeroport, type, suggestionsDiv); }); suggestionsDiv.classList.remove('hidden'); } else { suggestionsDiv.classList.add('hidden'); } } } function addSuggestion(aeroport, type, suggestionsDiv) { const div = document.createElement('div'); div.className = 'px-4 py-3 hover:bg-gray-100 cursor-pointer flex items-center text-sm md:text-base transition-colors'; div.innerHTML = `<i class="fas fa-plane mr-3 text-primary-600"></i>${aeroport}`; div.onclick = function() { selectAeroport(aeroport, type); }; suggestionsDiv.appendChild(div); } function selectAeroport(aeroport, type) { document.getElementById('aeroport_' + type).value = aeroport; document.getElementById('suggestions-' + type).classList.add('hidden'); calculerCreneauxAvion(); } function calculerCreneauxAvion() { const depart = document.getElementById('aeroport_depart').value; const arrivee = document.getElementById('aeroport_arrivee').value; const date = document.getElementById('date_voyage_avion').value; if(depart && arrivee && date && depart !== arrivee && aeroports.includes(depart) && aeroports.includes(arrivee)) { const distanceDepart = aeroportsDistances[depart] || 0; const distanceArrivee = aeroportsDistances[arrivee] || 0; const distanceVol = Math.abs(distanceArrivee - distanceDepart); const prixBase = 200 + (distanceVol * 0.8); const dureeVol = Math.max(1, Math.floor(distanceVol / 400)); const creneauxContainer = document.getElementById('creneaux-container'); creneauxContainer.innerHTML = ''; const creneaux = [ { heure: 8, label: 'Matin', multiplicateur: 1.0, description: 'Vol matinal' }, { heure: 11, label: 'Milieu de journée', multiplicateur: 0.85, description: 'Tarif avantageux' }, { heure: 14, label: 'Après-midi', multiplicateur: 1.1, description: 'Vol standard' }, { heure: 17, label: 'Fin d\'après-midi', multiplicateur: 1.2, description: 'Forte affluence' }, { heure: 20, label: 'Soirée', multiplicateur: 1.15, description: 'Vol en soirée' } ]; const dateSelectionnee = new Date(date); const aujourdhui = new Date(); aujourdhui.setHours(0, 0, 0, 0); const estAujourdhui = dateSelectionnee.getTime() === aujourdhui.getTime(); const heureActuelle = new Date().getHours(); creneaux.forEach((creneau, index) => { const heureDepart = creneau.heure; const heureArrivee = heureDepart + dureeVol; const prix = Math.round(prixBase * creneau.multiplicateur); const estPasse = estAujourdhui && heureDepart <= heureActuelle; const creneauCard = document.createElement('div'); creneauCard.className = `creneau-card border-2 border-gray-200 rounded-xl p-4 md:p-5 ${estPasse ? 'disabled' : 'cursor-pointer hover:border-primary-500 hover:bg-primary-50'} transition-all duration-200`; if(!estPasse) { creneauCard.onclick = function() { selectCreneau(this, heureDepart, heureArrivee, prix, dureeVol); }; } let badgeColor = 'bg-blue-100 text-blue-800'; if(creneau.multiplicateur < 1) { badgeColor = 'bg-green-100 text-green-800'; } else if(creneau.multiplicateur > 1.1) { badgeColor = 'bg-orange-100 text-orange-800'; } if(estPasse) { badgeColor = 'bg-gray-100 text-gray-500'; } creneauCard.innerHTML = ` <div class="flex justify-between items-start mb-3"> <div> <h4 class="font-semibold text-gray-900 text-sm md:text-base ${estPasse ? 'text-gray-400' : ''}">${creneau.label}</h4> <p class="text-xs md:text-sm text-gray-500 mt-1">${estPasse ? 'Heure passée' : creneau.description}</p> </div> <span class="inline-block px-3 py-1.5 ${badgeColor} text-xs md:text-sm rounded-lg font-semibold whitespace-nowrap ml-2">${prix} F&</span> </div> <div class="flex items-center text-xs md:text-sm text-gray-600 mt-3"> <i class="fas fa-plane-departure mr-2 text-primary-600"></i> <span class="font-medium">${heureDepart}h00</span> <i class="fas fa-arrow-right mx-3 text-gray-400"></i> <i class="fas fa-plane-arrival mr-2 text-primary-600"></i> <span class="font-medium">${heureArrivee}h00</span> </div> <div class="text-xs md:text-sm text-gray-500 mt-2 flex items-center"> <i class="fas fa-clock mr-2"></i> Durée : ${dureeVol}h de vol </div> `; creneauxContainer.appendChild(creneauCard); }); document.getElementById('creneaux-section').style.display = 'block'; } else { document.getElementById('creneaux-section').style.display = 'none'; } } function selectCreneau(element, heureDepart, heureArrivee, prix, duree) { document.querySelectorAll('.creneau-card').forEach(card => { card.classList.remove('selected'); }); element.classList.add('selected'); document.getElementById('heure_depart_input').value = heureDepart + ':00'; document.getElementById('heure_arrivee_input').value = heureArrivee + ':00'; document.getElementById('prix_vol_input').value = prix; const btnReserver = document.getElementById('btn-reserver-vol'); btnReserver.disabled = false; btnReserver.classList.remove('bg-gray-400', 'cursor-not-allowed'); btnReserver.classList.add('bg-gradient-to-r', 'from-primary-600', 'to-blue-600', 'hover:from-primary-700', 'hover:to-blue-700'); } document.addEventListener('click', function(event) { if(!event.target.closest('.relative')) { document.querySelectorAll('[id^="suggestions-"]').forEach(div => { div.classList.add('hidden'); }); } }); document.addEventListener('click', function(event) { if(event.target.closest('[id^="suggestions-"]')) { event.stopPropagation(); } }); </script> </body> </html>
| ver. 1.6 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка