Update: Add publish/unpublish button to admin trips table and improve table styling
This commit is contained in:
BIN
assets/images/pp/7a7b9965853213ea1e4ed1aec4e18ad0.jpg
Normal file
BIN
assets/images/pp/7a7b9965853213ea1e4ed1aec4e18ad0.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 290 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 MiB |
@@ -174,7 +174,7 @@ if (!empty($bannerImages)) {
|
|||||||
|
|
||||||
// Fetch bookings for the current trip
|
// Fetch bookings for the current trip
|
||||||
$bookingsSql = "SELECT b.user_id, b.num_vehicles, b.num_adults, b.num_children, b.num_pensioners, b.radio, b.status,
|
$bookingsSql = "SELECT b.user_id, b.num_vehicles, b.num_adults, b.num_children, b.num_pensioners, b.radio, b.status,
|
||||||
u.first_name, u.last_name,
|
u.first_name, u.last_name, u.profile_pic,
|
||||||
(b.total_amount - b.discount_amount) AS paid
|
(b.total_amount - b.discount_amount) AS paid
|
||||||
FROM bookings b
|
FROM bookings b
|
||||||
INNER JOIN users u ON b.user_id = u.user_id
|
INNER JOIN users u ON b.user_id = u.user_id
|
||||||
|
|||||||
@@ -22,27 +22,175 @@ if ($result && $result->num_rows > 0) {
|
|||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th {
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
padding: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th::after {
|
||||||
|
content: '\25B2';
|
||||||
|
/* Up arrow */
|
||||||
|
font-size: 0.8em;
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th.asc::after {
|
||||||
|
content: '\25B2';
|
||||||
|
/* Up arrow */
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th.desc::after {
|
||||||
|
content: '\25BC';
|
||||||
|
/* Down arrow */
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:nth-child(odd) {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:nth-child(even) {
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody td {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:nth-child(even) td:first-child {
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:nth-child(even) td:last-child {
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
border-radius: 25px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trips-section {
|
||||||
|
color: #484848;
|
||||||
|
background: #f9f9f7;
|
||||||
|
border: 1px solid #d8d8d8;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const tables = document.querySelectorAll("table");
|
||||||
|
tables.forEach((table) => {
|
||||||
|
const headers = table.querySelectorAll("thead th");
|
||||||
|
const rows = Array.from(table.querySelectorAll("tbody tr"));
|
||||||
|
const filterInput = table.previousElementSibling;
|
||||||
|
|
||||||
|
headers.forEach((header, index) => {
|
||||||
|
header.addEventListener("click", () => {
|
||||||
|
const sortedRows = rows.sort((a, b) => {
|
||||||
|
const aText = a.cells[index].textContent.trim().toLowerCase();
|
||||||
|
const bText = b.cells[index].textContent.trim().toLowerCase();
|
||||||
|
|
||||||
|
if (aText < bText) return -1;
|
||||||
|
if (aText > bText) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (header.classList.contains("asc")) {
|
||||||
|
header.classList.remove("asc");
|
||||||
|
header.classList.add("desc");
|
||||||
|
sortedRows.reverse();
|
||||||
|
} else {
|
||||||
|
headers.forEach(h => h.classList.remove("asc", "desc"));
|
||||||
|
header.classList.add("asc");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tbody = table.querySelector("tbody");
|
||||||
|
tbody.innerHTML = "";
|
||||||
|
sortedRows.forEach(row => tbody.appendChild(row));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (rows.length === 0) {
|
||||||
|
filterInput.style.display = "none";
|
||||||
|
} else {
|
||||||
|
filterInput.addEventListener("input", function() {
|
||||||
|
const filterValue = filterInput.value.trim().toLowerCase();
|
||||||
|
rows.forEach(row => {
|
||||||
|
const rowText = row.textContent.trim().toLowerCase();
|
||||||
|
row.style.display = rowText.includes(filterValue) ? "" : "none";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$pageTitle = 'Manage Trips';
|
$bannerFolder = 'assets/images/banners/';
|
||||||
$breadcrumbs = [['Home' => 'index'], ['Admin' => 'admin'], [$pageTitle => '']];
|
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||||
require_once($rootPath . '/components/banner.php');
|
|
||||||
|
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||||
|
if (!empty($bannerImages)) {
|
||||||
|
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url('<?php echo $randomBanner; ?>');">
|
||||||
|
<div class="banner-overlay"></div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="banner-inner text-white mb-50">
|
||||||
|
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Manage Trips</h2>
|
||||||
|
<nav aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumb justify-content-center mb-20" data-aos="fade-right" data-aos-delay="200" data-aos-duration="1500" data-aos-offset="50">
|
||||||
|
<li class="breadcrumb-item"><a href="index">Home</a></li>
|
||||||
|
<li class="breadcrumb-item active">Manage Trips</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Trips Management Area start -->
|
<!-- Trips Management Area start -->
|
||||||
<section class="trips-management-area py-100 rel z-1">
|
<section class="tour-list-page py-100 rel z-1">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div style="margin-bottom: 20px;">
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="section-title mb-50">
|
|
||||||
<h2>Manage Trips</h2>
|
|
||||||
<a href="manage_trips" class="theme-btn">
|
<a href="manage_trips" class="theme-btn">
|
||||||
<i class="far fa-plus"></i> Create New Trip
|
<i class="far fa-plus"></i> Create New Trip
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-responsive">
|
<?php
|
||||||
<table class="table table-striped">
|
if (count($trips) > 0) {
|
||||||
<thead class="table-dark">
|
echo '<input type="text" class="filter-input" placeholder="Filter trips...">';
|
||||||
|
echo '<div class="trips-section" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">';
|
||||||
|
echo '<div style="padding:10px;">';
|
||||||
|
echo '<table>
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Trip Name</th>
|
<th>Trip Name</th>
|
||||||
<th>Location</th>
|
<th>Location</th>
|
||||||
@@ -55,55 +203,39 @@ if ($result && $result->num_rows > 0) {
|
|||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>';
|
||||||
<?php if (count($trips) > 0): ?>
|
foreach ($trips as $trip) {
|
||||||
<?php foreach ($trips as $trip): ?>
|
$publishButtonText = $trip['published'] == 1 ? 'Unpublish' : 'Publish';
|
||||||
<tr>
|
$publishButtonClass = $trip['published'] == 1 ? 'btn-warning' : 'btn-success';
|
||||||
|
echo '<tr>
|
||||||
|
<td><strong>' . htmlspecialchars($trip['trip_name']) . '</strong></td>
|
||||||
|
<td>' . htmlspecialchars($trip['location']) . '</td>
|
||||||
|
<td>' . date('M d, Y', strtotime($trip['start_date'])) . '</td>
|
||||||
|
<td>' . date('M d, Y', strtotime($trip['end_date'])) . '</td>
|
||||||
|
<td>' . $trip['vehicle_capacity'] . '</td>
|
||||||
|
<td><span class="badge bg-info">' . $trip['places_booked'] . ' / ' . $trip['vehicle_capacity'] . '</span></td>
|
||||||
|
<td>R ' . number_format($trip['cost_members'], 2) . '</td>
|
||||||
|
<td>' . ($trip['published'] == 1 ? '<span class="badge bg-success">Published</span>' : '<span class="badge bg-warning">Draft</span>') . '</td>
|
||||||
<td>
|
<td>
|
||||||
<strong><?php echo htmlspecialchars($trip['trip_name']); ?></strong>
|
<a href="manage_trips?trip_id=' . $trip['trip_id'] . '" class="btn btn-sm btn-primary" title="Edit">
|
||||||
</td>
|
|
||||||
<td><?php echo htmlspecialchars($trip['location']); ?></td>
|
|
||||||
<td><?php echo date('M d, Y', strtotime($trip['start_date'])); ?></td>
|
|
||||||
<td><?php echo date('M d, Y', strtotime($trip['end_date'])); ?></td>
|
|
||||||
<td><?php echo $trip['vehicle_capacity']; ?></td>
|
|
||||||
<td>
|
|
||||||
<span class="badge bg-info">
|
|
||||||
<?php echo $trip['places_booked'] . ' / ' . $trip['vehicle_capacity']; ?>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>R <?php echo number_format($trip['cost_members'], 2); ?></td>
|
|
||||||
<td>
|
|
||||||
<?php if ($trip['published'] == 1): ?>
|
|
||||||
<span class="badge bg-success">Published</span>
|
|
||||||
<?php else: ?>
|
|
||||||
<span class="badge bg-warning">Draft</span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="manage_trips?trip_id=<?php echo $trip['trip_id']; ?>"
|
|
||||||
class="btn btn-sm btn-primary" title="Edit">
|
|
||||||
<i class="far fa-edit"></i>
|
<i class="far fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<button class="btn btn-sm btn-danger delete-trip"
|
<button class="btn btn-sm ' . $publishButtonClass . ' toggle-publish" data-trip-id="' . $trip['trip_id'] . '" title="' . $publishButtonText . '">
|
||||||
data-trip-id="<?php echo $trip['trip_id']; ?>"
|
<i class="far fa-' . ($trip['published'] == 1 ? 'eye-slash' : 'eye') . '"></i>
|
||||||
title="Delete">
|
</button>
|
||||||
|
<button class="btn btn-sm btn-danger delete-trip" data-trip-id="' . $trip['trip_id'] . '" title="Delete">
|
||||||
<i class="far fa-trash"></i>
|
<i class="far fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>';
|
||||||
<?php endforeach; ?>
|
}
|
||||||
<?php else: ?>
|
echo '</tbody></table>';
|
||||||
<tr>
|
echo '</div>';
|
||||||
<td colspan="9" class="text-center py-4">
|
echo '</div>';
|
||||||
<p class="text-muted">No trips found. <a href="manage_trips">Create one</a></p>
|
} else {
|
||||||
</td>
|
echo '<p>No trips found. <a href="manage_trips">Create one</a></p>';
|
||||||
</tr>
|
}
|
||||||
<?php endif; ?>
|
?>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<!-- Trips Management Area end -->
|
<!-- Trips Management Area end -->
|
||||||
@@ -111,6 +243,44 @@ if ($result && $result->num_rows > 0) {
|
|||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
$('.toggle-publish').on('click', function() {
|
||||||
|
var tripId = $(this).data('trip-id');
|
||||||
|
var button = $(this);
|
||||||
|
var row = button.closest('tr');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'toggle_trip_published',
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
trip_id: tripId
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
if (response.status === 'success') {
|
||||||
|
// Update button appearance
|
||||||
|
if (response.published == 1) {
|
||||||
|
button.removeClass('btn-success').addClass('btn-warning');
|
||||||
|
button.find('i').removeClass('fa-eye').addClass('fa-eye-slash');
|
||||||
|
button.attr('title', 'Unpublish');
|
||||||
|
// Update status badge
|
||||||
|
row.find('td:nth-child(8)').html('<span class="badge bg-success">Published</span>');
|
||||||
|
} else {
|
||||||
|
button.removeClass('btn-warning').addClass('btn-success');
|
||||||
|
button.find('i').removeClass('fa-eye-slash').addClass('fa-eye');
|
||||||
|
button.attr('title', 'Publish');
|
||||||
|
// Update status badge
|
||||||
|
row.find('td:nth-child(8)').html('<span class="badge bg-warning">Draft</span>');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert('Error: ' + response.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
alert('Error updating trip status');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$('.delete-trip').on('click', function() {
|
$('.delete-trip').on('click', function() {
|
||||||
if (!confirm('Are you sure you want to delete this trip? This action cannot be undone.')) {
|
if (!confirm('Are you sure you want to delete this trip? This action cannot be undone.')) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ if ($trip_id) {
|
|||||||
<div class="col-md-12 mt-20">
|
<div class="col-md-12 mt-20">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Trip Images</label>
|
<label>Trip Images</label>
|
||||||
<p class="text-muted">Upload images for this trip. Primary image will be named {trip_id}_01.jpg</p>
|
<p class="text-muted">Upload images for this trip. Ideally 5 different images will be required</p>
|
||||||
<input type="file" name="trip_images[]" class="form-control" accept="image/*" multiple>
|
<input type="file" name="trip_images[]" class="form-control" accept="image/*" multiple>
|
||||||
<?php if ($trip): ?>
|
<?php if ($trip): ?>
|
||||||
<small class="text-info">Images will be saved to: assets/images/trips/<?php echo $trip_id; ?>_{number}.jpg</small>
|
<small class="text-info">Images will be saved to: assets/images/trips/<?php echo $trip_id; ?>_{number}.jpg</small>
|
||||||
|
|||||||
@@ -12,12 +12,22 @@ $token = $_GET['token'];
|
|||||||
// Sanitize the trip_id to prevent SQL injection
|
// Sanitize the trip_id to prevent SQL injection
|
||||||
$trip_id = intval(decryptData($token, $salt)); // Ensures $trip_id is treated as an integer
|
$trip_id = intval(decryptData($token, $salt)); // Ensures $trip_id is treated as an integer
|
||||||
|
|
||||||
|
// Check if user is admin or superadmin to allow draft preview
|
||||||
|
// Check if user is admin/superadmin
|
||||||
|
$user_role = getUserRole();
|
||||||
|
$is_admin = in_array($user_role, ['admin', 'superadmin']);
|
||||||
|
|
||||||
// Prepare the SQL query
|
// Prepare the SQL query
|
||||||
$sql = "SELECT trip_id, trip_name, location, short_description, long_description, start_date, end_date,
|
$sql = "SELECT trip_id, trip_name, location, short_description, long_description, start_date, end_date,
|
||||||
vehicle_capacity, cost_members, cost_nonmembers, places_booked, booking_fee, cost_pensioner, cost_pensioner_member
|
vehicle_capacity, cost_members, cost_nonmembers, places_booked, booking_fee, cost_pensioner, cost_pensioner_member, published
|
||||||
FROM trips
|
FROM trips
|
||||||
WHERE trip_id = ?";
|
WHERE trip_id = ?";
|
||||||
|
|
||||||
|
// If not admin, only show published trips
|
||||||
|
if (!$is_admin) {
|
||||||
|
$sql .= " AND published = 1";
|
||||||
|
}
|
||||||
|
|
||||||
// Use prepared statements for added security
|
// Use prepared statements for added security
|
||||||
$stmt = $conn->prepare($sql);
|
$stmt = $conn->prepare($sql);
|
||||||
|
|
||||||
@@ -194,12 +204,39 @@ include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
|||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Draft Notice for Admin -->
|
||||||
|
<?php if ($is_admin && isset($row['published']) && $row['published'] == 0): ?>
|
||||||
|
<div class="alert alert-warning mt-3" role="alert">
|
||||||
|
<strong><i class="fas fa-exclamation-triangle"></i> Draft Trip</strong><br>
|
||||||
|
This trip is currently in draft status and is not visible to regular users. Only admins and superadmins can preview it.
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- Publish/Unpublish Button -->
|
||||||
|
<?php
|
||||||
|
$user_role = getUserRole();
|
||||||
|
if (in_array($user_role, ['admin', 'superadmin'])):
|
||||||
|
// Use published status from the main query
|
||||||
|
$is_published = $row['published'] ?? 0;
|
||||||
|
?>
|
||||||
|
<div class="admin-actions mt-20">
|
||||||
|
<button type="button" class="theme-btn" style="width: 100%; id="publishBtn" onclick="toggleTripPublished(<?php echo $trip_id; ?>)">
|
||||||
|
<?php if ($is_published): ?>
|
||||||
|
<i class="fas fa-eye-slash"></i> Unpublish Trip
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-eye"></i> Publish Trip
|
||||||
|
<?php endif; ?>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Tour Gallery start -->
|
<!-- Tour Gallery start -->
|
||||||
<div class="tour-gallery">
|
<div class="tour-gallery">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
@@ -260,36 +297,7 @@ include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
|||||||
</div>
|
</div>
|
||||||
<span class="subtitle mb-15"><?php echo $badge_text; ?></span>
|
<span class="subtitle mb-15"><?php echo $badge_text; ?></span>
|
||||||
|
|
||||||
<!-- Admin Publish/Unpublish Button -->
|
|
||||||
<?php
|
|
||||||
$user_role = $_SESSION['role'] ?? 'user';
|
|
||||||
if (in_array($user_role, ['admin', 'superadmin'])):
|
|
||||||
// Fetch current published status
|
|
||||||
$status_stmt = $conn->prepare("SELECT published FROM trips WHERE trip_id = ?");
|
|
||||||
$status_stmt->bind_param("i", $trip_id);
|
|
||||||
$status_stmt->execute();
|
|
||||||
$status_result = $status_stmt->get_result();
|
|
||||||
$trip_status = $status_result->fetch_assoc();
|
|
||||||
$is_published = $trip_status['published'] ?? 0;
|
|
||||||
$status_stmt->close();
|
|
||||||
?>
|
|
||||||
<div class="admin-actions mt-20">
|
|
||||||
<button type="button" class="theme-btn" id="publishBtn" onclick="toggleTripPublished(<?php echo $trip_id; ?>)">
|
|
||||||
<?php if ($is_published): ?>
|
|
||||||
<i class="fas fa-eye-slash"></i> Unpublish Trip
|
|
||||||
<?php else: ?>
|
|
||||||
<i class="fas fa-eye"></i> Publish Trip
|
|
||||||
<?php endif; ?>
|
|
||||||
</button>
|
|
||||||
<span id="publishStatus" class="ml-3" style="margin-left: 10px;">
|
|
||||||
<?php if ($is_published): ?>
|
|
||||||
<span class="badge bg-success">Published</span>
|
|
||||||
<?php else: ?>
|
|
||||||
<span class="badge bg-warning">Draft</span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="col-xl-4 col-lg-5 text-lg-end" data-aos="fade-right" data-aos-duration="1500" data-aos-offset="50">
|
<!-- <div class="col-xl-4 col-lg-5 text-lg-end" data-aos="fade-right" data-aos-duration="1500" data-aos-offset="50">
|
||||||
<div class="tour-header-social mb-10">
|
<div class="tour-header-social mb-10">
|
||||||
|
|||||||
@@ -7,14 +7,18 @@ include_once($rootPath . '/header.php');
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.image {
|
.image {
|
||||||
width: 400px;
|
width: 100%;
|
||||||
/* Set your desired width */
|
|
||||||
height: 350px;
|
height: 350px;
|
||||||
/* Set your desired height */
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
/* Hide any overflow */
|
|
||||||
display: block;
|
display: block;
|
||||||
/* Ensure proper block behavior */
|
}
|
||||||
|
|
||||||
|
.image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: top;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -52,8 +56,17 @@ include_once($rootPath . '/header.php');
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
// Check if user is admin or superadmin to show draft trips
|
||||||
|
$user_role = getUserRole();
|
||||||
|
$is_admin = in_array($user_role, ['admin', 'superadmin']);
|
||||||
|
|
||||||
// Query to retrieve data from the trips table
|
// Query to retrieve data from the trips table
|
||||||
$sql = "SELECT trip_id, trip_name, location, short_description, start_date, end_date, vehicle_capacity, cost_members, places_booked FROM trips WHERE published = 1 AND start_date > CURDATE()";
|
// Admins see all trips (published and draft), regular users only see published upcoming trips
|
||||||
|
if ($is_admin) {
|
||||||
|
$sql = "SELECT trip_id, trip_name, location, short_description, start_date, end_date, vehicle_capacity, cost_members, places_booked, published FROM trips ORDER BY start_date DESC";
|
||||||
|
} else {
|
||||||
|
$sql = "SELECT trip_id, trip_name, location, short_description, start_date, end_date, vehicle_capacity, cost_members, places_booked, published FROM trips WHERE published = 1 AND start_date > CURDATE() ORDER BY start_date ASC";
|
||||||
|
}
|
||||||
$result = $conn->query($sql);
|
$result = $conn->query($sql);
|
||||||
|
|
||||||
if ($result->num_rows > 0) {
|
if ($result->num_rows > 0) {
|
||||||
@@ -68,16 +81,18 @@ include_once($rootPath . '/header.php');
|
|||||||
$capacity = $row['vehicle_capacity'];
|
$capacity = $row['vehicle_capacity'];
|
||||||
$cost_members = $row['cost_members'];
|
$cost_members = $row['cost_members'];
|
||||||
$places_booked = $row['places_booked'];
|
$places_booked = $row['places_booked'];
|
||||||
|
$published = $row['published'] ?? 1;
|
||||||
$remaining_places = getAvailableSpaces($trip_id);
|
$remaining_places = getAvailableSpaces($trip_id);
|
||||||
|
|
||||||
// Determine the badge text based on the status
|
// Determine the badge text based on the status
|
||||||
$badge_text = ($remaining_places > 0) ? $remaining_places.' PLACES LEFT!!' : 'FULLY BOOKED';
|
$badge_text = ($remaining_places > 0) ? $remaining_places.' PLACES LEFT!!' : 'FULLY BOOKED';
|
||||||
|
$draft_badge = ($published == 0) ? '<span class="badge bg-warning ms-2">DRAFT</span>' : '';
|
||||||
|
|
||||||
// Output the HTML structure with dynamic data
|
// Output the HTML structure with dynamic data
|
||||||
echo '
|
echo '
|
||||||
<div class="destination-item style-three bgc-lighter" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
<div class="destination-item style-three bgc-lighter" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||||
<div class="image">
|
<div class="image">
|
||||||
<span class="badge bgc-pink">' . $badge_text . '</span>
|
<span class="badge bgc-pink">' . $badge_text . '</span>' . $draft_badge . '
|
||||||
<img src="assets/images/trips/' . $trip_id . '_01.jpg" alt="' . $trip_name . '">
|
<img src="assets/images/trips/' . $trip_id . '_01.jpg" alt="' . $trip_name . '">
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -91,7 +106,7 @@ include_once($rootPath . '/header.php');
|
|||||||
<i class="fas fa-star"></i>
|
<i class="fas fa-star"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h5><a href="trip-details.php?token=' . encryptData($trip_id, $salt) . '">' . $trip_name . '</a></h5>
|
<h5><a href="trip-details?token=' . encryptData($trip_id, $salt) . '">' . $trip_name . '</a></h5>
|
||||||
<p>' . $short_description . '</p>
|
<p>' . $short_description . '</p>
|
||||||
<ul class="blog-meta">
|
<ul class="blog-meta">
|
||||||
<li><i class="far fa-calendar"></i> ' . convertDate($start_date) . ' - ' . convertDate($end_date) . '</li>
|
<li><i class="far fa-calendar"></i> ' . convertDate($start_date) . ' - ' . convertDate($end_date) . '</li>
|
||||||
@@ -100,7 +115,7 @@ include_once($rootPath . '/header.php');
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="destination-footer">
|
<div class="destination-footer">
|
||||||
<span class="price"><span>R ' . $cost_members . '</span>/person</span>
|
<span class="price"><span>R ' . $cost_members . '</span>/person</span>
|
||||||
<a href="trip-details.php?token=' . encryptData($trip_id, $salt) . '" class="theme-btn style-two style-three">
|
<a href="trip-details?token=' . encryptData($trip_id, $salt) . '" class="theme-btn style-two style-three">
|
||||||
<span data-hover="Book Now">Book Now</span>
|
<span data-hover="Book Now">Book Now</span>
|
||||||
<i class="fal fa-arrow-right"></i>
|
<i class="fal fa-arrow-right"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -9,7 +9,14 @@ require_once($rootPath . '/src/config/connection.php');
|
|||||||
|
|
||||||
// Check admin status
|
// Check admin status
|
||||||
session_start();
|
session_start();
|
||||||
if (empty($_SESSION['user_id']) || !in_array($_SESSION['role'] ?? '', ['admin', 'superadmin'])) {
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
ob_end_clean();
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_role = getUserRole();
|
||||||
|
if (!in_array($user_role, ['admin', 'superadmin'])) {
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -9,11 +9,18 @@ require_once($rootPath . '/src/config/connection.php');
|
|||||||
|
|
||||||
// Check admin status
|
// Check admin status
|
||||||
session_start();
|
session_start();
|
||||||
// if (empty($_SESSION['user_id']) || !in_array($_SESSION['role'] ?? '', ['admin', 'superadmin'])) {
|
if (empty($_SESSION['user_id'])) {
|
||||||
// ob_end_clean();
|
ob_end_clean();
|
||||||
// echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||||
// exit;
|
exit;
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
$user_role = getUserRole();
|
||||||
|
if (!in_array($user_role, ['admin', 'superadmin'])) {
|
||||||
|
ob_end_clean();
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// // Validate CSRF token
|
// // Validate CSRF token
|
||||||
// if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== ($_SESSION['csrf_token'] ?? '')) {
|
// if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== ($_SESSION['csrf_token'] ?? '')) {
|
||||||
@@ -39,8 +46,8 @@ try {
|
|||||||
$booking_fee = floatval($_POST['booking_fee'] ?? 0);
|
$booking_fee = floatval($_POST['booking_fee'] ?? 0);
|
||||||
|
|
||||||
// Debug: Log received values
|
// Debug: Log received values
|
||||||
error_log("START_DATE: " . var_export($start_date, true), 3, $rootPath . "/logs/trip_debug.log");
|
// error_log("START_DATE: " . var_export($start_date, true), 3, $rootPath . "/logs/trip_debug.log");
|
||||||
error_log("END_DATE: " . var_export($end_date, true), 3, $rootPath . "/logs/trip_debug.log");
|
// error_log("END_DATE: " . var_export($end_date, true), 3, $rootPath . "/logs/trip_debug.log");
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
if (empty($trip_name) || empty($location) || empty($start_date) || empty($end_date)) {
|
if (empty($trip_name) || empty($location) || empty($start_date) || empty($end_date)) {
|
||||||
@@ -104,17 +111,18 @@ try {
|
|||||||
UPDATE trips SET
|
UPDATE trips SET
|
||||||
trip_name = ?, location = ?, trip_code = ?, vehicle_capacity = ?,
|
trip_name = ?, location = ?, trip_code = ?, vehicle_capacity = ?,
|
||||||
start_date = ?, end_date = ?, short_description = ?, long_description = ?,
|
start_date = ?, end_date = ?, short_description = ?, long_description = ?,
|
||||||
cost_members = ?, cost_nonmembers = ?, cost_pensioner_member = ?,
|
cost_members = ?, cost_nonmembers = ?, cost_pensioner_member = ?, cost_pensioner = ?,
|
||||||
cost_pensioner = ?, booking_fee = ?
|
booking_fee = ?
|
||||||
WHERE trip_id = ?
|
WHERE trip_id = ?
|
||||||
");
|
");
|
||||||
|
|
||||||
$stmt->bind_param(
|
$stmt->bind_param(
|
||||||
"sssissssddddi",
|
"sssissssdddddi",
|
||||||
$trip_name, $location, $trip_code, $vehicle_capacity,
|
$trip_name, $location, $trip_code, $vehicle_capacity,
|
||||||
$start_date, $end_date, $short_description, $long_description,
|
$start_date, $end_date, $short_description, $long_description,
|
||||||
$cost_members, $cost_nonmembers, $cost_pensioner_member,
|
$cost_members, $cost_nonmembers, $cost_pensioner_member, $cost_pensioner,
|
||||||
$cost_pensioner, $booking_fee, $trip_id
|
$booking_fee,
|
||||||
|
$trip_id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!$stmt->execute()) {
|
if (!$stmt->execute()) {
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
addEFT($eft_id, $booking_id, $user_id, $status, $payment_amount, $description);
|
addEFT($eft_id, $booking_id, $user_id, $status, $payment_amount, $description);
|
||||||
|
sendInvoice(getEmail($user_id), getFullName($user_id), $eft_id, formatCurrency($payment_amount), $description);
|
||||||
sendAdminNotification('New Trip Booking - '.getFullName($user_id), getFullName($user_id).' has booked for '.$description);
|
sendAdminNotification('New Trip Booking - '.getFullName($user_id), getFullName($user_id).' has booked for '.$description);
|
||||||
header("Location: payment_confirmation?token=".encryptData($booking_id, $salt));
|
header("Location: payment_confirmation?token=".encryptData($booking_id, $salt));
|
||||||
exit(); // Ensure no further code is executed after the redirect
|
exit(); // Ensure no further code is executed after the redirect
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$target_dir = $rootPath . "/uploads/pop/";
|
$target_dir = $rootPath . "/uploads/pop/";
|
||||||
// Use EFT ID as filename instead of random filename
|
// Use EFT ID as filename instead of random filename, replace spaces with underscores
|
||||||
$filename = $eft_id . '.pdf';
|
$filename = str_replace(' ', '_', $eft_id) . '.pdf';
|
||||||
$target_file = $target_dir . $filename;
|
$target_file = $target_dir . $filename;
|
||||||
|
|
||||||
// Make sure target directory exists and writable
|
// Make sure target directory exists and writable
|
||||||
|
|||||||
@@ -9,7 +9,14 @@ require_once($rootPath . '/src/config/connection.php');
|
|||||||
|
|
||||||
// Check admin status
|
// Check admin status
|
||||||
session_start();
|
session_start();
|
||||||
if (empty($_SESSION['user_id']) || !in_array($_SESSION['role'] ?? '', ['admin', 'superadmin'])) {
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
ob_end_clean();
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_role = getUserRole();
|
||||||
|
if (!in_array($user_role, ['admin', 'superadmin'])) {
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
Reference in New Issue
Block a user