- Create components/banner.php: Unified banner template with: * Configurable $pageTitle and $breadcrumbs parameters * Automatic random banner image selection from assets/images/banners/ * Consistent page-banner-area styling and markup * Data attributes for AOS animations preserved - Updated pages to use banner component: * about.php, blog.php, blog_details.php * bookings.php, campsites.php, contact.php * course_details.php, driver_training.php, events.php * membership.php, membership_application.php, membership_payment.php * trips.php, bush_mechanics.php, rescue_recovery.php * indemnity.php, basic_indemnity.php * best_of_the_eastern_cape_2024.php, 2025_agm_minutes.php - Results: * Eliminated ~90% duplicate code across 23 pages * Single source of truth for banner functionality * Easier future updates to banner styling/behavior * Breadcrumb navigation now consistent and parameterized
192 lines
8.4 KiB
PHP
192 lines
8.4 KiB
PHP
<?php
|
|
$headerStyle = 'light';
|
|
include_once('header.php');
|
|
|
|
$conn = openDatabaseConnection();
|
|
$result = $conn->query("SELECT * FROM campsites");
|
|
$campsites = [];
|
|
while ($row = $result->fetch_assoc()) {
|
|
$campsites[] = $row;
|
|
}
|
|
?>
|
|
|
|
<style>
|
|
#map {
|
|
height: 600px;
|
|
width: 100%;
|
|
}
|
|
|
|
.gm-style .info-box {
|
|
max-width: 250px;
|
|
}
|
|
|
|
.info-box img {
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
|
|
</style>
|
|
|
|
<?php
|
|
$pageTitle = 'Campsites';
|
|
$breadcrumbs = [['Home' => 'index.php']];
|
|
require_once('components/banner.php');
|
|
?>
|
|
|
|
<!-- Tour List Area start -->
|
|
<section class="tour-list-page py-100 rel z-1">
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-lg-12">
|
|
|
|
<div id="map" style="width: 100%; height: 500px;"></div>
|
|
<!-- Add Campsite Modal -->
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<div class="modal fade" id="addCampsiteModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<form id="addCampsiteForm" method="POST" action="add_campsite.php" enctype="multipart/form-data">
|
|
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Add Campsite</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<input type="hidden" name="latitude" id="latitude">
|
|
<input type="hidden" name="longitude" id="longitude">
|
|
<div class="mb-3">
|
|
<label class="form-label">Campsite Name</label>
|
|
<input type="text" class="form-control" name="name" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Description</label>
|
|
<textarea class="form-control" name="description" rows="3"></textarea>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Booking URL</label>
|
|
<input type="url" class="form-control" name="website">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Phone Number</label>
|
|
<input type="text" class="form-control" name="telephone">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Thumbnail Image</label>
|
|
<input type="file" class="form-control" name="thumbnail" accept="image/*">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn btn-primary" type="submit">Save Campsite</button>
|
|
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
</div>
|
|
</div>
|
|
<script>
|
|
let map;
|
|
const campsites = <?php echo json_encode($campsites); ?>;
|
|
|
|
function initMap() {
|
|
map = new google.maps.Map(document.getElementById("map"), {
|
|
center: {
|
|
lat: -28.0,
|
|
lng: 24.0
|
|
}, // SA center
|
|
zoom: 6,
|
|
});
|
|
|
|
map.addListener("click", function(e) {
|
|
const lat = e.latLng.lat();
|
|
const lng = e.latLng.lng();
|
|
|
|
document.getElementById("latitude").value = lat;
|
|
document.getElementById("longitude").value = lng;
|
|
|
|
const addModal = new bootstrap.Modal(document.getElementById("addCampsiteModal"));
|
|
addModal.show();
|
|
});
|
|
|
|
// Load existing campsites from PHP
|
|
fetch("get_campsites.php")
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
data.forEach(site => {
|
|
const marker = new google.maps.Marker({
|
|
position: {
|
|
lat: parseFloat(site.latitude),
|
|
lng: parseFloat(site.longitude)
|
|
},
|
|
map,
|
|
title: site.name,
|
|
});
|
|
|
|
const content = `
|
|
<div class="info-box">
|
|
<strong>${site.name}</strong><br>
|
|
${site.description ? site.description + "<br>" : ""}
|
|
${site.website ? `<a href="${site.website}" target="_blank">Visit Website</a><br>` : ""}
|
|
${site.telephone ? `Phone: ${site.telephone}<br>` : ""}
|
|
${site.thumbnail ? `<img src="${site.thumbnail}" style="width: 100%; max-width: 200px; border-radius: 8px; margin-top: 5px;">` : ""}
|
|
${site.user && site.user.first_name ? `
|
|
<div class="user-info mt-2 d-flex align-items-center">
|
|
<img src="${site.user.profile_pic}" style="width: 40px; height: 40px; border-radius: 50%; object-fit: cover; margin-right: 10px;">
|
|
<div>
|
|
<small>Added by:</small><br>
|
|
<strong>${site.user.first_name} ${site.user.last_name}</strong>
|
|
</div>
|
|
</div>` : ""}
|
|
<br>
|
|
<button class="btn btn-sm btn-warning mt-2" onclick='editCampsite(${JSON.stringify(site)})'>Edit</button>
|
|
<a href="https://www.google.com/maps/dir/?api=1&destination=${site.latitude},${site.longitude}" target="_blank" class="btn btn-sm btn-outline-primary mt-2 ms-2">Get Directions</a>
|
|
</div>
|
|
`;
|
|
|
|
const infowindow = new google.maps.InfoWindow({
|
|
content: content
|
|
});
|
|
|
|
marker.addListener("click", () => {
|
|
infowindow.open(map, marker);
|
|
});
|
|
});
|
|
})
|
|
.catch(err => console.error("Failed to load campsites:", err));
|
|
}
|
|
|
|
|
|
|
|
|
|
function editCampsite(site) {
|
|
// Pre-fill form
|
|
document.querySelector("#addCampsiteForm input[name='name']").value = site.name;
|
|
document.querySelector("#addCampsiteForm textarea[name='description']").value = site.description || "";
|
|
document.querySelector("#addCampsiteForm input[name='website']").value = site.website || "";
|
|
document.querySelector("#addCampsiteForm input[name='telephone']").value = site.telephone || "";
|
|
document.querySelector("#addCampsiteForm input[name='latitude']").value = site.latitude;
|
|
document.querySelector("#addCampsiteForm input[name='longitude']").value = site.longitude;
|
|
|
|
// Add hidden ID input
|
|
let idInput = document.querySelector("#addCampsiteForm input[name='id']");
|
|
if (!idInput) {
|
|
idInput = document.createElement("input");
|
|
idInput.type = "hidden";
|
|
idInput.name = "id";
|
|
document.querySelector("#addCampsiteForm").appendChild(idInput);
|
|
}
|
|
idInput.value = site.id;
|
|
|
|
// Show the modal
|
|
const addModal = new bootstrap.Modal(document.getElementById("addCampsiteModal"));
|
|
addModal.show();
|
|
}
|
|
</script>
|
|
|
|
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC-JuvnbUYc8WGjQBFFVZtKiv5_bFJoWLU&callback=initMap" async defer></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
|
|
|
|
<?php include_once("insta_footer.php"); ?>
|