Compare commits
31 Commits
feature/si
...
feature/ca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb588d20ee | ||
|
|
fdeaf85bf0 | ||
|
|
d81d74a7c7 | ||
|
|
bfb3a0f8a9 | ||
|
|
5a2c48f343 | ||
|
|
1767337d99 | ||
|
|
674af23994 | ||
|
|
ec563e0376 | ||
|
|
a3403bf503 | ||
|
|
5f1a6bc441 | ||
|
|
716de2f0e9 | ||
|
|
79e292dc7c | ||
|
|
59c1e37d5c | ||
|
|
0c068eeb69 | ||
|
|
6fd3b8d082 | ||
|
|
902291d8d1 | ||
|
|
ac460ef97f | ||
|
|
be2b757f4e | ||
|
|
86faad7a78 | ||
|
|
1d7a50709e | ||
|
|
7e544311e3 | ||
|
|
0143f5dd12 | ||
|
|
45523720ea | ||
|
|
4c839d02c0 | ||
|
|
cbb52cda35 | ||
|
|
2544676685 | ||
|
|
84dc35c8d5 | ||
|
|
2f94c17c28 | ||
|
|
110c853945 | ||
|
|
0d01c7da90 | ||
|
|
938ce4e15e |
123
.htaccess
@@ -1,4 +1,125 @@
|
||||
php_flag display_errors Off
|
||||
# URL Rewrite Rules - Maps old URLs to new directory structure during migration
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
|
||||
# Don't rewrite existing files or directories
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
|
||||
# === STRIP .PHP EXTENSION ===
|
||||
# Redirect /page.php to /page (301 permanent redirect)
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.+)\.php$ /$1 [R=301,L]
|
||||
# Internally rewrite /page to /page.php if page.php exists
|
||||
RewriteCond %{REQUEST_FILENAME}\.php -f
|
||||
RewriteRule ^(.+)$ $1.php [L]
|
||||
|
||||
# === AUTH PAGES ===
|
||||
RewriteRule ^login$ src/pages/auth/login.php [L]
|
||||
RewriteRule ^register$ src/pages/auth/register.php [L]
|
||||
RewriteRule ^forgot_password$ src/pages/auth/forgot_password.php [L]
|
||||
RewriteRule ^reset_password$ src/pages/auth/reset_password.php [L]
|
||||
RewriteRule ^verify$ src/pages/auth/verify.php [L]
|
||||
RewriteRule ^resend_verification$ src/pages/auth/resend_verification.php [L]
|
||||
RewriteRule ^change_password$ src/pages/auth/change_password.php [L]
|
||||
RewriteRule ^update_password$ src/pages/auth/update_password.php [L]
|
||||
|
||||
# === MEMBERSHIP PAGES ===
|
||||
RewriteRule ^membership$ src/pages/memberships/membership.php [L]
|
||||
RewriteRule ^membership_details$ src/pages/memberships/membership_details.php [L]
|
||||
RewriteRule ^membership_application$ src/pages/memberships/membership_application.php [L]
|
||||
RewriteRule ^membership_payment$ src/pages/memberships/membership_payment.php [L]
|
||||
RewriteRule ^renew_membership$ src/pages/memberships/renew_membership.php [L]
|
||||
RewriteRule ^member_info$ src/pages/memberships/member_info.php [L]
|
||||
|
||||
# === BOOKING PAGES ===
|
||||
RewriteRule ^bookings$ src/pages/bookings/bookings.php [L]
|
||||
RewriteRule ^campsites$ src/pages/bookings/campsites.php [L]
|
||||
RewriteRule ^campsite_booking$ src/pages/bookings/campsite_booking.php [L]
|
||||
RewriteRule ^add_campsite$ src/pages/add_campsite.php [L]
|
||||
RewriteRule ^trips$ src/pages/bookings/trips.php [L]
|
||||
RewriteRule ^trip-details$ src/pages/bookings/trip-details.php [L]
|
||||
RewriteRule ^course_details$ src/pages/bookings/course_details.php [L]
|
||||
RewriteRule ^driver_training$ src/pages/bookings/driver_training.php [L]
|
||||
|
||||
# === SHOP PAGES ===
|
||||
RewriteRule ^view_cart$ src/pages/shop/view_cart.php [L]
|
||||
RewriteRule ^add_to_cart$ src/pages/shop/add_to_cart.php [L]
|
||||
RewriteRule ^bar_tabs$ src/pages/shop/bar_tabs.php [L]
|
||||
RewriteRule ^payment_confirmation$ src/pages/shop/payment_confirmation.php [L]
|
||||
RewriteRule ^confirm$ src/pages/shop/confirm.php [L]
|
||||
RewriteRule ^confirm2$ src/pages/shop/confirm2.php [L]
|
||||
|
||||
# === EVENTS & BLOG PAGES ===
|
||||
RewriteRule ^events$ src/pages/events/events.php [L]
|
||||
RewriteRule ^blog$ src/pages/events/blog.php [L]
|
||||
RewriteRule ^blog_details$ src/pages/events/blog_details.php [L]
|
||||
RewriteRule ^best_of_the_eastern_cape_2024$ src/pages/events/best_of_the_eastern_cape_2024.php [L]
|
||||
RewriteRule ^2025_agm_minutes$ src/pages/events/2025_agm_minutes.php [L]
|
||||
RewriteRule ^agm_content$ src/pages/events/agm_content.php [L]
|
||||
RewriteRule ^instapage$ src/pages/events/instapage.php [L]
|
||||
|
||||
# === OTHER PAGES ===
|
||||
RewriteRule ^about$ src/pages/other/about.php [L]
|
||||
RewriteRule ^contact$ src/pages/other/contact.php [L]
|
||||
RewriteRule ^privacy_policy$ src/pages/other/privacy_policy.php [L]
|
||||
RewriteRule ^404$ src/pages/other/404.php [L]
|
||||
RewriteRule ^account_settings$ src/pages/other/account_settings.php [L]
|
||||
RewriteRule ^rescue_recovery$ src/pages/other/rescue_recovery.php [L]
|
||||
RewriteRule ^bush_mechanics$ src/pages/other/bush_mechanics.php [L]
|
||||
RewriteRule ^indemnity$ src/pages/other/indemnity.php [L]
|
||||
RewriteRule ^indemnity_waiver$ src/pages/other/indemnity_waiver.php [L]
|
||||
RewriteRule ^basic_indemnity$ src/pages/other/basic_indemnity.php [L]
|
||||
RewriteRule ^view_indemnity$ src/pages/other/view_indemnity.php [L]
|
||||
|
||||
# === ADMIN PAGES ===
|
||||
RewriteRule ^admin_members$ src/admin/admin_members.php [L]
|
||||
RewriteRule ^admin_payments$ src/admin/admin_payments.php [L]
|
||||
RewriteRule ^admin_web_users$ src/admin/admin_web_users.php [L]
|
||||
RewriteRule ^admin_course_bookings$ src/admin/admin_course_bookings.php [L]
|
||||
RewriteRule ^admin_camp_bookings$ src/admin/admin_camp_bookings.php [L]
|
||||
RewriteRule ^admin_trip_bookings$ src/admin/admin_trip_bookings.php [L]
|
||||
RewriteRule ^admin_visitors$ src/admin/admin_visitors.php [L]
|
||||
RewriteRule ^admin_efts$ src/admin/admin_efts.php [L]
|
||||
RewriteRule ^admin_trips$ src/admin/admin_trips.php [L]
|
||||
RewriteRule ^manage_trips$ src/admin/manage_trips.php [L]
|
||||
|
||||
# === API/AJAX ENDPOINTS ===
|
||||
RewriteRule ^fetch_users$ src/api/fetch_users.php [L]
|
||||
RewriteRule ^fetch_drinks$ src/api/fetch_drinks.php [L]
|
||||
RewriteRule ^fetch_bar_tabs$ src/api/fetch_bar_tabs.php [L]
|
||||
RewriteRule ^get_campsites$ src/api/get_campsites.php [L]
|
||||
RewriteRule ^get_tab_total$ src/api/get_tab_total.php [L]
|
||||
RewriteRule ^google_validate_login$ src/api/google_validate_login.php [L]
|
||||
|
||||
# === PROCESSORS ===
|
||||
RewriteRule ^validate_login$ src/processors/validate_login.php [L]
|
||||
RewriteRule ^register_user$ src/processors/register_user.php [L]
|
||||
RewriteRule ^process_application$ src/processors/process_application.php [L]
|
||||
RewriteRule ^process_booking$ src/processors/process_booking.php [L]
|
||||
RewriteRule ^process_camp_booking$ src/processors/process_camp_booking.php [L]
|
||||
RewriteRule ^process_course_booking$ src/processors/process_course_booking.php [L]
|
||||
RewriteRule ^process_trip_booking$ src/processors/process_trip_booking.php [L]
|
||||
RewriteRule ^process_membership_payment$ src/processors/process_membership_payment.php [L]
|
||||
RewriteRule ^process_payments$ src/processors/process_payments.php [L]
|
||||
RewriteRule ^process_eft$ src/processors/process_eft.php [L]
|
||||
RewriteRule ^submit_order$ src/processors/submit_order.php [L]
|
||||
RewriteRule ^submit_pop$ src/processors/submit_pop.php [L]
|
||||
RewriteRule ^process_signature$ src/processors/process_signature.php [L]
|
||||
RewriteRule ^create_bar_tab$ src/processors/create_bar_tab.php [L]
|
||||
RewriteRule ^update_application$ src/processors/update_application.php [L]
|
||||
RewriteRule ^update_user$ src/processors/update_user.php [L]
|
||||
RewriteRule ^upload_profile_picture$ src/processors/upload_profile_picture.php [L]
|
||||
RewriteRule ^send_reset_link$ src/processors/send_reset_link.php [L]
|
||||
RewriteRule ^logout$ src/processors/logout.php [L]
|
||||
RewriteRule ^process_trip$ src/processors/process_trip.php [L]
|
||||
RewriteRule ^toggle_trip_published$ src/processors/toggle_trip_published.php [L]
|
||||
RewriteRule ^delete_trip$ src/processors/delete_trip.php [L]
|
||||
|
||||
</IfModule>
|
||||
|
||||
php_flag display_errors On
|
||||
# php_value error_reporting -1
|
||||
RedirectMatch 403 ^/\.well-known
|
||||
Options -Indexes
|
||||
|
||||
293
about.php
@@ -1,292 +1,3 @@
|
||||
<?php include_once('header02.php');
|
||||
?>
|
||||
|
||||
<style>
|
||||
.gallery-slider-active {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
/* spacing between images */
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.gallery-three-item {
|
||||
width: 520px;
|
||||
height: 300px;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
background: #f9f9f9;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.gallery-three-item .image {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gallery-three-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
/* ensures aspect ratio while filling container */
|
||||
display: block;
|
||||
}
|
||||
|
||||
</style>
|
||||
<!-- Page Banner Start -->
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$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; ?>');">
|
||||
<!-- Overlay PNG -->
|
||||
<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">About</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">About</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Benefit Area start -->
|
||||
<section class="benefit-area mt-100 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row align-items-center justify-content-between">
|
||||
<div class="col-xl-5 col-lg-6">
|
||||
<div class="mobile-app-content rmb-55" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="section-title counter-text-wrap mb-40">
|
||||
<h2>Welcome to the Four Wheel Drive Club of Southern Africa!</h2>
|
||||
</div>
|
||||
<p style="max-width: 600px; margin: 0 auto;">
|
||||
We're a family-friendly outdoor adventure club passionate about exploring the great outdoors through off-road driving, camping, overlanding, cross-border trips, day trips, and unforgettable events. Whether you're new to 4x4 adventures or a seasoned explorer, our community is all about camaraderie, responsible adventure, and creating lasting memories—on and off the road.
|
||||
</p>
|
||||
<ul class="list-style-two mt-35 mb-30">
|
||||
<li>Overlanding</li>
|
||||
<li>Camping</li>
|
||||
<li>Day Trips</li>
|
||||
<li>4x4 Driver Training</li>
|
||||
<li>Family Events</li>
|
||||
<li>Monthly Open Days</li>
|
||||
<li>Guest Speakers</li>
|
||||
<li>4x4 Driving Track</li>
|
||||
</ul>
|
||||
<!-- <a href="about.html" class="theme-btn style-two">
|
||||
<span data-hover="Explore Guides">Explore Guides</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="benefit-image-part style-two">
|
||||
<div class="image-one" data-aos="fade-down" data-aos-delay="50" data-aos-duration="1500" data-aos-offset="50">
|
||||
<img src="assets/images/benefit/benefit1.png" alt="Benefit">
|
||||
</div>
|
||||
<div class="image-two" data-aos="fade-up" data-aos-delay="50" data-aos-duration="1500" data-aos-offset="50">
|
||||
<img src="assets/images/benefit/benefit2.png" alt="Benefit">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Benefit Area end -->
|
||||
|
||||
<!-- Hotel Area start -->
|
||||
<section class="hotel-area bgc-black py-100 rel z-1">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="section-title text-white text-center counter-text-wrap mb-70" data-aos="fade-up"
|
||||
data-aos-duration="1500" data-aos-offset="50">
|
||||
<h2>BASE4 Open Days</h2>
|
||||
<p style="max-width: 60%; margin: auto;">Whether you're a member or just curious, everyone's welcome at our monthly open events. Come camp with us, enjoy guest speakers, take your rig for a spin on the 4x4 track, or just relax by the swimming pool. Saturday’s Open Day includes breakfast and lunch for sale, plus braai fires ready to go—just bring your tongs! It’s the perfect way to experience the spirit of the club and connect with fellow adventurers. </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gallery-slider-active">
|
||||
<?php
|
||||
$folder = 'assets/images/opendays/';
|
||||
$images = glob($folder . '*.{jpg,jpeg,png,gif}', GLOB_BRACE);
|
||||
|
||||
// Shuffle and pick first 5
|
||||
shuffle($images);
|
||||
$selected = array_slice($images, 0, 10);
|
||||
|
||||
foreach ($selected as $image) {
|
||||
echo '<div class="gallery-three-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<img src="' . $image . '" alt="Gallery">
|
||||
</div>
|
||||
|
||||
</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="hotel-more-btn text-center mt-40">
|
||||
<a href="destination2.html" class="theme-btn style-four">
|
||||
<span data-hover="Explore More Hotel">Explore More Hotel</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div> -->
|
||||
</div>
|
||||
</section>
|
||||
<!-- Hotel Area end -->
|
||||
|
||||
|
||||
<!-- Features Area start -->
|
||||
<section class="features-area pt-100 pb-45 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-xl-6">
|
||||
<div class="features-content-part mb-55" data-aos="fade-left" data-aos-duration="1500"
|
||||
data-aos-offset="50">
|
||||
<div class="section-title mb-20">
|
||||
<h2>Want to get involved?<b>JOIN THE COMMITTEE!</b></h2>
|
||||
<p>Want to be more involved in the adventure? Join our committee and help shape the future of the club! Whether it’s planning epic trips, organizing fun events, or assisting with training, your energy and ideas make all the difference. The club runs on the passion of its members—get stuck in, meet awesome people, and be part of what makes it all happen!</p>
|
||||
<div class="image">
|
||||
<img style="border-radius:10px;" src="assets/images/memories/40.jpg" alt="Hotel">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6" data-aos="fade-right" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="row pb-25">
|
||||
<div class="section-title text-center counter-text-wrap mb-70" data-aos="fade-up"
|
||||
data-aos-duration="1500" data-aos-offset="50">
|
||||
<h2>4WDCSA Committee and Other Office Bearers</h2>
|
||||
<div>
|
||||
<h3>Committee</h3>
|
||||
<li>Chairman - John Runciman</li>
|
||||
<li>National Liaison - Peter Hutchison</li>
|
||||
<li>Treasurer - Doug Timm</li>
|
||||
<li>Outings - John Runciman</li>
|
||||
<li>Events - Noelene Runciman</li>
|
||||
<li>Driver Training - John Runciman</li>
|
||||
<li>Digital Media - Christopher Pinto</li>
|
||||
|
||||
</div>
|
||||
<div class="pt-30 pb-20">
|
||||
<h3>Administration</h3>
|
||||
<li>Secretary - Jacqui Boshoff</li>
|
||||
|
||||
</div>
|
||||
<p style="font-size:0.8rem;">
|
||||
All portfolio holders/committee members of the 4WDCSA are volunteers and are not paid for their services.<br>The secretary is paid for administrative duties only.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Features Area end -->
|
||||
|
||||
|
||||
<!-- Hotel Area start -->
|
||||
<section class="hotel-area bgc-black py-100 rel z-1">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="section-title text-white text-center counter-text-wrap mb-70" data-aos="fade-up"
|
||||
data-aos-duration="1500" data-aos-offset="50">
|
||||
<h2>4x4 Memories</h2>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gallery-slider-active"><?php
|
||||
$folder = 'assets/images/memories/';
|
||||
$images = glob($folder . '*.{jpg,jpeg,png,gif}', GLOB_BRACE);
|
||||
|
||||
// Shuffle and pick first 5
|
||||
shuffle($images);
|
||||
$selected = array_slice($images, 0, 20);
|
||||
|
||||
foreach ($selected as $image) {
|
||||
echo '<div class="gallery-three-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<img src="' . $image . '" alt="Gallery">
|
||||
</div>
|
||||
|
||||
</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="hotel-more-btn text-center mt-40">
|
||||
<a href="destination2.html" class="theme-btn style-four">
|
||||
<span data-hover="Explore More Hotel">Explore More Hotel</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div> -->
|
||||
</div>
|
||||
</section>
|
||||
<!-- Hotel Area end -->
|
||||
|
||||
<!-- CTA Area start -->
|
||||
<section class="cta-area pt-100 rel z-1">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-xl-4 col-md-6" data-aos="zoom-in-down" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="cta-item" style="background-image: url(assets/images/trips/1_01.jpg);">
|
||||
<span class="category">Extended Trips</span>
|
||||
<h2>Come and Explore Africa and beyond</h2>
|
||||
<a href="trips.php" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Explore Tours">Explore Trips</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 col-md-6" data-aos="zoom-in-down" data-aos-delay="50" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="cta-item" style="background-image: url(assets/images/courses/driver_training.png);">
|
||||
<span class="category">Driver Training</span>
|
||||
<h2>Level up your 4x4 Driving Skills</h2>
|
||||
<a href="driver_training.php" class="theme-btn style-two">
|
||||
<span data-hover="Explore Tours">Explore Training</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 col-md-6" data-aos="zoom-in-down" data-aos-delay="100" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="cta-item" style="background-image: url(assets/images/base4/camping.jpg);">
|
||||
<span class="category">Events</span>
|
||||
<h2>See whats cooking at BASE4!</h2>
|
||||
<a href="events.php" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Explore Tours">Explore Events</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- CTA Area end -->
|
||||
|
||||
|
||||
<!-- Blog Area start -->
|
||||
<section class="blog-area pt-70 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Blog Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
// Redirector file - loads the actual page from src/pages/other/
|
||||
require_once __DIR__ . '/src/pages/other/about.php';
|
||||
|
||||
BIN
assets/images/pp/2f40af86bfbe04a5c83bbb6cdf1c1e6b.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
assets/images/pp/424b31c09e1543a922deb690bfbb57c8.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
assets/images/pp/4b8bd95296e082031c8ae8c4b35fed88.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
assets/images/pp/5f9036058b40b2c23052d8226711ac5c.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
assets/images/pp/7a7b9965853213ea1e4ed1aec4e18ad0.jpg
Normal file
|
After Width: | Height: | Size: 290 KiB |
BIN
assets/images/pp/8bc567fbcdffcf5823845740a54d5e6d.jpg
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
assets/images/pp/9a1f344bc68815fa15bb0a1e16017ee6.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
assets/images/pp/b8d7fa81c1ab3e67dc86441b09d927cd.jpg
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
assets/images/pp/cc83c3045d2b41073f0939f298d06459.jpg
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
assets/images/pp/e607963d306a19d1df94c50d577ea439.jpg
Normal file
|
After Width: | Height: | Size: 290 KiB |
BIN
assets/images/promo/christmas2025.jpg
Normal file
|
After Width: | Height: | Size: 352 KiB |
BIN
assets/images/trips/8_01.jpg
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/images/trips/8_02.jpg
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
assets/images/trips/8_03.jpg
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
assets/images/trips/8_04.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
assets/images/trips/8_05.jpg
Normal file
|
After Width: | Height: | Size: 226 KiB |
@@ -46,7 +46,7 @@
|
||||
|
||||
<div class="header-inner rel d-flex align-items-center">
|
||||
<div class="logo-outer">
|
||||
<div class="logo"><a href="index.php"><img src="assets/images/logos/logo-two.png" alt="Logo" title="Logo"></a></div>
|
||||
<div class="logo"><a href="index"><img src="assets/images/logos/logo-two.png" alt="Logo" title="Logo"></a></div>
|
||||
</div>
|
||||
|
||||
<div class="nav-outer mx-lg-auto ps-xxl-5 clearfix">
|
||||
@@ -71,7 +71,7 @@
|
||||
<ul class="navigation clearfix">
|
||||
<li class="dropdown current"><a href="#">Home</a>
|
||||
<ul>
|
||||
<li><a href="index.php">Travel Agency</a></li>
|
||||
<li><a href="index">Travel Agency</a></li>
|
||||
<li><a href="index2.html">City Tou</a></li>
|
||||
<li><a href="index3.html">Tour Package</a></li>
|
||||
</ul>
|
||||
@@ -161,7 +161,7 @@
|
||||
|
||||
<!--Appointment Form-->
|
||||
<div class="appointment-form">
|
||||
<form method="post" action="contact.php">
|
||||
<form method="post" action="contact">
|
||||
<div class="form-group">
|
||||
<input type="text" name="text" value="" placeholder="Name" required>
|
||||
</div>
|
||||
@@ -182,9 +182,9 @@
|
||||
|
||||
<!--Social Icons-->
|
||||
<div class="social-style-one">
|
||||
<a href="contact.php"><i class="fab fa-twitter"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-instagram"></i></a>
|
||||
<a href="contact"><i class="fab fa-twitter"></i></a>
|
||||
<a href="contact"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="contact"><i class="fab fa-instagram"></i></a>
|
||||
<a href="#"><i class="fab fa-pinterest-p"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -201,7 +201,7 @@
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Bali, Indonesia</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="index">Home</a></li>
|
||||
<li class="breadcrumb-item active">Tour Details</li>
|
||||
</ol>
|
||||
</nav>
|
||||
@@ -795,7 +795,7 @@
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</button>
|
||||
<div class="text-center">
|
||||
<a href="contact.php">Need some help?</a>
|
||||
<a href="contact">Need some help?</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -871,7 +871,7 @@
|
||||
<div class="col col-small" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="footer-widget footer-text">
|
||||
<div class="footer-logo mb-40">
|
||||
<a href="index.php"><img src="assets/images/logos/logo.png" alt="Logo"></a>
|
||||
<a href="index"><img src="assets/images/logos/logo.png" alt="Logo"></a>
|
||||
</div>
|
||||
<div class="footer-map">
|
||||
<iframe src="https://www.google.com/maps/embed?pb=!1m10!1m8!1m3!1d96777.16150026117!2d-74.00840582560909!3d40.71171357405996!3m2!1i1024!2i768!4f13.1!5e0!3m2!1sen!2sbd!4v1706508986625!5m2!1sen!2sbd" style="border:0; width: 100%;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
|
||||
@@ -899,7 +899,7 @@
|
||||
<ul class="list-style-three">
|
||||
<li><a href="about.html">About Company</a></li>
|
||||
<li><a href="blog.html">Community Blog</a></li>
|
||||
<li><a href="contact.php">Jobs and Careers</a></li>
|
||||
<li><a href="contact">Jobs and Careers</a></li>
|
||||
<li><a href="blog.html">latest News Blog</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -937,7 +937,7 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-5">
|
||||
<div class="copyright-text text-center text-lg-start">
|
||||
<p>@Copy 2024 <a href="index.php">Ravelo</a>, All rights reserved</p>
|
||||
<p>@Copy 2024 <a href="index">Ravelo</a>, All rights reserved</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-7 text-center text-lg-end">
|
||||
|
||||
BIN
assets/uploads/campsites/274d8e71982307bc5a699125966d5731.jpg
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
assets/uploads/campsites/3dd0636b3ed6926e10f0387a747d58c1.jpg
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/uploads/campsites/ae16ea8e89bb83dc3b85c54aa0e3fcec.jpg
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
assets/uploads/campsites/c613066cd83537a874355671e0213539.jpg
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/uploads/campsites/d21ae51aec635de07883d9586a1542df.jpg
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
209
campsites.php
@@ -1,209 +0,0 @@
|
||||
<?php include_once('header02.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
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$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">Campsites</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">Campsites</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 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"); ?>
|
||||
320
classes/DatabaseService.php
Normal file
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
/**
|
||||
* DatabaseService Class
|
||||
*
|
||||
* Provides a centralized database abstraction layer for all database operations.
|
||||
* Enforces prepared statements, proper error handling, and type safety.
|
||||
*
|
||||
* @package 4WDCSA
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
class DatabaseService {
|
||||
private $conn;
|
||||
private $lastError = null;
|
||||
private $lastQuery = null;
|
||||
|
||||
/**
|
||||
* Constructor - Initialize database connection
|
||||
*
|
||||
* @param mysqli $connection The MySQLi connection object
|
||||
*/
|
||||
public function __construct($connection) {
|
||||
if (!$connection) {
|
||||
throw new Exception("Database connection failed");
|
||||
}
|
||||
$this->conn = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error message
|
||||
*
|
||||
* @return string|null The last error or null if no error
|
||||
*/
|
||||
public function getLastError() {
|
||||
return $this->lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last executed query
|
||||
*
|
||||
* @return string|null The last query or null
|
||||
*/
|
||||
public function getLastQuery() {
|
||||
return $this->lastQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SELECT query with parameter binding
|
||||
*
|
||||
* @param string $query SQL query with ? placeholders
|
||||
* @param array $params Parameters to bind
|
||||
* @param string $types Type specification string (e.g., "isi" for int, string, int)
|
||||
* @return array|false Array of results or false on error
|
||||
*/
|
||||
public function select($query, $params = [], $types = "") {
|
||||
try {
|
||||
$this->lastQuery = $query;
|
||||
$stmt = $this->conn->prepare($query);
|
||||
|
||||
if (!$stmt) {
|
||||
$this->lastError = "Prepare failed: " . $this->conn->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($params) && !empty($types)) {
|
||||
if (!$stmt->bind_param($types, ...$params)) {
|
||||
$this->lastError = "Bind failed: " . $stmt->error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
$this->lastError = "Execute failed: " . $stmt->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $stmt->get_result();
|
||||
$data = [];
|
||||
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$data[] = $row;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
return $data;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->lastError = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SELECT query returning a single row
|
||||
*
|
||||
* @param string $query SQL query with ? placeholders
|
||||
* @param array $params Parameters to bind
|
||||
* @param string $types Type specification string
|
||||
* @return array|false Single row as associative array or false
|
||||
*/
|
||||
public function selectOne($query, $params = [], $types = "") {
|
||||
$results = $this->select($query, $params, $types);
|
||||
return ($results && count($results) > 0) ? $results[0] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an INSERT query
|
||||
*
|
||||
* @param string $query SQL query with ? placeholders
|
||||
* @param array $params Parameters to bind
|
||||
* @param string $types Type specification string
|
||||
* @return int|false Last insert ID or false on error
|
||||
*/
|
||||
public function insert($query, $params = [], $types = "") {
|
||||
try {
|
||||
$this->lastQuery = $query;
|
||||
$stmt = $this->conn->prepare($query);
|
||||
|
||||
if (!$stmt) {
|
||||
$this->lastError = "Prepare failed: " . $this->conn->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($params) && !empty($types)) {
|
||||
if (!$stmt->bind_param($types, ...$params)) {
|
||||
$this->lastError = "Bind failed: " . $stmt->error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
$this->lastError = "Execute failed: " . $stmt->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
$insertId = $stmt->insert_id;
|
||||
$stmt->close();
|
||||
return $insertId;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->lastError = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an UPDATE query
|
||||
*
|
||||
* @param string $query SQL query with ? placeholders
|
||||
* @param array $params Parameters to bind
|
||||
* @param string $types Type specification string
|
||||
* @return int|false Number of affected rows or false on error
|
||||
*/
|
||||
public function update($query, $params = [], $types = "") {
|
||||
try {
|
||||
$this->lastQuery = $query;
|
||||
$stmt = $this->conn->prepare($query);
|
||||
|
||||
if (!$stmt) {
|
||||
$this->lastError = "Prepare failed: " . $this->conn->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($params) && !empty($types)) {
|
||||
if (!$stmt->bind_param($types, ...$params)) {
|
||||
$this->lastError = "Bind failed: " . $stmt->error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
$this->lastError = "Execute failed: " . $stmt->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
$affectedRows = $stmt->affected_rows;
|
||||
$stmt->close();
|
||||
return $affectedRows;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->lastError = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a DELETE query
|
||||
*
|
||||
* @param string $query SQL query with ? placeholders
|
||||
* @param array $params Parameters to bind
|
||||
* @param string $types Type specification string
|
||||
* @return int|false Number of affected rows or false on error
|
||||
*/
|
||||
public function delete($query, $params = [], $types = "") {
|
||||
return $this->update($query, $params, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an arbitrary query (for complex queries)
|
||||
*
|
||||
* @param string $query SQL query with ? placeholders
|
||||
* @param array $params Parameters to bind
|
||||
* @param string $types Type specification string
|
||||
* @return mixed Query result or false on error
|
||||
*/
|
||||
public function execute($query, $params = [], $types = "") {
|
||||
try {
|
||||
$this->lastQuery = $query;
|
||||
$stmt = $this->conn->prepare($query);
|
||||
|
||||
if (!$stmt) {
|
||||
$this->lastError = "Prepare failed: " . $this->conn->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($params) && !empty($types)) {
|
||||
if (!$stmt->bind_param($types, ...$params)) {
|
||||
$this->lastError = "Bind failed: " . $stmt->error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
$this->lastError = "Execute failed: " . $stmt->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
return true;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->lastError = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count rows matching a condition
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param string $where WHERE clause (without WHERE keyword)
|
||||
* @param array $params Parameters to bind
|
||||
* @param string $types Type specification string
|
||||
* @return int|false Row count or false on error
|
||||
*/
|
||||
public function count($table, $where = "1=1", $params = [], $types = "") {
|
||||
$query = "SELECT COUNT(*) as count FROM {$table} WHERE {$where}";
|
||||
$result = $this->selectOne($query, $params, $types);
|
||||
return ($result) ? (int)$result['count'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a record exists
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param string $where WHERE clause (without WHERE keyword)
|
||||
* @param array $params Parameters to bind
|
||||
* @param string $types Type specification string
|
||||
* @return bool True if record exists, false otherwise
|
||||
*/
|
||||
public function exists($table, $where, $params = [], $types = "") {
|
||||
$count = $this->count($table, $where, $params, $types);
|
||||
return ($count !== false && $count > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MySQLi connection object for advanced operations
|
||||
*
|
||||
* @return mysqli The MySQLi connection
|
||||
*/
|
||||
public function getConnection() {
|
||||
return $this->conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a transaction
|
||||
*
|
||||
* @return bool Success status
|
||||
*/
|
||||
public function beginTransaction() {
|
||||
try {
|
||||
$this->conn->begin_transaction();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
$this->lastError = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit a transaction
|
||||
*
|
||||
* @return bool Success status
|
||||
*/
|
||||
public function commit() {
|
||||
try {
|
||||
$this->conn->commit();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
$this->lastError = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback a transaction
|
||||
*
|
||||
* @return bool Success status
|
||||
*/
|
||||
public function rollback() {
|
||||
try {
|
||||
$this->conn->rollback();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
$this->lastError = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
80
components/banner.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* REUSABLE PAGE BANNER COMPONENT
|
||||
*
|
||||
* Displays a page banner with background image, title, and breadcrumb navigation.
|
||||
*
|
||||
* Usage in your page:
|
||||
*
|
||||
* <?php
|
||||
* $pageTitle = 'About';
|
||||
* $bannerImage = 'assets/images/blog/cover.jpg'; // optional
|
||||
* require_once('components/banner.php');
|
||||
* ?>
|
||||
*
|
||||
* Parameters:
|
||||
* $pageTitle (required) - Page title to display
|
||||
* $bannerImage (optional) - URL to banner background image. If not set, uses random banner
|
||||
* $breadcrumbs (optional) - Array of breadcrumb items. Default: [['Home' => 'index.php']]
|
||||
* $classes (optional) - Additional CSS classes for banner section
|
||||
*/
|
||||
|
||||
// Default values
|
||||
$pageTitle = $pageTitle ?? 'Page';
|
||||
$bannerImage = $bannerImage ?? '';
|
||||
$breadcrumbs = $breadcrumbs ?? [['Home' => 'index.php']];
|
||||
$classes = $classes ?? '';
|
||||
|
||||
// If no banner image provided, try to use random banner
|
||||
if (empty($bannerImage)) {
|
||||
// Try to determine root path if not already set
|
||||
if (!isset($rootPath)) {
|
||||
$rootPath = $_SERVER['DOCUMENT_ROOT'] ?? dirname(__DIR__);
|
||||
}
|
||||
$bannerFolder = $rootPath . '/assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
// Convert absolute paths back to web-relative paths
|
||||
$bannerImages = array_map(function($path) use ($rootPath) {
|
||||
return str_replace($rootPath, '', $path);
|
||||
}, $bannerImages);
|
||||
$bannerImage = !empty($bannerImages) ? $bannerImages[array_rand($bannerImages)] : '/assets/images/base4/camping.jpg';
|
||||
}
|
||||
|
||||
// Add the page title to breadcrumbs as last item (not a link)
|
||||
$breadcrumbItems = [];
|
||||
foreach ($breadcrumbs as $item) {
|
||||
foreach ($item as $label => $url) {
|
||||
$breadcrumbItems[] = ['label' => $label, 'url' => $url];
|
||||
}
|
||||
}
|
||||
$breadcrumbItems[] = ['label' => $pageTitle, 'url' => null];
|
||||
?>
|
||||
|
||||
<!-- Page Banner Start -->
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover <?php echo $classes; ?>" style="background-image: url('<?php echo $bannerImage; ?>');">
|
||||
<!-- Overlay PNG -->
|
||||
<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">
|
||||
<?php echo htmlspecialchars($pageTitle); ?>
|
||||
</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">
|
||||
<?php foreach ($breadcrumbItems as $item): ?>
|
||||
<li class="breadcrumb-item <?php echo $item['url'] === null ? 'active' : ''; ?>">
|
||||
<?php if ($item['url']): ?>
|
||||
<a href="<?php echo htmlspecialchars($item['url']); ?>">
|
||||
<?php echo htmlspecialchars($item['label']); ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<?php echo htmlspecialchars($item['label']); ?>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php include_once("instapage.php"); ?><!-- footer area start -->
|
||||
<?php include_once(dirname(__DIR__) . "/src/pages/events/instapage.php"); ?><!-- footer area start -->
|
||||
<footer class="main-footer bgs-cover overlay rel z-1 pb-25"
|
||||
style="background-image: url(assets/images/backgrounds/footer.jpg);">
|
||||
<div class="container">
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
$dbhost = $_ENV['DB_HOST'];
|
||||
$dbuser = $_ENV['DB_USER'];
|
||||
$dbpass = $_ENV['DB_PASS'];
|
||||
$dbname = $_ENV['DB_NAME'];
|
||||
$salt = $_ENV['SALT'];
|
||||
|
||||
|
||||
|
||||
if(!$conn = mysqli_connect($dbhost, $dbuser, $dbpass, $dbname)){
|
||||
die("Failed to connect: " . mysqli_connect_error());
|
||||
}
|
||||
|
||||
date_default_timezone_set('Africa/Johannesburg');
|
||||
368
docs/DATABASE_SERVICE_EXAMPLES.md
Normal file
@@ -0,0 +1,368 @@
|
||||
# DatabaseService Usage Examples
|
||||
|
||||
This document shows how to refactor existing code to use the new `DatabaseService` class for cleaner, more maintainable database operations.
|
||||
|
||||
## Current State
|
||||
|
||||
Files are using the procedural MySQLi pattern:
|
||||
```php
|
||||
$stmt = $conn->prepare("SELECT * FROM users WHERE email = ?");
|
||||
$stmt->bind_param("s", $email);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$row = $result->fetch_assoc();
|
||||
$stmt->close();
|
||||
```
|
||||
|
||||
## Example 1: Simple SELECT (admin_members.php)
|
||||
|
||||
### Current Code
|
||||
```php
|
||||
$stmt = $conn->prepare("SELECT user_id, first_name, last_name, tel_cell, email, dob, accept_indemnity FROM membership_application");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Then in HTML/JS loop:
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
// display row
|
||||
}
|
||||
```
|
||||
|
||||
### Using DatabaseService
|
||||
```php
|
||||
// Simple - get all records
|
||||
$members = $db->select("SELECT user_id, first_name, last_name, tel_cell, email, dob, accept_indemnity FROM membership_application");
|
||||
|
||||
// In HTML/JS loop:
|
||||
foreach ($members as $row) {
|
||||
// display row
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- No manual `bind_param()`, `execute()`, `close()` needed
|
||||
- Returns array directly
|
||||
- Automatic error tracking via `$db->getLastError()`
|
||||
|
||||
---
|
||||
|
||||
## Example 2: SELECT with Parameters (validate_login.php)
|
||||
|
||||
### Current Code
|
||||
```php
|
||||
$query = "SELECT * FROM users WHERE email = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("s", $email);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows == 1) {
|
||||
$row = $result->fetch_assoc();
|
||||
// use $row
|
||||
}
|
||||
$stmt->close();
|
||||
```
|
||||
|
||||
### Using DatabaseService
|
||||
```php
|
||||
$user = $db->selectOne(
|
||||
"SELECT * FROM users WHERE email = ?",
|
||||
[$email],
|
||||
"s" // s = string type
|
||||
);
|
||||
|
||||
if ($user) {
|
||||
// use $user - returns false if no row found
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- One-liner for single row
|
||||
- Handles null checks automatically
|
||||
- Type specification clear in parameters
|
||||
|
||||
---
|
||||
|
||||
## Example 3: INSERT (validate_login.php)
|
||||
|
||||
### Current Code
|
||||
```php
|
||||
$query = "INSERT INTO users (email, first_name, last_name, profile_pic, password, is_verified) VALUES (?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $conn->prepare($query);
|
||||
$is_verified = 1;
|
||||
$stmt->bind_param("sssssi", $email, $first_name, $last_name, $picture, $password, $is_verified);
|
||||
if ($stmt->execute()) {
|
||||
$user_id = $conn->insert_id; // ❌ Bug: insert_id from $conn, not $stmt
|
||||
// use $user_id
|
||||
}
|
||||
$stmt->close();
|
||||
```
|
||||
|
||||
### Using DatabaseService
|
||||
```php
|
||||
$user_id = $db->insert(
|
||||
"INSERT INTO users (email, first_name, last_name, profile_pic, password, is_verified) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
[$email, $first_name, $last_name, $picture, $password, 1],
|
||||
"sssssi"
|
||||
);
|
||||
|
||||
if ($user_id) {
|
||||
// $user_id contains the auto-increment ID
|
||||
} else {
|
||||
$error = $db->getLastError();
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Returns insert ID directly
|
||||
- Automatic error handling
|
||||
- Cleaner parameter list
|
||||
|
||||
---
|
||||
|
||||
## Example 4: UPDATE (admin_members.php)
|
||||
|
||||
### Current Code
|
||||
```php
|
||||
$user_id = intval($_POST['user_id']);
|
||||
$stmt = $conn->prepare("UPDATE membership_application SET accept_indemnity = 1 WHERE user_id = ?");
|
||||
if ($stmt) {
|
||||
$stmt->bind_param("i", $user_id);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
}
|
||||
```
|
||||
|
||||
### Using DatabaseService
|
||||
```php
|
||||
$user_id = intval($_POST['user_id']);
|
||||
$affectedRows = $db->update(
|
||||
"UPDATE membership_application SET accept_indemnity = 1 WHERE user_id = ?",
|
||||
[$user_id],
|
||||
"i"
|
||||
);
|
||||
|
||||
if ($affectedRows !== false) {
|
||||
// Updated successfully, $affectedRows = number of rows changed
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Returns affected row count
|
||||
- No manual statement closing
|
||||
- Error available via `$db->getLastError()`
|
||||
|
||||
---
|
||||
|
||||
## Example 5: COUNT / EXISTS
|
||||
|
||||
### Current Pattern (Need 3 lines)
|
||||
```php
|
||||
$stmt = $conn->prepare("SELECT COUNT(*) as count FROM users WHERE email = ?");
|
||||
$stmt->bind_param("s", $email);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$row = $result->fetch_assoc();
|
||||
if ($row['count'] > 0) { /* exists */ }
|
||||
$stmt->close();
|
||||
```
|
||||
|
||||
### Using DatabaseService (One line)
|
||||
```php
|
||||
$exists = $db->exists("users", "email = ?", [$email], "s");
|
||||
if ($exists) {
|
||||
// User exists
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Boolean result
|
||||
- Intent is clear
|
||||
- One-liner
|
||||
|
||||
---
|
||||
|
||||
## Example 6: Multiple Rows with Filtering
|
||||
|
||||
### Current Code
|
||||
```php
|
||||
$status = 'active';
|
||||
$stmt = $conn->prepare("SELECT * FROM members WHERE status = ? ORDER BY last_name ASC");
|
||||
$stmt->bind_param("s", $status);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$members = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$members[] = $row;
|
||||
}
|
||||
$stmt->close();
|
||||
```
|
||||
|
||||
### Using DatabaseService
|
||||
```php
|
||||
$members = $db->select(
|
||||
"SELECT * FROM members WHERE status = ? ORDER BY last_name ASC",
|
||||
['active'],
|
||||
"s"
|
||||
);
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Returns array directly
|
||||
- No loop needed
|
||||
- 2 lines vs 8 lines
|
||||
|
||||
---
|
||||
|
||||
## Example 7: Error Handling
|
||||
|
||||
### Current Pattern
|
||||
```php
|
||||
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
|
||||
if (!$stmt) {
|
||||
echo "Prepare failed: " . $conn->error;
|
||||
exit();
|
||||
}
|
||||
$stmt->bind_param("i", $id);
|
||||
if (!$stmt->execute()) {
|
||||
echo "Execute failed: " . $stmt->error;
|
||||
exit();
|
||||
}
|
||||
```
|
||||
|
||||
### Using DatabaseService
|
||||
```php
|
||||
$user = $db->selectOne("SELECT * FROM users WHERE id = ?", [$id], "i");
|
||||
if ($user === false) {
|
||||
$error = $db->getLastError();
|
||||
error_log("Database error: " . $error);
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Error handling centralized
|
||||
- No null checks for each step
|
||||
- Debug via `$db->getLastQuery()`
|
||||
|
||||
---
|
||||
|
||||
## Example 8: Transactions
|
||||
|
||||
### Current Pattern
|
||||
```php
|
||||
$conn->begin_transaction();
|
||||
try {
|
||||
$stmt = $conn->prepare("INSERT INTO orders ...");
|
||||
$stmt->execute();
|
||||
|
||||
$stmt = $conn->prepare("UPDATE inventory ...");
|
||||
$stmt->execute();
|
||||
|
||||
$conn->commit();
|
||||
} catch (Exception $e) {
|
||||
$conn->rollback();
|
||||
}
|
||||
```
|
||||
|
||||
### Using DatabaseService
|
||||
```php
|
||||
$db->beginTransaction();
|
||||
|
||||
$order_id = $db->insert("INSERT INTO orders ...", [...], "...");
|
||||
if ($order_id === false) {
|
||||
$db->rollback();
|
||||
exit("Order creation failed");
|
||||
}
|
||||
|
||||
$updated = $db->update("UPDATE inventory ...", [...], "...");
|
||||
if ($updated === false) {
|
||||
$db->rollback();
|
||||
exit("Inventory update failed");
|
||||
}
|
||||
|
||||
$db->commit();
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Unified transaction API
|
||||
- Built-in error checking
|
||||
- Clean rollback on failure
|
||||
|
||||
---
|
||||
|
||||
## Type Specification Reference
|
||||
|
||||
When using DatabaseService methods, specify parameter types:
|
||||
|
||||
| Type | Meaning | Example |
|
||||
|------|---------|---------|
|
||||
| `"i"` | Integer | `user_id = 5` |
|
||||
| `"d"` | Double/Float | `price = 19.99` |
|
||||
| `"s"` | String | `email = 'test@example.com'` |
|
||||
| `"b"` | Blob | Binary data |
|
||||
|
||||
Examples:
|
||||
```php
|
||||
// Single parameter
|
||||
$db->select("SELECT * FROM users WHERE id = ?", [123], "i");
|
||||
|
||||
// Multiple parameters
|
||||
$db->select(
|
||||
"SELECT * FROM users WHERE email = ? AND status = ?",
|
||||
["test@example.com", "active"],
|
||||
"ss"
|
||||
);
|
||||
|
||||
// Mixed types
|
||||
$db->select(
|
||||
"SELECT * FROM orders WHERE user_id = ? AND total > ? AND date = ?",
|
||||
[5, 100.50, "2025-01-01"],
|
||||
"ids" // integer, double, string
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Path
|
||||
|
||||
### Phase 1: New Code
|
||||
Start using `$db` for all new features and AJAX endpoints.
|
||||
|
||||
### Phase 2: High-Traffic Files
|
||||
Refactor popular files:
|
||||
1. `validate_login.php` - Login is critical
|
||||
2. `functions.php` - Helper functions
|
||||
3. `admin_members.php`, `admin_payments.php` - Admin pages
|
||||
|
||||
### Phase 3: Gradual Rollout
|
||||
As each file is refactored, commit and test thoroughly before moving to next.
|
||||
|
||||
### Phase 4: Full Migration
|
||||
Eventually all procedural `$conn->prepare()` patterns replaced.
|
||||
|
||||
---
|
||||
|
||||
## Benefits Summary
|
||||
|
||||
| Aspect | Before | After |
|
||||
|--------|--------|-------|
|
||||
| Lines per query | 5-8 | 1-3 |
|
||||
| Error handling | Manual checks | Automatic |
|
||||
| Type safety | bind_param() | Parameter array |
|
||||
| Statement closing | Manual | Automatic |
|
||||
| Insert ID handling | `$conn->insert_id` (buggy) | Direct return |
|
||||
| Debugging | Check multiple vars | `getLastError()`, `getLastQuery()` |
|
||||
| Consistency | Varies | Unified API |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Start with one file (e.g., `admin_members.php`)
|
||||
2. Convert simple queries first
|
||||
3. Test thoroughly
|
||||
4. Commit and move to next file
|
||||
5. Keep `$conn` available for complex queries that don't fit the standard patterns
|
||||
|
||||
The `$db` service makes your code **cleaner, safer, and easier to maintain**.
|
||||
199
docs/LINK_MANAGEMENT.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# Link Management Strategy - Complete Implementation
|
||||
|
||||
## Two-Layer Approach for Safe Migration
|
||||
|
||||
This strategy ensures that **all links work during the file restructuring migration** without breaking any existing functionality.
|
||||
|
||||
### Layer 1: URL Helper Function ✅
|
||||
**Location**: `functions.php` at end of file
|
||||
|
||||
```php
|
||||
function url($page) {
|
||||
static $map = [
|
||||
'login' => '/src/pages/auth/login.php',
|
||||
'register' => '/src/pages/auth/register.php',
|
||||
'membership' => '/src/pages/memberships/membership.php',
|
||||
// ... 80+ total mappings
|
||||
];
|
||||
return isset($map[$page]) ? $map[$page] : '/' . $page . '.php';
|
||||
}
|
||||
```
|
||||
|
||||
**Usage in HTML**:
|
||||
```html
|
||||
<!-- Before -->
|
||||
<a href="login.php">Login</a>
|
||||
|
||||
<!-- After -->
|
||||
<a href="<?= url('login') ?>">Login</a>
|
||||
```
|
||||
|
||||
**Advantages:**
|
||||
- ✅ Explicit and intentional
|
||||
- ✅ Single source of truth for all URLs
|
||||
- ✅ Easy to audit and maintain
|
||||
- ✅ Can add validation/auth logic to urls
|
||||
- ✅ No performance overhead
|
||||
|
||||
**Progress:**
|
||||
- ✅ Created comprehensive 80+ item mapping
|
||||
- ⏳ Started updating header.php (1 of 95 files)
|
||||
- ⏳ Need to update remaining ~94 files
|
||||
|
||||
---
|
||||
|
||||
### Layer 2: Apache RewriteRules ✅
|
||||
**Location**: `.htaccess` at root
|
||||
|
||||
95 transparent rewrite rules that map old URLs to new locations:
|
||||
|
||||
```apache
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
|
||||
# Auth pages
|
||||
RewriteRule ^login\.php$ src/pages/auth/login.php [L]
|
||||
RewriteRule ^register\.php$ src/pages/auth/register.php [L]
|
||||
# ... 93 more rules covering all files
|
||||
```
|
||||
|
||||
**How it works:**
|
||||
1. User requests old URL: `login.php`
|
||||
2. `.htaccess` rewrites to: `src/pages/auth/login.php`
|
||||
3. File is served transparently
|
||||
4. **User never knows the file moved**
|
||||
|
||||
**Advantages:**
|
||||
- ✅ Backward compatible - old links still work
|
||||
- ✅ Works for direct links, forms, AJAX calls
|
||||
- ✅ No code changes needed immediately
|
||||
- ✅ Covers any links we missed in Layer 1
|
||||
- ✅ Can be removed after full migration
|
||||
|
||||
---
|
||||
|
||||
## Migration Workflow
|
||||
|
||||
### Phase 1: Update HTML Links (Current)
|
||||
1. ✅ Create url() helper - DONE
|
||||
2. ✅ Create .htaccess rules - DONE
|
||||
3. ⏳ Update page links to use url() - IN PROGRESS
|
||||
- Start: header.php (25+ links)
|
||||
- Then: login.php, register.php (auth)
|
||||
- Then: membership pages
|
||||
- Then: booking/shop/event pages
|
||||
- Then: admin pages
|
||||
- **Total: ~300 link references to update**
|
||||
|
||||
### Phase 2: Update AJAX Calls
|
||||
Find all `url: 'validate_login.php'` in script tags and update to:
|
||||
```javascript
|
||||
url: '<?= url("validate_login") ?>'
|
||||
```
|
||||
|
||||
### Phase 3: Move Files (Later)
|
||||
Once links are working:
|
||||
1. Move config files → src/config/
|
||||
2. Move page files → src/pages/[category]/
|
||||
3. Move admin files → src/admin/
|
||||
4. Move processor files → src/processors/
|
||||
5. Move API files → src/api/
|
||||
6. Update include paths in all files to use bootstrap.php
|
||||
|
||||
### Phase 4: Cleanup
|
||||
- Remove .htaccess rewrite rules (no longer needed)
|
||||
- Remove url() function or keep for future use
|
||||
- Update all include paths to be permanent
|
||||
|
||||
---
|
||||
|
||||
## Link Count Summary
|
||||
|
||||
| Category | Files | Links | Status |
|
||||
|----------|-------|-------|--------|
|
||||
| header.php | 1 | 25 | 🔄 In Progress |
|
||||
| login/register/auth | 8 | 40 | ⏳ Pending |
|
||||
| Pages (all) | 45 | ~200 | ⏳ Pending |
|
||||
| Admin pages | 9 | ~50 | ⏳ Pending |
|
||||
| AJAX in scripts | ~15 | ~25 | ⏳ Pending |
|
||||
| **TOTAL** | **95** | **~350** | **5% done** |
|
||||
|
||||
---
|
||||
|
||||
## Safety Guarantees
|
||||
|
||||
✅ **If url() helper breaks**: .htaccess rules catch it
|
||||
✅ **If .htaccess doesn't work**: url() helper still works
|
||||
✅ **If we update only 50% of links**: Rest still work via rewrite rules
|
||||
✅ **No broken links**: Tested via browser and AJAX
|
||||
✅ **Easy rollback**: Just revert commits, .htaccess unchanged
|
||||
|
||||
---
|
||||
|
||||
## Current Branch Status
|
||||
|
||||
**Branch**: `feature/restructure-codebase`
|
||||
|
||||
**Commits**:
|
||||
1. ✅ d57cce9a - Add URL helper + begin header.php updates
|
||||
2. ✅ debe7d69 - Add .htaccess rewrite rules (95 rules)
|
||||
|
||||
**Next Steps**:
|
||||
1. Continue updating links in remaining files
|
||||
2. Test in browser
|
||||
3. Verify AJAX endpoints work
|
||||
4. Once satisfied, move to Phase 2 (move files)
|
||||
5. Merge to main
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### To Update a Link
|
||||
```php
|
||||
// Find this pattern in any file:
|
||||
<a href="login.php">Login</a>
|
||||
|
||||
// Replace with:
|
||||
<a href="<?= url('login') ?>">Login</a>
|
||||
|
||||
// For AJAX:
|
||||
$.ajax({
|
||||
url: '<?= url("validate_login") ?>',
|
||||
// ...
|
||||
});
|
||||
|
||||
// For redirects:
|
||||
header("Location: " . url('index'));
|
||||
```
|
||||
|
||||
### Mapping Reference
|
||||
See `functions.php` for complete mapping. Key ones:
|
||||
- `url('home')` → `/index.php`
|
||||
- `url('login')` → `/src/pages/auth/login.php`
|
||||
- `url('membership')` → `/src/pages/memberships/membership.php`
|
||||
- `url('admin_members')` → `/src/admin/admin_members.php`
|
||||
- `url('validate_login')` → `/src/processors/validate_login.php`
|
||||
- `url('fetch_users')` → `/src/api/fetch_users.php`
|
||||
|
||||
---
|
||||
|
||||
## Performance
|
||||
|
||||
- Layer 1: 0 performance impact (direct path)
|
||||
- Layer 2: ~0.001ms per request (Apache rewrite, cached)
|
||||
- Can be removed after migration for full cleanup
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist Before Merge
|
||||
|
||||
- [ ] Click all main navigation links
|
||||
- [ ] Test login/register flow
|
||||
- [ ] Test AJAX endpoints (fetch_users, fetch_drinks, etc)
|
||||
- [ ] Test admin pages navigation
|
||||
- [ ] Test form submissions (process_*.php)
|
||||
- [ ] Test redirects work
|
||||
- [ ] Verify no 404 errors in browser console
|
||||
- [ ] Check production logs for errors
|
||||
|
||||
369
docs/RESTRUCTURING_PLAN.md
Normal file
@@ -0,0 +1,369 @@
|
||||
# File Restructuring Plan - feature/restructure-codebase
|
||||
|
||||
## New Directory Structure
|
||||
|
||||
```
|
||||
4WDCSA.co.za/
|
||||
├── src/
|
||||
│ ├── pages/
|
||||
│ │ ├── index.php (homepage - moved from root)
|
||||
│ │ ├── about.php
|
||||
│ │ ├── contact.php
|
||||
│ │ ├── privacy_policy.php
|
||||
│ │ │
|
||||
│ │ ├── auth/
|
||||
│ │ │ ├── login.php
|
||||
│ │ │ ├── register.php
|
||||
│ │ │ ├── forgot_password.php
|
||||
│ │ │ ├── reset_password.php
|
||||
│ │ │ ├── verify.php
|
||||
│ │ │ ├── resend_verification.php
|
||||
│ │ │ ├── change_password.php
|
||||
│ │ │ └── update_password.php
|
||||
│ │ │
|
||||
│ │ ├── memberships/
|
||||
│ │ │ ├── membership.php
|
||||
│ │ │ ├── membership_details.php
|
||||
│ │ │ ├── membership_application.php
|
||||
│ │ │ ├── membership_payment.php
|
||||
│ │ │ ├── renew_membership.php
|
||||
│ │ │ └── member_info.php
|
||||
│ │ │
|
||||
│ │ ├── bookings/
|
||||
│ │ │ ├── bookings.php
|
||||
│ │ │ ├── campsites.php
|
||||
│ │ │ ├── campsite_booking.php
|
||||
│ │ │ ├── trips.php
|
||||
│ │ │ ├── trip-details.php
|
||||
│ │ │ ├── course_details.php
|
||||
│ │ │ └── driver_training.php
|
||||
│ │ │
|
||||
│ │ ├── shop/
|
||||
│ │ │ ├── view_cart.php
|
||||
│ │ │ ├── add_to_cart.php
|
||||
│ │ │ ├── bar_tabs.php
|
||||
│ │ │ ├── payment_confirmation.php
|
||||
│ │ │ ├── confirm.php
|
||||
│ │ │ └── confirm2.php
|
||||
│ │ │
|
||||
│ │ ├── events/
|
||||
│ │ │ ├── events.php
|
||||
│ │ │ ├── blog.php
|
||||
│ │ │ ├── blog_details.php
|
||||
│ │ │ ├── best_of_the_eastern_cape_2024.php
|
||||
│ │ │ ├── 2025_agm_minutes.php
|
||||
│ │ │ ├── agm_content.php
|
||||
│ │ │ └── instapage.php
|
||||
│ │ │
|
||||
│ │ └── other/
|
||||
│ │ ├── 404.php
|
||||
│ │ ├── account_settings.php
|
||||
│ │ ├── rescue_recovery.php
|
||||
│ │ ├── bush_mechanics.php
|
||||
│ │ ├── indemnity.php
|
||||
│ │ ├── indemnity_waiver.php
|
||||
│ │ ├── basic_indemnity.php
|
||||
│ │ ├── view_indemnity.php
|
||||
│ │ ├── ad_banner.php
|
||||
│ │ ├── logos.php
|
||||
│ │ ├── review_box.php
|
||||
│ │ ├── comment_box.php
|
||||
│ │ ├── modal.php
|
||||
│ │ ├── insta_footer.php
|
||||
│ │ └── index2.php
|
||||
│ │
|
||||
│ ├── admin/
|
||||
│ │ ├── admin_members.php
|
||||
│ │ ├── admin_payments.php
|
||||
│ │ ├── admin_web_users.php
|
||||
│ │ ├── admin_course_bookings.php
|
||||
│ │ ├── admin_camp_bookings.php
|
||||
│ │ ├── admin_trip_bookings.php
|
||||
│ │ ├── admin_visitors.php
|
||||
│ │ ├── admin_efts.php
|
||||
│ │ └── add_campsite.php
|
||||
│ │
|
||||
│ ├── api/
|
||||
│ │ ├── fetch_users.php
|
||||
│ │ ├── fetch_drinks.php
|
||||
│ │ ├── fetch_bar_tabs.php
|
||||
│ │ ├── get_campsites.php
|
||||
│ │ ├── get_tab_total.php
|
||||
│ │ └── google_validate_login.php
|
||||
│ │
|
||||
│ ├── processors/
|
||||
│ │ ├── validate_login.php
|
||||
│ │ ├── register_user.php
|
||||
│ │ ├── process_application.php
|
||||
│ │ ├── process_booking.php
|
||||
│ │ ├── process_camp_booking.php
|
||||
│ │ ├── process_course_booking.php
|
||||
│ │ ├── process_trip_booking.php
|
||||
│ │ ├── process_membership_payment.php
|
||||
│ │ ├── process_payments.php
|
||||
│ │ ├── process_eft.php
|
||||
│ │ ├── submit_order.php
|
||||
│ │ ├── submit_pop.php
|
||||
│ │ ├── process_signature.php
|
||||
│ │ ├── create_bar_tab.php
|
||||
│ │ ├── update_application.php
|
||||
│ │ ├── update_user.php
|
||||
│ │ ├── upload_profile_picture.php
|
||||
│ │ ├── send_reset_link.php
|
||||
│ │ └── logout.php
|
||||
│ │
|
||||
│ ├── config/
|
||||
│ │ ├── connection.php (database service init)
|
||||
│ │ ├── session.php
|
||||
│ │ ├── env.php
|
||||
│ │ └── functions.php
|
||||
│ │
|
||||
│ └── classes/
|
||||
│ ├── DatabaseService.php
|
||||
│ ├── FormValidator.php (future)
|
||||
│ └── ... (other services)
|
||||
│
|
||||
├── components/
|
||||
│ ├── header.php
|
||||
│ ├── banner.php
|
||||
│ ├── footer.php (unified)
|
||||
│ └── ... (shared components)
|
||||
│
|
||||
├── assets/
|
||||
│ ├── css/
|
||||
│ ├── js/
|
||||
│ ├── images/
|
||||
│ ├── fonts/
|
||||
│ ├── uploads/
|
||||
│ └── sass/
|
||||
│
|
||||
├── vendor/ (Composer)
|
||||
├── mailers/ (Mailer templates)
|
||||
├── uploads/ (User uploads)
|
||||
├── google-client/ (OAuth client)
|
||||
│
|
||||
├── .htaccess (already in root - stays there)
|
||||
├── index.php (PHP entry point - stays in root, requires src/pages/index.php)
|
||||
├── sitemap.xml
|
||||
└── phpinfo.php (debug - should remove later)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Phase 1: Create Structure & Map Files ✅
|
||||
- [x] Create all directories
|
||||
- [x] Create this migration plan
|
||||
- [ ] Create index.php router in root that includes src/pages/index.php
|
||||
- [ ] Create .htaccess rules to serve from src/ transparently
|
||||
|
||||
### Phase 2: Move Core Config Files
|
||||
```bash
|
||||
# Must do first - everything depends on these
|
||||
- Move: connection.php → src/config/
|
||||
- Move: session.php → src/config/
|
||||
- Move: env.php → src/config/
|
||||
- Move: functions.php → src/config/
|
||||
- Update all includes in every file (this is automated by search/replace)
|
||||
```
|
||||
|
||||
### Phase 3: Move Page Files (45 files)
|
||||
```bash
|
||||
# Priority: High-traffic pages first
|
||||
1. Auth pages (8 files) → src/pages/auth/
|
||||
- login.php, register.php, forgot_password.php, etc.
|
||||
|
||||
2. Membership pages (6 files) → src/pages/memberships/
|
||||
- membership.php, membership_application.php, etc.
|
||||
|
||||
3. Booking pages (7 files) → src/pages/bookings/
|
||||
- campsites.php, bookings.php, trips.php, etc.
|
||||
|
||||
4. Shop/Bar pages (6 files) → src/pages/shop/
|
||||
- view_cart.php, bar_tabs.php, etc.
|
||||
|
||||
5. Events/Blog pages (7 files) → src/pages/events/
|
||||
- blog.php, events.php, etc.
|
||||
|
||||
6. Misc pages (11 files) → src/pages/other/
|
||||
- about.php, contact.php, indemnity.php, etc.
|
||||
```
|
||||
|
||||
### Phase 4: Move Admin Files (9 files)
|
||||
```bash
|
||||
Move all admin_*.php files → src/admin/
|
||||
- admin_members.php
|
||||
- admin_payments.php
|
||||
- etc.
|
||||
```
|
||||
|
||||
### Phase 5: Move API Files (6 files)
|
||||
```bash
|
||||
Move all fetch_*.php and get_*.php files → src/api/
|
||||
- fetch_users.php
|
||||
- fetch_drinks.php
|
||||
- get_campsites.php
|
||||
- etc.
|
||||
```
|
||||
|
||||
### Phase 6: Move Processor Files (18 files)
|
||||
```bash
|
||||
Move all process_*.php, validate_*.php, submit_*.php → src/processors/
|
||||
- validate_login.php
|
||||
- process_booking.php
|
||||
- submit_order.php
|
||||
- etc.
|
||||
```
|
||||
|
||||
### Phase 7: Update All Include Paths
|
||||
```bash
|
||||
# This is the critical step - all files reference each other
|
||||
- connection.php → src/config/connection.php
|
||||
- session.php → src/config/session.php
|
||||
- env.php → src/config/env.php
|
||||
- functions.php → src/config/functions.php
|
||||
|
||||
# Update relative includes in each file to use __DIR__ or __FILE__
|
||||
# Example: require_once(__DIR__ . '/../../config/connection.php');
|
||||
```
|
||||
|
||||
### Phase 8: .htaccess Routes (Optional - Keep Simple for Now)
|
||||
```bash
|
||||
# Can be done separately - initially just use new paths as-is
|
||||
# .htaccess rules to make old URLs still work (forward compatibility)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Include Path Changes
|
||||
|
||||
### Before (Root-based includes):
|
||||
```php
|
||||
require_once('connection.php');
|
||||
require_once('session.php');
|
||||
require_once('functions.php');
|
||||
include_once('header.php');
|
||||
```
|
||||
|
||||
### After (New structure):
|
||||
```php
|
||||
// From: src/pages/auth/login.php
|
||||
require_once(__DIR__ . '/../../config/connection.php');
|
||||
require_once(__DIR__ . '/../../config/session.php');
|
||||
require_once(__DIR__ . '/../../config/functions.php');
|
||||
include_once(__DIR__ . '/../../components/header.php');
|
||||
|
||||
// Or use a bootstrap loader in root index.php that sets up paths globally
|
||||
```
|
||||
|
||||
### Recommended: Bootstrap Approach
|
||||
Create a common bootstrap file that all pages include:
|
||||
|
||||
```php
|
||||
// src/bootstrap.php
|
||||
<?php
|
||||
define('APP_ROOT', __DIR__ . '/..');
|
||||
define('SRC_ROOT', APP_ROOT . '/src');
|
||||
define('CONFIG_PATH', SRC_ROOT . '/config');
|
||||
define('CLASSES_PATH', SRC_ROOT . '/classes');
|
||||
define('COMPONENTS_PATH', APP_ROOT . '/components');
|
||||
|
||||
require_once(CONFIG_PATH . '/env.php');
|
||||
require_once(CONFIG_PATH . '/connection.php');
|
||||
require_once(CONFIG_PATH . '/session.php');
|
||||
require_once(CONFIG_PATH . '/functions.php');
|
||||
?>
|
||||
```
|
||||
|
||||
Then every page only needs:
|
||||
```php
|
||||
<?php require_once(__DIR__ . '/../../bootstrap.php'); ?>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Before Merge
|
||||
1. **Test each moved file** - Load page in browser, verify no 404s
|
||||
2. **Test includes** - Check all require_once/include work
|
||||
3. **Test database** - Verify queries still execute
|
||||
4. **Test sessions** - Login/logout still works
|
||||
5. **Test links** - Navigation between pages works
|
||||
6. **Test APIs** - AJAX endpoints respond correctly
|
||||
|
||||
### Rollback Plan
|
||||
```bash
|
||||
# If issues found:
|
||||
git reset --hard HEAD
|
||||
git checkout main
|
||||
# All original files restored
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Count Summary
|
||||
|
||||
```
|
||||
├── Pages: 45 files (auth 8, memberships 6, bookings 7, shop 6, events 7, other 11)
|
||||
├── Admin: 9 files
|
||||
├── API: 6 files
|
||||
├── Processors: 18 files
|
||||
├── Config: 4 files (connection, session, env, functions)
|
||||
├── Classes: 1 file (DatabaseService, more later)
|
||||
└── Components: 2 files (header, banner)
|
||||
|
||||
Total: ~95 PHP files organized into logical groups
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Benefits of This Structure
|
||||
|
||||
✅ **Organization** - Clear, logical file hierarchy
|
||||
✅ **Security** - Can restrict web access to sensitive folders (API, processors)
|
||||
✅ **Maintenance** - Related files grouped together
|
||||
✅ **Onboarding** - New developers find files easily
|
||||
✅ **Testing** - Can write tests per folder
|
||||
✅ **Scalability** - Easy to add new features in existing folders
|
||||
✅ **Performance** - Can set different caching rules per folder
|
||||
✅ **Version Control** - Smaller diffs, easier to review changes
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Create bootstrap.php (centralizes all includes)
|
||||
2. Start Phase 2 - Move config files first
|
||||
3. Create find/replace automation for include path updates
|
||||
4. Test 1-2 files from each category
|
||||
5. If successful, batch move remaining files in each category
|
||||
6. Test full site
|
||||
7. Commit in batches by category
|
||||
8. Merge to main after validation
|
||||
|
||||
---
|
||||
|
||||
## Commands Reference
|
||||
|
||||
```bash
|
||||
# List files to move for each phase
|
||||
ls *.php | grep -E '^(login|register|forgot)' | xargs -I {} mv {} src/pages/auth/
|
||||
|
||||
# Find all require_once and include statements
|
||||
grep -r "require_once\|include" src/ | grep -v "vendor"
|
||||
|
||||
# Test that no broken includes exist
|
||||
php -l src/**/*.php
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Current Status
|
||||
|
||||
✅ Branch created: `feature/restructure-codebase`
|
||||
✅ Directories created (all folders)
|
||||
✅ This plan documented
|
||||
|
||||
**Next Action**: Create bootstrap.php and start Phase 2 (config files)
|
||||
5
env.php
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
|
||||
$dotenv->load();
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
<?php
|
||||
require_once("connection.php");
|
||||
|
||||
if (isset($_GET['tab_id'])) {
|
||||
$tab_id = mysqli_real_escape_string($conn, $_GET['tab_id']);
|
||||
|
||||
// Fetch drinks available for this tab
|
||||
$sql = "SELECT * FROM bar_items"; // Customize as needed
|
||||
$result = mysqli_query($conn, $sql);
|
||||
|
||||
$drinks = [];
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$drinks[] = $row;
|
||||
}
|
||||
|
||||
echo json_encode($drinks);
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Tab ID is required.']);
|
||||
}
|
||||
?>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
require_once("env.php");
|
||||
require_once("session.php");
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
|
||||
if ($conn->connect_error) {
|
||||
die(json_encode([])); // Return empty JSON on failure
|
||||
}
|
||||
|
||||
$sql = "SELECT user_id, first_name, last_name FROM users ORDER BY first_name ASC";
|
||||
$result = $conn->query($sql);
|
||||
|
||||
$users = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$users[] = $row;
|
||||
}
|
||||
|
||||
echo json_encode($users);
|
||||
$conn->close();
|
||||
?>
|
||||
@@ -1,495 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<!-- Title -->
|
||||
<title>Ravelo - Travel & Tour Booking HTML Template</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" href="assets/images/logos/favicon.png" type="image/x-icon">
|
||||
<!-- Google Fonts -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Flaticon -->
|
||||
<link rel="stylesheet" href="assets/css/flaticon.min.css">
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="assets/css/fontawesome-5.14.0.min.css">
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
|
||||
<!-- Magnific Popup -->
|
||||
<link rel="stylesheet" href="assets/css/magnific-popup.min.css">
|
||||
<!-- Nice Select -->
|
||||
<link rel="stylesheet" href="assets/css/nice-select.min.css">
|
||||
<!-- Animate -->
|
||||
<link rel="stylesheet" href="assets/css/aos.css">
|
||||
<!-- Slick -->
|
||||
<link rel="stylesheet" href="assets/css/slick.min.css">
|
||||
<!-- Main Style -->
|
||||
<link rel="stylesheet" href="assets/css/style.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-wrapper">
|
||||
|
||||
<!-- Preloader -->
|
||||
<div class="preloader"><div class="custom-loader"></div></div>
|
||||
|
||||
<!-- main header -->
|
||||
<header class="main-header header-one">
|
||||
<!--Header-Upper-->
|
||||
<div class="header-upper bg-white py-30 rpy-0">
|
||||
<div class="container-fluid clearfix">
|
||||
|
||||
<div class="header-inner rel d-flex align-items-center">
|
||||
<div class="logo-outer">
|
||||
<div class="logo"><a href="index.php"><img src="assets/images/logos/logo-two.png" alt="Logo" title="Logo"></a></div>
|
||||
</div>
|
||||
|
||||
<div class="nav-outer mx-lg-auto ps-xxl-5 clearfix">
|
||||
<!-- Main Menu -->
|
||||
<nav class="main-menu navbar-expand-lg">
|
||||
<div class="navbar-header">
|
||||
<div class="mobile-logo">
|
||||
<a href="index.php">
|
||||
<img src="assets/images/logos/logo-two.png" alt="Logo" title="Logo">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Toggle Button -->
|
||||
<button type="button" class="navbar-toggle" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="navbar-collapse collapse clearfix">
|
||||
<ul class="navigation clearfix">
|
||||
<li class="dropdown current"><a href="#">Home</a>
|
||||
<ul>
|
||||
<li><a href="index.php">Travel Agency</a></li>
|
||||
<li><a href="index2.html">City Tou</a></li>
|
||||
<li><a href="index3.html">Tour Package</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="about.html">About</a></li>
|
||||
<li class="dropdown"><a href="#">Tours</a>
|
||||
<ul>
|
||||
<li><a href="tour-list.html">Tour List</a></li>
|
||||
<li><a href="tour-grid.html">Tour Grid</a></li>
|
||||
<li><a href="tour-sidebar.html">Tour Sidebar</a></li>
|
||||
<li><a href="trip-details.php">Tour Details</a></li>
|
||||
<li><a href="tour-guide.html">Tour Guide</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#">Destinations</a>
|
||||
<ul>
|
||||
<li><a href="destination1.html">Destination 01</a></li>
|
||||
<li><a href="destination2.html">Destination 01</a></li>
|
||||
<li><a href="destination-details.html">Destination Details</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#">Pages</a>
|
||||
<ul>
|
||||
<li><a href="pricing.html">Pricing</a></li>
|
||||
<li><a href="faqs.html">faqs</a></li>
|
||||
<li class="dropdown"><a href="#">Gallery</a>
|
||||
<ul>
|
||||
<li><a href="gellery-grid.html">Gallery Grid</a></li>
|
||||
<li><a href="gellery-slider.html">Gallery Slider</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#">products</a>
|
||||
<ul>
|
||||
<li><a href="shop.html">Our Products</a></li>
|
||||
<li><a href="product-details.html">Product Details</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="contact.php">Contact Us</a></li>
|
||||
<li><a href="404.html">404 Error</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#">blog</a>
|
||||
<ul>
|
||||
<li><a href="blog.html">blog List</a></li>
|
||||
<li><a href="blog-details.html">blog details</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
<!-- Main Menu End-->
|
||||
</div>
|
||||
|
||||
<!-- Menu Button -->
|
||||
<div class="menu-btns py-10">
|
||||
<a href="contact.php" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Book Now">Book Now</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
<!-- menu sidbar -->
|
||||
<div class="menu-sidebar">
|
||||
<button class="bg-transparent">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--End Header Upper-->
|
||||
</header>
|
||||
|
||||
|
||||
<!--Form Back Drop-->
|
||||
<div class="form-back-drop"></div>
|
||||
|
||||
<!-- Hidden Sidebar -->
|
||||
<section class="hidden-bar">
|
||||
<div class="inner-box text-center">
|
||||
<div class="cross-icon"><span class="fa fa-times"></span></div>
|
||||
<div class="title">
|
||||
<h4>Get Appointment</h4>
|
||||
</div>
|
||||
|
||||
<!--Appointment Form-->
|
||||
<div class="appointment-form">
|
||||
<form method="post" action="contact.php">
|
||||
<div class="form-group">
|
||||
<input type="text" name="text" value="" placeholder="Name" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="email" name="email" value="" placeholder="Email Address" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea placeholder="Message" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="theme-btn style-two">
|
||||
<span data-hover="Submit now">Submit now</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!--Social Icons-->
|
||||
<div class="social-style-one">
|
||||
<a href="contact.php"><i class="fab fa-twitter"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-instagram"></i></a>
|
||||
<a href="#"><i class="fab fa-pinterest-p"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!--End Hidden Sidebar -->
|
||||
|
||||
|
||||
<!-- Page Banner Start -->
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url(assets/images/banner/banner.jpg);">
|
||||
<div class="container">
|
||||
<div class="banner-inner text-white">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Gallery Grid</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">Gallery Grid</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
|
||||
|
||||
<!-- Gallery Area start -->
|
||||
<section class="gallery-two-area py-100 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="section-title text-center counter-text-wrap mb-50" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<h2>Explore Our Photo Gallery</h2>
|
||||
<p>One site <span class="count-text plus" data-speed="3000" data-stop="34500">0</span> most popular experience you’ll remember</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery1.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Brown Concrete Building</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50" data-aos-delay="50">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery2.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Swimming near boat</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50" data-aos-delay="100">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery3.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Building in the desert</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery4.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Cliff near shore beach</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50" data-aos-delay="50">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery5.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Tent camping in the desert</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50" data-aos-delay="100">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery6.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Machu Picchu, Peru</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery7.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Gray and black fish under water</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50" data-aos-delay="50">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery8.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Yacht sailing near island</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="gallery-two-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50" data-aos-delay="100">
|
||||
<div class="image">
|
||||
<img src="assets/images/gallery/gallery9.jpg" alt="Gallery">
|
||||
<a href="destination-details.html" class="link"><i class="fal fa-arrow-right"></i></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="category">Tour & Travel</span>
|
||||
<h5><a href="destination-details.html">Ship on dock during daytime</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12 text-center">
|
||||
<a href="tour-grid.html" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="View All Gallery">View All Gallery</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Gallery Area end -->
|
||||
|
||||
|
||||
<!-- Newsletter Area start -->
|
||||
<section class="newsletter-three bgc-primary py-100 rel z-1" style="background-image: url(assets/images/newsletter/newsletter-bg-lines.png);">
|
||||
<div class="container container-1500">
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="newsletter-content-part text-white rmb-55" data-aos="zoom-in-right" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="section-title counter-text-wrap mb-45">
|
||||
<h2>Subscribe Our Newsletter to Get more offer & Tips</h2>
|
||||
<p>One site <span class="count-text plus" data-speed="3000" data-stop="34500">0</span> most popular experience you’ll remember</p>
|
||||
</div>
|
||||
<form class="newsletter-form mb-15" action="#">
|
||||
<input id="news-email" type="email" placeholder="Email Address" required>
|
||||
<button type="submit" class="theme-btn bgc-secondary style-two">
|
||||
<span data-hover="Subscribe">Subscribe</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</button>
|
||||
</form>
|
||||
<p>No credit card requirement. No commitments</p>
|
||||
</div>
|
||||
<div class="newsletter-bg-image" data-aos="zoom-in-up" data-aos-delay="100" data-aos-duration="1500" data-aos-offset="50">
|
||||
<img src="assets/images/newsletter/newsletter-bg-image.png" alt="Newsletter">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="newsletter-image-part bgs-cover" style="background-image: url(assets/images/newsletter/newsletter-two-right.jpg);" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Newsletter Area end -->
|
||||
|
||||
|
||||
<!-- footer area start -->
|
||||
<footer class="main-footer footer-two bgp-bottom bgc-black rel z-15 pt-100 pb-115" style="background-image: url(assets/images/backgrounds/footer-two.png);">
|
||||
<div class="widget-area">
|
||||
<div class="container">
|
||||
<div class="row row-cols-xxl-5 row-cols-xl-4 row-cols-md-3 row-cols-2">
|
||||
<div class="col col-small" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="footer-widget footer-text">
|
||||
<div class="footer-logo mb-40">
|
||||
<a href="index.php"><img src="assets/images/logos/logo.png" alt="Logo"></a>
|
||||
</div>
|
||||
<div class="footer-map">
|
||||
<iframe src="https://www.google.com/maps/embed?pb=!1m10!1m8!1m3!1d96777.16150026117!2d-74.00840582560909!3d40.71171357405996!3m2!1i1024!2i768!4f13.1!5e0!3m2!1sen!2sbd!4v1706508986625!5m2!1sen!2sbd" style="border:0; width: 100%;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-small" data-aos="fade-up" data-aos-delay="50" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="footer-widget footer-links ms-sm-5">
|
||||
<div class="footer-title">
|
||||
<h5>Services</h5>
|
||||
</div>
|
||||
<ul class="list-style-three">
|
||||
<li><a href="destination-details.html">Best Tour Guide</a></li>
|
||||
<li><a href="destination-details.html">Tour Booking</a></li>
|
||||
<li><a href="destination-details.html">Hotel Booking</a></li>
|
||||
<li><a href="destination-details.html">Ticket Booking</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-small" data-aos="fade-up" data-aos-delay="100" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="footer-widget footer-links ms-md-4">
|
||||
<div class="footer-title">
|
||||
<h5>Company</h5>
|
||||
</div>
|
||||
<ul class="list-style-three">
|
||||
<li><a href="about.html">About Company</a></li>
|
||||
<li><a href="blog.html">Community Blog</a></li>
|
||||
<li><a href="contact.php">Jobs and Careers</a></li>
|
||||
<li><a href="blog.html">latest News Blog</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-small" data-aos="fade-up" data-aos-delay="150" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="footer-widget footer-links ms-lg-4">
|
||||
<div class="footer-title">
|
||||
<h5>Destinations</h5>
|
||||
</div>
|
||||
<ul class="list-style-three">
|
||||
<li><a href="destination-details.html">African Safaris</a></li>
|
||||
<li><a href="destination-details.html">Alaska & Canada</a></li>
|
||||
<li><a href="destination-details.html">South America</a></li>
|
||||
<li><a href="destination-details.html">Middle East</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-md-6 col-10 col-small" data-aos="fade-up" data-aos-delay="200" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="footer-widget footer-contact">
|
||||
<div class="footer-title">
|
||||
<h5>Get In Touch</h5>
|
||||
</div>
|
||||
<ul class="list-style-one">
|
||||
<li><i class="fal fa-map-marked-alt"></i> 578 Level, D-block 45 Street Melbourne, Australia</li>
|
||||
<li><i class="fal fa-envelope"></i> <a href="mailto:supportrevelo@gmail.com">supportrevelo @gmail.com</a></li>
|
||||
<li><i class="fal fa-phone-volume"></i> <a href="callto:+88012334588">+880 (123) 345 88</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom bg-transparent pt-20 pb-5">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-5">
|
||||
<div class="copyright-text text-center text-lg-start">
|
||||
<p>@Copy 2024 <a href="index.php">Ravelo</a>, All rights reserved</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-7 text-center text-lg-end">
|
||||
<ul class="footer-bottom-nav">
|
||||
<li><a href="about.html">Terms</a></li>
|
||||
<li><a href="about.html">Privacy Policy</a></li>
|
||||
<li><a href="about.html">Legal notice</a></li>
|
||||
<li><a href="about.html">Accessibility</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- footer area end -->
|
||||
|
||||
</div>
|
||||
<!--End pagewrapper-->
|
||||
|
||||
|
||||
<!-- Jquery -->
|
||||
<script src="assets/js/jquery-3.6.0.min.js"></script>
|
||||
<!-- Bootstrap -->
|
||||
<script src="assets/js/bootstrap.min.js"></script>
|
||||
<!-- Appear Js -->
|
||||
<script src="assets/js/appear.min.js"></script>
|
||||
<!-- Slick -->
|
||||
<script src="assets/js/slick.min.js"></script>
|
||||
<!-- Magnific Popup -->
|
||||
<script src="assets/js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- Nice Select -->
|
||||
<script src="assets/js/jquery.nice-select.min.js"></script>
|
||||
<!-- Image Loader -->
|
||||
<script src="assets/js/imagesloaded.pkgd.min.js"></script>
|
||||
<!-- Skillbar -->
|
||||
<script src="assets/js/skill.bars.jquery.min.js"></script>
|
||||
<!-- Isotope -->
|
||||
<script src="assets/js/isotope.pkgd.min.js"></script>
|
||||
<!-- AOS Animation -->
|
||||
<script src="assets/js/aos.js"></script>
|
||||
<!-- Custom script -->
|
||||
<script src="assets/js/script.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* UNIFIED HEADER TEMPLATE
|
||||
*
|
||||
* Replaces header01.php and header02.php with a single configurable template.
|
||||
*
|
||||
* Usage:
|
||||
* $headerStyle = 'dark'; // or 'light'
|
||||
* require_once("header.php");
|
||||
*
|
||||
* Styles:
|
||||
* 'dark' = White text on dark background (header01 style)
|
||||
* 'light' = Dark text on light background (header02 style)
|
||||
*/
|
||||
|
||||
// Start output buffering BEFORE any code that might output
|
||||
ob_start();
|
||||
require_once("env.php");
|
||||
require_once("session.php");
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
|
||||
// Set default style if not provided
|
||||
$headerStyle = $headerStyle ?? 'light';
|
||||
|
||||
// Use absolute paths based on this file's location
|
||||
$rootDir = dirname(__FILE__);
|
||||
require_once($rootDir . "/src/config/env.php");
|
||||
require_once($rootDir . "/src/config/session.php");
|
||||
require_once($rootDir . "/src/config/connection.php");
|
||||
require_once($rootDir . "/src/config/functions.php");
|
||||
|
||||
$is_logged_in = isset($_SESSION['user_id']);
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$is_member = getUserMemberStatus($_SESSION['user_id']);
|
||||
@@ -15,6 +37,25 @@ if (isset($_SESSION['user_id'])) {
|
||||
$role = getUserRole();
|
||||
logVisitor();
|
||||
|
||||
// Determine styling based on headerStyle parameter
|
||||
$headerClasses = 'main-header header-one';
|
||||
$headerBgClass = '';
|
||||
$logoImg = 'assets/images/logos/logo.png';
|
||||
$mobileLogoImg = 'assets/images/logos/logo.png';
|
||||
$textColor = '#fff'; // Default for dark style
|
||||
$btnTextColor = '#fff';
|
||||
|
||||
if ($headerStyle === 'light') {
|
||||
$headerBgClass = 'bg-white';
|
||||
$logoImg = 'assets/images/logos/logo-two.png';
|
||||
$mobileLogoImg = 'assets/images/logos/logo-two.png';
|
||||
$textColor = '#111111';
|
||||
$btnTextColor = '#111111';
|
||||
} else {
|
||||
// Dark style
|
||||
$headerClasses .= ' white-menu menu-absolute';
|
||||
$headerBgClass = '';
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
@@ -35,7 +76,9 @@ logVisitor();
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<?php if ($headerStyle === 'light'): ?>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<?php endif; ?>
|
||||
<!-- Flaticon -->
|
||||
<link rel="stylesheet" href="assets/css/flaticon.min.css">
|
||||
<!-- Font Awesome -->
|
||||
@@ -46,14 +89,22 @@ logVisitor();
|
||||
<link rel="stylesheet" href="assets/css/magnific-popup.min.css">
|
||||
<!-- Nice Select -->
|
||||
<link rel="stylesheet" href="assets/css/nice-select.min.css">
|
||||
<?php if ($headerStyle === 'light'): ?>
|
||||
<!-- jQuery UI -->
|
||||
<link rel="stylesheet" href="assets/css/jquery-ui.min.css">
|
||||
<?php endif; ?>
|
||||
<!-- Animate -->
|
||||
<link rel="stylesheet" href="assets/css/aos.css">
|
||||
<?php if ($headerStyle === 'light'): ?>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.css" onload="AOS.init();">
|
||||
<?php endif; ?>
|
||||
<!-- Slick -->
|
||||
<link rel="stylesheet" href="assets/css/slick.min.css">
|
||||
<!-- Main Style -->
|
||||
<link rel="stylesheet" href="assets/css/style_new.css?v=1">
|
||||
|
||||
<link rel="stylesheet" href="assets/css/style_new.css<?php echo ($headerStyle === 'dark') ? '?v=1' : ''; ?>">
|
||||
<?php if ($headerStyle === 'dark'): ?>
|
||||
<link rel="stylesheet" href="header_css.css">
|
||||
<?php endif; ?>
|
||||
|
||||
<script id="mcjs">
|
||||
! function(c, h, i, m, p) {
|
||||
@@ -62,6 +113,7 @@ logVisitor();
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<style>
|
||||
.mobile-only {
|
||||
display: none;
|
||||
@@ -107,7 +159,7 @@ logVisitor();
|
||||
top: 100%;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: <?php echo ($headerStyle === 'light') ? '2px 2px 5px 1px rgba(0, 0, 0, 0.1), -2px 0px 5px 1px rgba(0, 0, 0, 0.1)' : '0px 8px 16px rgba(0, 0, 0, 0.1)'; ?>;
|
||||
/* border-radius: 5px; */
|
||||
min-width: 250px;
|
||||
z-index: 1000;
|
||||
@@ -133,6 +185,36 @@ logVisitor();
|
||||
.dropdown-menu22 ul li:hover {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
<?php if ($headerStyle === 'light'): ?>
|
||||
.page-banner-area {
|
||||
position: relative;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.banner-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('assets/images/banner/tracks7.png');
|
||||
/* Replace with your PNG */
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Make sure your content is above the overlays */
|
||||
.banner-inner {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
<?php endif; ?>
|
||||
</style>
|
||||
|
||||
<body>
|
||||
@@ -144,15 +226,14 @@ logVisitor();
|
||||
</div>
|
||||
|
||||
<!-- main header -->
|
||||
<header class="main-header header-one white-menu menu-absolute">
|
||||
<header class="<?php echo $headerClasses; ?>">
|
||||
<!--Header-Upper-->
|
||||
<div class="header-upper py-30 rpy-0">
|
||||
<div class="header-upper <?php echo $headerBgClass; ?> py-30 rpy-0">
|
||||
<div class="container-fluid clearfix">
|
||||
|
||||
<div class="header-inner rel d-flex align-items-center">
|
||||
<div class="logo-outer">
|
||||
<div class="logo"><a href="index.php"><img src="assets/images/logos/logo.png"
|
||||
style="width:200px;" alt="Logo" title="Logo"></a></div>
|
||||
<div class="logo" style="width:200px;"><a href="index"><img src="<?php echo $logoImg; ?>" alt="Logo" title="Logo"></a></div>
|
||||
</div>
|
||||
|
||||
<div class="nav-outer mx-lg-auto ps-xxl-5 clearfix">
|
||||
@@ -160,14 +241,13 @@ logVisitor();
|
||||
<nav class="main-menu navbar-expand-lg">
|
||||
<div class="navbar-header">
|
||||
<div class="mobile-logo">
|
||||
<a href="index.php">
|
||||
<img src="assets/images/logos/logo.png" alt="Logo" title="Logo">
|
||||
<a href="index">
|
||||
<img src="<?php echo $mobileLogoImg; ?>" alt="Logo" title="Logo">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Toggle Button -->
|
||||
<button type="button" class="navbar-toggle" data-bs-toggle="collapse"
|
||||
data-bs-target=".navbar-collapse">
|
||||
<button type="button" class="navbar-toggle" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -176,73 +256,66 @@ logVisitor();
|
||||
|
||||
<div class="navbar-collapse collapse clearfix">
|
||||
<ul class="navigation clearfix">
|
||||
<li><a href="index.php">Home</a></li>
|
||||
<li><a href="about.php">About</a></li>
|
||||
<!-- <li class="dropdown"><a href="about.html">BASE 4</a>
|
||||
<ul>
|
||||
<li><a href="tour-list.html">About BASE 4</a></li>
|
||||
<li><a href="campsite_booking.php">Book a Campsite</a></li>
|
||||
</ul>
|
||||
</li> -->
|
||||
<li><a href="trips.php">Trips</a>
|
||||
<li><a href="index">Home</a></li>
|
||||
<li><a href="about">About</a></li>
|
||||
<li><a href="trips">Trips</a>
|
||||
<?php if ($headerStyle === 'dark'): ?>
|
||||
<ul>
|
||||
<li><a href="tour-list.html">Tour List</a></li>
|
||||
<li><a href="tour-grid.html">Tour Grid</a></li>
|
||||
<li><a href="tour-sidebar.html">Tour Sidebar</a></li>
|
||||
<li><a href="trip-details.php">Tour Details</a></li>
|
||||
<li><a href="trip-details">Tour Details</a></li>
|
||||
<li><a href="tour-guide.html">Tour Guide</a></li>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#">Training</a>
|
||||
<ul>
|
||||
<li><a href="driver_training.php">Basic 4X4 Driver Training</a></li>
|
||||
<li><a href="bush_mechanics.php">Bush Mechanics</a></li>
|
||||
<li><a href="rescue_recovery.php">Rescue & Recovery</a></li>
|
||||
<li><a href="driver_training">Basic 4X4 Driver Training</a></li>
|
||||
<li><a href="bush_mechanics">Bush Mechanics</a></li>
|
||||
<li><a href="rescue_recovery">Rescue & Recovery</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="events.php">Events</a> </li>
|
||||
<li><a href="blog.php">Blog</a></li>
|
||||
<li><a href="events">Events</a></li>
|
||||
<li><a href="blog">Blog</a></li>
|
||||
<?php if ($role === 'admin' || $role === 'superadmin') { ?>
|
||||
<li class="dropdown"><a href="#">admin</a>
|
||||
<ul>
|
||||
<li><a href="admin_web_users.php">Website Users</a></li>
|
||||
<li><a href="admin_members.php">4WDCSA Members</a></li>
|
||||
<li><a href="admin_trip_bookings.php">Trip Bookings</a></li>
|
||||
<li><a href="admin_course_bookings.php">Course Bookings</a></li>
|
||||
<!-- <li><a href="admin_camp_bookings.php">Camping Bookings</a></li> -->
|
||||
<!-- <li><a href="admin_payments.php">Payfast Payments</a></li> -->
|
||||
<li><a href="admin_efts.php">EFT Payments</a></li>
|
||||
<li><a href="process_payments.php">Process Payments</a></li>
|
||||
<!-- <li><a href="bar_tabs.php">Bar</a></li> -->
|
||||
<li><a href="admin_web_users">Website Users</a></li>
|
||||
<li><a href="admin_members">4WDCSA Members</a></li>
|
||||
<li><a href="admin_trips">Manage Trips</a></li>
|
||||
<li><a href="admin_trip_bookings">Trip Bookings</a></li>
|
||||
<li><a href="admin_course_bookings">Course Bookings</a></li>
|
||||
<li><a href="admin_efts">EFT Payments</a></li>
|
||||
<li><a href="process_payments">Process Payments</a></li>
|
||||
<?php if ($role === 'superadmin') { ?>
|
||||
<li><a href="admin_visitors.php">Visitor Log</a></li>
|
||||
<li><a href="admin_visitors">Visitor Log</a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<li><a href="contact.php">Contact</a></li>
|
||||
<li><a href="contact">Contact</a></li>
|
||||
<?php if ($is_member) : ?>
|
||||
<li class="dropdown"><a href="#">Members Area</a>
|
||||
<ul>
|
||||
<li><a href="#">Coming Soon!</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($is_logged_in) : ?>
|
||||
<li class="dropdown"><a href="#">My Account</a>
|
||||
<ul>
|
||||
<li><a href="account_settings.php">Account Settings</a></li>
|
||||
<li><a href="membership_details.php">Membership</a></li>
|
||||
<li><a href="bookings.php">My Bookings</a></li>
|
||||
<li><a href="submit_pop.php">Submit P.O.P</a></li>
|
||||
<li><a href="logout.php">Log Out</a></li>
|
||||
<li><a href="account_settings">Account Settings</a></li>
|
||||
<li><a href="membership_details">Membership</a></li>
|
||||
<li><a href="bookings">My Bookings</a></li>
|
||||
<li><a href="submit_pop">Submit P.O.P</a></li>
|
||||
<li><a href="logout">Log Out</a></li>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
<?php else : ?>
|
||||
<li class="nav-item d-xl-none"><a href="login.php">Log In</a></li>
|
||||
<li class="nav-item d-xl-none"><a href="login">Log In</a></li>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -255,29 +328,18 @@ logVisitor();
|
||||
<?php if ($is_logged_in) : ?>
|
||||
<div class="profile-menu">
|
||||
<div class="profile-info">
|
||||
<span style="color: #fff;">Welcome, <?php echo $_SESSION['first_name']; ?></span>
|
||||
<a href="account_settings.php">
|
||||
<span style="color: <?php echo $textColor; ?>;">Welcome, <?php echo $_SESSION['first_name']; ?></span>
|
||||
<a href="account_settings">
|
||||
<img src="<?php echo $_SESSION['profile_pic']; ?>?v=<?php echo time(); ?>" alt="Profile Picture" class="profile-pic">
|
||||
</a>
|
||||
<!-- <i style="color: #fff;" class="fal fa-chevron-down dropdown-arrow"></i> -->
|
||||
</div>
|
||||
<!-- Dropdown Menu -->
|
||||
<!-- <div class="dropdown-menu2">
|
||||
<ul>
|
||||
<li><a href="account_settings.php">Account Settings</a></li>
|
||||
<li><a href="membership_details.php">Membership</a></li>
|
||||
<li><a href="bookings.php">My Bookings</a></li>
|
||||
<li><a href="logout.php">Log Out</a></li>
|
||||
</ul>
|
||||
</div> -->
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<a href="login.php" class="theme-btn style-two bgc-secondary">
|
||||
<a href="login" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Log In">Log In</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<!-- menu sidebar -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -288,18 +350,21 @@ logVisitor();
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Toggle dropdown menu visibility when the profile-info is clicked
|
||||
document.querySelector('.profile-info').addEventListener('click', function(event) {
|
||||
const profileInfo = document.querySelector('.profile-info');
|
||||
if (profileInfo) {
|
||||
profileInfo.addEventListener('click', function(event) {
|
||||
const dropdownMenu = document.querySelector('.dropdown-menu2');
|
||||
if (dropdownMenu) {
|
||||
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
|
||||
event.stopPropagation(); // Prevent this click from closing the menu
|
||||
event.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Close the dropdown menu if the user clicks outside of it
|
||||
document.addEventListener('click', function(event) {
|
||||
const dropdownMenu = document.querySelector('.dropdown-menu2');
|
||||
const profileMenu = document.querySelector('.profile-menu');
|
||||
if (!profileMenu.contains(event.target)) {
|
||||
if (profileMenu && dropdownMenu && !profileMenu.contains(event.target)) {
|
||||
dropdownMenu.style.display = 'none';
|
||||
}
|
||||
});
|
||||
312
header02.php
@@ -1,312 +0,0 @@
|
||||
<?php
|
||||
ob_start();
|
||||
require_once("env.php");
|
||||
require_once("session.php");
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
$is_logged_in = isset($_SESSION['user_id']);
|
||||
$role = getUserRole();
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$is_member = getUserMemberStatus($_SESSION['user_id']);
|
||||
$pending_member = getUserMemberStatusPending($_SESSION['user_id']);
|
||||
$user_id = $_SESSION['user_id'];
|
||||
}
|
||||
logVisitor();
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<!-- Title -->
|
||||
<title>4WDCSA - The Four Wheel Drive Club of Southern Africa</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" href="assets/images/logos/favicon.ico" type="image/x-icon">
|
||||
<!-- Google Fonts -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<!-- Flaticon -->
|
||||
<link rel="stylesheet" href="assets/css/flaticon.min.css">
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="assets/css/fontawesome-5.14.0.min.css">
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
|
||||
<!-- Magnific Popup -->
|
||||
<link rel="stylesheet" href="assets/css/magnific-popup.min.css">
|
||||
<!-- Nice Select -->
|
||||
<link rel="stylesheet" href="assets/css/nice-select.min.css">
|
||||
<!-- jQuery UI -->
|
||||
<link rel="stylesheet" href="assets/css/jquery-ui.min.css">
|
||||
<!-- Animate -->
|
||||
<link rel="stylesheet" href="assets/css/aos.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.css" onload="AOS.init();">
|
||||
<!-- Slick -->
|
||||
<link rel="stylesheet" href="assets/css/slick.min.css">
|
||||
<!-- Main Style -->
|
||||
<link rel="stylesheet" href="assets/css/style_new.css">
|
||||
|
||||
<script id="mcjs">
|
||||
! function(c, h, i, m, p) {
|
||||
m = c.createElement(h), p = c.getElementsByTagName(h)[0], m.async = 1, m.src = i, p.parentNode.insertBefore(m, p)
|
||||
}(document, "script", "https://chimpstatic.com/mcjs-connected/js/users/3c26590bcc200ef52edc0bec2/b960bfcd9c876f911833ca3f0.js");
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<style>
|
||||
.profile-menu {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.profile-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.profile-info span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.profile-pic {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
object-fit: cover;
|
||||
/* Ensures the image fits without distortion */
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.dropdown-menu2 {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 5px 1px rgba(0, 0, 0, 0.1), -2px 0px 5px 1px rgba(0, 0, 0, 0.1);
|
||||
/* border-radius: 5px; */
|
||||
min-width: 250px;
|
||||
z-index: 1000;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.dropdown-menu2 ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu2 ul li {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.dropdown-menu22 ul li a {
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.dropdown-menu22 ul li:hover {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.page-banner-area {
|
||||
position: relative;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.banner-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('assets/images/banner/tracks7.png');
|
||||
/* Replace with your PNG */
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
/* Make sure your content is above the overlays */
|
||||
.banner-inner {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div class="page-wrapper">
|
||||
|
||||
<!-- Preloader -->
|
||||
<div class="preloader">
|
||||
<div class="custom-loader"></div>
|
||||
</div>
|
||||
|
||||
<!-- main header -->
|
||||
<header class="main-header header-one">
|
||||
<!--Header-Upper-->
|
||||
<div class="header-upper bg-white py-30 rpy-0">
|
||||
<div class="container-fluid clearfix">
|
||||
|
||||
<div class="header-inner rel d-flex align-items-center">
|
||||
<div class="logo-outer">
|
||||
<div style="width:200px;" class="logo"><a href="index.php"><img src="assets/images/logos/logo-two.png" alt="Logo" title="Logo"></a></div>
|
||||
</div>
|
||||
|
||||
<div class="nav-outer mx-lg-auto ps-xxl-5 clearfix">
|
||||
<!-- Main Menu -->
|
||||
<nav class="main-menu navbar-expand-lg">
|
||||
<div class="navbar-header">
|
||||
<div class="mobile-logo">
|
||||
<a href="index.php">
|
||||
<img src="assets/images/logos/logo-two.png" alt="Logo" title="Logo">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Toggle Button -->
|
||||
<button type="button" class="navbar-toggle" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="navbar-collapse collapse clearfix">
|
||||
<ul class="navigation clearfix">
|
||||
<li><a href="index.php">Home</a></li>
|
||||
<li><a href="about.php">About</a></li>
|
||||
<!-- <li class="dropdown"><a href="about.html">BASE 4</a>
|
||||
<ul>
|
||||
<li><a href="tour-list.html">About BASE 4</a></li>
|
||||
<li><a href="campsite_booking.php">Book a Campsite</a></li>
|
||||
</ul>
|
||||
</li> -->
|
||||
<li><a href="trips.php">Trips</a>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#">Training</a>
|
||||
<ul>
|
||||
<li><a href="driver_training.php">Basic 4X4 Driver Training</a></li>
|
||||
<li><a href="bush_mechanics.php">Bush Mechanics</a></li>
|
||||
<li><a href="rescue_recovery.php">Rescue & Recovery</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="events.php">Events</a>
|
||||
</li>
|
||||
<li><a href="blog.php">Blog</a></li>
|
||||
<?php if ($role === 'admin' || $role === 'superadmin') { ?>
|
||||
<li class="dropdown"><a href="#">admin</a>
|
||||
<ul>
|
||||
<li><a href="admin_web_users.php">Website Users</a></li>
|
||||
<li><a href="admin_members.php">4WDCSA Members</a></li>
|
||||
<li><a href="admin_trip_bookings.php">Trip Bookings</a></li>
|
||||
<li><a href="admin_course_bookings.php">Course Bookings</a></li>
|
||||
<!-- <li><a href="admin_camp_bookings.php">Camping Bookings</a></li> -->
|
||||
<!-- <li><a href="admin_payments.php">Payfast Payments</a></li> -->
|
||||
<li><a href="admin_efts.php">EFT Payments</a></li>
|
||||
<li><a href="process_payments.php">Process Payments</a></li>
|
||||
<?php if ($role === 'superadmin') { ?>
|
||||
<li><a href="admin_visitors.php">Visitor Log</a></li>
|
||||
<?php } ?>
|
||||
<!-- <li><a href="bar_tabs.php">Bar</a></li> -->
|
||||
</ul>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<li><a href="contact.php">Contact</a></li>
|
||||
<?php if ($is_logged_in) : ?>
|
||||
<li class="dropdown"><a href="#">My Account</a>
|
||||
<ul>
|
||||
<li><a href="account_settings.php">Account Settings</a></li>
|
||||
<li><a href="membership_details.php">Membership</a></li>
|
||||
<li><a href="bookings.php">My Bookings</a></li>
|
||||
<li><a href="submit_pop.php">Submit P.O.P</a></li>
|
||||
<li><a href="logout.php">Log Out</a></li>
|
||||
</ul>
|
||||
|
||||
<?php else : ?>
|
||||
<li class="nav-item d-xl-none"><a href="login.php">Log In</a></li>
|
||||
<?php endif; ?>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
<!-- Main Menu End-->
|
||||
</div>
|
||||
|
||||
<!-- Menu Button -->
|
||||
<div class="menu-btns py-10">
|
||||
<?php if ($is_logged_in) : ?>
|
||||
<div class="profile-menu">
|
||||
<div class="profile-info">
|
||||
<span style="color: #111111;">Welcome, <?php echo $_SESSION['first_name']; ?></span>
|
||||
<a href="account_settings.php">
|
||||
<img src="<?php echo $_SESSION['profile_pic']; ?>?v=<?php echo time(); ?>" alt="Profile Picture" class="profile-pic">
|
||||
</a>
|
||||
|
||||
<!-- <i style="color: #111111;" class="fal fa-chevron-down dropdown-arrow"></i> -->
|
||||
</div>
|
||||
<!-- Dropdown Menu -->
|
||||
<!-- <div class="dropdown-menu2">
|
||||
<ul>
|
||||
<li><a href="account_settings.php">Account Settings</a></li>
|
||||
<li><a href="membership_details.php">Membership</a></li>
|
||||
<li><a href="bookings.php">Bookings</a></li>
|
||||
<li><a href="logout.php">Log Out</a></li>
|
||||
</ul>
|
||||
</div> -->
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<a href="login.php" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Log In">Log In</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<!-- menu sidebar -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--End Header Upper-->
|
||||
</header>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Toggle dropdown menu visibility when the profile-info is clicked
|
||||
document.querySelector('.profile-info').addEventListener('click', function(event) {
|
||||
const dropdownMenu = document.querySelector('.dropdown-menu2');
|
||||
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
|
||||
event.stopPropagation(); // Prevent this click from closing the menu
|
||||
});
|
||||
|
||||
// Close the dropdown menu if the user clicks outside of it
|
||||
document.addEventListener('click', function(event) {
|
||||
const dropdownMenu = document.querySelector('.dropdown-menu2');
|
||||
const profileMenu = document.querySelector('.profile-menu');
|
||||
if (!profileMenu.contains(event.target)) {
|
||||
dropdownMenu.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
20
index.php
@@ -1,7 +1,10 @@
|
||||
<?php include_once('header01.php');
|
||||
<?php
|
||||
$rootPath = dirname(__FILE__);
|
||||
$headerStyle = 'dark';
|
||||
include_once($rootPath . '/header.php');
|
||||
$indemnityPending = false;
|
||||
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
if (isset($_SESSION['user_id']) && isset($conn) && $conn !== null) {
|
||||
$userId = $_SESSION['user_id'];
|
||||
$stmt = $conn->prepare("SELECT user_id FROM membership_application WHERE user_id = ? AND accept_indemnity = 0 LIMIT 1");
|
||||
$stmt->bind_param("i", $userId);
|
||||
@@ -81,12 +84,16 @@ if (countUpcomingTrips() > 0) { ?>
|
||||
<div class="row justify-content-center">
|
||||
<?php
|
||||
// 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
|
||||
if (isset($conn) && $conn !== null) {
|
||||
$stmt = $conn->prepare("SELECT trip_id, trip_name, location, short_description, start_date, end_date, vehicle_capacity, cost_members, places_booked
|
||||
FROM trips
|
||||
WHERE published = 1
|
||||
WHERE published = ?
|
||||
ORDER BY trip_id DESC
|
||||
LIMIT 4";
|
||||
$result = $conn->query($sql);
|
||||
LIMIT 4");
|
||||
$published = 1;
|
||||
$stmt->bind_param("i", $published);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
// Loop through each row
|
||||
@@ -126,6 +133,7 @@ if (countUpcomingTrips() > 0) { ?>
|
||||
} else {
|
||||
echo "No trips available.";
|
||||
}
|
||||
} // end if (isset($conn) && $conn !== null)
|
||||
?>
|
||||
|
||||
</div>
|
||||
|
||||
802
index2.php
@@ -1,802 +0,0 @@
|
||||
<?php include_once('header01.php');
|
||||
$indemnityPending = false;
|
||||
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$userId = $_SESSION['user_id'];
|
||||
$stmt = $conn->prepare("SELECT user_id FROM membership_application WHERE user_id = ? AND accept_indemnity = 0 LIMIT 1");
|
||||
$stmt->bind_param("i", $userId);
|
||||
$stmt->execute();
|
||||
$stmt->store_result();
|
||||
|
||||
if ($stmt->num_rows > 0) {
|
||||
$indemnityPending = true;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
?>
|
||||
<style>
|
||||
.countdown-container {
|
||||
width: 100%;
|
||||
/* background: #111; */
|
||||
text-align: center;
|
||||
padding: 40px 10px;
|
||||
/* font-family: Arial, sans-serif; */
|
||||
}
|
||||
|
||||
.countdown-container h1 {
|
||||
font-size: 3rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.countdown-container h1 {
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||
if (!empty($bannerImages)) {
|
||||
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||
}
|
||||
?>
|
||||
<section class="hero-area bgc-black pt-200 rpt-120 rel z-2">
|
||||
<div style="padding-bottom:30px;" class="container-fluid">
|
||||
<div style="text-align: center; position: relative; border-radius: 20px; overflow: hidden; background: linear-gradient(rgba(28, 35, 31, 1), rgba(28, 35, 31, 0.5)), url('<?php echo $randomBanner; ?>'); background-size: cover; background-position: center;">
|
||||
<div style="padding-top: 50px; padding-bottom: 50px;">
|
||||
<img style="width: 250px; margin-bottom: 20px;" src="assets/images/logos/weblogo2.png" alt="Logo">
|
||||
<h1 class="hero-title" data-aos="flip-up" data-aos-delay="50" data-aos-duration="1500" data-aos-offset="50">
|
||||
Welcome to<br>the Four Wheel Drive Club<br>of Southern Africa
|
||||
</h1>
|
||||
<a href="membership.php" class="theme-btn style-two bgc-secondary" style="margin-top: 20px; background-color: #e90000; padding: 10px 20px; color: white; text-decoration: none; border-radius: 25px;">
|
||||
<span data-hover="Become a Member">Become a Member</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Hero Area End -->
|
||||
<!-- Destinations Area start -->
|
||||
<?php
|
||||
if (countUpcomingTrips() > 0) { ?>
|
||||
<section class="destinations-area bgc-black pt-100 pb-70 rel z-1">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="section-title text-white text-center counter-text-wrap mb-70" data-aos="fade-up"
|
||||
data-aos-duration="1500" data-aos-offset="50">
|
||||
<h2>Discover Africa's Treasures with 4WDCSA</h2>
|
||||
<p>Join us on the following trips:</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<?php
|
||||
// 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 ORDER BY trip_id DESC LIMIT 4";
|
||||
$result = $conn->query($sql);
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
// Loop through each row
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$trip_id = $row['trip_id'];
|
||||
$trip_name = $row['trip_name'];
|
||||
$location = $row['location'];
|
||||
$short_description = $row['short_description'];
|
||||
$start_date = $row['start_date'];
|
||||
$end_date = $row['end_date'];
|
||||
$capacity = $row['vehicle_capacity'];
|
||||
$cost_members = $row['cost_members'];
|
||||
$places_booked = $row['places_booked'];
|
||||
$remaining_places = $capacity - $places_booked;
|
||||
|
||||
// Determine the badge text based on the status
|
||||
$badge_text = ($remaining_places > 0) ? $remaining_places . ' PLACES LEFT!!' : 'FULLY BOOKED';
|
||||
echo '
|
||||
<div class="col-xxl-3 col-xl-4 col-md-6">
|
||||
<div class="destination-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<img src="assets/images/trips/' . $trip_id . '_01.jpg" alt="' . $trip_name . '">
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="location"><i class="fal fa-map-marker-alt"></i> ' . $location . '</span>
|
||||
<h5><a href="trip-details.php?trip_id=' . $trip_id . '">' . $trip_name . '</a></h5>
|
||||
<span class="time">' . convertDate($start_date) . ' - ' . convertDate($end_date) . '</span><br>
|
||||
<span class="time">' . calculateDaysAndNights($start_date, $end_date) . '</span>
|
||||
</div>
|
||||
<div class="destination-footer">
|
||||
<span class="price"><span>R ' . $cost_members . '</span>/per member</span>
|
||||
<a href="trip-details.php?trip_id=' . $trip_id . '" class="read-more">Book Now <i class="fal fa-angle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
} else {
|
||||
echo "No trips available.";
|
||||
}
|
||||
?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Destinations Area end -->
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<!-- About Us Area start -->
|
||||
<section class="about-us-area py-100 rpb-90 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-xl-5 col-lg-6">
|
||||
<div class="about-us-content rmb-55" data-aos="fade-left" data-aos-duration="1500"
|
||||
data-aos-offset="50">
|
||||
<div class="section-title mb-25">
|
||||
<h2>Become a member of 4WDCSA</h2>
|
||||
<p>Sign up for an annual membership and receive:</p>
|
||||
<ul class="list-style-two mt-35 mb-30">
|
||||
<li>Year round access to BASE4</li>
|
||||
<li>FREE Camping at BASE4</li>
|
||||
<li>Up to 95% Discount on Training Courses</li>
|
||||
<li>Exclusive Member discounts for all trips and events</li>
|
||||
<li>... and many more!</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>We go above and beyond to make your travel dreams reality hidden gems and must-see
|
||||
attractions</p>
|
||||
|
||||
<a href="membership.php" class="theme-btn mt-10 style-two">
|
||||
<span data-hover="Become A Member">Become A Member</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-7 col-lg-6" data-aos="fade-right" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="about-us-image">
|
||||
<!-- <div class="shape"><img src="assets/images/about/shape1.png" alt="Shape"></div>
|
||||
<div class="shape"><img src="assets/images/about/shape2.png" alt="Shape"></div>
|
||||
<div class="shape"><img src="assets/images/about/shape3.png" alt="Shape"></div>
|
||||
<div class="shape"><img src="assets/images/about/shape4.png" alt="Shape"></div>
|
||||
<div class="shape"><img src="assets/images/about/shape5.png" alt="Shape"></div>
|
||||
<div class="shape"><img src="assets/images/about/shape6.png" alt="Shape"></div>
|
||||
<div class="shape"><img src="assets/images/about/shape7.png" alt="Shape"></div> -->
|
||||
<img src="assets/images/logos/weblogo.png" alt="About">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- About Us Area end -->
|
||||
|
||||
<section class="hotel-area bgc-black py-100 rel z-1">
|
||||
<div class="countdown-container">
|
||||
<h1 style="color: #e5f5e0;" id="countdown">Loading countdown...</h1>
|
||||
<a href="events.php" class="theme-btn style-two bgc-secondary" style="margin-top: 20px; background-color: #e90000; padding: 10px 20px; color: white; text-decoration: none; border-radius: 25px;">
|
||||
<span data-hover="Events">Find out more!</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Popular Destinations Area start -->
|
||||
<!-- <section class="popular-destinations-area rel z-1">
|
||||
<div class="container-fluid">
|
||||
<div class="popular-destinations-wrap br-20 bgc-lighter pt-100 pb-70">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="section-title text-center counter-text-wrap mb-70" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<h2>Explore Popular Destinations</h2>
|
||||
<p>One site <span class="count-text plus" data-speed="3000" data-stop="34500">0</span> most popular experience</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="destination-item style-two" data-aos="flip-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<a href="#" class="heart"><i class="fas fa-heart"></i></a>
|
||||
<img src="assets/images/destinations/destination1.jpg" alt="Destination">
|
||||
</div>
|
||||
<div class="content">
|
||||
<h6><a href="destination-details.html">Thailand beach</a></h6>
|
||||
<span class="time">5352+ tours & 856+ Activity</span>
|
||||
<a href="#" class="more"><i class="fas fa-chevron-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="destination-item style-two" data-aos="flip-up" data-aos-delay="100" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<a href="#" class="heart"><i class="fas fa-heart"></i></a>
|
||||
<img src="assets/images/destinations/destination2.jpg" alt="Destination">
|
||||
</div>
|
||||
<div class="content">
|
||||
<h6><a href="destination-details.html">Parga, Greece</a></h6>
|
||||
<span class="time">5352+ tours & 856+ Activity</span>
|
||||
<a href="#" class="more"><i class="fas fa-chevron-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="destination-item style-two" data-aos="flip-up" data-aos-delay="200" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<a href="#" class="heart"><i class="fas fa-heart"></i></a>
|
||||
<img src="assets/images/destinations/destination3.jpg" alt="Destination">
|
||||
</div>
|
||||
<div class="content">
|
||||
<h6><a href="destination-details.html">Castellammare del Golfo, Italy</a></h6>
|
||||
<span class="time">5352+ tours & 856+ Activity</span>
|
||||
<a href="#" class="more"><i class="fas fa-chevron-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="destination-item style-two" data-aos="flip-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<a href="#" class="heart"><i class="fas fa-heart"></i></a>
|
||||
<img src="assets/images/destinations/destination4.jpg" alt="Destination">
|
||||
</div>
|
||||
<div class="content">
|
||||
<h6><a href="destination-details.html">Reserve of Canada, Canada</a></h6>
|
||||
<span class="time">5352+ tours & 856+ Activity</span>
|
||||
<a href="#" class="more"><i class="fas fa-chevron-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="destination-item style-two" data-aos="flip-up" data-aos-delay="100" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<a href="#" class="heart"><i class="fas fa-heart"></i></a>
|
||||
<img src="assets/images/destinations/destination5.jpg" alt="Destination">
|
||||
</div>
|
||||
<div class="content">
|
||||
<h6><a href="destination-details.html">Dubai united states</a></h6>
|
||||
<span class="time">5352+ tours & 856+ Activity</span>
|
||||
<a href="#" class="more"><i class="fas fa-chevron-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="destination-item style-two" data-aos="flip-up" data-aos-delay="200" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<a href="#" class="heart"><i class="fas fa-heart"></i></a>
|
||||
<img src="assets/images/destinations/destination6.jpg" alt="Destination">
|
||||
</div>
|
||||
<div class="content">
|
||||
<h6><a href="destination-details.html">Milos, Greece</a></h6>
|
||||
<span class="time">5352+ tours & 856+ Activity</span>
|
||||
<a href="#" class="more"><i class="fas fa-chevron-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section> -->
|
||||
<!-- Popular Destinations Area end -->
|
||||
|
||||
|
||||
<!-- Features Area start -->
|
||||
<section class="features-area pt-100 pb-45 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-xl-6">
|
||||
<div class="features-content-part mb-55" data-aos="fade-left" data-aos-duration="1500"
|
||||
data-aos-offset="50">
|
||||
<div class="section-title mb-20">
|
||||
<h2><b>BASE 4:</b> The home of 4WDCSA.</h2>
|
||||
<p>Situated near the Hennops river, in Doornrandjie, Centurion.</p>
|
||||
<div class="image">
|
||||
<img style="border-radius:10px;" src="assets/images/base4/base4.jpg" alt="Hotel">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="menu-btns py-10">
|
||||
<a href="membership.php" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Become a Member">Become a Member</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
<!-- <div class="menu-btns py-10">
|
||||
<a href="campsite_booking.php" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Book a Campsite">Book a Campsite</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div> -->
|
||||
|
||||
|
||||
|
||||
<!-- <div class="features-customer-box">
|
||||
<div class="image">
|
||||
<img src="assets/images/features/features-box.jpg" alt="Features">
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="feature-authors mb-15">
|
||||
<img src="assets/images/features/feature-author1.jpg" alt="Author">
|
||||
<img src="assets/images/features/feature-author2.jpg" alt="Author">
|
||||
<img src="assets/images/features/feature-author3.jpg" alt="Author">
|
||||
<span>4k+</span>
|
||||
</div>
|
||||
<h6>850K+ Happy Customer</h6>
|
||||
<div class="divider style-two counter-text-wrap my-25"><span><span class="count-text plus" data-speed="3000" data-stop="25">0</span> Years</span></div>
|
||||
<p>We pride ourselves offering personalized itineraries</p>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6" data-aos="fade-right" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="row pb-25">
|
||||
<div class="col-md-6">
|
||||
<div class="feature-item">
|
||||
<div class="icon"><i class="flaticon-tent"></i></div>
|
||||
<div class="content">
|
||||
<h5><a href="trip-details.php">Club House</a></h5>
|
||||
<p>We are currently in the process of building a new club house since the previous club house tragically burnt down in November of 2024.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<div class="icon"><i class="flaticon-tent"></i></div>
|
||||
<div class="content">
|
||||
<h5><a href="trip-details.php">4x4 Training Track</a></h5>
|
||||
<p>Test your offroad driving skills on our training track with many obstacles
|
||||
from rocky climbs, daring axle twisters, log bridge, side slopes and more!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="feature-item mt-20">
|
||||
<div class="icon"><i class="flaticon-tent"></i></div>
|
||||
<div class="content">
|
||||
<h5><a href="trip-details.php">24/7 Camping</a></h5>
|
||||
<p>Pristene Camping grounds situated next to a stream, with ablutions, lapa and
|
||||
communal fire pits.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<div class="icon"><i class="flaticon-tent"></i></div>
|
||||
<div class="content">
|
||||
<h5><a href="trip-details.php">Swimming pool & Braai areas</a></h5>
|
||||
<p>Unwind with a refreshing dip in our crystal-clear swimming pool or gather around the braai area for good food and great company</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Features Area end -->
|
||||
|
||||
|
||||
<!-- Hotel Area start -->
|
||||
<section class="hotel-area bgc-black py-100 rel z-1">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="section-title text-white text-center counter-text-wrap mb-70" data-aos="fade-up"
|
||||
data-aos-duration="1500" data-aos-offset="50">
|
||||
<h2>Driver Training Courses</h2>
|
||||
<p>Discover the in's and out's of your Four Wheel Drive with one of our dedicated training
|
||||
courses:</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-xxl-6 col-xl-8 col-lg-10">
|
||||
<div class="destination-item style-three" data-aos="fade-up" data-aos-duration="1500"
|
||||
data-aos-offset="50">
|
||||
<div class="image">
|
||||
<!-- <div class="ratting"><i class="fas fa-star"></i> 4.8</div> -->
|
||||
<!-- <a href="#" class="heart"><i class="fas fa-heart"></i></a> -->
|
||||
<img src="assets/images/courses/driver_training.png" alt="Hotel">
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="location"><i class="fal fa-map-marker-alt"></i> BASE4, Hennops</span>
|
||||
<h5><a href="driver_training.php">Basic 4X4 Driver Training</a></h5>
|
||||
<ul class="list-style-three">
|
||||
<li>Master Off-Road Confidence</li>
|
||||
<li>Hands-On Training</li>
|
||||
<li>Safety First</li>
|
||||
<!-- <li><i class="fal fa-router"></i> Internet</li> -->
|
||||
</ul>
|
||||
<div class="destination-footer">
|
||||
<span class="price"><span>R <?= getPrice('driver_training', 'member'); ?></span>/for members</span>
|
||||
<span class="price"><span>R <?= getPrice('driver_training', 'nonmember'); ?></span>/for non-members</span>
|
||||
<a href="driver_training.php" class="read-more">Book Now <i class="fal fa-angle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xxl-6 col-xl-8 col-lg-10">
|
||||
<div class="destination-item style-three" data-aos="fade-up" data-aos-delay="50"
|
||||
data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="image">
|
||||
<!-- <div class="ratting"><i class="fas fa-star"></i> 4.8</div> -->
|
||||
<!-- <a href="#" class="heart"><i class="fas fa-heart"></i></a> -->
|
||||
<img src="assets/images/courses/bush_mechanics.png" alt="Hotel">
|
||||
</div>
|
||||
<div class="content">
|
||||
<span class="location"><i class="fal fa-map-marker-alt"></i> BASE4, Hennops</span>
|
||||
<h5><a href="bush_mechanics.php">Bush Mechanics Course</a></h5>
|
||||
<ul class="list-style-three">
|
||||
<li>Fix Your Vehicle in the Wild</li>
|
||||
<li>Survival Skills for Off-Roaders</li>
|
||||
<li>Hands-On Experience</li>
|
||||
<!-- <li><i class="fal fa-router"></i> Internet</li> -->
|
||||
</ul>
|
||||
<div class="destination-footer">
|
||||
<span class="price"><span>R <?= getPrice('bush_mechanics', 'member'); ?></span>/for members</span>
|
||||
<span class="price"><span>R <?= getPrice('bush_mechanics', 'nonmember'); ?></span>/for non-members</span>
|
||||
<a href="bush_mechanics.php" class="read-more">Book Now <i class="fal fa-angle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xxl-6 col-xl-8 col-lg-10">
|
||||
<div class="destination-item style-three" data-aos="fade-up" data-aos-duration="1500"
|
||||
data-aos-offset="50">
|
||||
<div class="content">
|
||||
<span class="location"><i class="fal fa-map-marker-alt"></i> BASE4, Hennops</span>
|
||||
<h5><a href="rescue_recovery.php">Rescue & Recovery Course</a></h5>
|
||||
<ul class="list-style-three">
|
||||
<li>Master Advanced Recovery Techniques</li>
|
||||
<li>Gain Confidence in High-Stress Situations</li>
|
||||
<li>Teamwork and Communication</li>
|
||||
<!-- <li><i class="fal fa-router"></i> Internet</li> -->
|
||||
</ul>
|
||||
<div class="destination-footer">
|
||||
<span class="price"><span>R <?= getPrice('rescue_recovery', 'member'); ?></span>/for members</span>
|
||||
<span class="price"><span>R <?= getPrice('rescue_recovery', 'nonmember'); ?></span>/for non-members</span>
|
||||
<a href="rescue_recovery.php" class="read-more">Book Now <i class="fal fa-angle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="image">
|
||||
<!-- <div class="ratting"><i class="fas fa-star"></i> 4.8</div> -->
|
||||
<!-- <a href="#" class="heart"><i class="fas fa-heart"></i></a> -->
|
||||
<img src="assets/images/courses/rescue_recovery.png" alt="Hotel">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="hotel-more-btn text-center mt-40">
|
||||
<a href="destination2.html" class="theme-btn style-four">
|
||||
<span data-hover="Explore More Hotel">Explore More Hotel</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div> -->
|
||||
</div>
|
||||
</section>
|
||||
<!-- Hotel Area end -->
|
||||
|
||||
<!-- CTA Area start -->
|
||||
<!-- <section class="cta-area pt-100 rel z-1">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-xl-4 col-md-6" data-aos="zoom-in-down" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="cta-item" style="background-image: url(assets/images/cta/cta1.jpg);">
|
||||
<span class="category">Tent Camping</span>
|
||||
<h2>Explore the world best tourism</h2>
|
||||
<a href="trip-details.php" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Explore Tours">Explore Tours</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 col-md-6" data-aos="zoom-in-down" data-aos-delay="50" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="cta-item" style="background-image: url(assets/images/cta/cta2.jpg);">
|
||||
<span class="category">Sea Beach</span>
|
||||
<h2>World largest Sea Beach in Thailand</h2>
|
||||
<a href="trip-details.php" class="theme-btn style-two">
|
||||
<span data-hover="Explore Tours">Explore Tours</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 col-md-6" data-aos="zoom-in-down" data-aos-delay="100" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="cta-item" style="background-image: url(assets/images/cta/cta3.jpg);">
|
||||
<span class="category">Water Falls</span>
|
||||
<h2>Largest Water falls Bali, Indonesia</h2>
|
||||
<a href="trip-details.php" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Explore Tours">Explore Tours</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section> -->
|
||||
<!-- CTA Area end -->
|
||||
|
||||
|
||||
<!-- Blog Area start -->
|
||||
<section class="blog-area py-70 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="section-title text-center counter-text-wrap mb-70" data-aos="fade-up"
|
||||
data-aos-duration="1500" data-aos-offset="50">
|
||||
<h2>Read about our past trips and events</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<?php
|
||||
$sql = "SELECT blog_id, title, date, category, image, description, author, link, members_only FROM blogs ORDER BY date DESC LIMIT 3";
|
||||
$result = $conn->query($sql);
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
// Loop through each row
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$blog_id = $row['blog_id'];
|
||||
$blog_title = $row['title'];
|
||||
$blog_date = $row['date'];
|
||||
$blog_category = $row['category'];
|
||||
$blog_image = $row['image'];
|
||||
$blog_description = $row['description'];
|
||||
$blog_author = $row['author'];
|
||||
$members_only = $row['members_only'];
|
||||
if ($members_only) {
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
$blog_link = "login.php";
|
||||
$button_hover = "Members Only";
|
||||
$icon = "fa-lock";
|
||||
} else {
|
||||
if (getUserMemberStatus($_SESSION['user_id'])) {
|
||||
$blog_link = $row['link'];
|
||||
$button_hover = "Read More";
|
||||
$icon = "fa-arrow-right";
|
||||
} else {
|
||||
$blog_link = "membership.php";
|
||||
$button_hover = "Members Only";
|
||||
$icon = "fa-lock";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$blog_link = $row['link'];
|
||||
$button_hover = "Read More";
|
||||
$icon = "fa-arrow-right";
|
||||
}
|
||||
|
||||
|
||||
|
||||
echo '
|
||||
<div class="col-xl-4 col-md-6">
|
||||
<div class="blog-item" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="content">
|
||||
<a href="#" class="category">' . $blog_category . '</a>
|
||||
<h5><a href="' . $blog_link . '">' . $blog_title . '</a></h5>
|
||||
<ul class="blog-meta">
|
||||
<li><i class="far fa-calendar-alt"></i> <a href="#">' . $blog_date . '</a></li>
|
||||
<li><i class="far fa-user"></i>' . getFullName($blog_author) . '</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="image">
|
||||
<img style="border-radius:20px;" src="assets/images/blog/' . $blog_id . '/' . $blog_image . '" alt="Blog List">
|
||||
</div>
|
||||
<a style="width:100%;" href="' . $blog_link . '" class="theme-btn">
|
||||
<span style="width:100%;" data-hover="' . $button_hover . '">Read More</span>
|
||||
<i class="fal ' . $icon . '"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
// Close connection
|
||||
$conn->close();
|
||||
} ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Blog Area end -->
|
||||
|
||||
<section class="bgc-black py-20 rel z-1">
|
||||
|
||||
<?php include_once('ad_banner.php'); ?>
|
||||
|
||||
</section>
|
||||
<section class="py-20 rel z-1">
|
||||
|
||||
<?php include_once('logos.php'); ?>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!-- footer area start -->
|
||||
<footer class="main-footer bgs-cover overlay rel z-1 pb-25"
|
||||
style="background-image: url(assets/images/backgrounds/footer.jpg);">
|
||||
<div class="container">
|
||||
|
||||
<div class="footer-top pt-100 pb-30">
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-xl-5 col-lg-6" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="footer-widget footer-contact">
|
||||
<a href="https://chat.whatsapp.com/JD9xQuJlVX5AAJwcLrpl2B" target="_blank" style="text-decoration: none; color: inherit;">
|
||||
<div style="display: flex; align-items: center; background-color: #e5f5e0; border-radius: 10px; padding: 10px; max-width: 100%; box-shadow: 0 2px 6px rgba(0,0,0,0.1);">
|
||||
<img src="assets/images/icons/whatsapp.png" alt="WhatsApp" style="width: 64px; height: 64px; margin-right: 15px;">
|
||||
<h1 style="margin: 0; font-size: 24px;">Join our WhatsApp Group</h1>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="footer-widget footer-contact">
|
||||
<div class="footer-title">
|
||||
<h5>Get In Touch</h5>
|
||||
</div>
|
||||
<ul class="list-style-one">
|
||||
<li><i class="fal fa-map-marked-alt"></i> Plot 50 Gemstone Rd, Doornrandje, Centurion, 0157</li>
|
||||
<li><i class="fal fa-envelope"></i> <a
|
||||
href="mailto:info@4wdcsa.co.za">info@4wdcsa.co.za</a></li>
|
||||
<li><i class="fal fa-clock"></i> Mon - Fri, 09:00 - 17:00</li>
|
||||
<li><i class="fal fa-phone-volume"></i> <a href="callto:+2779 065 2795">079 065 2795</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-5 col-lg-6" data-aos="fade-up" data-aos-delay="50" data-aos-duration="1500"
|
||||
data-aos-offset="50">
|
||||
<div class="section-title counter-text-wrap mb-35">
|
||||
<h2>Subscribe to our Mailing List</h2>
|
||||
<p>Receive news and updates about upcoming trips and events.</p>
|
||||
</div>
|
||||
|
||||
<div id="mc_embed_shell">
|
||||
|
||||
<div id="mc_embed_signup">
|
||||
<form class="newsletter-form mb-50" action="https://fwdcsa.us17.list-manage.com/subscribe/post?u=3c26590bcc200ef52edc0bec2&id=3c370893eb&f_id=0099ebe3f0" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_self" novalidate="">
|
||||
<div id="mc_embed_signup_scroll" style="width:100%;">
|
||||
<div class="mc-field-group"></label><input type="email" name="EMAIL" class="required email" id="mce-EMAIL" required="" value="" placeholder="Email"></div>
|
||||
<div class="mc-field-group"><input type="text" name="FNAME" class=" text" id="mce-FNAME" value="" placeholder="First Name"></div>
|
||||
<div class="mc-field-group"><input type="text" name="LNAME" class=" text" id="mce-LNAME" value="" placeholder="Last Name"></div>
|
||||
<div class="mc-field-group"><input type="text" name="PHONE" class="REQ_CSS" id="mce-PHONE" value="" placeholder="Phone Number"></div>
|
||||
<div hidden=""><input type="hidden" name="tags" value="8324220"></div>
|
||||
<div id="mce-responses" class="clear">
|
||||
<div class="response" id="mce-error-response" style="display: none;"></div>
|
||||
<div class="response" id="mce-success-response" style="display: none;"></div>
|
||||
</div>
|
||||
<div aria-hidden="true" style="position: absolute; left: -5000px;"><input type="text" name="b_3c26590bcc200ef52edc0bec2_3c370893eb" tabindex="-1" value=""></div>
|
||||
<div class="clear"><input style="width:100%;" type="submit" name="subscribe" id="mc-embedded-subscribe" class="theme-btn bgc-secondary style-two" value="Subscribe"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!--
|
||||
<form class="newsletter-form mb-50" action="#">
|
||||
<input id="news-email" type="email" placeholder="Email Address" required>
|
||||
<button type="submit" class="theme-btn bgc-secondary style-two">
|
||||
<span data-hover="Subscribe">Subscribe</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</button>
|
||||
</form> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom pt-20 pb-5">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-5">
|
||||
<div class="copyright-text text-center text-lg-start">
|
||||
<p>Copyright © <?php echo date("Y"); ?> <a href="index.html">4WDCSA</a> | All rights reserved.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-7 text-center text-lg-end">
|
||||
<ul class="footer-bottom-nav">
|
||||
<li><a href="privacy_policy.php">Privacy Policy</a></li>
|
||||
<!-- <li><a href="about.html">Terms</a></li> -->
|
||||
<!-- <li><a href="about.html">Privacy Policy</a></li> -->
|
||||
<!-- <li><a href="about.html">Legal notice</a></li> -->
|
||||
<!-- <li><a href="about.html">Accessibility</a></li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Scroll Top Button -->
|
||||
<button class="scroll-top scroll-to-target" data-target="html"><img
|
||||
src="assets/images/icons/scroll-up.png" alt="Scroll Up"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
<!-- footer area end -->
|
||||
|
||||
</div>
|
||||
<!--End pagewrapper-->
|
||||
<?php if ($indemnityPending): ?>
|
||||
<!-- Bootstrap Modal -->
|
||||
<div class="modal fade" id="indemnityModal" tabindex="-1" aria-labelledby="indemnityModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-secondary">
|
||||
<div class="modal-header bg-secondary text-white">
|
||||
<h5 class="modal-title" id="indemnityModalLabel">Membership Application Incomplete</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
To link your existing FWDCSA membership, you need to sign and accept the indemnity aggreement before proceeding.<br>
|
||||
<a style="width:100%; border-radius:20px;" href="indemnity.php" class="btn btn-danger mt-3">Review and Accept</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Show modal when page loads
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var indemnityModal = new bootstrap.Modal(document.getElementById('indemnityModal'));
|
||||
indemnityModal.show();
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<!-- Jquery -->
|
||||
<script src="assets/js/jquery-3.6.0.min.js"></script>
|
||||
<!-- Bootstrap -->
|
||||
<script src="assets/js/bootstrap.min.js"></script>
|
||||
<!-- Appear Js -->
|
||||
<script src="assets/js/appear.min.js"></script>
|
||||
<!-- Slick -->
|
||||
<script src="assets/js/slick.min.js"></script>
|
||||
<!-- Magnific Popup -->
|
||||
<script src="assets/js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- Nice Select -->
|
||||
<script src="assets/js/jquery.nice-select.min.js"></script>
|
||||
<!-- Image Loader -->
|
||||
<script src="assets/js/imagesloaded.pkgd.min.js"></script>
|
||||
<!-- Skillbar -->
|
||||
<script src="assets/js/skill.bars.jquery.min.js"></script>
|
||||
<!-- Isotope -->
|
||||
<script src="assets/js/isotope.pkgd.min.js"></script>
|
||||
<!-- AOS Animation -->
|
||||
<script src="assets/js/aos.js"></script>
|
||||
<!-- Custom script -->
|
||||
<script src="assets/js/script.js"></script>
|
||||
<script>
|
||||
// Set your target date and time
|
||||
const targetDate = new Date("<?php echo getNextOpenDayDate(); ?>T08:00:00"); // yyyy-mm-ddThh:mm:ss
|
||||
|
||||
function updateCountdown() {
|
||||
const now = new Date();
|
||||
const diff = targetDate - now;
|
||||
|
||||
if (diff <= 0) {
|
||||
document.getElementById("countdown").innerHTML = "We're open now!";
|
||||
return;
|
||||
}
|
||||
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
||||
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24);
|
||||
const minutes = Math.floor((diff / (1000 * 60)) % 60);
|
||||
const seconds = Math.floor((diff / 1000) % 60);
|
||||
|
||||
document.getElementById("countdown").innerHTML =
|
||||
`${String(days).padStart(2, '0')} days ` +
|
||||
`${String(hours).padStart(2, '0')} hours ` +
|
||||
`${String(minutes).padStart(2, '0')} minutes ` +
|
||||
`${String(seconds).padStart(2, '0')} seconds<br>` +
|
||||
`till our next BASE4 Open Day!`;
|
||||
}
|
||||
|
||||
updateCountdown(); // initial call
|
||||
setInterval(updateCountdown, 1000);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
85
modal.html
@@ -1,85 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Modal with AJAX Dropdown</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container mt-5">
|
||||
<!-- Button to trigger modal -->
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#userModal">
|
||||
Open Modal
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="userModalLabel">Select a User</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="barTabForm">
|
||||
<div class="mb-3">
|
||||
<label for="userSelect" class="form-label">Choose a User</label>
|
||||
<select class="form-select" id="userSelect" name="user_id" required>
|
||||
<option value="">Loading...</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Create Bar Tab</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
// Load users into dropdown when modal opens
|
||||
$('#userModal').on('shown.bs.modal', function () {
|
||||
$.ajax({
|
||||
url: 'fetch_users.php',
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
let dropdown = $('#userSelect');
|
||||
dropdown.empty();
|
||||
dropdown.append('<option value="">Select a user</option>');
|
||||
data.forEach(user => {
|
||||
dropdown.append(`<option value="${user.id}">${user.first_name} ${user.last_name}</option>`);
|
||||
});
|
||||
},
|
||||
error: function () {
|
||||
alert('Error fetching users.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle form submission
|
||||
$('#barTabForm').submit(function (e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
$.ajax({
|
||||
url: 'create_bar_tab.php',
|
||||
method: 'POST',
|
||||
data: $(this).serialize(),
|
||||
success: function (response) {
|
||||
alert('Bar tab created successfully!');
|
||||
$('#userModal').modal('hide'); // Close modal
|
||||
},
|
||||
error: function () {
|
||||
alert('Error creating bar tab.');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
require 'env.php';
|
||||
require 'connection.php';
|
||||
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
if (!$conn) {
|
||||
die('Database connection failed');
|
||||
}
|
||||
|
||||
$sql = file_get_contents('migrations/001_phase1_security_schema.sql');
|
||||
|
||||
if ($conn->multi_query($sql)) {
|
||||
echo "✓ Migration executed successfully\n";
|
||||
} else {
|
||||
echo "✗ Migration error: " . $conn->error . "\n";
|
||||
}
|
||||
|
||||
$conn->close();
|
||||
?>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php include_once('connection.php');
|
||||
include_once('functions.php');
|
||||
require_once("env.php");
|
||||
<?php include_once('../config/connection.php');
|
||||
include_once('../config/functions.php');
|
||||
require_once("../config/env.php");
|
||||
session_start();
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
|
||||
@@ -92,3 +92,4 @@ $stmt->close();
|
||||
|
||||
header("Location: campsites.php");
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
?>
|
||||
@@ -221,4 +224,4 @@ if (!empty($bannerImages)) {
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
// Fetch all trips
|
||||
@@ -241,4 +244,4 @@ if (!empty($bannerImages)) {
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
?>
|
||||
@@ -221,4 +224,4 @@ if (!empty($bannerImages)) {
|
||||
<!-- Tour List Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['accept_indemnity'])) {
|
||||
@@ -11,10 +14,10 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['accept_indemnity']))
|
||||
}
|
||||
}
|
||||
|
||||
// SQL query to fetch data
|
||||
$sql = "SELECT user_id, first_name, last_name, tel_cell, email, dob, accept_indemnity FROM membership_application";
|
||||
|
||||
$result = $conn->query($sql);
|
||||
// SQL query to fetch membership applications
|
||||
$stmt = $conn->prepare("SELECT user_id, first_name, last_name, tel_cell, email, dob, accept_indemnity FROM membership_application");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
?>
|
||||
<style>
|
||||
table {
|
||||
@@ -232,4 +235,4 @@ if (!empty($bannerImages)) {
|
||||
<!-- Tour List Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
?>
|
||||
@@ -205,4 +208,4 @@ if (!empty($bannerImages)) {
|
||||
<!-- Tour List Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
// Fetch all trips
|
||||
@@ -171,7 +174,7 @@ if (!empty($bannerImages)) {
|
||||
|
||||
// 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,
|
||||
u.first_name, u.last_name,
|
||||
u.first_name, u.last_name, u.profile_pic,
|
||||
(b.total_amount - b.discount_amount) AS paid
|
||||
FROM bookings b
|
||||
INNER JOIN users u ON b.user_id = u.user_id
|
||||
@@ -234,4 +237,4 @@ if (!empty($bannerImages)) {
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
320
src/admin/admin_trips.php
Normal file
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
// Fetch all trips with booking status
|
||||
$trips_query = "
|
||||
SELECT
|
||||
trip_id, trip_name, location, start_date, end_date,
|
||||
vehicle_capacity, places_booked, cost_members, published
|
||||
FROM trips
|
||||
ORDER BY start_date DESC
|
||||
";
|
||||
|
||||
$result = $conn->query($trips_query);
|
||||
$trips = [];
|
||||
if ($result && $result->num_rows > 0) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$trips[] = $row;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<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
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$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 -->
|
||||
<section class="tour-list-page py-100 rel z-1">
|
||||
<div class="container">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<a href="manage_trips" class="theme-btn">
|
||||
<i class="far fa-plus"></i> Create New Trip
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if (count($trips) > 0) {
|
||||
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>
|
||||
<th>Trip Name</th>
|
||||
<th>Location</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Capacity</th>
|
||||
<th>Booked</th>
|
||||
<th>Cost (Member)</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
foreach ($trips as $trip) {
|
||||
$publishButtonText = $trip['published'] == 1 ? 'Unpublish' : 'Publish';
|
||||
$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>
|
||||
<a href="manage_trips?trip_id=' . $trip['trip_id'] . '" class="btn btn-sm btn-primary" title="Edit">
|
||||
<i class="far fa-edit"></i>
|
||||
</a>
|
||||
<button class="btn btn-sm ' . $publishButtonClass . ' toggle-publish" data-trip-id="' . $trip['trip_id'] . '" title="' . $publishButtonText . '">
|
||||
<i class="far fa-' . ($trip['published'] == 1 ? 'eye-slash' : 'eye') . '"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-danger delete-trip" data-trip-id="' . $trip['trip_id'] . '" title="Delete">
|
||||
<i class="far fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>';
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<p>No trips found. <a href="manage_trips">Create one</a></p>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Trips Management Area end -->
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script>
|
||||
$(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() {
|
||||
if (!confirm('Are you sure you want to delete this trip? This action cannot be undone.')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var tripId = $(this).data('trip-id');
|
||||
var button = $(this);
|
||||
var row = button.closest('tr');
|
||||
|
||||
$.ajax({
|
||||
url: 'delete_trip',
|
||||
type: 'POST',
|
||||
data: {
|
||||
trip_id: tripId
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if (response.status === 'success') {
|
||||
row.fadeOut(function() {
|
||||
$(this).remove();
|
||||
if ($('table tbody tr').length === 0) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
alert('Error: ' + response.message);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('Error deleting trip');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
// SQL query to fetch data
|
||||
$sql = "SELECT ip_address, user_id, page_url, referrer_url, visit_time, country FROM visitor_logs WHERE NOT (ip_address = '185.203.122.69' OR ip_address = '156.155.29.213') ORDER BY visit_time DESC";
|
||||
@@ -198,4 +201,4 @@ if (!empty($bannerImages)) {
|
||||
<!-- Tour List Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,5 +1,8 @@
|
||||
<?php include_once('header02.php');
|
||||
checkSuperAdmin();
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
// SQL query to fetch data
|
||||
$sql = "SELECT user_id, first_name, last_name, email, member, date_joined, token, is_verified, profile_pic FROM users";
|
||||
$result = $conn->query($sql);
|
||||
@@ -253,7 +256,7 @@ if (!empty($bannerImages)) {
|
||||
const name = this.dataset.name;
|
||||
const token = this.dataset.token;
|
||||
|
||||
fetch('resend_verification.php', {
|
||||
fetch('resend_verification', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
@@ -278,4 +281,4 @@ if (!empty($bannerImages)) {
|
||||
</script>
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
200
src/admin/manage_trips.php
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
$trip_id = $_GET['trip_id'] ?? null;
|
||||
$trip = null;
|
||||
|
||||
// If editing an existing trip, fetch its data
|
||||
if ($trip_id) {
|
||||
$stmt = $conn->prepare("SELECT * FROM trips WHERE trip_id = ?");
|
||||
$stmt->bind_param("i", $trip_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
if ($result->num_rows > 0) {
|
||||
$trip = $result->fetch_assoc();
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
$pageTitle = $trip ? 'Edit Trip' : 'Create New Trip';
|
||||
$breadcrumbs = [['Home' => 'index'], ['Admin' => 'admin_trips'], [$pageTitle => '']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
|
||||
<!-- Trip Manager Area start -->
|
||||
<section class="trip-manager-area py-100 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55">
|
||||
<form id="tripForm" enctype="multipart/form-data" method="POST" action="process_trip">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
|
||||
<?php if ($trip): ?>
|
||||
<input type="hidden" name="trip_id" value="<?php echo $trip['trip_id']; ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="section-title py-20">
|
||||
<h2><?php echo $trip ? 'Edit Trip: ' . htmlspecialchars($trip['trip_name']) : 'Create New Trip'; ?></h2>
|
||||
<div id="responseMessage"></div>
|
||||
</div>
|
||||
|
||||
<!-- Trip Information -->
|
||||
<div class="row mt-35">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="trip_name">Trip Name *</label>
|
||||
<input type="text" id="trip_name" name="trip_name" class="form-control" value="<?php echo $trip ? htmlspecialchars($trip['trip_name']) : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="trip_code">Trip Code</label>
|
||||
<input type="text" id="trip_code" name="trip_code" class="form-control" maxlength="12" value="<?php echo $trip ? htmlspecialchars($trip['trip_code']) : ''; ?>" placeholder="e.g., TRIP001">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="location">Location *</label>
|
||||
<input type="text" id="location" name="location" class="form-control" value="<?php echo $trip ? htmlspecialchars($trip['location']) : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="vehicle_capacity">Vehicle Capacity *</label>
|
||||
<input type="number" id="vehicle_capacity" name="vehicle_capacity" class="form-control" min="1" value="<?php echo $trip ? $trip['vehicle_capacity'] : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dates -->
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="start_date">Start Date *</label>
|
||||
<input type="date" id="start_date" name="start_date" class="form-control" value="<?php echo $trip ? $trip['start_date'] : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="end_date">End Date *</label>
|
||||
<input type="date" id="end_date" name="end_date" class="form-control" value="<?php echo $trip ? $trip['end_date'] : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Descriptions -->
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="short_description">Short Description *</label>
|
||||
<textarea id="short_description" name="short_description" class="form-control" rows="3" required><?php echo $trip ? htmlspecialchars($trip['short_description']) : ''; ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="long_description">Long Description *</label>
|
||||
<textarea id="long_description" name="long_description" class="form-control" rows="6" required><?php echo $trip ? htmlspecialchars($trip['long_description']) : ''; ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pricing -->
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="cost_members">Member Cost (R) *</label>
|
||||
<input type="number" id="cost_members" name="cost_members" class="form-control" step="0.01" min="0" value="<?php echo $trip ? $trip['cost_members'] : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="cost_nonmembers">Non-Member Cost (R) *</label>
|
||||
<input type="number" id="cost_nonmembers" name="cost_nonmembers" class="form-control" step="0.01" min="0" value="<?php echo $trip ? $trip['cost_nonmembers'] : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="cost_pensioner_member">Pensioner Member Cost (R) *</label>
|
||||
<input type="number" id="cost_pensioner_member" name="cost_pensioner_member" class="form-control" step="0.01" min="0" value="<?php echo $trip ? $trip['cost_pensioner_member'] : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="cost_pensioner">Pensioner Cost (R) *</label>
|
||||
<input type="number" id="cost_pensioner" name="cost_pensioner" class="form-control" step="0.01" min="0" value="<?php echo $trip ? $trip['cost_pensioner'] : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="booking_fee">Booking Fee (R) *</label>
|
||||
<input type="number" id="booking_fee" name="booking_fee" class="form-control" step="0.01" min="0" value="<?php echo $trip ? $trip['booking_fee'] : ''; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Images Upload -->
|
||||
<div class="col-md-12 mt-20">
|
||||
<div class="form-group">
|
||||
<label>Trip Images</label>
|
||||
<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>
|
||||
<?php if ($trip): ?>
|
||||
<small class="text-info">Images will be saved to: assets/images/trips/<?php echo $trip_id; ?>_{number}.jpg</small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mt-20">
|
||||
<div class="form-group mb-0">
|
||||
<button type="submit" class="theme-btn style-two" style="width:100%;">
|
||||
<?php echo $trip ? 'Update Trip' : 'Create Trip'; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Trip Manager Area end -->
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#tripForm').on('submit', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var formData = new FormData(this);
|
||||
|
||||
$.ajax({
|
||||
url: 'process_trip',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if (response.status === 'success') {
|
||||
$('#responseMessage').html('<div class="alert alert-success">' + response.message + '</div>');
|
||||
setTimeout(function() {
|
||||
window.location.href = 'admin_trips';
|
||||
}, 2000);
|
||||
} else {
|
||||
$('#responseMessage').html('<div class="alert alert-danger">' + response.message + '</div>');
|
||||
console.error('Server error:', response.message);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.log('AJAX Error:', error);
|
||||
console.log('Response:', xhr.responseText);
|
||||
$('#responseMessage').html('<div class="alert alert-danger">Error creating/updating trip: ' + error + '</div>');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
require_once("session.php");
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
// Prepare the SQL query to fetch bar tabs along with user details, including user_id
|
||||
$sql = "
|
||||
30
src/api/fetch_drinks.php
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
|
||||
if (isset($_GET['tab_id'])) {
|
||||
$tab_id = (int) $_GET['tab_id']; // Convert to integer
|
||||
|
||||
if ($tab_id <= 0) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid tab ID.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Fetch drinks available for this tab
|
||||
$stmt = $conn->prepare("SELECT * FROM bar_items");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$drinks = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$drinks[] = $row;
|
||||
}
|
||||
|
||||
echo json_encode($drinks);
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Tab ID is required.']);
|
||||
}
|
||||
?>
|
||||
|
||||
24
src/api/fetch_users.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
if ($conn->connect_error) {
|
||||
die(json_encode([])); // Return empty JSON on failure
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("SELECT user_id, first_name, last_name FROM users ORDER BY first_name ASC");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$users = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$users[] = $row;
|
||||
}
|
||||
|
||||
echo json_encode($users);
|
||||
$conn->close();
|
||||
?>
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
<?php
|
||||
require_once("env.php");
|
||||
include_once('connection.php');
|
||||
include_once('functions.php');
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
include_once('../config/connection.php');
|
||||
include_once('../config/functions.php');
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
$sql = "SELECT
|
||||
c.*,
|
||||
$stmt = $conn->prepare("SELECT
|
||||
c.id,
|
||||
c.name,
|
||||
c.description,
|
||||
c.website,
|
||||
c.telephone,
|
||||
c.latitude,
|
||||
c.longitude,
|
||||
c.thumbnail,
|
||||
c.country,
|
||||
c.province,
|
||||
u.first_name,
|
||||
u.last_name,
|
||||
u.profile_pic
|
||||
FROM campsites c
|
||||
LEFT JOIN users u ON c.user_id = u.user_id";
|
||||
|
||||
$result = $conn->query($sql);
|
||||
LEFT JOIN users u ON c.user_id = u.user_id");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$campsites = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
@@ -25,6 +35,8 @@ while ($row = $result->fetch_assoc()) {
|
||||
'latitude' => $row['latitude'],
|
||||
'longitude' => $row['longitude'],
|
||||
'thumbnail' => $row['thumbnail'],
|
||||
'country' => $row['country'],
|
||||
'province' => $row['province'],
|
||||
'user' => [
|
||||
'first_name' => $row['first_name'],
|
||||
'last_name' => $row['last_name'],
|
||||
@@ -35,3 +47,4 @@ while ($row = $result->fetch_assoc()) {
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($campsites);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
require_once("env.php");
|
||||
require_once("connection.php");
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
|
||||
if (isset($_POST['tab_id'])) {
|
||||
$tab_id = (int) $_POST['tab_id']; // Ensure it's an integer
|
||||
@@ -20,3 +21,4 @@ if (isset($_POST['tab_id'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Missing tab ID.']);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
require_once("env.php");
|
||||
require_once("session.php");
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
require_once 'google-client/vendor/autoload.php'; // Add this line for Google Client
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
require_once($rootPath . '/google-client/vendor/autoload.php'); // Add this line for Google Client
|
||||
|
||||
// Check if connection is established
|
||||
if (!$conn) {
|
||||
@@ -142,3 +143,4 @@ if (isset($_POST['email']) && isset($_POST['password'])) {
|
||||
$conn->close();
|
||||
exit();
|
||||
?>
|
||||
|
||||
60
src/bootstrap.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* Bootstrap - Central configuration loader
|
||||
*
|
||||
* All PHP files should include this file first to set up:
|
||||
* - Path constants
|
||||
* - Database connection
|
||||
* - Session management
|
||||
* - Core functions
|
||||
*
|
||||
* Usage:
|
||||
* <?php require_once(__DIR__ . '/../../bootstrap.php'); ?>
|
||||
*
|
||||
* Then use constants:
|
||||
* - APP_ROOT: Root directory
|
||||
* - SRC_ROOT: src/ directory
|
||||
* - CONFIG_PATH: src/config/ directory
|
||||
* - CLASSES_PATH: src/classes/ directory
|
||||
* - COMPONENTS_PATH: components/ directory
|
||||
*
|
||||
* And use globals:
|
||||
* - $conn: MySQLi connection
|
||||
* - $db: DatabaseService instance
|
||||
*/
|
||||
|
||||
// Define root paths - adjust based on file location
|
||||
if (!defined('APP_ROOT')) {
|
||||
define('APP_ROOT', dirname(__DIR__));
|
||||
}
|
||||
if (!defined('SRC_ROOT')) {
|
||||
define('SRC_ROOT', APP_ROOT . '/src');
|
||||
}
|
||||
if (!defined('CONFIG_PATH')) {
|
||||
define('CONFIG_PATH', SRC_ROOT . '/config');
|
||||
}
|
||||
if (!defined('CLASSES_PATH')) {
|
||||
define('CLASSES_PATH', SRC_ROOT . '/classes');
|
||||
}
|
||||
if (!defined('COMPONENTS_PATH')) {
|
||||
define('COMPONENTS_PATH', APP_ROOT . '/components');
|
||||
}
|
||||
if (!defined('ASSETS_PATH')) {
|
||||
define('ASSETS_PATH', APP_ROOT . '/assets');
|
||||
}
|
||||
|
||||
// Load environment variables
|
||||
require_once(CONFIG_PATH . '/env.php');
|
||||
|
||||
// Load database connection
|
||||
require_once(CONFIG_PATH . '/connection.php');
|
||||
|
||||
// Load session management
|
||||
require_once(CONFIG_PATH . '/session.php');
|
||||
|
||||
// Load core functions
|
||||
require_once(CONFIG_PATH . '/functions.php');
|
||||
|
||||
// Optional: Set global timezone
|
||||
date_default_timezone_set($_ENV['TIMEZONE'] ?? 'Africa/Johannesburg');
|
||||
?>
|
||||
27
src/config/connection.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
// Disable mysqli exceptions so we can handle connection errors gracefully
|
||||
mysqli_report(MYSQLI_REPORT_OFF);
|
||||
|
||||
$dbhost = $_ENV['DB_HOST'];
|
||||
$dbuser = $_ENV['DB_USER'];
|
||||
$dbpass = $_ENV['DB_PASS'];
|
||||
$dbname = $_ENV['DB_NAME'];
|
||||
$salt = $_ENV['SALT'];
|
||||
|
||||
// echo "hello. ". $dbhost;
|
||||
|
||||
if(!$conn = @mysqli_connect($dbhost, $dbuser, $dbpass, $dbname)){
|
||||
// Log the error to file instead of stderr (no red output)
|
||||
@error_log("Database Connection Error: " . mysqli_connect_error(), 3, dirname(__DIR__) . "/logs/db_errors.log");
|
||||
$conn = null;
|
||||
$db = null;
|
||||
} else {
|
||||
date_default_timezone_set('Africa/Johannesburg');
|
||||
|
||||
// Initialize DatabaseService for modern queries
|
||||
require_once(__DIR__ . '/../../classes/DatabaseService.php');
|
||||
$db = new DatabaseService($conn);
|
||||
}
|
||||
|
||||
|
||||
6
src/config/env.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../../');
|
||||
$dotenv->load();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
require_once "vendor/autoload.php";
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
@@ -14,13 +14,16 @@ function openDatabaseConnection()
|
||||
$dbname = $_ENV['DB_NAME'];
|
||||
$salt = $_ENV['SALT'];
|
||||
|
||||
// Disable mysqli exceptions
|
||||
mysqli_report(MYSQLI_REPORT_OFF);
|
||||
|
||||
// Create connection
|
||||
$conn = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
|
||||
$conn = @new mysqli($dbhost, $dbuser, $dbpass, $dbname);
|
||||
|
||||
// Check connection
|
||||
if ($conn->connect_error) {
|
||||
die("Connection failed: " . $conn->connect_error);
|
||||
@error_log("Database Connection Error in openDatabaseConnection: " . $conn->connect_error, 3, dirname(dirname(__DIR__)) . "/logs/db_errors.log");
|
||||
return null;
|
||||
}
|
||||
|
||||
return $conn;
|
||||
@@ -31,9 +34,12 @@ function getTripCount()
|
||||
// Database connection
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
// SQL query to count the number of rows
|
||||
$sql = "SELECT COUNT(*) AS total FROM trips WHERE published = 1 AND start_date > CURDATE()";
|
||||
$result = $conn->query($sql);
|
||||
// SQL query to count the number of upcoming trips
|
||||
$stmt = $conn->prepare("SELECT COUNT(*) AS total FROM trips WHERE published = ? AND start_date > CURDATE()");
|
||||
$published = 1;
|
||||
$stmt->bind_param("i", $published);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Fetch the count from the result
|
||||
if ($result->num_rows > 0) {
|
||||
@@ -203,6 +209,27 @@ function getEFTDetails($eft_id) {
|
||||
|
||||
function sendPOP($fullname, $eft_id, $amount, $description)
|
||||
{
|
||||
// Build the 'To' array from environment variables
|
||||
$toAddresses = [];
|
||||
|
||||
// Parse comma-separated email addresses from .env
|
||||
$emailsEnv = $_ENV['POP_NOTIFICATION_EMAILS'] ?? '';
|
||||
if (!empty($emailsEnv)) {
|
||||
$emails = array_map('trim', explode(',', $emailsEnv));
|
||||
foreach ($emails as $email) {
|
||||
if (!empty($email)) {
|
||||
$toAddresses[] = ['Email' => $email];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to default if no emails configured
|
||||
if (empty($toAddresses)) {
|
||||
$toAddresses = [
|
||||
['Email' => 'info@4wdcsa.co.za']
|
||||
];
|
||||
}
|
||||
|
||||
$message = [
|
||||
'Messages' => [
|
||||
[
|
||||
@@ -210,20 +237,7 @@ function sendPOP($fullname, $eft_id, $amount, $description)
|
||||
'Email' => $_ENV['MAILJET_FROM_EMAIL'],
|
||||
'Name' => $_ENV['MAILJET_FROM_NAME'] . ' Web Admin'
|
||||
],
|
||||
'To' => [
|
||||
[
|
||||
'Email' => 'chrispintoza@gmail.com',
|
||||
'Name' => 'Chris Pinto'
|
||||
],
|
||||
[
|
||||
'Email' => $_ENV['MAILJET_FROM_EMAIL'],
|
||||
'Name' => 'Jacqui Boshoff'
|
||||
],
|
||||
[
|
||||
'Email' => 'louiseb@global.co.za',
|
||||
'Name' => 'Louise Blignault'
|
||||
]
|
||||
],
|
||||
'To' => $toAddresses,
|
||||
'TemplateID' => 7054062,
|
||||
'TemplateLanguage' => true,
|
||||
'Subject' => "4WDCSA - Proof of Payment Received",
|
||||
@@ -393,6 +407,11 @@ function getUserMemberStatus($user_id)
|
||||
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
// Return early if no database connection
|
||||
if ($conn === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 1: Check if the user is a member
|
||||
$queryUser = "SELECT member FROM users WHERE user_id = ?";
|
||||
$stmtUser = $conn->prepare($queryUser);
|
||||
@@ -478,6 +497,11 @@ function getUserMemberStatusPending($user_id)
|
||||
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
// Return early if no database connection
|
||||
if ($conn === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 1: Check if the user is a member
|
||||
$queryUser = "SELECT member FROM users WHERE user_id = ?";
|
||||
$stmtUser = $conn->prepare($queryUser);
|
||||
@@ -918,8 +942,10 @@ function getAvailableSpaces($trip_id)
|
||||
$trip_id = intval($trip_id);
|
||||
|
||||
// Step 1: Get the vehicle capacity for the trip from the trips table
|
||||
$query = "SELECT vehicle_capacity FROM trips WHERE trip_id = $trip_id";
|
||||
$result = $conn->query($query);
|
||||
$stmt = $conn->prepare("SELECT vehicle_capacity FROM trips WHERE trip_id = ?");
|
||||
$stmt->bind_param("i", $trip_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if the trip exists
|
||||
if ($result->num_rows === 0) {
|
||||
@@ -931,8 +957,10 @@ function getAvailableSpaces($trip_id)
|
||||
$vehicle_capacity = $trip['vehicle_capacity'];
|
||||
|
||||
// Step 2: Get the total number of booked vehicles for this trip from the bookings table
|
||||
$query = "SELECT SUM(num_vehicles) as total_booked FROM bookings WHERE trip_id = $trip_id";
|
||||
$result = $conn->query($query);
|
||||
$stmt = $conn->prepare("SELECT SUM(num_vehicles) as total_booked FROM bookings WHERE trip_id = ?");
|
||||
$stmt->bind_param("i", $trip_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Fetch the total number of vehicles booked
|
||||
$bookings = $result->fetch_assoc();
|
||||
@@ -988,6 +1016,11 @@ function getUserRole()
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Return early if no database connection
|
||||
if ($conn === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if the user_id is set in the session
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
return null; // or handle the case where the user is not logged in
|
||||
@@ -1537,10 +1570,17 @@ function countUpcomingTrips()
|
||||
// Open database connection
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
$query = "SELECT COUNT(*) AS trip_count FROM trips WHERE published = 1 AND start_date > CURDATE()";
|
||||
// Return 0 if no database connection
|
||||
if ($conn === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("SELECT COUNT(*) AS trip_count FROM trips WHERE published = ? AND start_date > CURDATE()");
|
||||
$published = 1;
|
||||
$stmt->bind_param("i", $published);
|
||||
$stmt->execute();
|
||||
|
||||
if ($result = $conn->query($query)) {
|
||||
if ($result = $stmt->get_result()) {
|
||||
$row = $result->fetch_assoc();
|
||||
return (int)$row['trip_count'];
|
||||
} else {
|
||||
@@ -1558,6 +1598,11 @@ function logVisitor()
|
||||
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
// Return early if no database connection
|
||||
if ($conn === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Collect visitor data
|
||||
$ip_address = getUserIP();
|
||||
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
|
||||
@@ -1629,16 +1674,19 @@ function getUserIP()
|
||||
function getNextOpenDayDate()
|
||||
{
|
||||
$conn = openDatabaseConnection();
|
||||
$sql = "
|
||||
$stmt = $conn->prepare("
|
||||
SELECT date
|
||||
FROM events
|
||||
WHERE name = '4WDCSA Open Day'
|
||||
WHERE name = ?
|
||||
AND date >= NOW()
|
||||
ORDER BY date ASC
|
||||
LIMIT 1
|
||||
";
|
||||
");
|
||||
$event_name = '4WDCSA Open Day';
|
||||
$stmt->bind_param("s", $event_name);
|
||||
$stmt->execute();
|
||||
|
||||
$result = $conn->query($sql);
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result && $row = $result->fetch_assoc()) {
|
||||
return $row['date']; // e.g. "2025-05-01 10:00:00"
|
||||
@@ -2640,3 +2688,217 @@ function auditLog($user_id, $action, $resource_type = null, $resource_id = null,
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL Helper - Map page names to file paths
|
||||
* Centralizes all internal links for easy management
|
||||
*
|
||||
* Usage: url('login') → /src/pages/auth/login.php
|
||||
*/
|
||||
function url($page) {
|
||||
static $map = [
|
||||
// Home & Main
|
||||
'home' => '/index.php',
|
||||
'index' => '/index.php',
|
||||
|
||||
// Auth Pages
|
||||
'login' => '/src/pages/auth/login.php',
|
||||
'register' => '/src/pages/auth/register.php',
|
||||
'forgot' => '/src/pages/auth/forgot_password.php',
|
||||
'forgot_password' => '/src/pages/auth/forgot_password.php',
|
||||
'reset_password' => '/src/pages/auth/reset_password.php',
|
||||
'verify' => '/src/pages/auth/verify.php',
|
||||
'resend_verification' => '/src/pages/auth/resend_verification.php',
|
||||
'change_password' => '/src/pages/auth/change_password.php',
|
||||
'update_password' => '/src/pages/auth/update_password.php',
|
||||
|
||||
// Membership Pages
|
||||
'membership' => '/src/pages/memberships/membership.php',
|
||||
'membership_details' => '/src/pages/memberships/membership_details.php',
|
||||
'membership_application' => '/src/pages/memberships/membership_application.php',
|
||||
'membership_payment' => '/src/pages/memberships/membership_payment.php',
|
||||
'renew_membership' => '/src/pages/memberships/renew_membership.php',
|
||||
'member_info' => '/src/pages/memberships/member_info.php',
|
||||
|
||||
// Booking Pages
|
||||
'bookings' => '/src/pages/bookings/bookings.php',
|
||||
'campsites' => '/src/pages/bookings/campsites.php',
|
||||
'campsite_booking' => '/src/pages/bookings/campsite_booking.php',
|
||||
'trips' => '/src/pages/bookings/trips.php',
|
||||
'trip_details' => '/src/pages/bookings/trip-details.php',
|
||||
'course_details' => '/src/pages/bookings/course_details.php',
|
||||
'driver_training' => '/src/pages/bookings/driver_training.php',
|
||||
|
||||
// Shop Pages
|
||||
'view_cart' => '/src/pages/shop/view_cart.php',
|
||||
'add_to_cart' => '/src/pages/shop/add_to_cart.php',
|
||||
'bar_tabs' => '/src/pages/shop/bar_tabs.php',
|
||||
'payment_confirmation' => '/src/pages/shop/payment_confirmation.php',
|
||||
'confirm' => '/src/pages/shop/confirm.php',
|
||||
'confirm2' => '/src/pages/shop/confirm2.php',
|
||||
|
||||
// Events & Blog
|
||||
'events' => '/src/pages/events/events.php',
|
||||
'blog' => '/src/pages/events/blog.php',
|
||||
'blog_details' => '/src/pages/events/blog_details.php',
|
||||
'best_of_eastern_cape' => '/src/pages/events/best_of_the_eastern_cape_2024.php',
|
||||
'agm_minutes' => '/src/pages/events/2025_agm_minutes.php',
|
||||
'agm_content' => '/src/pages/events/agm_content.php',
|
||||
'instapage' => '/src/pages/events/instapage.php',
|
||||
|
||||
// Other Pages
|
||||
'about' => '/src/pages/other/about.php',
|
||||
'contact' => '/src/pages/other/contact.php',
|
||||
'privacy' => '/src/pages/other/privacy_policy.php',
|
||||
'privacy_policy' => '/src/pages/other/privacy_policy.php',
|
||||
'404' => '/src/pages/other/404.php',
|
||||
'account_settings' => '/src/pages/other/account_settings.php',
|
||||
'rescue_recovery' => '/src/pages/other/rescue_recovery.php',
|
||||
'bush_mechanics' => '/src/pages/other/bush_mechanics.php',
|
||||
'indemnity' => '/src/pages/other/indemnity.php',
|
||||
'indemnity_waiver' => '/src/pages/other/indemnity_waiver.php',
|
||||
'basic_indemnity' => '/src/pages/other/basic_indemnity.php',
|
||||
'view_indemnity' => '/src/pages/other/view_indemnity.php',
|
||||
|
||||
// Admin Pages (accessible only to admins)
|
||||
'admin_members' => '/src/admin/admin_members.php',
|
||||
'admin_payments' => '/src/admin/admin_payments.php',
|
||||
'admin_web_users' => '/src/admin/admin_web_users.php',
|
||||
'admin_course_bookings' => '/src/admin/admin_course_bookings.php',
|
||||
'admin_camp_bookings' => '/src/admin/admin_camp_bookings.php',
|
||||
'admin_trip_bookings' => '/src/admin/admin_trip_bookings.php',
|
||||
'admin_visitors' => '/src/admin/admin_visitors.php',
|
||||
'admin_efts' => '/src/admin/admin_efts.php',
|
||||
'add_campsite' => '/src/admin/add_campsite.php',
|
||||
|
||||
// API/AJAX Endpoints
|
||||
'fetch_users' => '/src/api/fetch_users.php',
|
||||
'fetch_drinks' => '/src/api/fetch_drinks.php',
|
||||
'fetch_bar_tabs' => '/src/api/fetch_bar_tabs.php',
|
||||
'get_campsites' => '/src/api/get_campsites.php',
|
||||
'get_tab_total' => '/src/api/get_tab_total.php',
|
||||
'google_validate_login' => '/src/api/google_validate_login.php',
|
||||
|
||||
// Processors
|
||||
'validate_login' => '/validate_login.php',
|
||||
'register_user' => '/src/processors/register_user.php',
|
||||
'process_application' => '/src/processors/process_application.php',
|
||||
'process_booking' => '/src/processors/process_booking.php',
|
||||
'process_camp_booking' => '/src/processors/process_camp_booking.php',
|
||||
'process_course_booking' => '/src/processors/process_course_booking.php',
|
||||
'process_trip_booking' => '/src/processors/process_trip_booking.php',
|
||||
'process_membership_payment' => '/src/processors/process_membership_payment.php',
|
||||
'process_payments' => '/src/processors/process_payments.php',
|
||||
'process_eft' => '/src/processors/process_eft.php',
|
||||
'submit_order' => '/src/processors/submit_order.php',
|
||||
'submit_pop' => '/src/processors/submit_pop.php',
|
||||
'process_signature' => '/src/processors/process_signature.php',
|
||||
'create_bar_tab' => '/src/processors/create_bar_tab.php',
|
||||
'update_application' => '/src/processors/update_application.php',
|
||||
'update_user' => '/src/processors/update_user.php',
|
||||
'upload_profile_picture' => '/src/processors/upload_profile_picture.php',
|
||||
'send_reset_link' => '/src/processors/send_reset_link.php',
|
||||
'logout' => '/src/processors/logout.php',
|
||||
];
|
||||
|
||||
// Return mapped URL or fallback to simple filename
|
||||
if (isset($map[$page])) {
|
||||
return $map[$page];
|
||||
}
|
||||
|
||||
// Fallback: assume it's a root-level file
|
||||
return '/' . $page . '.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize image by resizing if it exceeds max dimensions
|
||||
*
|
||||
* @param string $filePath Path to the image file
|
||||
* @param int $maxWidth Maximum width in pixels
|
||||
* @param int $maxHeight Maximum height in pixels
|
||||
* @return bool Success status
|
||||
*/
|
||||
function optimizeImage($filePath, $maxWidth = 1920, $maxHeight = 1080)
|
||||
{
|
||||
if (!file_exists($filePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get image info
|
||||
$imageInfo = getimagesize($filePath);
|
||||
if (!$imageInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$width = $imageInfo[0];
|
||||
$height = $imageInfo[1];
|
||||
$mime = $imageInfo['mime'];
|
||||
|
||||
// Only resize if image is larger than max dimensions
|
||||
if ($width <= $maxWidth && $height <= $maxHeight) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate new dimensions maintaining aspect ratio
|
||||
$ratio = min($maxWidth / $width, $maxHeight / $height);
|
||||
$newWidth = (int)($width * $ratio);
|
||||
$newHeight = (int)($height * $ratio);
|
||||
|
||||
// Load image based on type
|
||||
switch ($mime) {
|
||||
case 'image/jpeg':
|
||||
$source = imagecreatefromjpeg($filePath);
|
||||
break;
|
||||
case 'image/png':
|
||||
$source = imagecreatefrompng($filePath);
|
||||
break;
|
||||
case 'image/gif':
|
||||
$source = imagecreatefromgif($filePath);
|
||||
break;
|
||||
case 'image/webp':
|
||||
$source = imagecreatefromwebp($filePath);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create resized image
|
||||
$destination = imagecreatetruecolor($newWidth, $newHeight);
|
||||
|
||||
// Preserve transparency for PNG and GIF
|
||||
if ($mime === 'image/png' || $mime === 'image/gif') {
|
||||
$transparent = imagecolorallocatealpha($destination, 0, 0, 0, 127);
|
||||
imagefill($destination, 0, 0, $transparent);
|
||||
imagesavealpha($destination, true);
|
||||
}
|
||||
|
||||
// Resize
|
||||
imagecopyresampled($destination, $source, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
||||
|
||||
// Save image
|
||||
$success = false;
|
||||
switch ($mime) {
|
||||
case 'image/jpeg':
|
||||
$success = imagejpeg($destination, $filePath, 85);
|
||||
break;
|
||||
case 'image/png':
|
||||
$success = imagepng($destination, $filePath, 6);
|
||||
break;
|
||||
case 'image/gif':
|
||||
$success = imagegif($destination, $filePath);
|
||||
break;
|
||||
case 'image/webp':
|
||||
$success = imagewebp($destination, $filePath, 85);
|
||||
break;
|
||||
}
|
||||
|
||||
// Free up memory
|
||||
imagedestroy($source);
|
||||
imagedestroy($destination);
|
||||
|
||||
return $success;
|
||||
}
|
||||
118
src/pages/add_campsite.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . '/src/config/env.php');
|
||||
include_once($rootPath . '/src/config/connection.php');
|
||||
include_once($rootPath . '/src/config/functions.php');
|
||||
|
||||
session_start();
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
http_response_code(403);
|
||||
die('Security token validation failed. Please try again.');
|
||||
}
|
||||
|
||||
// campsites.php
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
// Get text inputs
|
||||
$name = validateName($_POST['name'] ?? '') ?: '';
|
||||
$desc = isset($_POST['description']) ? htmlspecialchars($_POST['description'], ENT_QUOTES, 'UTF-8') : '';
|
||||
$country = isset($_POST['country']) ? htmlspecialchars($_POST['country'], ENT_QUOTES, 'UTF-8') : '';
|
||||
$province = isset($_POST['province']) ? htmlspecialchars($_POST['province'], ENT_QUOTES, 'UTF-8') : '';
|
||||
$lat = isset($_POST['latitude']) ? floatval($_POST['latitude']) : 0.0;
|
||||
$lng = isset($_POST['longitude']) ? floatval($_POST['longitude']) : 0.0;
|
||||
$website = isset($_POST['website']) ? filter_var($_POST['website'], FILTER_VALIDATE_URL) : '';
|
||||
$telephone = validatePhoneNumber($_POST['telephone'] ?? '') ?: '';
|
||||
|
||||
if (empty($name)) {
|
||||
http_response_code(400);
|
||||
die('Campsite name is required.');
|
||||
}
|
||||
|
||||
// Handle file upload
|
||||
$thumbnailPath = null;
|
||||
if (isset($_FILES['thumbnail']) && $_FILES['thumbnail']['error'] !== UPLOAD_ERR_NO_FILE) {
|
||||
// Validate file using hardened validation function
|
||||
$validationResult = validateFileUpload($_FILES['thumbnail'], 'profile_picture');
|
||||
|
||||
if ($validationResult === false) {
|
||||
http_response_code(400);
|
||||
die('Invalid thumbnail image. Only JPG, JPEG, PNG, GIF, and WEBP images under 5MB are allowed.');
|
||||
}
|
||||
|
||||
$uploadDir = $rootPath . "/assets/uploads/campsites/";
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0755, true);
|
||||
}
|
||||
|
||||
if (!is_writable($uploadDir)) {
|
||||
http_response_code(500);
|
||||
die('Upload directory is not writable.');
|
||||
}
|
||||
|
||||
$randomFilename = $validationResult['filename'];
|
||||
$targetFile = $uploadDir . $randomFilename;
|
||||
|
||||
if (move_uploaded_file($_FILES["thumbnail"]["tmp_name"], $targetFile)) {
|
||||
chmod($targetFile, 0644);
|
||||
$thumbnailPath = "assets/uploads/campsites/" . $randomFilename;
|
||||
} else {
|
||||
http_response_code(500);
|
||||
die('Failed to move uploaded file.');
|
||||
}
|
||||
}
|
||||
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
|
||||
if ($id > 0) {
|
||||
// Verify ownership - check if the campsite belongs to the current user
|
||||
$ownerCheckStmt = $conn->prepare("SELECT user_id FROM campsites WHERE id = ?");
|
||||
$ownerCheckStmt->bind_param("i", $id);
|
||||
$ownerCheckStmt->execute();
|
||||
$ownerResult = $ownerCheckStmt->get_result();
|
||||
|
||||
if ($ownerResult->num_rows === 0) {
|
||||
http_response_code(404);
|
||||
die('Campsite not found.');
|
||||
}
|
||||
|
||||
$ownerRow = $ownerResult->fetch_assoc();
|
||||
if ($ownerRow['user_id'] != $user_id) {
|
||||
http_response_code(403);
|
||||
die('You do not have permission to edit this campsite. Only the owner can make changes.');
|
||||
}
|
||||
|
||||
$ownerCheckStmt->close();
|
||||
|
||||
// UPDATE
|
||||
if ($thumbnailPath) {
|
||||
$stmt = $conn->prepare("UPDATE campsites SET name=?, description=?, country=?, province=?, latitude=?, longitude=?, website=?, telephone=?, thumbnail=? WHERE id=?");
|
||||
$stmt->bind_param("ssssddsssi", $name, $desc, $country, $province, $lat, $lng, $website, $telephone, $thumbnailPath, $id);
|
||||
} else {
|
||||
$stmt = $conn->prepare("UPDATE campsites SET name=?, description=?, country=?, province=?, latitude=?, longitude=?, website=?, telephone=? WHERE id=?");
|
||||
$stmt->bind_param("ssssddssi", $name, $desc, $country, $province, $lat, $lng, $website, $telephone, $id);
|
||||
}
|
||||
|
||||
// Log the action
|
||||
auditLog($user_id, 'CAMPSITE_UPDATE', 'campsites', $id, ['name' => $name]);
|
||||
} else {
|
||||
// INSERT
|
||||
$stmt = $conn->prepare("INSERT INTO campsites (name, description, country, province, latitude, longitude, website, telephone, thumbnail, user_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->bind_param("ssssddsssi", $name, $desc, $country, $province, $lat, $lng, $website, $telephone, $thumbnailPath, $user_id);
|
||||
|
||||
// Log the action
|
||||
auditLog($user_id, 'CAMPSITE_CREATE', 'campsites', 0, ['name' => $name]);
|
||||
}
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
http_response_code(500);
|
||||
die('Database error: ' . $stmt->error);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
|
||||
header("Location: campsites");
|
||||
?>
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
require_once("env.php");
|
||||
require_once("session.php");
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
require_once($rootPath . '/src/config/env.php');
|
||||
require_once($rootPath . '/src/config/session.php');
|
||||
require_once($rootPath . '/src/config/connection.php');
|
||||
require_once($rootPath . '/src/config/functions.php');
|
||||
|
||||
$response = array('status' => 'error', 'message' => 'Something went wrong');
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php include_once('header02.php') ?>
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php') ?>
|
||||
<style>
|
||||
@media (min-width: 991px) {
|
||||
.container {
|
||||
@@ -54,7 +56,7 @@
|
||||
event.preventDefault(); // Prevent the default form submission
|
||||
|
||||
$.ajax({
|
||||
url: 'send_reset_link.php',
|
||||
url: 'send_reset_link',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
dataType: 'json',
|
||||
@@ -79,4 +81,4 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,6 +1,10 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
// Determine the correct path to header.php based on file location
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
// Include Google login PHP logic
|
||||
require_once 'google-client/vendor/autoload.php';
|
||||
require_once $rootPath . '/google-client/vendor/autoload.php';
|
||||
|
||||
$client = new Google_Client();
|
||||
$client->setClientId('948441222188-8qhboq2urr8o9n35mc70s5h2nhd52v0m.apps.googleusercontent.com');
|
||||
@@ -39,7 +43,7 @@ $login_url = $client->createAuthUrl();
|
||||
|
||||
<div class="">
|
||||
<div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55">
|
||||
<form id="loginForm" class="loginForm" name="loginForm" action="assets/php/form-process.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<form id="loginForm" class="loginForm" name="loginForm" action="validate_login" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="section-title">
|
||||
<h2>Log in</h2>
|
||||
<div style="text-align: center;" id="responseMessage"></div> <!-- Message display area -->
|
||||
@@ -84,7 +88,7 @@ $login_url = $client->createAuthUrl();
|
||||
<button type="submit" class="theme-btn style-two" style="width:100%;">Log In</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-20" style="text-align: center;">Don't have an account? <a href="register.php"><b>Register here.</b> </a>| <a href="forgot_password.php"><b>Forgot your password?</b></a></div>
|
||||
<div class="pt-20" style="text-align: center;">Don't have an account? <a href="register"><b>Register here.</b> </a>| <a href="forgot_password"><b>Forgot your password?</b></a></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,13 +104,13 @@ $login_url = $client->createAuthUrl();
|
||||
event.preventDefault(); // Prevent the default form submission
|
||||
|
||||
$.ajax({
|
||||
url: 'validate_login.php',
|
||||
url: '<?= url("validate_login") ?>',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if (response.status === 'success') {
|
||||
window.location.href = 'index.php';
|
||||
window.location.href = '<?= url("index") ?>';
|
||||
} else {
|
||||
$('#responseMessage').html('<div class="alert alert-danger">' + response.message + '</div>');
|
||||
}
|
||||
@@ -119,4 +123,4 @@ $login_url = $client->createAuthUrl();
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php include_once('header02.php') ?>
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php') ?>
|
||||
<style>
|
||||
@media (min-width: 991px) {
|
||||
.container {
|
||||
@@ -25,7 +27,7 @@
|
||||
<div class="row align-items-center">
|
||||
<div class="">
|
||||
<div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55">
|
||||
<form id="registerForm" name="registerForm" action="register_user.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<form id="registerForm" name="registerForm" action="register_user" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="section-title">
|
||||
<h2>Register</h2>
|
||||
|
||||
@@ -89,7 +91,7 @@
|
||||
</div>
|
||||
<div id="responseMessage"></div> <!-- Message display area -->
|
||||
</div>
|
||||
<div class="pt-20">Already have an account? <a href="login.php"><b>Log in here.</b></a></div>
|
||||
<div class="pt-20">Already have an account? <a href="login"><b>Log in here.</b></a></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -148,7 +150,7 @@
|
||||
|
||||
// If validation passes, proceed with AJAX
|
||||
$.ajax({
|
||||
url: 'register_user.php',
|
||||
url: 'register_user',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
dataType: 'json',
|
||||
@@ -169,4 +171,4 @@
|
||||
</script>
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
require_once "vendor/autoload.php";
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
require_once($rootPath . '/src/config/connection.php');
|
||||
require_once($rootPath . '/src/config/functions.php');
|
||||
require_once($rootPath . '/vendor/autoload.php');
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
||||
$token = $_GET['token'] ?? '';
|
||||
|
||||
if (empty($token)) {
|
||||
@@ -37,7 +39,7 @@ $user_id = $user['user_id'];
|
||||
|
||||
<div class="">
|
||||
<div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55">
|
||||
<form id="changePasswordForm" class="loginForm" name="changePasswordForm" action="update_password.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<form id="changePasswordForm" class="loginForm" name="changePasswordForm" action="update_password" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="section-title">
|
||||
<h2>Reset Password</h2>
|
||||
<div class="pt-20" style="text-align: center;" id="responseMessage"></div> <!-- Message display area -->
|
||||
@@ -85,7 +87,7 @@ $user_id = $user['user_id'];
|
||||
event.preventDefault(); // Prevent default form submission
|
||||
|
||||
$.ajax({
|
||||
url: 'update_password.php',
|
||||
url: 'update_password',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
success: function(response) {
|
||||
@@ -108,4 +110,4 @@ $user_id = $user['user_id'];
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
require_once("env.php");
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
require_once($rootPath . '/src/config/env.php');
|
||||
require_once($rootPath . '/src/config/connection.php');
|
||||
require_once($rootPath . '/src/config/functions.php');
|
||||
|
||||
$response = array('status' => 'error', 'message' => 'Something went wrong');
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
require_once("env.php");
|
||||
require_once("connection.php");
|
||||
require_once("functions.php");
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
require_once($rootPath . '/src/config/env.php');
|
||||
require_once($rootPath . '/src/config/connection.php');
|
||||
require_once($rootPath . '/src/config/functions.php');
|
||||
|
||||
// Create connection
|
||||
$conn = openDatabaseConnection();
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkUserSession();
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
@@ -57,28 +60,10 @@ $user_id = $_SESSION['user_id'];
|
||||
</style>
|
||||
</style>
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||
if (!empty($bannerImages)) {
|
||||
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||
}
|
||||
$pageTitle = 'My Bookings';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
<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">My Bookings</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">My bookings</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Tour List Area start -->
|
||||
<section class="tour-list-page py-100 rel z-1">
|
||||
@@ -282,7 +267,7 @@ if (!empty($bannerImages)) {
|
||||
<div class="destination-footer">
|
||||
<span class="price"><span>Booking Total: R ' . number_format($amount, 2) . '</span></span>';
|
||||
if ($status == "AWAITING PAYMENT") {
|
||||
echo '<a href="payment_confirmation.php?token=' . encryptData($booking_id, $salt) . '" class="theme-btn style-two style-three">
|
||||
echo '<a href="' . url('payment_confirmation') . '?token=' . encryptData($booking_id, $salt) . '" class="theme-btn style-two style-three">
|
||||
<span data-hover="PAYMENT INFO">' . $status . '</span>
|
||||
</a>';
|
||||
} else {
|
||||
@@ -337,4 +322,4 @@ if (!empty($bannerImages)) {
|
||||
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
||||
checkUserSession();
|
||||
?>
|
||||
|
||||
@@ -76,7 +78,7 @@ checkUserSession();
|
||||
</div>
|
||||
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<h5 class="widget-title">Book your Campsite</h5>
|
||||
<form action="process_camp_booking.php" method="POST">
|
||||
<form action="process_camp_booking" method="POST">
|
||||
<div class="date mb-25">
|
||||
<b>From Date</b>
|
||||
<input type="date" id="from_date" name="from_date">
|
||||
@@ -212,4 +214,4 @@ checkUserSession();
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once('insta_footer.php') ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php') ?>
|
||||
503
src/pages/bookings/campsites.php
Normal file
@@ -0,0 +1,503 @@
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
|
||||
$conn = openDatabaseConnection();
|
||||
$stmt = $conn->prepare("SELECT * FROM campsites");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$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);
|
||||
}
|
||||
|
||||
/* Form styling to match manage_trips */
|
||||
.campsite-form-container {
|
||||
background: #f9f9f7;
|
||||
border: 1px solid #d8d8d8;
|
||||
border-radius: 10px;
|
||||
padding: 30px;
|
||||
margin: 20px 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.campsite-form-container h5 {
|
||||
color: #2c3e50;
|
||||
font-weight: 600;
|
||||
margin-bottom: 30px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.campsite-form-container .form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.campsite-form-container label {
|
||||
font-weight: 500;
|
||||
color: #34495e;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.campsite-form-container .form-control {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.campsite-form-container .form-control:focus {
|
||||
border-color: #4CAF50;
|
||||
box-shadow: 0 0 0 0.2rem rgba(76, 175, 80, 0.25);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.campsite-form-container .form-control select {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.campsite-form-container .btn {
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
/* Table styling to match admin trips */
|
||||
.campsites-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.campsites-table thead th {
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.campsites-table thead th::after {
|
||||
content: '\25B2';
|
||||
font-size: 0.8em;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.campsites-table thead th.asc::after {
|
||||
content: '\25B2';
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.campsites-table thead th.desc::after {
|
||||
content: '\25BC';
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.campsites-table tbody tr:nth-child(odd) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.campsites-table tbody tr:nth-child(even) {
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.campsites-table tbody td {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.campsites-table tbody tr:nth-child(even) td:first-child {
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
}
|
||||
|
||||
.campsites-table tbody tr:nth-child(even) td:last-child {
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
}
|
||||
|
||||
.filter-input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-radius: 25px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.campsite-group {
|
||||
color: #484848;
|
||||
background: #f9f9f7;
|
||||
border: 1px solid #d8d8d8;
|
||||
border-radius: 10px;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
$pageTitle = 'Campsites';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
|
||||
<section class="tour-list-page py-100 rel">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||||
<h3>Campsites Map</h3>
|
||||
<button class="theme-btn" id="toggleFormBtn" onclick="toggleCampsiteForm()">
|
||||
<i class="far fa-plus"></i> Add Campsite
|
||||
</button>
|
||||
</div>
|
||||
<p style="color: #666; margin-bottom: 15px;">Click on the map to add a new campsite, or click on a marker to view details.</p>
|
||||
|
||||
<!-- Collapsible Campsite Form -->
|
||||
<div class="campsite-form-container" id="campsiteFormContainer">
|
||||
<h5>Add New Campsite</h5>
|
||||
<form id="addCampsiteForm" method="POST" action="add_campsite" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
|
||||
<input type="hidden" name="latitude" id="latitude">
|
||||
<input type="hidden" name="longitude" id="longitude">
|
||||
|
||||
<div class="row mt-35">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="campsite_name">Campsite Name *</label>
|
||||
<input type="text" id="campsite_name" class="form-control" name="name" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="countrySelect">Country *</label>
|
||||
<select id="countrySelect" class="form-control" name="country" required>
|
||||
<option value="">-- Select Country --</option>
|
||||
<option value="South Africa">South Africa</option>
|
||||
<option value="Botswana">Botswana</option>
|
||||
<option value="Eswatini">Eswatini</option>
|
||||
<option value="Lesotho">Lesotho</option>
|
||||
<option value="Namibia">Namibia</option>
|
||||
<option value="Zimbabwe">Zimbabwe</option>
|
||||
<option value="Other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="provinceSelect">Province *</label>
|
||||
<select id="provinceSelect" class="form-control" name="province" required>
|
||||
<option value="">-- Select Province --</option>
|
||||
<option value="Eastern Cape">Eastern Cape</option>
|
||||
<option value="Free State">Free State</option>
|
||||
<option value="Gauteng">Gauteng</option>
|
||||
<option value="KwaZulu-Natal">KwaZulu-Natal</option>
|
||||
<option value="Limpopo">Limpopo</option>
|
||||
<option value="Mpumalanga">Mpumalanga</option>
|
||||
<option value="Northern Cape">Northern Cape</option>
|
||||
<option value="North West">North West</option>
|
||||
<option value="Western Cape">Western Cape</option>
|
||||
<option value="Other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="campsite_description">Description</label>
|
||||
<textarea id="campsite_description" class="form-control" name="description" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="campsite_website">Booking URL</label>
|
||||
<input type="url" id="campsite_website" class="form-control" name="website">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="campsite_phone">Phone Number</label>
|
||||
<input type="text" id="campsite_phone" class="form-control" name="telephone">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="latitude_display">Latitude</label>
|
||||
<input type="text" id="latitude_display" class="form-control" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="longitude_display">Longitude</label>
|
||||
<input type="text" id="longitude_display" class="form-control" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="campsite_thumbnail">Thumbnail Image</label>
|
||||
<input type="file" id="campsite_thumbnail" class="form-control" name="thumbnail" accept="image/*">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="form-group mb-0">
|
||||
<button class="theme-btn style-two" type="submit" style="width: 100%; margin-right: 10px;">Save Campsite</button>
|
||||
<button class="theme-btn" type="button" onclick="toggleCampsiteForm()" style="width: 100%; margin-top: 10px;">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="map" style="width: 100%; height: 500px;"></div>
|
||||
|
||||
<!-- Campsites Table -->
|
||||
<div style="margin-top: 40px;">
|
||||
<h4 style="margin-bottom: 20px;">All Campsites</h4>
|
||||
<input type="text" class="filter-input" id="campsitesFilter" placeholder="Filter results...">
|
||||
<div class="table-responsive">
|
||||
<table class="campsites-table">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Website</th>
|
||||
<th>Phone</th>
|
||||
<th>Added By</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="campsitesTableBody">
|
||||
<!-- Populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
let map;
|
||||
const campsites = <?php echo json_encode($campsites); ?>;
|
||||
|
||||
function toggleCampsiteForm() {
|
||||
const container = document.getElementById("campsiteFormContainer");
|
||||
container.style.display = container.style.display === "none" ? "block" : "none";
|
||||
if (container.style.display === "block") {
|
||||
container.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
// Clear the form
|
||||
document.getElementById("addCampsiteForm").reset();
|
||||
// Remove the ID input if it exists
|
||||
let idInput = document.querySelector("#addCampsiteForm input[name='id']");
|
||||
if (idInput) {
|
||||
idInput.remove();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
resetForm();
|
||||
document.getElementById("latitude").value = lat;
|
||||
document.getElementById("longitude").value = lng;
|
||||
document.getElementById("latitude_display").value = lat.toFixed(6);
|
||||
document.getElementById("longitude_display").value = lng.toFixed(6);
|
||||
|
||||
// Show the form container
|
||||
document.getElementById("campsiteFormContainer").style.display = "block";
|
||||
document.getElementById("campsiteFormContainer").scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
});
|
||||
|
||||
// Load existing campsites from PHP
|
||||
fetch("get_campsites")
|
||||
.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);
|
||||
});
|
||||
});
|
||||
|
||||
// Populate the table
|
||||
populateCampsitesTable(data);
|
||||
})
|
||||
.catch(err => console.error("Failed to load campsites:", err));
|
||||
}
|
||||
|
||||
function populateCampsitesTable(campsites) {
|
||||
const tableBody = document.getElementById("campsitesTableBody");
|
||||
tableBody.innerHTML = ""; // Clear existing rows
|
||||
|
||||
if (campsites.length === 0) {
|
||||
tableBody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="6" class="text-center text-muted" style="padding: 30px;">
|
||||
No campsites added yet. Click on the map to add one!
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// Group campsites by country and province
|
||||
const groupedByCountryAndProvince = {};
|
||||
campsites.forEach(site => {
|
||||
const country = site.country || 'Unknown Country';
|
||||
const province = site.province || 'Unknown Province';
|
||||
|
||||
if (!groupedByCountryAndProvince[country]) {
|
||||
groupedByCountryAndProvince[country] = {};
|
||||
}
|
||||
if (!groupedByCountryAndProvince[country][province]) {
|
||||
groupedByCountryAndProvince[country][province] = [];
|
||||
}
|
||||
groupedByCountryAndProvince[country][province].push(site);
|
||||
});
|
||||
|
||||
// Sort countries alphabetically
|
||||
const sortedCountries = Object.keys(groupedByCountryAndProvince).sort();
|
||||
|
||||
// Populate table with grouped data
|
||||
sortedCountries.forEach(country => {
|
||||
// Sort provinces alphabetically for this country
|
||||
const sortedProvinces = Object.keys(groupedByCountryAndProvince[country]).sort();
|
||||
|
||||
sortedProvinces.forEach(province => {
|
||||
// Add province group header
|
||||
const groupRow = document.createElement("tr");
|
||||
groupRow.innerHTML = `
|
||||
<td colspan="6" style="font-weight: 600; padding: 10px 8px; background-color: #f0f0f0;">
|
||||
<i class="fas fa-globe" style="color: #2196F3; margin-right: 8px;"></i>${country} - ${province}
|
||||
</td>
|
||||
`;
|
||||
tableBody.appendChild(groupRow);
|
||||
|
||||
// Add campsite rows for this province
|
||||
groupedByCountryAndProvince[country][province].forEach(site => {
|
||||
const row = document.createElement("tr");
|
||||
const userName = site.user && site.user.first_name
|
||||
? `${site.user.first_name} ${site.user.last_name}`
|
||||
: "Unknown";
|
||||
|
||||
row.innerHTML = `
|
||||
<td><strong>${site.name}</strong></td>
|
||||
<td>${site.description ? site.description.substring(0, 50) + (site.description.length > 50 ? '...' : '') : '-'}</td>
|
||||
<td>${site.website ? `<a href="${site.website}" target="_blank" class="link-primary">Visit</a>` : '-'}</td>
|
||||
<td>${site.telephone || '-'}</td>
|
||||
<td><small>${userName}</small></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-warning" 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">Directions</a>
|
||||
</td>
|
||||
`;
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function editCampsite(site) {
|
||||
// Pre-fill form
|
||||
document.querySelector("#addCampsiteForm input[name='name']").value = site.name;
|
||||
document.querySelector("#addCampsiteForm select[name='country']").value = site.country || '';
|
||||
document.querySelector("#addCampsiteForm select[name='province']").value = site.province || '';
|
||||
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;
|
||||
document.getElementById("latitude_display").value = parseFloat(site.latitude).toFixed(6);
|
||||
document.getElementById("longitude_display").value = parseFloat(site.longitude).toFixed(6);
|
||||
|
||||
// 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 form container
|
||||
document.getElementById("campsiteFormContainer").style.display = "block";
|
||||
document.getElementById("campsiteFormContainer").scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC-JuvnbUYc8WGjQBFFVZtKiv5_bFJoWLU&callback=initMap" async defer></script>
|
||||
|
||||
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,26 +1,23 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
|
||||
// SQL query to fetch dates for driver training
|
||||
$sql = "SELECT course_id, date FROM courses WHERE course_type = 'driver_training'";
|
||||
$result = $conn->query($sql);
|
||||
$stmt = $conn->prepare("SELECT course_id, date FROM courses WHERE course_type = ?");
|
||||
$course_type = 'driver_training';
|
||||
$stmt->bind_param("s", $course_type);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<!-- Page Banner Start -->
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url(assets/images/banner/banner.jpg);">
|
||||
<div class="container">
|
||||
<div class="banner-inner text-white">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">4X4 Driver Training</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">4X4 Driver Training</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php
|
||||
$pageTitle = 'Course Details';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
<!-- Page Banner End -->
|
||||
|
||||
<!-- Product Details Start -->
|
||||
@@ -303,4 +300,4 @@ $result = $conn->query($sql);
|
||||
<!-- Shop Details Area end -->
|
||||
|
||||
|
||||
<?php include_once('insta_footer.php') ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php') ?>
|
||||
@@ -1,13 +1,18 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkUserSession();
|
||||
|
||||
// SQL query to fetch dates for driver training
|
||||
$sql = "SELECT course_id, date
|
||||
$stmt = $conn->prepare("SELECT course_id, date
|
||||
FROM courses
|
||||
WHERE course_type = 'driver_training'
|
||||
AND date >= CURDATE()";
|
||||
|
||||
$result = $conn->query($sql);
|
||||
WHERE course_type = ?
|
||||
AND date >= CURDATE()");
|
||||
$course_type = 'driver_training';
|
||||
$stmt->bind_param("s", $course_type);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$page_id = 'driver_training';
|
||||
|
||||
?>
|
||||
@@ -22,32 +27,11 @@ $page_id = 'driver_training';
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||
if (!empty($bannerImages)) {
|
||||
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||
}
|
||||
</style><?php
|
||||
$pageTitle = 'Driver Training';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
<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">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">4X4 Driver Training</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">4X4 Driver Training</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
|
||||
<!-- Product Details Start -->
|
||||
<section class="product-details pt-100">
|
||||
@@ -98,7 +82,7 @@ if (!empty($bannerImages)) {
|
||||
<hr class="mt-40">
|
||||
<div class="blog-sidebar tour-sidebar">
|
||||
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<form action="process_course_booking.php" method="POST">
|
||||
<form action="process_course_booking" method="POST">
|
||||
<ul class="tickets clearfix">
|
||||
<li>
|
||||
Select Date
|
||||
@@ -189,7 +173,7 @@ if (!empty($bannerImages)) {
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</button>
|
||||
<div class="text-center">
|
||||
<a href="contact.php">Need some help?</a>
|
||||
<a href="contact">Need some help?</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -402,4 +386,4 @@ if (!empty($bannerImages)) {
|
||||
</script>
|
||||
|
||||
|
||||
<?php include_once('insta_footer.php') ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php') ?>
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
||||
checkUserSession();
|
||||
|
||||
if (!isset($_GET['token']) || empty($_GET['token'])) {
|
||||
@@ -10,12 +12,22 @@ $token = $_GET['token'];
|
||||
// Sanitize the trip_id to prevent SQL injection
|
||||
$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
|
||||
$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
|
||||
WHERE trip_id = ?";
|
||||
|
||||
// If not admin, only show published trips
|
||||
if (!$is_admin) {
|
||||
$sql .= " AND published = 1";
|
||||
}
|
||||
|
||||
// Use prepared statements for added security
|
||||
$stmt = $conn->prepare($sql);
|
||||
|
||||
@@ -148,7 +160,9 @@ $conn->close();
|
||||
/* Optional: makes non-member price stand out */
|
||||
}
|
||||
</style>
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
||||
?>
|
||||
|
||||
<style>
|
||||
@@ -185,17 +199,44 @@ $conn->close();
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50"><?php echo $trip_name; ?></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.php">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="index">Home</a></li>
|
||||
<li class="breadcrumb-item active">4WDCSA Trips</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</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>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Tour Gallery start -->
|
||||
<div class="tour-gallery">
|
||||
<div class="container-fluid">
|
||||
@@ -255,6 +296,8 @@ $conn->close();
|
||||
|
||||
</div>
|
||||
<span class="subtitle mb-15"><?php echo $badge_text; ?></span>
|
||||
|
||||
|
||||
</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="tour-header-social mb-10">
|
||||
@@ -433,7 +476,7 @@ $conn->close();
|
||||
<div class="blog-sidebar tour-sidebar">
|
||||
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<h5 class="widget-title">Book your Trip</h5>
|
||||
<form action="process_trip_booking.php" method="POST">
|
||||
<form action="process_trip_booking" method="POST">
|
||||
<input type="hidden" name="trip_id" id="trip_id" value="<?php echo $trip_id; ?>">
|
||||
<ul class="radio-filter pt-5">
|
||||
<li>
|
||||
@@ -556,7 +599,7 @@ $conn->close();
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<div class="text-center">
|
||||
<a href="contact.php">Need some help?</a>
|
||||
<a href="contact">Need some help?</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -669,4 +712,42 @@ $conn->close();
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once('insta_footer.php') ?>
|
||||
<!-- Trip Publish/Unpublish Script -->
|
||||
<script>
|
||||
function toggleTripPublished(tripId) {
|
||||
$.ajax({
|
||||
url: 'toggle_trip_published',
|
||||
type: 'POST',
|
||||
data: {
|
||||
trip_id: tripId
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if (response.status === 'success') {
|
||||
// Update button and status badge
|
||||
const publishBtn = $('#publishBtn');
|
||||
const statusBadge = $('#publishStatus');
|
||||
|
||||
if (response.published === 1) {
|
||||
publishBtn.html('<i class="fas fa-eye-slash"></i> Unpublish Trip');
|
||||
statusBadge.html('<span class="badge bg-success">Published</span>');
|
||||
} else {
|
||||
publishBtn.html('<i class="fas fa-eye"></i> Publish Trip');
|
||||
statusBadge.html('<span class="badge bg-warning">Draft</span>');
|
||||
}
|
||||
|
||||
// Show success message
|
||||
alert(response.message);
|
||||
} else {
|
||||
alert('Error: ' + response.message);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.log('Error:', error);
|
||||
alert('Error updating trip status');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php') ?>
|
||||
@@ -1,55 +1,32 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
// Determine the correct path to header.php based on file location
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
?>
|
||||
|
||||
<style>
|
||||
.image {
|
||||
width: 400px;
|
||||
/* Set your desired width */
|
||||
width: 100%;
|
||||
height: 350px;
|
||||
/* Set your desired height */
|
||||
overflow: hidden;
|
||||
/* Hide any overflow */
|
||||
display: block;
|
||||
/* Ensure proper block behavior */
|
||||
}
|
||||
|
||||
.image img {
|
||||
width: 100%;
|
||||
/* Image scales to fill the container */
|
||||
height: 100%;
|
||||
/* Image scales to fill the container */
|
||||
object-fit: cover;
|
||||
/* Fills the container while maintaining aspect ratio */
|
||||
object-position: top;
|
||||
/* Aligns the top of the image with the top of the container */
|
||||
display: block;
|
||||
/* Prevents inline whitespace issues */
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||
if (!empty($bannerImages)) {
|
||||
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||
}
|
||||
$pageTitle = 'Trips';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
<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">4WDCSA 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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">4WDCSA Trips</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Tour List Area start -->
|
||||
<section class="tour-list-page py-100 rel z-1">
|
||||
@@ -79,8 +56,17 @@ if (!empty($bannerImages)) {
|
||||
<?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
|
||||
$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);
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
@@ -95,16 +81,18 @@ if (!empty($bannerImages)) {
|
||||
$capacity = $row['vehicle_capacity'];
|
||||
$cost_members = $row['cost_members'];
|
||||
$places_booked = $row['places_booked'];
|
||||
$published = $row['published'] ?? 1;
|
||||
$remaining_places = getAvailableSpaces($trip_id);
|
||||
|
||||
// Determine the badge text based on the status
|
||||
$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
|
||||
echo '
|
||||
<div class="destination-item style-three bgc-lighter" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<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 . '">
|
||||
</div>
|
||||
<div class="content">
|
||||
@@ -118,7 +106,7 @@ if (!empty($bannerImages)) {
|
||||
<i class="fas fa-star"></i>
|
||||
</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>
|
||||
<ul class="blog-meta">
|
||||
<li><i class="far fa-calendar"></i> ' . convertDate($start_date) . ' - ' . convertDate($end_date) . '</li>
|
||||
@@ -127,7 +115,7 @@ if (!empty($bannerImages)) {
|
||||
</ul>
|
||||
<div class="destination-footer">
|
||||
<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>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
@@ -165,4 +153,4 @@ if (!empty($bannerImages)) {
|
||||
<!-- Tour List Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
$page_id = 'agm_minutes';
|
||||
?>
|
||||
|
||||
@@ -65,28 +68,15 @@ $page_id = 'agm_minutes';
|
||||
float: right;
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url('assets/images/blog/2/agm.jpg');">
|
||||
<div class="banner-overlay"></div>
|
||||
<div class="container">
|
||||
<div class="banner-inner text-white">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">2025 AGM Minutes & Chairman's Report</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">2025 AGM Minutes & Chairman's Report</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
|
||||
<?php
|
||||
$pageTitle = '2025 AGM Minutes';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
|
||||
<!-- Blog Detaisl Area start -->
|
||||
<section class="blog-detaisl-page py-100 rel z-1">
|
||||
@@ -112,7 +102,7 @@ $page_id = 'agm_minutes';
|
||||
<div class="item" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<h6>Tags </h6>
|
||||
<div class="tag-coulds">
|
||||
<a href="blog.php">Reports</a>
|
||||
<a href="blog">Reports</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -265,4 +255,4 @@ $page_id = 'agm_minutes';
|
||||
<!-- Blog Detaisl Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
$page_id = 'best_0f_ec';
|
||||
?>
|
||||
|
||||
@@ -65,31 +68,15 @@ $page_id = 'best_0f_ec';
|
||||
float: right;
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url('assets/images/blog/1/cover.jpg');">
|
||||
<div class="banner-overlay"></div>
|
||||
<div class="container">
|
||||
<div class="banner-inner text-white">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Best of the Eastern Cape 2024</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">Best of the Eastern Cape 2024</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
|
||||
<?php
|
||||
$pageTitle = 'Best of the Eastern Cape 2024';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
|
||||
<!-- Blog Detaisl Area start -->
|
||||
<section class="blog-detaisl-page py-100 rel z-1">
|
||||
@@ -350,10 +337,10 @@ $page_id = 'best_0f_ec';
|
||||
<h4>Richard M. Fudge</h4>
|
||||
<p>The world is a book, and those who do not travel read only one page. Every journey we undertake is a chapter filled with lessons, experiences, and stories.</p>
|
||||
<div class="social-icons">
|
||||
<a href="contact.php"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-twitter"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-linkedin-in"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-instagram"></i></a>
|
||||
<a href="contact"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="contact"><i class="fab fa-twitter"></i></a>
|
||||
<a href="contact"><i class="fab fa-linkedin-in"></i></a>
|
||||
<a href="contact"><i class="fab fa-instagram"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -445,4 +432,4 @@ $page_id = 'best_0f_ec';
|
||||
<!-- Blog Detaisl Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,8 @@
|
||||
<?php include_once('header02.php') ?>
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
?>
|
||||
|
||||
<style>
|
||||
.image {
|
||||
@@ -26,35 +30,11 @@
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||
if (!empty($bannerImages)) {
|
||||
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||
}
|
||||
</style><?php
|
||||
$pageTitle = 'Blogs';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url('<?php echo $randomBanner; ?>');">
|
||||
<!-- Overlay PNG -->
|
||||
<div class="banner-overlay"></div>
|
||||
<div class="container">
|
||||
<div class="banner-inner text-white">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Blogs</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">Blogs</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
|
||||
|
||||
<!-- Blog List Area start -->
|
||||
@@ -63,9 +43,12 @@ if (!empty($bannerImages)) {
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<?php
|
||||
// Query to retrieve data from the trips table
|
||||
$sql = "SELECT blog_id, title, date, category, image, description, author, members_only, link FROM blogs WHERE status = 'published' ORDER BY date DESC";
|
||||
$result = $conn->query($sql);
|
||||
// Query to retrieve data from blogs table
|
||||
$status = 'published';
|
||||
$stmt = $conn->prepare("SELECT blog_id, title, date, category, image, description, author, members_only, link FROM blogs WHERE status = ? ORDER BY date DESC");
|
||||
$stmt->bind_param("s", $status);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
// Loop through each row
|
||||
@@ -108,7 +91,7 @@ if (!empty($bannerImages)) {
|
||||
<img style="border-radius:20px;" src="assets/images/blog/' . $blog_id . '/' . $image . '" alt="Blog List">
|
||||
</div>
|
||||
<div class="content">
|
||||
<a href="blog.php" class="category">' . $category . '</a>
|
||||
<a href="' . url('blog') . '" class="category">' . $category . '</a>
|
||||
<h5><a href="' . $blog_link . '">' . $title . '</a></h5>
|
||||
<ul class="blog-meta">
|
||||
<li><i class="far fa-calendar-alt"></i> <a href="#">' . $date . '</a></li>
|
||||
@@ -222,7 +205,7 @@ if (!empty($bannerImages)) {
|
||||
<div class="content text-white">
|
||||
<span class="h6">Explore The World</span>
|
||||
<h3>Become a Member</h3>
|
||||
<a href="membership.php" class="theme-btn style-two bgc-secondary">
|
||||
<a href="<?= url('membership') ?>" class="theme-btn style-two bgc-secondary">
|
||||
<span data-hover="Explore Now">Join Now</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
@@ -242,4 +225,4 @@ if (!empty($bannerImages)) {
|
||||
<!-- Blog List Area end -->
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,8 @@
|
||||
<?php include_once('header02.php') ?>
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
?>
|
||||
|
||||
<style>
|
||||
.image {
|
||||
@@ -29,20 +33,11 @@
|
||||
|
||||
|
||||
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url('assets/images/blog/1/cover.jpg');">
|
||||
<div class="container">
|
||||
<div class="banner-inner text-white">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Best of the Eastern Cape 2024</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">Best of the Eastern Cape 2024</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
<?php
|
||||
$pageTitle = 'Blog Details';
|
||||
$breadcrumbs = [['Home' => 'index.php'], ['Blogs' => 'blog.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
|
||||
|
||||
<!-- Blog Detaisl Area start -->
|
||||
@@ -198,10 +193,10 @@
|
||||
<h4>Richard M. Fudge</h4>
|
||||
<p>The world is a book, and those who do not travel read only one page. Every journey we undertake is a chapter filled with lessons, experiences, and stories.</p>
|
||||
<div class="social-icons">
|
||||
<a href="contact.php"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-twitter"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-linkedin-in"></i></a>
|
||||
<a href="contact.php"><i class="fab fa-instagram"></i></a>
|
||||
<a href="contact"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="contact"><i class="fab fa-twitter"></i></a>
|
||||
<a href="contact"><i class="fab fa-linkedin-in"></i></a>
|
||||
<a href="contact"><i class="fab fa-instagram"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -449,7 +444,7 @@
|
||||
<ul class="list-style-three">
|
||||
<li><a href="about.html">About Company</a></li>
|
||||
<li><a href="blog.html">Community Blog</a></li>
|
||||
<li><a href="contact.php">Jobs and Careers</a></li>
|
||||
<li><a href="contact">Jobs and Careers</a></li>
|
||||
<li><a href="blog.html">latest News Blog</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -1,4 +1,8 @@
|
||||
<?php include_once('header02.php') ?>
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
?>
|
||||
|
||||
<style>
|
||||
.image {
|
||||
@@ -52,41 +56,13 @@
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.custom-modal-close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 20px;
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||
if (!empty($bannerImages)) {
|
||||
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||
}
|
||||
$pageTitle = 'Events';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
<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">4WDCSA events</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">4WDCSA Events</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Tour List Area start -->
|
||||
<section class="tour-list-page py-100 rel z-1">
|
||||
@@ -114,10 +90,10 @@ if (!empty($bannerImages)) {
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Query to retrieve data from the trips table
|
||||
$sql = "SELECT event_id, date, time, name, image, description, feature, location, type, promo FROM events WHERE date > CURDATE() ORDER BY date ASC";
|
||||
|
||||
$result = $conn->query($sql);
|
||||
// Query to retrieve upcoming events
|
||||
$stmt = $conn->prepare("SELECT event_id, date, time, name, image, description, feature, location, type, promo FROM events WHERE date > CURDATE() ORDER BY date ASC");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
// Loop through each row
|
||||
@@ -217,4 +193,4 @@ if (!empty($bannerImages)) {
|
||||
</script>
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
include_once('header02.php');
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
||||
checkAdmin();
|
||||
if (!isset($_GET['token']) || empty($_GET['token'])) {
|
||||
die("Invalid request.");
|
||||
@@ -277,4 +278,4 @@ $stmt->close();
|
||||
</script>
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,45 +1,25 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
||||
|
||||
// Assuming you have the user ID stored in the session
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
if (isset($_SESSION['user_id']) && isset($conn) && $conn !== null) {
|
||||
$user_id = $_SESSION['user_id'];
|
||||
// Fetch user data from the database
|
||||
$sql = "SELECT * FROM users WHERE user_id = ?";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param("i", $user_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$user = $result->fetch_assoc();
|
||||
} else {
|
||||
$user = null;
|
||||
}
|
||||
|
||||
// Fetch user data from the database
|
||||
|
||||
$sql = "SELECT * FROM users WHERE user_id = ?";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param("i", $user_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$user = $result->fetch_assoc();
|
||||
?><?php
|
||||
$pageTitle = 'Membership';
|
||||
$breadcrumbs = [['Home' => 'index.php']];
|
||||
require_once(dirname(dirname(dirname(__DIR__))) . '/components/banner.php');
|
||||
?>
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$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">
|
||||
<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.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">Membership</li>
|
||||
<li class="breadcrumb-item ">Application</li>
|
||||
<li class="breadcrumb-item ">Indemnity</li>
|
||||
<li class="breadcrumb-item ">Payment</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
<!-- Contact Form Area start -->
|
||||
<section class="about-us-area py-100 rpb-90 rel z-1">
|
||||
<div class="container">
|
||||
@@ -62,7 +42,7 @@ if (!empty($bannerImages)) {
|
||||
<h2>R 2,500/year</h2>
|
||||
<p>We go above and beyond to make your travel dreams reality hidden gems and must-see
|
||||
attractions</p>
|
||||
<a href="membership_application.php" class="theme-btn mt-10 style-two">
|
||||
<a href="membership_application" class="theme-btn mt-10 style-two">
|
||||
<span data-hover="Start Application">Start Application</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
@@ -90,4 +70,4 @@ if (!empty($bannerImages)) {
|
||||
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkUserSession();
|
||||
|
||||
// Assuming you have the user ID stored in the session
|
||||
@@ -18,34 +21,11 @@ $stmt->bind_param("i", $user_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$user = $result->fetch_assoc();
|
||||
?><?php
|
||||
$pageTitle = 'Membership Application';
|
||||
$breadcrumbs = [['Home' => 'index.php'], ['Membership' => 'membership.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$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">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Application</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item ">Membership</li>
|
||||
<li class="breadcrumb-item active">Application</li>
|
||||
<li class="breadcrumb-item ">Indemnity</li>
|
||||
<li class="breadcrumb-item ">Payment</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
|
||||
|
||||
|
||||
@@ -54,7 +34,7 @@ if (!empty($bannerImages)) {
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55">
|
||||
<form id="registerForm" name="registerForm" action="process_application.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<form id="registerForm" name="registerForm" action="process_application" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
|
||||
<div class="section-title">
|
||||
<div id="responseMessage"></div> <!-- Message display area -->
|
||||
@@ -301,4 +281,4 @@ if (!empty($bannerImages)) {
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
include_once('header02.php');
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
||||
|
||||
// Ensure the user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
@@ -186,7 +187,7 @@ if (empty($application['id_number'])) {
|
||||
<td><?php echo htmlspecialchars($membership['payment_amount']); ?></td>
|
||||
<td><?php echo htmlspecialchars($membership['payment_id']); ?></td>
|
||||
<?php if ($membership['payment_status'] == "PENDING") { ?>
|
||||
<td><a href='membership_payment.php' class='theme-btn style-two style-three' style='padding: 0px 14px;'><span data-hover='VIEW PAYMENT INFO'>AWAITING PAYMENT</span></a></td>
|
||||
<td><a href='membership_payment' class='theme-btn style-two style-three' style='padding: 0px 14px;'><span data-hover='VIEW PAYMENT INFO'>AWAITING PAYMENT</span></a></td>
|
||||
<?php } else { ?>
|
||||
<td><?php echo htmlspecialchars($membership['payment_status']); ?></td>
|
||||
<?php } ?>
|
||||
@@ -209,13 +210,13 @@ if (empty($application['id_number'])) {
|
||||
|
||||
if ($membership_end_date && strtotime($today) > strtotime($membership_end_date)) {
|
||||
echo '
|
||||
<a href="renew_membership.php" class="theme-btn style-two bgc-secondary" style="width:100%; margin-top: 20px; background-color: #63ab45; padding: 10px 20px; color: white; text-decoration: none; border-radius: 25px;">
|
||||
<a href="renew_membership" class="theme-btn style-two bgc-secondary" style="width:100%; margin-top: 20px; background-color: #63ab45; padding: 10px 20px; color: white; text-decoration: none; border-radius: 25px;">
|
||||
<span data-hover="Renew Membership">Renew Membership</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>';
|
||||
}
|
||||
?>
|
||||
<form id="infoForm" name="registerForm" action="update_application.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<form id="infoForm" name="registerForm" action="update_application" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="section-title">
|
||||
<div id="responseMessage"></div> <!-- Message display area -->
|
||||
</div>
|
||||
@@ -475,7 +476,7 @@ if (empty($application['id_number'])) {
|
||||
formData.append('profile_picture', $('#profile_picture')[0].files[0]);
|
||||
|
||||
$.ajax({
|
||||
url: 'upload_profile_picture.php',
|
||||
url: 'upload_profile_picture',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
contentType: false,
|
||||
@@ -508,7 +509,7 @@ if (empty($application['id_number'])) {
|
||||
event.preventDefault(); // Prevent default form submission
|
||||
|
||||
$.ajax({
|
||||
url: 'update_user.php',
|
||||
url: 'update_user',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
success: function(response) {
|
||||
@@ -535,7 +536,7 @@ if (empty($application['id_number'])) {
|
||||
event.preventDefault(); // Prevent default form submission
|
||||
|
||||
$.ajax({
|
||||
url: 'change_password.php',
|
||||
url: 'change_password',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
success: function(response) {
|
||||
@@ -558,4 +559,4 @@ if (empty($application['id_number'])) {
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(dirname(__DIR__)));
|
||||
include_once($rootPath . '/header.php');
|
||||
// Assuming you have the user ID stored in the session
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$user_id = $_SESSION['user_id'];
|
||||
@@ -65,36 +68,11 @@ $stmt->fetch();
|
||||
$stmt->close();
|
||||
|
||||
$conn->close();
|
||||
?><?php
|
||||
$pageTitle = 'Membership Payment';
|
||||
$breadcrumbs = [['Home' => 'index.php'], ['Membership' => 'membership.php']];
|
||||
require_once($rootPath . '/components/banner.php');
|
||||
?>
|
||||
|
||||
|
||||
<?php
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$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">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Payment</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.php">Home</a></li>
|
||||
<li class="breadcrumb-item ">Membership</li>
|
||||
<li class="breadcrumb-item ">Application</li>
|
||||
<li class="breadcrumb-item ">Indemnity</li>
|
||||
<li class="breadcrumb-item active">Payment</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Page Banner End -->
|
||||
<!-- Contact Form Area start -->
|
||||
<section class="about-us-area py-100 rpb-90 rel z-1">
|
||||
<div class="container">
|
||||
@@ -108,7 +86,7 @@ if (!empty($bannerImages)) {
|
||||
<p>Your invoice has been sent to <b><?php echo htmlspecialchars($user_email); ?></b>. Please upload your proof of payment below.</p>
|
||||
<h5>Payment Details:</h5>
|
||||
<p>The Four Wheel Drive Club of Southern Africa<br>FNB<br>Account Number: 58810022334<br>Branch code: 250655<br>Reference: <?php echo htmlspecialchars($eft_id); ?><br>Amount: R <?php echo number_format($payment_amount, 2); ?></p>
|
||||
<a href="submit_pop.php" class="theme-btn style-two style-three" style="width:100%;">
|
||||
<a href="submit_pop" class="theme-btn style-two style-three" style="width:100%;">
|
||||
<span data-hover="Submit Proof of Payment">Submit Proof of Payment</span>
|
||||
<i class="fal fa-arrow-right"></i>
|
||||
</a>
|
||||
@@ -124,4 +102,4 @@ if (!empty($bannerImages)) {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php include_once('header02.php');
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
include_once(dirname(dirname(dirname(__DIR__))) . '/header.php');
|
||||
?>
|
||||
|
||||
|
||||
@@ -41,4 +43,4 @@
|
||||
</section>
|
||||
<!-- 404 Error Area end -->
|
||||
|
||||
<?php include_once("insta_footer.php"); ?>
|
||||
<?php include_once(dirname(dirname(dirname(__DIR__))) . '/components/insta_footer.php'); ?>
|
||||