diff --git a/app/static/base.css b/app/static/base.css index 42985421b93f7916af529959f9bc4c8db4fe8ba9..5c761e7f0b55e9df17ecee26dd3b05250a47dc67 100644 --- a/app/static/base.css +++ b/app/static/base.css @@ -1,4 +1,4 @@ -@import url('https://fonts.googleapis.com/css2?family=Afacad+Flux:wght@100..1000&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Afacad+Flux:wght@100,1000&display=swap'); html, body { max-width: 100%; diff --git a/app/templates/admin/manage_bookings.html b/app/templates/admin/manage_bookings.html index 37a5e2fdaa058b6910fbfc3c004987adbb79df1c..e925d0ab1f38b53dfbf520e4dc401a7cecd6a441 100644 --- a/app/templates/admin/manage_bookings.html +++ b/app/templates/admin/manage_bookings.html @@ -1,168 +1,157 @@ {% extends 'base.html' %} {% block content %} -<head> - <meta charset="UTF-8"> - <link rel="stylesheet" href="https://cdn.datatables.net/1.10.21/css/jquery.dataTables.min.css"> - <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> - <script src="https://code.jquery.com/jquery-3.5.1.js"></script> - <script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script> - <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script> -</head> -<body> - <div class="container my-4"> - <div class="d-flex justify-content-between mb-3"> - <h2>Manage Bookings</h2> - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#filterModal"> - <i class="fa-solid fa-filter"></i> Filter - </button> - </div> +<div class="container my-4"> + <div class="d-flex justify-content-between mb-3"> + <h2>Manage Bookings</h2> + <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#filterModal"> + <i class="fa-solid fa-filter"></i> Filter + </button> + </div> - <!-- Hidden Filter Modal --> - <div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="filterModalLabel" aria-hidden="true"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <h5 class="modal-title" id="filterModalLabel"><i class="fa-solid fa-filter"></i> Filter Options</h5> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"> - <span aria-hidden="true">×</span> - </button> - </div> - <div class="modal-body"> - <form id="filter-form"> - <div class="form-group"> - <label for="depart_location">Depart Location:</label> - <input type="text" class="form-control" id="depart_location" name="depart_location"> - </div> - <div class="form-group"> - <label for="destination_location">Destination Location:</label> - <input type="text" class="form-control" id="destination_location" name="destination_location"> - </div> - <div class="form-group"> - <label for="min_depart_time">Minimum Depart Time:</label> - <input type="text" class="form-control" id="min_depart_time" name="min_depart_time"> - </div> - <div class="form-group"> - <label for="max_depart_time">Maximum Depart Time:</label> - <input type="text" class="form-control" id="max_depart_time" name="max_depart_time"> - </div> - <div class="form-group"> - <label for="min_fair_cost">Minimum Fair Cost:</label> - <input type="number" class="form-control" id="min_fair_cost" name="min_fair_cost"> - </div> - <div class="form-group"> - <label for="max_fair_cost">Maximum Fair Cost:</label> - <input type="number" class="form-control" id="max_fair_cost" name="max_fair_cost"> - </div> - <div class="form-group"> - <label for="transport_type">Transport Type:</label> - <input type="text" class="form-control" id="transport_type" name="transport_type"> - </div> - </form> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> - <button type="button" class="btn btn-primary" id="apply-filters">Apply Filters</button> - </div> + <!-- Hidden Filter Modal --> + <div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="filterModalLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="filterModalLabel"><i class="fa-solid fa-filter"></i> Filter Options</h5> + <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> + </div> + <div class="modal-body"> + <form id="filter-form"> + <div class="mb-3"> + <label for="depart_location" class="form-label">Depart Location:</label> + <input type="text" class="form-control" id="depart_location" name="depart_location"> + </div> + <div class="mb-3"> + <label for="destination_location" class="form-label">Destination Location:</label> + <input type="text" class="form-control" id="destination_location" name="destination_location"> + </div> + <div class="mb-3"> + <label for="min_depart_time" class="form-label">Minimum Depart Time:</label> + <input type="text" class="form-control" id="min_depart_time" name="min_depart_time"> + </div> + <div class="mb-3"> + <label for="max_depart_time" class="form-label">Maximum Depart Time:</label> + <input type="text" class="form-control" id="max_depart_time" name="max_depart_time"> + </div> + <div class="mb-3"> + <label for="min_fair_cost" class="form-label">Minimum Fair Cost:</label> + <input type="number" class="form-control" id="min_fair_cost" name="min_fair_cost"> + </div> + <div class="mb-3"> + <label for="max_fair_cost" class="form-label">Maximum Fair Cost:</label> + <input type="number" class="form-control" id="max_fair_cost" name="max_fair_cost"> + </div> + <div class="mb-3"> + <label for="transport_type" class="form-label">Transport Type:</label> + <input type="text" class="form-control" id="transport_type" name="transport_type"> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" id="apply-filters">Apply Filters</button> </div> </div> </div> + </div> - <!-- Data table starts --> - <div class="table-container"> - <table id="manage_bookings" class="table table-striped table-bordered display" style="width:95%"> - <thead> - <tr> - <th>Depart Location</th> - <th>Depart Time</th> - <th>Destination Location</th> - <th>Arrival Time</th> - <th>Fair Cost ($)</th> - <th>Transport Type</th> - <th>Actions</th> - </tr> - </thead> - <tbody> - </tbody> - </table> - </div> + <!-- Data table starts --> + <div class="table-container"> + <table id="manage_bookings" class="table table-striped table-bordered display" style="width:95%"> + <thead> + <tr> + <th>Depart Location</th> + <th>Depart Time</th> + <th>Destination Location</th> + <th>Arrival Time</th> + <th>Fair Cost ($)</th> + <th>Transport Type</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + </tbody> + </table> </div> - <style> +</div> +<style> + .table-container { + width: 100%; + overflow-x: auto; /* Allow horizontal scroll if table is too wide */ + } + @media (max-width: 800px) { .table-container { - width: 100%; - overflow-x: auto; /* Allow horizontal scroll if table is too wide */ + padding: 0 10px; + overflow-x: auto; } - @media (max-width: 800px) { - .table-container { - padding: 0 10px; - overflow-x: auto; + } + .dataTables_wrapper { + width: 100%; + } +</style> +<script> + $(document).ready(function() { + const table = $('#manage_bookings').DataTable({ + pageLength: 25, + lengthChange: false, + searching: false, + ajax: { + url: "{{ url_for('api.get_data') }}", + dataSrc: '', + data: function(d) { + d.depart_location = $('#depart_location').val(); + d.destination_location = $('#destination_location').val(); + d.min_depart_time = $('#min_depart_time').val(); + d.max_depart_time = $('#max_depart_time').val(); + d.min_fair_cost = $('#min_fair_cost').val(); + d.max_fair_cost = $('#max_fair_cost').val(); + d.transport_type = $('#transport_type').val(); + } + }, + columns: [ + { data: 'depart_location' }, + { data: 'depart_time' }, + { data: 'destination_location' }, + { data: 'destination_time' }, + { data: 'fair_cost' }, + { data: 'transport_type' }, + { + data: null, + className: "dt-center", + defaultContent: ` + <div class="dropdown"> + <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false"> + Actions + </button> + <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> + <a class="dropdown-item edit-btn" href="#">Edit</a> + <a class="dropdown-item delete-btn" href="#">Delete</a> + </div> + </div>` + } + ], + drawCallback: function(settings) { + $('.dropdown-toggle').dropdown(); } - } - .dataTables_wrapper { - width: 100%; - } - </style> - <script> - $(document).ready(function() { - const table = $('#manage_bookings').DataTable({ - pageLength: 25, - lengthChange: false, - searching: false, - ajax: { - url: "{{ url_for('api.get_data') }}", - dataSrc: '', - data: function(d) { - d.depart_location = $('#depart_location').val(); - d.destination_location = $('#destination_location').val(); - d.min_depart_time = $('#min_depart_time').val(); - d.max_depart_time = $('#max_depart_time').val(); - d.min_fair_cost = $('#min_fair_cost').val(); - d.max_fair_cost = $('#max_fair_cost').val(); - d.transport_type = $('#transport_type').val(); - } - }, - columns: [ - { data: 'depart_location' }, - { data: 'depart_time' }, - { data: 'destination_location' }, - { data: 'destination_time' }, - { data: 'fair_cost' }, - { data: 'transport_type' }, - { - data: null, - className: "dt-center", - defaultContent: ` - <div class="dropdown"> - <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false"> - Actions - </button> - <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> - <a class="dropdown-item edit-btn" href="#">Edit</a> - <a class="dropdown-item delete-btn" href="#">Delete</a> - </div> - </div>` - } - ] - }); + }); - $('#apply-filters').on('click', function() { - table.ajax.reload(); - $('#filterModal').modal('hide'); - }); + $('#apply-filters').on('click', function() { + table.ajax.reload(); + $('#filterModal').modal('hide'); + }); - $('#manage_bookings tbody').on('click', '.edit-btn', function() { - const data = table.row($(this).parents('tr')).data(); - // Handle edit action - alert('Edit entry for ' + data.depart_location); - }); + $('#manage_bookings tbody').on('click', '.edit-btn', function() { + const data = table.row($(this).parents('tr')).data(); + // Handle edit action + alert('Edit entry for ' + data.depart_location); + }); - $('#manage_bookings tbody').on('click', '.delete-btn', function() { - const data = table.row($(this).parents('tr')).data(); - // Handle delete action - alert('Delete entry for ' + data.depart_location); - }); + $('#manage_bookings tbody').on('click', '.delete-btn', function() { + const data = table.row($(this).parents('tr')).data(); + // Handle delete action + alert('Delete entry for ' + data.depart_location); }); - </script> -</body> -</html> + }); +</script> {% endblock %} diff --git a/app/templates/base.html b/app/templates/base.html index a6b41891c21ea845dc930cb0c282d9150cefbe6f..c08818e9a5496d7153a531dab4b07bbbb59cc51b 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -1,95 +1,92 @@ -<!-- Core HTML page which includes navigation bar and footer and determines the order in which items are loaded, all other templates should extend this base template --> <!DOCTYPE html> -<html> +<html lang="en"> <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="csrf-token" content="{{ csrf_token() }}"> - <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='base.css')}}"> - <link rel="stylesheet" href="{{ url_for('static', filename='generic.js')}}"> - <script src="https://kit.fontawesome.com/11fd621de6.js" crossorigin="anonymous"></script> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> + <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='base.css') }}"> + <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='bootstrap_overrides.css') }}"> + <link rel="stylesheet" href="https://kit.fontawesome.com/11fd621de6.js" crossorigin="anonymous"> + <link rel="stylesheet" href="https://cdn.datatables.net/1.10.21/css/jquery.dataTables.min.css"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> + <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> + <script src="https://unpkg.com/@popperjs/core@2/dist/umd/popper.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> - <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> - <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script> - <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> - <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='bootstrap_overrides.css')}}"> - <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script> <title>Horizon Travels</title> </head> - <body> - <div class="main_content"> - <div class="wrapper"> - {% block navigation %} - <!-- Nav bar taken from https://htmljstemplates.com/html/bootstrap-5-navbars and modified --> - <div class="navigation"> - <nav class="navbar navbar-expand-lg navbar-dark nav_background p-3"> - <div class="container-fluid"> - <a class="navbar-brand" href="{{ url_for('main.index') }}">Horizon Travels</a> - <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> + + +<body> + <div class="main_content"> + <div class="wrapper"> + {% block navigation %} + <div class="navigation"> + <nav class="navbar navbar-expand-lg navbar-dark nav_background p-3"> + <div class="container-fluid"> + <a class="navbar-brand" href="{{ url_for('main.index') }}">Horizon Travels</a> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> - </button> - - <div class=" collapse navbar-collapse" id="navbarNavDropdown"> - <ul class="navbar-nav ms-auto "> + </button> + <div class="collapse navbar-collapse" id="navbarNavDropdown"> + <ul class="navbar-nav ms-auto"> <li class="nav-item"> - <a class="nav-link mx-2 active" aria-current="page" href="{{ url_for('main.index') }}">Home</a> + <a class="nav-link mx-2 active" aria-current="page" href="{{ url_for('main.index') }}">Home</a> </li> <li class="nav-item"> - <a class="nav-link mx-2" href="{{ url_for('bookings.index') }}">Find a booking</a> + <a class="nav-link mx-2" href="{{ url_for('bookings.index') }}">Find a booking</a> </li> <li class="nav-item dropdown"> - <a class="nav-link mx-2 dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> - Account - </a> - <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> - {% if user_in_session %} - {% if g.is_admin %} - <li><a class="dropdown-item" href="{{ url_for('admin.index') }}">Admin Options</a></li> - {% endif %} - <li><a class="dropdown-item" href="{{ url_for('profile.index') }}">Account Details</a></li> - <li><a class="dropdown-item" href="{{ url_for('profile.manage_bookings')}}">My Bookings</a></li> - <li><a class="dropdown-item" href="{{ url_for('profile.logout') }}">Log Out</a></li> - {% else %} - <li><a class="dropdown-item" href="{{ url_for('profile.signup') }}">Sign Up</a></li> - <li><a class="dropdown-item" href="{{ url_for('profile.login') }}">Log In</a></li> - {% endif %} - </ul> - + <a class="nav-link mx-2 dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> + Account + </a> + <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> + {% if user_in_session %} + {% if g.is_admin %} + <li><a class="dropdown-item" href="{{ url_for('admin.index') }}">Admin Options</a></li> + {% endif %} + <li><a class="dropdown-item" href="{{ url_for('profile.index') }}">Account Details</a></li> + <li><a class="dropdown-item" href="{{ url_for('profile.manage_bookings')}}">My Bookings</a></li> + <li><a class="dropdown-item" href="{{ url_for('profile.logout') }}">Log Out</a></li> + {% else %} + <li><a class="dropdown-item" href="{{ url_for('profile.signup') }}">Sign Up</a></li> + <li><a class="dropdown-item" href="{{ url_for('profile.login') }}">Log In</a></li> + {% endif %} + </ul> </li> </ul> - </div> </div> - </nav> - </div> - {% endblock %} - - <div class="content"> - {% block content %} {% endblock %} - </div> + </div> + </nav> </div> - {% block footer %} - <footer> - <div class="footer"> - <div class="footer_row"> - <div class="footer_column"> - <div>About Us</div> - <div>Contact Us</div> - </div> - <div class="footer_column"> - <a>About Us</a> - <a>Contact Us</a> - </div> - <div class="footer_column"><a>Login</a></div> + {% endblock %} + <div class="content"> + {% block content %}{% endblock %} + </div> + </div> + {% block footer %} + <footer> + <div class="footer"> + <div class="footer_row"> + <div class="footer_column"> + <div>About Us</div> + <div>Contact Us</div> </div> - <div class="footer_row"> - <div class="copyright"> - <p>© 2024-2025 Horizon Travels</p> - </div> + <div class="footer_column"> + <a>About Us</a> + <a>Contact Us</a> </div> + <div class="footer_column"><a>Login</a></div> </div> - </footer> - {% endblock %} - </div> - </body> -</html> \ No newline at end of file + <div class="footer_row"> + <div class="copyright"> + <p>© 2024-2025 Horizon Travels</p> + </div> + </div> + </div> + </footer> + {% endblock %} + </div> +</body> +</html> diff --git a/app/templates/bookings/listings.html b/app/templates/bookings/listings.html index e553c5fa6dd5a27272638ad755619f40bf42412d..1237234872f7e6d17c6556cfb1af3cb6df74f197 100644 --- a/app/templates/bookings/listings.html +++ b/app/templates/bookings/listings.html @@ -1,11 +1,5 @@ {% extends 'base.html' %} {% block content %} -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Simplified Carousel Example</title> <style> .container { width: 60%; @@ -36,9 +30,6 @@ } .carousel-item { height: 400px; - position: absolute; - width: 100%; - transition: transform 0.5s ease-in-out; } .carousel-inner { position: relative; @@ -46,27 +37,8 @@ overflow: hidden; display: flex; } - .carousel-item.active { - position: relative; - } - .carousel-item-next, - .carousel-item-prev, - .carousel-item.active { - display: block; - } - .carousel-item-next { - transform: translateX(100%); - } - .carousel-item-prev { - transform: translateX(-100%); - } - .carousel-item-left, - .carousel-item-next.carousel-item-left { - transform: translateX(0); - } - .carousel-item-right, - .carousel-item-prev.carousel-item-right { - transform: translateX(0); + .carousel-indicators li { + background-color: #000; } </style> </head> @@ -100,40 +72,39 @@ <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="imageModalLabel">Image Gallery</h5> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"> - <span aria-hidden="true">×</span> - </button> + <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> - <div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel"> + <div id="carouselExampleIndicators" class="carousel slide" data-bs-ride="carousel"> <ol class="carousel-indicators" id="carouselIndicators"></ol> <div class="carousel-inner" id="carouselInner"></div> - <a class="carousel-control-prev" href="#carouselExampleIndicators" role="button" data-slide="prev"> + <button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="prev"> <span class="carousel-control-prev-icon" aria-hidden="true"></span> - <span class="sr-only">Previous</span> - </a> - <a class="carousel-control-next" href="#carouselExampleIndicators" role="button" data-slide="next"> + <span class="visually-hidden">Previous</span> + </button> + <button class="carousel-control-next" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="next"> <span class="carousel-control-next-icon" aria-hidden="true"></span> - <span class="sr-only">Next</span> - </a> + <span class="visually-hidden">Next</span> + </button> </div> </div> <div class="modal-footer"> - <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> </div> </div> </div> </div> <script> + // Initialize Bootstrap modal with jQuery $(document).ready(function() { - $('#imageModal .close, #imageModal .btn-secondary').on('click', function() { + $('#imageModal .btn-close, #imageModal .btn-secondary').on('click', function() { console.log("Close button clicked"); $('#imageModal').modal('hide'); }); }); - // Shows pop up with images attached to specific booking + // Shows pop-up with images attached to specific booking function showModal(imageUrls) { console.log("showModal called with imageUrls:", imageUrls); @@ -156,15 +127,16 @@ // Create carousel indicators var li = document.createElement('li'); - li.setAttribute('data-target', '#carouselExampleIndicators'); - li.setAttribute('data-slide-to', index); + li.setAttribute('data-bs-target', '#carouselExampleIndicators'); + li.setAttribute('data-bs-slide-to', index); if (index === 0) { li.className = 'active'; } carouselIndicators.appendChild(li); }); - $('#imageModal').modal('show'); + var imageModal = new bootstrap.Modal(document.getElementById('imageModal')); + imageModal.show(); } function filterResults() {