Compare commits

...

9 Commits

Author SHA1 Message Date
55b3fbfc63 TZ changes from prod 2025-06-01 07:18:11 +00:00
c4cfb43edc ICAO and IATA code lookup 2025-04-15 17:13:47 +00:00
31c1172e08 Add bookout system POC 2025-04-15 16:21:23 +00:00
94010fec01 Dave's public board 2025-04-07 16:27:01 +00:00
391f057824 v1 release 2025-03-31 16:37:40 +00:00
41dcd937cd Prep for 1.0 2025-03-31 12:33:26 +00:00
ac5cd4f3a0 Menu bar and Upcoming PPR 2025-03-31 12:08:39 +00:00
f6368f12f1 Tweaks 2025-03-31 10:23:40 +00:00
f6ba990e1c TZ and editable fields 2025-03-31 10:04:40 +00:00
18 changed files with 1018 additions and 324 deletions

View File

@@ -116,6 +116,11 @@
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
let id = "<?php echo $_GET['id'];?>"; let id = "<?php echo $_GET['id'];?>";
// Disable all dropdowns by default
document.querySelectorAll("select.editable").forEach((element) => {
element.disabled = true;
});
// Select all editable elements // Select all editable elements
document.querySelectorAll(".editable").forEach((element) => { document.querySelectorAll(".editable").forEach((element) => {
let oldValue = element.value || element.textContent.trim(); // Store initial value let oldValue = element.value || element.textContent.trim(); // Store initial value
@@ -157,6 +162,9 @@ function editField(button) {
if (element.tagName === "INPUT") { if (element.tagName === "INPUT") {
element.readOnly = false; element.readOnly = false;
element.focus(); element.focus();
} else if (element.tagName === "SELECT") {
element.disabled = false; // Enable dropdown
element.focus();
} else { } else {
element.contentEditable = true; element.contentEditable = true;
element.focus(); element.focus();
@@ -165,6 +173,8 @@ function editField(button) {
element.addEventListener("blur", function () { element.addEventListener("blur", function () {
if (element.tagName === "INPUT") { if (element.tagName === "INPUT") {
element.readOnly = true; element.readOnly = true;
} else if (element.tagName === "SELECT") {
element.disabled = true; // Disable dropdown
} else { } else {
element.contentEditable = false; element.contentEditable = false;
} }
@@ -281,19 +291,23 @@ function opDetail() {
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
echo '<div class="container">'; echo '<div class="container">';
echo '<table class="details">'; echo '<table class="details">';
echo '<tr><th>Aircraft Reg</th><td></td><td>' . $row['ac_reg'] . '</td></tr>'; echo '<tr><th>Aircraft Reg</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="text" class="editable" data-column="ac_reg" value="' . $row['ac_reg'] . '" readonly></td></tr>';
echo '<tr><th>Aircraft Type</th><td></td><td>' . $row['ac_type'] . '</td></tr>'; echo '<tr><th>Aircraft Type</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="text" class="editable" data-column="ac_type" value="' . $row['ac_type'] . '" readonly></td></tr>';
echo '<tr><th>Callsign</th><td></td><td>' . $row['ac_call'] . '</td></tr>'; echo '<tr><th>Callsign</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="text" class="editable" data-column="ac_call" value="' . $row['ac_call'] . '" readonly></td></tr>';
echo '<tr><th>Captain</th><td></td><td>' . $row['captain'] . '</td></tr>'; echo '<tr><th>Captain</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="text" class="editable" data-column="captain" value="' . $row['captain'] . '" readonly></td></tr>';
echo '<tr><th>Arriving From:</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><span class="editable" data-column="in_from">' . $row['in_from'] . '</span></td></tr>'; echo '<tr><th>Arriving From:</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><span class="editable" data-column="in_from">' . $row['in_from'] . '</span></td></tr>';
echo '<tr><th>POB IN</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="number" class="editable" data-column="pob_in" value="' . $row['pob_in'] . '" readonly></td></tr>'; echo '<tr><th>POB IN</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="number" class="editable" data-column="pob_in" value="' . $row['pob_in'] . '" readonly></td></tr>';
echo '<tr><th>ETA</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="datetime-local" class="editable" data-column="eta" value="' . ($row['eta'] ? date('Y-m-d\TH:i', strtotime($row['eta'])) : '') . '" readonly></td></tr>'; echo '<tr><th>ETA Z</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="datetime-local" class="editable" data-column="eta" value="' . ($row['eta'] ? date('Y-m-d\TH:i', strtotime($row['eta'])) : '') . '" readonly></td></tr>';
echo '<tr><th>Fuel</th><td></td><td>' . $row['fuel'] . '</td></tr>'; echo '<tr><th>Fuel</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><select class="editable" data-column="fuel" onchange="this.blur()" disabled>';
echo '<option value="None"' . ($row['fuel'] === 'None' ? ' selected' : '') . '>None</option>';
echo '<option value="100LL"' . ($row['fuel'] === '100LL' ? ' selected' : '') . '>100LL</option>';
echo '<option value="JET A1"' . ($row['fuel'] === 'JET A1' ? ' selected' : '') . '>JET A1</option>';
echo '</select></td></tr>';
echo '<tr><th>POB OUT</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="number" class="editable" data-column="pob_out" value="' . $row['pob_out'] . '" readonly></td></tr>'; echo '<tr><th>POB OUT</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="number" class="editable" data-column="pob_out" value="' . $row['pob_out'] . '" readonly></td></tr>';
echo '<tr><th>Outbound To</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><span class="editable" data-column="out_to">' . $row['out_to'] . '</span></td></tr>'; echo '<tr><th>Outbound To</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><span class="editable" data-column="out_to">' . $row['out_to'] . '</span></td></tr>';
echo '<tr><th>ETD</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="datetime-local" class="editable" data-column="etd" value="' . ($row['etd'] ? date('Y-m-d\TH:i', strtotime($row['etd'])) : '') . '" readonly></td></tr>'; echo '<tr><th>ETD Z</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="datetime-local" class="editable" data-column="etd" value="' . ($row['etd'] ? date('Y-m-d\TH:i', strtotime($row['etd'])) : '') . '" readonly></td></tr>';
echo '<tr><th>Email Address</th><td></td><td>' . $row['email'] . '</td></tr>'; echo '<tr><th>Email Address</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="email" class="editable" data-column="email" value="' . $row['email'] . '" readonly></td></tr>';
echo '<tr><th>Phone</th><td></td><td>' . $row['phone'] . '</td></tr>'; echo '<tr><th>Phone</th><td><button class="edit-button" onclick="editField(this)"><img src="assets/edit.png" alt="Edit"></button></td><td><input type="tel" class="editable" data-column="phone" value="' . $row['phone'] . '" readonly></td></tr>';
echo '<tr><th>Notes</th><td></td><td>' . $row['notes'] . '</td></tr>'; echo '<tr><th>Notes</th><td></td><td>' . $row['notes'] . '</td></tr>';
echo '<tr><th>PPR created</th><td></td><td>' . $row['submitted_dt'] . ' by ' . $row['created_by'] . '</td></tr>'; echo '<tr><th>PPR created</th><td></td><td>' . $row['submitted_dt'] . ' by ' . $row['created_by'] . '</td></tr>';
echo '</table>'; echo '</table>';

170
admin.php
View File

@@ -6,70 +6,9 @@ require_db_auth();
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta http-equiv="refresh" content="300">
<script>
document.addEventListener("DOMContentLoaded", function() {
let rows = document.querySelectorAll("table tbody tr");
rows.forEach(row => {
let fuelCell = row.cells[3]; // Get the "Fuel" cell (index 3)
if (fuelCell.textContent == "100LL") {
row.classList.add("highlight100LL"); // Add the class
} else if (fuelCell.textContent == "JET A1") {
row.classList.add("highlightJET"); // Add the class
}
});
// Sorting functionality
let table = document.querySelector("table");
let headers = table.querySelectorAll("th");
let sortDirection = {}; // Track sort direction for each column
headers.forEach((header, index) => {
header.addEventListener("click", function() {
let direction = sortDirection[index] === "asc" ? "desc" : "asc";
sortDirection[index] = direction;
sortTable(table, index, direction);
// Update visual indication
headers.forEach(h => h.classList.remove("sorted-asc", "sorted-desc"));
header.classList.add(direction === "asc" ? "sorted-asc" : "sorted-desc");
});
});
function sortTable(table, columnIndex, direction) {
let rows = Array.from(table.querySelectorAll("tbody tr"));
let isDate = !isNaN(Date.parse(rows[0].cells[columnIndex]?.textContent.trim() || ""));
let isNumeric = !isNaN(rows[0].cells[columnIndex]?.textContent.trim() || "");
let sortedRows = rows.sort((a, b) => {
let aText = a.cells[columnIndex]?.textContent.trim() || null;
let bText = b.cells[columnIndex]?.textContent.trim() || null;
if (aText === null || bText === null) {
return aText === null ? 1 : -1; // Place null/empty values at the bottom
}
if (isDate) {
let aDate = new Date(aText);
let bDate = new Date(bText);
return direction === "asc" ? aDate - bDate : bDate - aDate;
} else if (isNumeric) {
return direction === "asc" ? aText - bText : bText - aText;
} else {
return direction === "asc" ? aText.localeCompare(bText) : bText.localeCompare(aText);
}
});
let tbody = table.querySelector("tbody");
tbody.innerHTML = "";
sortedRows.forEach(row => tbody.appendChild(row));
}
});
</script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Swansea Daily PPR</title> <title>PPR Monthly Reports</title>
<style> <style>
/* Styling for the table */ /* Styling for the table */
@@ -104,16 +43,6 @@ require_db_auth();
background-color: #f1f1f1; background-color: #f1f1f1;
} }
.highlight100LL {
background-color: #ADD8E6 !important;
#font-weight: bold;
}
.highlightJET {
background-color: yellow !important; /* Allow it to override the odd/even shading */
#font-weight: bold;
}
button { button {
padding: 10px 20px; padding: 10px 20px;
font-size: 1rem; font-size: 1rem;
@@ -136,42 +65,18 @@ require_db_auth();
border-radius: 5px; border-radius: 5px;
} }
/* Add styles for sorted columns */ .container {
th.sorted-asc::after { text-align: center;
content: " ▲"; margin-bottom: 20px;
font-size: 0.8em;
}
th.sorted-desc::after {
content: " ▼";
font-size: 0.8em;
} }
</style> </style>
</head> </head>
<body> <body>
<?php include("menu.php"); ?>
<script> <script>
function markLanded(id) {
page="action.php?op=landed&id=" + id;
var xhr = new XMLHttpRequest();
xhr.open("GET", page, false); // 'false' makes the request synchronous
xhr.send();
window.location.reload(true);
}
function markCancel(id) {
page="action.php?op=cancel&id=" + id;
var xhr = new XMLHttpRequest();
xhr.open("GET", page, false); // 'false' makes the request synchronous
xhr.send();
window.location.reload(true);
}
function deletePpr(id) {
page="action.php?op=delete&id=" + id;
var xhr = new XMLHttpRequest();
xhr.open("GET", page, false); // 'false' makes the request synchronous
xhr.send();
window.location.reload(true);
}
function openDetail(id) { function openDetail(id) {
page="action.php?op=detail&id=" + id; page="action.php?op=detail&id=" + id;
var popupWindow = window.open(page, "PopupWindow", "toolbar=no, location=no, directories=no,status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=yes, width=600, height=1100"); var popupWindow = window.open(page, "PopupWindow", "toolbar=no, location=no, directories=no,status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=yes, width=600, height=1100");
@@ -183,29 +88,31 @@ require_db_auth();
} }
</script> </script>
<center><h2>Swansea Inbound PPR ADMIN</h2></center> <center><h2>Swansea Inbound PPR ADMIN</h2></center>
<div class="container"> <div class="container">
<h2>Select a Month</h2> <div style="display: inline-block; text-align: left;">
<select id="monthSelect"> <select id="monthSelect">
<option value="1">January</option> <option value="1">January</option>
<option value="2">February</option> <option value="2">February</option>
<option value="3">March</option> <option value="3">March</option>
<option value="4">April</option> <option value="4">April</option>
<option value="5">May</option> <option value="5">May</option>
<option value="6">June</option> <option value="6">June</option>
<option value="7">July</option> <option value="7">July</option>
<option value="8">August</option> <option value="8">August</option>
<option value="9">September</option> <option value="9">September</option>
<option value="10">October</option> <option value="10">October</option>
<option value="11">November</option> <option value="11">November</option>
<option value="12">December</option> <option value="12">December</option>
</select> </select>
<select id="yearSelect"></select> <select id="yearSelect"></select>
<button onclick="selectMonthYear()">Submit</button> <button onclick="selectMonthYear()">Submit</button>
<button onclick="downloadCSV()">Download CSV</button> <button onclick="downloadCSV()">Download CSV</button>
<p id="output"></p> </div>
</div> <p id="output"></p>
</div>
<script> <script>
function populateYearDropdown() { function populateYearDropdown() {
@@ -251,15 +158,7 @@ require_db_auth();
<?php <?php
$conn = connectDb();
// Create connection
$conn = new mysqli($host, $username, $password, $database);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$year = $_GET['year'] ?? date('Y'); $year = $_GET['year'] ?? date('Y');
$month = $_GET['month'] ?? date('n'); $month = $_GET['month'] ?? date('n');
@@ -282,7 +181,6 @@ if ($result->num_rows > 0) {
} }
} }
// echo '<th>actions</th>';
echo ' </tr> echo ' </tr>
</thead> </thead>
@@ -304,15 +202,7 @@ if ($result->num_rows > 0) {
echo "No results found."; echo "No results found.";
} }
// Close the database connection
$conn->close(); $conn->close();
?> ?>
<center><button onclick="openPopup()">Log New PPR</button></center> <?php include("footer.php"); ?>
<script>
function openPopup() {
window.open("input.html", "PopupWindow", "toolbar=no, location=no, directories=no,status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=yes, width=600, height=1100");
}
</script>

View File

@@ -25,56 +25,53 @@ include("functions.php");
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Swansea Daily PPR</title> <title>Swansea Daily PPR</title>
<style> <style>
/* Styling for the table */ /* Styling for the table */
table { table {
width: 80%; width: 90%;
border-collapse: collapse; border-collapse: collapse;
margin: 20px 0; margin: 20px auto;
margin-left: auto; /* Automatically adjusts left margin */ background-color: #000; /* Black background for digital display effect */
margin-right: auto; /* Automatically adjusts right margin */ color: #0f0; /* Bright green text for digital display effect */
font-family: 'Courier New', Courier, monospace; /* Monospace font for digital look */
font-size: 18px;
text-align: center;
} }
table, th, td { table, th, td {
border: 1px solid #ddd; border: 1px solid #444; /* Subtle border for table cells */
} }
th { th {
padding: 8px; padding: 10px;
text-align: center; background-color: #222; /* Darker background for headers */
color: #fff; /* White text for headers */
font-weight: bold;
text-transform: uppercase;
} }
td { td {
padding: 8px; padding: 10px;
text-align: center;
font-family: Arial, sans-serif;
font-size: 16pt;
}
th {
background-color: #f2f2f2;
} }
tr:nth-child(even) { tr:nth-child(even) {
background-color: #f9f9f9; background-color: #111; /* Slightly lighter background for even rows */
} }
tr:hover { tr:hover {
background-color: #f1f1f1; background-color: #333; /* Highlight row on hover */
} }
/* Highlight styles for fuel types */
.highlight100LL { .highlight100LL {
background-color: #ADD8E6 !important; background-color: #0044cc !important; /* Blue for 100LL */
#font-weight: bold; color: #fff !important; /* White text */
} }
.highlightJET { .highlightJET {
background-color: yellow !important; /* Allow it to override the odd/even shading */ background-color: #ffcc00 !important; /* Yellow for JET A1 */
#font-weight: bold; color: #000 !important; /* Black text */
}
.acreg {
padding: 4px;
text-align: center;
font-family: Arial, sans-serif;
font-size: 10pt;
font-style: italic;
} }
/* Styling for aircraft registration */
.acreg {
font-size: 14px;
font-style: italic;
color: #ccc; /* Light gray for subtle emphasis */
}
</style> </style>
</head> </head>
<body> <body>

BIN
assets/WBCAFE.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
assets/flightImg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

259
bookout.html Normal file
View File

@@ -0,0 +1,259 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Book Out</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
.form-container {
max-width: 500px;
margin: 20px auto;
padding: 20px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.form-container h2 {
text-align: center;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input, .form-group select {
width: 100%;
padding: 10px;
font-size: 1rem;
border: 1px solid #ccc;
border-radius: 5px;
}
.form-group input:focus, .form-group select:focus {
border-color: #007bff;
outline: none;
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
}
.hidden {
display: none;
}
button {
width: 100%;
padding: 10px;
font-size: 1rem;
color: #fff;
background-color: #007bff;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
@media (max-width: 768px) {
.form-container {
width: 100%; /* Ensure it fits the screen */
margin: 20px auto;
padding: 15px;
box-sizing: border-box; /* Include padding in width calculation */
}
.form-group input, .form-group select, button {
font-size: 0.9rem;
padding: 8px;
}
h2 {
font-size: 1.5rem;
}
}
@media (max-width: 480px) {
.form-container {
width: 100%; /* Ensure it fits the screen */
margin: 10px auto;
padding: 10px;
box-sizing: border-box; /* Include padding in width calculation */
}
.form-group input, .form-group select, button {
font-size: 0.8rem;
padding: 6px;
}
h2 {
font-size: 1.2rem;
}
}
.nature-button {
flex: 1;
padding: 10px;
font-size: 1rem;
color: #fff;
background-color: #007bff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.nature-button:hover {
background-color: #0056b3;
}
.nature-button.selected {
background-color: #28a745; /* Green for selected */
}
.pob-button {
flex: 1;
padding: 10px;
font-size: 1rem;
color: #fff;
background-color: #007bff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.pob-button:hover {
background-color: #0056b3;
}
.pob-button.selected {
background-color: #28a745; /* Green for selected */
}
</style>
<script>
function toggleLandawayFields(natureOfFlight) {
const landawayFields = document.getElementById("landaway-fields");
document.getElementById("nature_of_flight").value = natureOfFlight;
// Update button styles
document.querySelectorAll(".nature-button").forEach(button => {
button.classList.remove("selected");
});
document.getElementById(`nature_${natureOfFlight}`).classList.add("selected");
if (natureOfFlight === "Landaway") {
landawayFields.classList.remove("hidden");
} else {
landawayFields.classList.add("hidden");
}
}
function selectPOB(pob) {
document.getElementById("pob").value = pob;
// Update button styles
document.querySelectorAll(".pob-button").forEach(button => {
button.classList.remove("selected");
});
document.getElementById(`pob_${pob}`).classList.add("selected");
}
function setCookie(name, value, days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
document.cookie = `${name}=${value};expires=${date.toUTCString()};path=/`;
}
function getCookie(name) {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.startsWith(name + '=')) {
return cookie.substring(name.length + 1);
}
}
return '';
}
function handleAircraftRegInput() {
const acRegInput = document.getElementById("ac_reg");
const acTypeInput = document.getElementById("ac_type");
const captainNameInput = document.getElementById("captain_name");
acRegInput.value = acRegInput.value.toUpperCase();
setCookie("ac_reg", acRegInput.value, 30);
setCookie("ac_type", acTypeInput.value, 30);
setCookie("captain_name", captainNameInput.value, 30);
}
function populateAircraftFields() {
const savedReg = getCookie("ac_reg");
const savedType = getCookie("ac_type");
const savedCaptainName = getCookie("captain_name");
if (savedReg) {
document.getElementById("ac_reg").value = savedReg;
}
if (savedType) {
document.getElementById("ac_type").value = savedType;
}
if (savedCaptainName) {
document.getElementById("captain_name").value = savedCaptainName;
}
}
document.addEventListener("DOMContentLoaded", populateAircraftFields);
</script>
</head>
<body>
<div class="form-container">
<h2>Log Outgoing Flight</h2>
<form action="submit_outgoing.php" method="POST">
<div class="form-group">
<label for="ac_reg">Aircraft Registration</label>
<input type="text" id="ac_reg" name="ac_reg" required maxlength="16" oninput="handleAircraftRegInput()">
</div>
<div class="form-group">
<label for="ac_type">Aircraft Type</label>
<input type="text" id="ac_type" name="ac_type" required maxlength="32" oninput="handleAircraftRegInput()">
</div>
<div class="form-group">
<label for="captain_name">Captain's Name</label>
<input type="text" id="captain_name" name="captain_name" required maxlength="64" oninput="handleAircraftRegInput()">
</div>
<div class="form-group">
<label>POB (Persons on Board)</label>
<input type="hidden" id="pob" name="pob" required>
<div style="display: flex; gap: 10px;">
<button type="button" id="pob_1" class="pob-button" onclick="selectPOB(1)">1</button>
<button type="button" id="pob_2" class="pob-button" onclick="selectPOB(2)">2</button>
<button type="button" id="pob_3" class="pob-button" onclick="selectPOB(3)">3</button>
<button type="button" id="pob_4" class="pob-button" onclick="selectPOB(4)">4</button>
<button type="button" id="pob_5" class="pob-button" onclick="selectPOB(5)">5</button>
<button type="button" id="pob_6" class="pob-button" onclick="selectPOB(6)">6</button>
</div>
</div>
<div class="form-group">
<label>Nature of Flight</label>
<input type="hidden" id="nature_of_flight" name="nature_of_flight" required>
<div style="display: flex; gap: 10px;">
<button type="button" id="nature_Local" class="nature-button" onclick="toggleLandawayFields('Local')">Local</button>
<button type="button" id="nature_Circuits" class="nature-button" onclick="toggleLandawayFields('Circuits')">Circuits</button>
<button type="button" id="nature_Landaway" class="nature-button" onclick="toggleLandawayFields('Landaway')">Landaway</button>
</div>
</div>
<div class="form-group">
<label for="departure_time">Time of Departure</label>
<input type="datetime-local" id="etd" name="etd" required>
</div>
<div id="landaway-fields" class="hidden">
<div class="form-group">
<label for="destination">Destination</label>
<input type="text" id="destination" name="destination" maxlength="64">
</div>
<div class="form-group">
<label for="return_time">Estimated Time of Return</label>
<input type="datetime-local" id="eta" name="eta">
</div>
</div>
<button type="submit">Submit</button>
</form>
</div>
</body>
</html>

36
footer.php Normal file
View File

@@ -0,0 +1,36 @@
<style>
.footer-bar {
display: flex;
justify-content: center;
align-items: center;
background-color: #333;
color: white;
padding: 10px 0;
font-family: Arial, sans-serif;
font-size: 14px;
position: fixed;
bottom: 0;
width: 100%;
height: 50px; /* Define the height explicitly */
box-sizing: border-box;
}
.footer-bar a {
color: #007bff;
text-decoration: none;
margin-left: 5px;
}
.footer-bar a:hover {
text-decoration: underline;
}
body {
padding-bottom: 50px; /* Add padding equal to the footer height */
box-sizing: border-box;
}
</style>
<div class="footer-bar">
<span>Swansea Airport PPR system Version 1.0</span>
</div>

View File

@@ -1,10 +1,11 @@
<?php <?php
// Database connection details // Database connection details
$host = 'sasaprod.pattinson.org'; // Replace with your database host (usually 'localhost') $host = 'sasaprod.pattinson.org';
$username = 'ppruser'; // Replace with your database username $username = 'ppruser';
$password = 'iJ8kN*5[g6P3jaqN'; // Replace with your database password $password = 'iJ8kN*5[g6P3jaqN';
$database = 'pprdevdb'; // Replace with your database name $database = 'pprdevdb';
$created_by = "Website (DEV)";
$mailHost = 'send.one.com'; // Your SMTP server $mailHost = 'send.one.com'; // Your SMTP server
$mailSMTPAuth = true; $mailSMTPAuth = true;
@@ -15,7 +16,7 @@ $mailPort = 465;
$mailFromAddress = 'noreply@swansea-airport.wales'; $mailFromAddress = 'noreply@swansea-airport.wales';
$mailFromName = 'Swansea Airport'; $mailFromName = 'Swansea Airport';
$baseUrl = "https://ppr.swansea-airport.wales/dev"; $baseUrl = "https://pprdev.swansea-airport.wales";
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
@@ -187,4 +188,24 @@ function generatePprEmail($entryId, $email, $ac_reg) {
logJournal($conn, $entryId, "Confirm email FAILED"); logJournal($conn, $entryId, "Confirm email FAILED");
} }
} }
function getAirport($conn, $code) {
$query = "";
if (strlen($code) === 4) {
$query = "SELECT name FROM airports WHERE icao = ?";
} elseif (strlen($code) === 3) {
$query = "SELECT name FROM airports WHERE iata = ?";
} else {
return null; // Invalid code length
}
$stmt = $conn->prepare($query);
$stmt->bind_param("s", $code);
$stmt->execute();
$stmt->bind_result($name);
$stmt->fetch();
$stmt->close();
return $name;
}
?> ?>

View File

@@ -161,7 +161,7 @@
<input type="number" id="pob_in" name="pob_in" required> <input type="number" id="pob_in" name="pob_in" required>
</div> </div>
<div class="form-group"></div> <div class="form-group"></div>
<label for="eta">ETA</label> <label for="eta">ETA (Local)</label>
<input type="datetime-local" id="eta" name="eta"> <input type="datetime-local" id="eta" name="eta">
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -173,7 +173,7 @@
<input type="number" id="pob_out" name="pob_out" > <input type="number" id="pob_out" name="pob_out" >
</div> </div>
<div class="form-group"></div> <div class="form-group"></div>
<label for="eta">Departing At</label> <label for="eta">Departing At (Local)</label>
<input type="datetime-local" id="etd" name="etd"> <input type="datetime-local" id="etd" name="etd">
</div> </div>

33
menu.php Normal file
View File

@@ -0,0 +1,33 @@
<style>
.menu-bar {
display: flex;
justify-content: center;
background-color: #333;
padding: 10px 0;
margin-bottom: 20px;
}
.menu-bar a {
color: white;
text-decoration: none;
padding: 10px 20px;
font-family: Arial, sans-serif;
font-size: 16px;
transition: background-color 0.3s;
}
.menu-bar a:hover {
background-color: #575757;
}
.menu-bar a.active {
background-color: #007bff;
font-weight: bold;
}
</style>
<div class="menu-bar">
<a href="tower.php" class="<?= basename($_SERVER['PHP_SELF']) === 'tower.php' ? 'active' : '' ?>">HOME</a>
<a href="upcoming.php" class="<?= basename($_SERVER['PHP_SELF']) === 'upcoming.php' ? 'active' : '' ?>">Future PPRs</a>
<a href="admin.php" class="<?= basename($_SERVER['PHP_SELF']) === 'admin.php' ? 'active' : '' ?>">Reports</a>
</div>

106
public.css Normal file
View File

@@ -0,0 +1,106 @@
/* Overall page styling */
body {
margin: 0;
font-family: Arial, sans-serif;
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: 1fr;
height: 100vh;
font-size: 30px; /* Increased font size */
}
/* Header styles */
header {
background-color: #333;
color: white;
padding: 20px;
text-align: center;
img.left-image {
position: absolute;
top: 0;
left: 0;
height: auto;
}
img.right-image {
position: absolute;
top: 0;
right: 0;
width: 9%;
height: auto;
}
}
/* Main section styles */
main {
display: grid;
grid-template-columns: 1fr 1fr; /* Two equal-width columns */
gap: 20px;
padding: 20px;
overflow-y: auto;
}
/* Table styles */
table {
width: 100%;
border-collapse: collapse;
margin: 0;
border: 1px solid #ccc;
}
th, td {
padding: 12px;
text-align: left;
border: 1px solid #ccc;
}
th {
background-color: #f4f4f4;
}
tr:nth-child(even) {
background-color: #d3d3d3;
}
/* Footer styles */
footer {
background-color: #333;
color: white;
text-align: center;
padding: 10px 0;
position: relative;
overflow: hidden;
}
/* Marquee container */
.marquee {
display: inline-block;
white-space: nowrap;
padding-right: 100%; /* This makes the text start out of view */
animation: scroll-left 20s linear infinte;
}
/* Keyframes for scrolling animation */
@keyframes scroll-left {
from {
transform: translateX(100%);
}
to {
transform: translateX(-100%);
}
}
/* Marquee text styling */
.marquee-text {
font-size: 18px;
font-weight: bold;
color: #f4f4f4;
padding-left: 50px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
}
/* Responsive adjustments */
@media (max-width: 768px) {
main {
grid-template-columns: 1fr; /* Stack columns on smaller screens */
}
}

116
public.php Normal file
View File

@@ -0,0 +1,116 @@
<?php
include("functions.php");
// Create connection
$conn = connectDb();
// Fetch arrivals for today's date with status 'NEW'
$arrivalsSql = "SELECT ac_reg, ac_type, in_from, TIME_FORMAT(eta, '%H:%i') AS due
FROM submitted
WHERE DATE(eta) = CURDATE() AND status = 'NEW'
ORDER BY eta ASC";
$arrivalsResult = $conn->query($arrivalsSql);
// Fetch departures for today's date with status 'LANDED'
$departuresSql = "SELECT ac_reg, ac_type, out_to, TIME_FORMAT(etd, '%H:%i') AS due
FROM submitted
WHERE DATE(etd) = CURDATE() AND status = 'LANDED'
ORDER BY etd ASC";
$departuresResult = $conn->query($departuresSql);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="300">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Swansea Airport - Arrivals & Departures</title>
<link rel="stylesheet" href="public.css">
</head>
<body>
<header>
<img src="assets/logo.png" alt="EGFH Logo" class="left-image">
<h1>Arrivals/Departures Information</h1>
<img src="assets/flightImg.png" alt="EGFH Logo" class="right-image">
</header>
<main>
<!-- Left column with arrivals table -->
<div>
<h2><center>Arrivals</center></h2>
<table>
<thead>
<tr>
<th>Registration</th>
<th>Aircraft Type</th>
<th>From</th>
<th>Due</th>
</tr>
</thead>
<tbody>
<?php if ($arrivalsResult->num_rows > 0): ?>
<?php while ($row = $arrivalsResult->fetch_assoc()): ?>
<tr>
<td><?= htmlspecialchars($row['ac_reg']) ?></td>
<td><?= htmlspecialchars($row['ac_type']) ?></td>
<td><?= htmlspecialchars($row['in_from']) ?></td>
<td><?= htmlspecialchars($row['due']) ?></td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="4">No arrivals found.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Right column with departures table -->
<div>
<h2><center>Departures</center></h2>
<table>
<thead>
<tr>
<th>Registration</th>
<th>Aircraft Type</th>
<th>To</th>
<th>Due</th>
</tr>
</thead>
<tbody>
<?php if ($departuresResult->num_rows > 0): ?>
<?php while ($row = $departuresResult->fetch_assoc()): ?>
<tr>
<td><?= htmlspecialchars($row['ac_reg']) ?></td>
<td><?= htmlspecialchars($row['ac_type']) ?></td>
<td><?= htmlspecialchars($row['out_to']) ?></td>
<td><?= htmlspecialchars($row['due']) ?></td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="4">No departures found.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</main>
<footer>
<!-- Footer content -->
<div class="iso-marquee-linkwrap">
<div class="iso-marquee--long iso-marquee">
<!-- Add marquee content here -->
</div>
</div>
</footer>
</body>
</html>
<?php
// Close the database connection
$conn->close();
?>

100
tower.php
View File

@@ -173,6 +173,8 @@ require_db_auth();
</head> </head>
<body> <body>
<?php include("menu.php"); ?>
<script> <script>
function markAction(id, action, title, buttonText) { function markAction(id, action, title, buttonText) {
const now = new Date(); const now = new Date();
@@ -213,11 +215,24 @@ function markLanded(id) {
} }
function markCancel(id) { function markCancel(id) {
const page = `action.php?op=cancel&id=${id}`; Swal.fire({
var xhr = new XMLHttpRequest(); title: "Are you sure?",
xhr.open("GET", page, false); // 'false' makes the request synchronous text: "This action will cancel the PPR.",
xhr.send(); icon: "warning",
window.location.reload(true); showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yes, cancel it!",
cancelButtonText: "No, keep it"
}).then((result) => {
if (result.isConfirmed) {
const page = `action.php?op=cancel&id=${id}`;
var xhr = new XMLHttpRequest();
xhr.open("GET", page, false); // 'false' makes the request synchronous
xhr.send();
window.location.reload(true);
}
});
} }
function openDetail(id) { function openDetail(id) {
@@ -245,6 +260,9 @@ function openDetail(id) {
<?php <?php
function renderTableCell($key, $value, $row) { function renderTableCell($key, $value, $row) {
if ($key == 'ETA' || $key == 'ETD') {
return "<td>" . htmlspecialchars($value ?? '') . (!empty($value) ? " Z" : "") . "</td>"; // Add "Z" suffix only if not blank
}
if ($key == 'ac_reg' && $row['ac_call'] != NULL) { if ($key == 'ac_reg' && $row['ac_call'] != NULL) {
$notes = htmlspecialchars($row['notes'] ?? ''); $notes = htmlspecialchars($row['notes'] ?? '');
$acCall = htmlspecialchars($row['ac_call'] ?? ''); $acCall = htmlspecialchars($row['ac_call'] ?? '');
@@ -257,11 +275,33 @@ function renderTableCell($key, $value, $row) {
$notes = htmlspecialchars($row['notes'] ?? ''); $notes = htmlspecialchars($row['notes'] ?? '');
$acReg = htmlspecialchars($value ?? ''); $acReg = htmlspecialchars($value ?? '');
return "<td class='red-triangle' data-notes='$notes'>$acReg</td>"; return "<td class='red-triangle' data-notes='$notes'>$acReg</td>";
} elseif ($key == 'in_from' || $key == 'out_to') {
if (!empty($value) && (strlen($value) === 3 || strlen($value) === 4)) {
$airportName = getAirport(connectDb(), $value);
if ($airportName) {
return "<td>" . htmlspecialchars($value) . "<br><span style='font-size: smaller; font-style: italic;'>" . htmlspecialchars($airportName) . "</span></td>";
}
}
return "<td>" . htmlspecialchars($value ?? '') . "</td>";
} else { } else {
return "<td>" . htmlspecialchars($value ?? '') . "</td>"; return "<td>" . htmlspecialchars($value ?? '') . "</td>";
} }
} }
function renderActionsCell($id, $status = null) {
if ($status === 'LANDED') {
return "<td>
<img src='assets/cancel-icon.webp' title='Cancel PPR' style='width: 25px; height: auto;' onclick='markCancel($id)'>
<img src='assets/depart.png' title='Depart' style='width: 30px; height: auto;' onclick='markDeparted($id)'>
</td>";
} else {
return "<td>
<img src='assets/cancel-icon.webp' title='Cancel PPR' style='width: 25px; height: auto;' onclick='markCancel($id)'>
<img src='assets/arrive.png' title='Land' style='width: 30px; height: auto;' onclick='markLanded($id)'>
</td>";
}
}
function renderTableRow($row) { function renderTableRow($row) {
$rowHtml = "<tr class='state-" . htmlspecialchars($row['status']) . "' data-id='" . htmlspecialchars($row['id']) . "'>"; $rowHtml = "<tr class='state-" . htmlspecialchars($row['status']) . "' data-id='" . htmlspecialchars($row['id']) . "'>";
foreach ($row as $key => $value) { foreach ($row as $key => $value) {
@@ -269,18 +309,11 @@ function renderTableRow($row) {
$rowHtml .= renderTableCell($key, $value, $row); $rowHtml .= renderTableCell($key, $value, $row);
} }
} }
$rowHtml .= renderActionsCell($row['id']); $rowHtml .= renderActionsCell($row['id'], $row['status']);
$rowHtml .= "</tr>"; $rowHtml .= "</tr>";
return $rowHtml; return $rowHtml;
} }
function renderActionsCell($id) {
return "<td>
<img src='assets/cancel-icon.webp' title='Cancel PPR' style='width: 25px; height: auto;' onclick='markCancel($id)'>
<img src='assets/arrive.png' title='Land' style='width: 30px; height: auto;' onclick='markLanded($id)'>
</td>";
}
function renderTable($result) { function renderTable($result) {
$tableHtml = "<table border='1' id='arrivals'> $tableHtml = "<table border='1' id='arrivals'>
<thead> <thead>
@@ -327,44 +360,7 @@ $result = $conn->query($sql);
// Check if there are results // Check if there are results
if ($result->num_rows > 0) { if ($result->num_rows > 0) {
// Start HTML table echo renderTable($result); // Use the renderTable function
echo '<table border="1" id="landed">
<thead>
<tr>';
// Output table headers (assuming column names are known)
$fields = $result->fetch_fields();
foreach ($fields as $field) {
if ($field->name != 'notes' && $field->name != 'status' && $field->name != 'id' && $field->name != 'ac_call') {
echo '<th>' . htmlspecialchars($field->name ?? '') . '</th>';
}
}
echo '<th>actions</th>';
echo ' </tr>
</thead>
<tbody>';
// Output table rows
while ($row = $result->fetch_assoc()) {
echo '<tr class="state-' . $row['status'] . '" data-id=' . $row['id'] . '>';
foreach ($row as $key => $value) {
if ($key != 'notes' && $key != 'status' && $key != 'id' && $key != 'ac_call') {
if ($key == 'ac_reg' && $row['ac_call'] != NULL) {
echo '<td>' . htmlspecialchars($row['ac_call'] ?? '') . "<br><span class=acreg>" . $value . '</span></td>';
} else if ($key == 'ac_reg' && !empty($row['notes'])) {
echo '<td class="red-triangle" data-notes="' . htmlspecialchars($row['notes'] ?? '') . '">' . htmlspecialchars($value ?? '') . '</td>';
} else {
echo '<td>' . htmlspecialchars($value ?? '') . '</td>';
}
}
}
echo '<td><img src="assets/cancel-icon.webp" title="Cancel PPR" style="width: 25px; height: auto;" onclick="markCancel(' . $row['id'] . ')"><img src="assets/depart.png" title="Depart" style="width: 30px; height: auto;" onclick="markDeparted(' . $row['id'] . ')"></td>';
echo '</tr>';
}
echo ' </tbody></table>';
} else { } else {
echo "No results found."; echo "No results found.";
} }
@@ -421,5 +417,5 @@ $conn->close();
</script> </script>
<?php include("footer.php"); ?>

304
upcoming.php Normal file
View File

@@ -0,0 +1,304 @@
<?php
include("functions.php");
require_db_auth();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="refresh" content="300">
<!-- Include SweetAlert -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Upcoming Movements</title>
<style>
/* Table styling */
table {
width: 80%;
border-collapse: collapse;
margin: 20px auto;
}
table, th, td {
border: 1px solid #ddd;
}
th, td {
padding: 8px;
text-align: center;
font-family: Arial, sans-serif;
}
th {
padding: 8px;
text-align: center;
}
td {
padding: 8px;
text-align: center;
font-family: Arial, sans-serif;
font-size: 16pt;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
tr:hover {
background-color: #f1f1f1;
}
.highlight100LL {
background-color: #ADD8E6 !important;
}
.highlightJET {
background-color: yellow !important;
}
/* Add this CSS for the red triangle */
.red-triangle {
position: relative;
}
.red-triangle::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
border-left: 10px solid red;
border-bottom: 10px solid transparent;
}
.red-triangle:hover::after {
content: attr(data-notes);
position: absolute;
top: 20px;
left: 0;
background: #fff;
border: 1px solid #ddd;
padding: 5px;
border-radius: 5px;
white-space: nowrap;
z-index: 10;
}
.checkbox-container {
display: flex;
gap: 15px;
margin-bottom: 15px;
padding: 10px;
background: #f9f9f9;
border-radius: 8px;
width: fit-content;
}
.heading {
width: 80%;
margin: 20px auto;
background-color: #fff;
text-align: center;
font-family: Arial, sans-serif;
font-size: 20pt;
}
label {
display: flex;
align-items: center;
gap: 5px;
font-size: 16px;
cursor: pointer;
}
.hidden {
display: none;
}
.state-CANCELED {
text-decoration: line-through;
color: gray;
}
.state-LANDED {
font-style: italic;
color: gray;
}
input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.acreg {
padding: 4px;
text-align: center;
font-family: Arial, sans-serif;
font-size: 10pt;
font-style: italic;
}
</style>
</head>
<body>
<?php include("menu.php"); ?>
<script>
function markAction(id, action, title, buttonText) {
const now = new Date();
const currentTime = now.toISOString().slice(11, 16); // Extract HH:MM
Swal.fire({
title: title,
html: `<input type="time" id="timepicker" class="swal2-input" value="${currentTime}">`,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: buttonText,
preConfirm: () => {
const time = document.getElementById("timepicker").value;
if (!time) {
Swal.showValidationMessage("Please select a time");
}
return time;
}
}).then((result) => {
if (result.isConfirmed) {
const page = `action.php?op=${action}&id=${id}&time=${encodeURIComponent(result.value)}`;
var xhr = new XMLHttpRequest();
xhr.open("GET", page, false); // 'false' makes the request synchronous
xhr.send();
window.location.reload(true);
}
});
}
function markCancel(id) {
Swal.fire({
title: "Are you sure?",
text: "This action will cancel the PPR.",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yes, cancel it!",
cancelButtonText: "No, keep it"
}).then((result) => {
if (result.isConfirmed) {
const page = `action.php?op=cancel&id=${id}`;
var xhr = new XMLHttpRequest();
xhr.open("GET", page, false); // 'false' makes the request synchronous
xhr.send();
window.location.reload(true);
}
});
}
function openDetail(id) {
const page = `action.php?op=detail&id=${id}`;
var popupWindow = window.open(page, "PopupWindow", "toolbar=no, location=no, directories=no,status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=yes, width=600, height=1100");
popupWindow.onload = function () {
var contentHeight = popupWindow.document.body.scrollHeight;
var contentWidth = popupWindow.document.body.scrollWidth;
popupWindow.resizeTo(contentWidth + 20, contentHeight + 180); // Adding padding to prevent clipping
};
}
</script>
<center><h2>Upcoming Movements</h2></center>
<?php
function renderTableCell($key, $value, $row) {
if ($key == 'ETA') {
return "<td>" . htmlspecialchars($value ?? '') . (!empty($value) ? " Z" : "") . "</td>";
}
if ($key == 'ac_reg' && $row['ac_call'] != NULL) {
$notes = htmlspecialchars($row['notes'] ?? '');
$acCall = htmlspecialchars($row['ac_call'] ?? '');
$acReg = htmlspecialchars($value ?? '');
if (!empty($row['notes'])) {
return "<td class='red-triangle' data-notes='$notes'>$acCall<br><span class='acreg'>$acReg</span></td>";
}
return "<td>$acCall<br><span class='acreg'>$acReg</span></td>";
} elseif ($key == 'ac_reg' && !empty($row['notes'])) {
$notes = htmlspecialchars($row['notes'] ?? '');
$acReg = htmlspecialchars($value ?? '');
return "<td class='red-triangle' data-notes='$notes'>$acReg</td>";
} elseif ($key == 'in_from' || $key == 'out_to') {
if (!empty($value) && (strlen($value) === 3 || strlen($value) === 4)) {
$airportName = getAirport(connectDb(), $value);
if ($airportName) {
return "<td>" . htmlspecialchars($value) . "<br><span style='font-size: smaller; font-style: italic;'>" . htmlspecialchars($airportName) . "</span></td>";
}
}
return "<td>" . htmlspecialchars($value ?? '') . "</td>";
} else {
return "<td>" . htmlspecialchars($value ?? '') . "</td>";
}
}
function renderActionsCell($id) {
return "<td>
<img src='assets/cancel-icon.webp' title='Cancel PPR' style='width: 25px; height: auto;' onclick='markCancel($id)'>
<img src='assets/edit.png' title='Edit Details' style='width: 25px; height: auto;' onclick='openDetail($id)'>
</td>";
}
function renderTableRow($row) {
$rowHtml = "<tr>";
foreach ($row as $key => $value) {
if (!in_array($key, ['id', 'ac_call', 'notes'])) { // Exclude 'notes'
$rowHtml .= renderTableCell($key, $value, $row);
}
}
$rowHtml .= renderActionsCell($row['id']);
$rowHtml .= "</tr>";
return $rowHtml;
}
function renderTable($result) {
$tableHtml = "<table border='1'>
<thead>
<tr>";
$fields = $result->fetch_fields();
foreach ($fields as $field) {
if (!in_array($field->name, ['id', 'ac_call', 'notes'])) { // Exclude 'notes'
$tableHtml .= "<th>" . htmlspecialchars($field->name ?? '') . "</th>";
}
}
$tableHtml .= "<th>Actions</th></tr></thead><tbody>";
while ($row = $result->fetch_assoc()) {
$tableHtml .= renderTableRow($row);
}
$tableHtml .= "</tbody></table>";
return $tableHtml;
}
$conn = connectDb();
$sql = "SELECT id, ac_reg, ac_type, ac_call, eta AS ETA, fuel, in_from, pob_in, notes
FROM submitted
WHERE DATE(eta) > CURDATE()
AND status != 'CANCELED'
ORDER BY eta ASC;";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
echo renderTable($result);
} else {
echo "<center>No upcoming movements found.</center>";
}
$conn->close();
?>
</body>
</html>
<?php include("footer.php"); ?>

View File

@@ -25,6 +25,14 @@ if (!in_array($column, $allowed_columns)) {
die(json_encode(['error' => 'Invalid column'])); die(json_encode(['error' => 'Invalid column']));
} }
// Convert eta or etd to UTC if supplied
// 1st June 2025 JP - NO - when editing just use Zulu time
//if (in_array($column, ['eta', 'etd'])) {
// $date = new DateTime($new_value, new DateTimeZone('Europe/London'));
// $date->setTimezone(new DateTimeZone('UTC'));
// $new_value = $date->format('Y-m-d H:i:s');
//}
$stmt = $conn->prepare("UPDATE submitted SET `$column` = ? WHERE id = ?"); $stmt = $conn->prepare("UPDATE submitted SET `$column` = ? WHERE id = ?");
if (!$stmt) { if (!$stmt) {
die(json_encode(['error' => 'Prepare statement failed'])); die(json_encode(['error' => 'Prepare statement failed']));

View File

@@ -1,8 +1,6 @@
<?php <?php
include("functions.php"); include("functions.php");
$created_by = "Website (DEV)";
$conn = connectDb(); $conn = connectDb();
// Check if the URL has a 'test' parameter set // Check if the URL has a 'test' parameter set

View File

@@ -1,84 +0,0 @@
<?php
// Basic connection settings
$databaseHost = 'sasaprod.pattinson.org';
$databaseUsername = 'root';
$databasePassword = 'PugPictureMousePen';
$databaseName = 'pprdevdb';
$created_by = "webhook-dev";
//ini_set("error_log", "ppr.log");
error_log("Webhook handler called");
// Connect to the database
$mysqli = mysqli_connect($databaseHost, $databaseUsername, $databasePassword, $databaseName);
header('Content-Type: application/json');
#if($json = json_decode(file_get_contents("php://input"), true)) {
if($json = json_decode(file_get_contents("testhook.json"), true)) {
$data = $json;
}
print_r($data);
$fieldMap = array();
$fieldMap['ac_reg'] = '617dd0cd-2d17-4d7f-826b-5348afdb30b3';
$fieldMap['ac_type'] = '148a55d8-5357-49a3-b9aa-2a5d4dc64173';
$fieldMap['ac_call'] = '52d7bc90-9d26-48a1-82db-b91b4ccd2f92';
$fieldMap['captain'] = '49b2de0d-5bd6-4b0c-86dd-b18b85f8b8ff';
$fieldMap['fuel'] = 'd153c8a5-8345-4e6a-abfd-cf8adcc06f2d';
$fieldMap['in_from'] = '4b4f7ecd-f80c-4e86-a7ab-6fadb3220df8';
$fieldMap['eta'] = 'ca4ac44f-0388-4a70-a072-38276ed2ac13';
$fieldMap['pob_in'] = '6fc47c54-7383-48fd-93fc-d8080f5ed8f5';
$fieldMap['out_to'] = 'ba95fd3f-1ec0-4553-95d3-a0b6a850738d';
$fieldMap['etd'] = '53d60abd-eb75-4b1f-92b6-5d47d26367ec';
$fieldMap['pob_out'] = 'd1ac0860-31f4-4914-9d0b-cae42dfc7eda';
$fieldMap['email'] = '0198c86c-edd1-4aaf-93a1-d68f8fc8c365';
$fieldMap['phone'] = 'e40ebc2d-887b-42b3-931d-c981c76b0c20';
$fieldMap['notes'] = '73d26c2c-1d3d-44e2-82fc-3a1a2600c393';
#print_r($json['data'][$fieldMap['eta']]['value']);
$stmt = mysqli_prepare($mysqli, "INSERT INTO submitted (ac_reg, ac_type, captain, fuel, in_from, eta, pob_in, etd, pob_out, email, phone, notes, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
// Check if the statement was prepared correctly
if ($stmt === false) {
die('MySQL prepare error: ' . mysqli_error($conn));
}
$ac_reg = $json['data'][$fieldMap['ac_reg']]['value'];
$ac_type = $json['data'][$fieldMap['ac_type']]['value'];
$captain = $json['data'][$fieldMap['captain']]['value'];
$in_from = $json['data'][$fieldMap['in_from']]['value'];
$fuel = $json['data'][$fieldMap['fuel']]['value'];
$date = DateTime::createFromFormat('d/m/Y H:i', $json['data'][$fieldMap['eta']]['value']);
$eta = $date->format('Y-m-d H:i:s');
$pob_in = $json['data'][$fieldMap['pob_in']]['value'];
if (array_key_exists($fieldMap['out_to'], $json['data'])) {
$date = DateTime::createFromFormat('d/m/Y H:i', $json['data'][$fieldMap['etd']]['value']);
$etd = $date->format('Y-m-d H:i:s');
$pob_out = $json['data'][$fieldMap['pob_out']]['value'];
$out_to = $json['data'][$fieldMap['out_to']]['value'];
}
$email = $json['data'][$fieldMap['email']]['value'];
$phone = $json['data'][$fieldMap['phone']]['value'];
$notes = $json['data'][$fieldMap['notes']]['value'];
mysqli_stmt_bind_param($stmt, "ssssssisissss", $ac_reg, $ac_type, $captain, $fuel, $in_from, $eta, $pob_in, $etd, $pob_out, $email, $phone, $notes, $created_by);
// Execute the statement
if (mysqli_stmt_execute($stmt)) {
error_log("Record inserted for " . $ac_reg);
} else {
error_log("Error: " . mysqli_stmt_error($stmt));
}
// Close the statement and connection
mysqli_stmt_close($stmt);
mysqli_close($mysqli);
?>