diff --git a/view-doc.php/parker-view-doc.php b/view-doc.php
similarity index 100%
rename from view-doc.php/parker-view-doc.php
rename to view-doc.php
diff --git a/view-doc.php/parker-admin.php b/view-doc.php/parker-admin.php
deleted file mode 100644
index 05cfcce..0000000
--- a/view-doc.php/parker-admin.php
+++ /dev/null
@@ -1,2233 +0,0 @@
-prepare("INSERT INTO admin_tokens (token, expires_at) VALUES (?, ?)")
- ->execute([$token, date('Y-m-d H:i:s', time() + 86400)]);
- db()->exec("DELETE FROM admin_tokens WHERE expires_at < NOW()");
- return $token;
-}
-function _verifyToken(string $token): bool {
- if (!preg_match('/^[a-f0-9]{64}$/', $token)) return false;
- $stmt = db()->prepare("SELECT token FROM admin_tokens WHERE token=? AND expires_at > NOW()");
- $stmt->execute([$token]);
- return (bool)$stmt->fetch();
-}
-
-$isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) || (($_SERVER['HTTP_ACCEPT'] ?? '') === 'application/json');
-
-// ── Auth ──────────────────────────────────────────────────────────────────────
-if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'login') {
- if (($_POST['username'] ?? '') === ADMIN_USER && password_verify($_POST['password'] ?? '', ADMIN_PASS)) {
- $t = _createToken();
- header('Location: /admin/?_t=' . $t);
- } else {
- header('Location: /admin/?err=1');
- }
- exit;
-}
-$rawToken = preg_replace('/[^a-f0-9]/', '', $_GET['_t'] ?? $_POST['_t'] ?? '');
-if (($_GET['action'] ?? '') === 'logout') {
- if ($rawToken) db()->prepare("DELETE FROM admin_tokens WHERE token=?")->execute([$rawToken]);
- header('Location: /admin/'); exit;
-}
-$authed = $rawToken !== '' && _verifyToken($rawToken);
-$token = $authed ? $rawToken : '';
-
-// ── AJAX handlers ─────────────────────────────────────────────────────────────
-if ($isAjax && !$authed) {
- http_response_code(401);
- header('Content-Type: application/json');
- echo json_encode(['error'=>'Session expired. Please log in again.']);
- exit;
-}
-if ($isAjax) {
- header('Content-Type: application/json');
- $action = $_POST['action'] ?? $_GET['action'] ?? '';
-
- if ($action === 'update_status') {
- $id = (int)($_POST['id'] ?? 0);
- $status = $_POST['status'] ?? '';
- $allowed = ['pending','confirmed','completed','cancelled'];
- if ($id && in_array($status, $allowed)) {
- db()->prepare("UPDATE bookings SET status=? WHERE id=?")->execute([$status, $id]);
- echo json_encode(['ok'=>true]);
- } else { echo json_encode(['error'=>'Invalid']); }
- exit;
- }
-
- if ($action === 'save_admin_notes') {
- $id = (int)($_POST['id'] ?? 0);
- $notes = substr(trim($_POST['notes'] ?? ''), 0, 1000);
- db()->prepare("UPDATE bookings SET admin_notes=? WHERE id=?")->execute([$notes, $id]);
- echo json_encode(['ok'=>true]);
- exit;
- }
-
- if ($action === 'toggle_requirement') {
- $id = (int)($_POST['id'] ?? 0);
- $field = $_POST['field'] ?? '';
- $allowed_fields = ['insurance_verified','deposit_received','license_verified','helmet_provided','safety_course','operational_course'];
- if ($id && in_array($field, $allowed_fields)) {
- $stmt = db()->prepare("SELECT `{$field}` FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $current = (int)$stmt->fetchColumn();
- $new = $current ? 0 : 1;
- db()->prepare("UPDATE bookings SET `{$field}`=? WHERE id=?")->execute([$new, $id]);
- echo json_encode(['ok'=>true,'value'=>$new]);
- } else { echo json_encode(['error'=>'Invalid']); }
- exit;
- }
-
- if ($action === 'send_reminder') {
- $id = (int)($_POST['id'] ?? 0);
- $keys = array_filter(explode(',', $_POST['items'] ?? ''));
- $stmt = db()->prepare("SELECT * FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $b = $stmt->fetch();
- if (!$b) { echo json_encode(['error'=>'Not found']); exit; }
-
- $pkg = PACKAGES[$b['package']] ?? ['label' => $b['package']];
- $dateLabel = date('F j, Y', strtotime($b['rental_date']));
- $ref = $b['booking_ref'];
-
- $itemDefs = [
- 'waiver' => [
- 'label' => 'Sign Your Rental Agreement',
- 'detail' => 'Your digital rental agreement still needs to be signed before your pickup. It only takes a minute and can be done on any device — no printer required.',
- 'cta' => "
",
- ],
- 'insurance' => [
- 'label' => 'Proof of Personal Auto Insurance',
- 'detail' => 'You\'ll need to show proof of valid personal auto insurance at pickup. To speed things up, you can upload it now — a photo of your insurance card is fine.',
- 'cta' => "",
- ],
- 'deposit' => [
- 'label' => 'Balance Due at Pickup',
- 'detail' => 'Your $' . number_format(DEPOSIT_AMOUNT, 2) . ' deposit hold has been placed on your card. The remaining balance is due at pickup — cash or card accepted. Your deposit hold will be released upon safe return of the vehicle.',
- 'cta' => '',
- ],
- 'license' => [
- 'label' => "Valid Driver's License",
- 'detail' => "Please bring your valid driver's license to pickup — we'll verify it before you head out. You can also upload a photo in advance to keep things moving at arrival.",
- 'cta' => "",
- ],
- ];
-
- $rowsHtml = '';
- $n = 1;
- foreach ($keys as $key) {
- if (!isset($itemDefs[$key])) continue;
- $d = $itemDefs[$key];
- $rowsHtml .= "
-
-
- {$n}
-
-
- " . htmlspecialchars($d['label']) . "
- " . htmlspecialchars($d['detail']) . "
- {$d['cta']}
-
- ";
- $n++;
- }
-
- if (!$rowsHtml) { echo json_encode(['error'=>'No items selected']); exit; }
-
- $html = "
-
-
-
Parker County Slingshot Rentals
-
-
-
Almost Ready — A Few Things Before Pickup
-
Hey " . htmlspecialchars($b['name']) . ", your " . htmlspecialchars($pkg['label']) . " rental on {$dateLabel} is coming up! (Ref: {$ref} )
-
To make sure pickup goes smoothly, here's what still needs to be taken care of:
-
-
-
Questions? Call or text (817) 555-0199 or reply to this email — we're happy to help.
-
-
Ride on,The Parker County Slingshot Team
-
-
-
© " . date('Y') . " Parker County Slingshot Rentals — Weatherford, TX
-
-
";
-
- $sent = sendEmail($b['email'], $b['name'], "Action Needed Before Your Rental — {$ref}", $html);
- if ($sent) {
- echo json_encode(['ok'=>true]);
- } else {
- echo json_encode(['ok'=>false,'error'=>'Email service not configured. Set MAILJET_API_KEY and MAILJET_SECRET_KEY in db.php.']);
- }
- exit;
- }
-
- if ($action === 'square_capture') {
- $id = (int)($_POST['id'] ?? 0);
- $stmt = db()->prepare("SELECT square_payment_id FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $b = $stmt->fetch();
- $pid = $b['square_payment_id'] ?? '';
- if (!$pid) { echo json_encode(['error'=>'No payment on file']); exit; }
- $resp = squareApi('POST', "/payments/{$pid}/complete");
- if (($resp['payment']['status'] ?? '') === 'COMPLETED') {
- db()->prepare("UPDATE bookings SET square_payment_status='COMPLETED', deposit_paid=?, deposit_received=1 WHERE id=?")
- ->execute([DEPOSIT_AMOUNT, $id]);
- echo json_encode(['ok'=>true,'status'=>'COMPLETED']);
- } else {
- echo json_encode(['error' => $resp['errors'][0]['detail'] ?? 'Capture failed']);
- }
- exit;
- }
-
- if ($action === 'square_void') {
- $id = (int)($_POST['id'] ?? 0);
- $stmt = db()->prepare("SELECT square_payment_id FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $b = $stmt->fetch();
- $pid = $b['square_payment_id'] ?? '';
- if (!$pid) { echo json_encode(['error'=>'No payment on file']); exit; }
- $resp = squareApi('POST', "/payments/{$pid}/cancel");
- if (($resp['payment']['status'] ?? '') === 'CANCELED') {
- db()->prepare("UPDATE bookings SET square_payment_status='CANCELED', status='cancelled' WHERE id=?")->execute([$id]);
- echo json_encode(['ok'=>true,'status'=>'CANCELED']);
- } else {
- echo json_encode(['error' => $resp['errors'][0]['detail'] ?? 'Void failed']);
- }
- exit;
- }
-
- if ($action === 'square_refund') {
- $id = (int)($_POST['id'] ?? 0);
- $stmt = db()->prepare("SELECT square_payment_id, deposit_paid FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $b = $stmt->fetch();
- $pid = $b['square_payment_id'] ?? '';
- if (!$pid) { echo json_encode(['error'=>'No payment on file']); exit; }
- $cents = (int)(((float)($b['deposit_paid'] ?: DEPOSIT_AMOUNT)) * 100);
- $resp = squareApi('POST', '/refunds', [
- 'idempotency_key' => $pid . '-refund-' . time(),
- 'payment_id' => $pid,
- 'amount_money' => ['amount' => $cents, 'currency' => 'USD'],
- 'reason' => 'Security deposit refund — booking returned in good condition',
- ]);
- if (!empty($resp['refund']['id'])) {
- db()->prepare("UPDATE bookings SET square_payment_status='REFUNDED', square_refund_id=?, deposit_paid=0, status='cancelled' WHERE id=?")
- ->execute([$resp['refund']['id'], $id]);
- echo json_encode(['ok'=>true,'status'=>'REFUNDED']);
- } else {
- echo json_encode(['error' => $resp['errors'][0]['detail'] ?? 'Refund failed']);
- }
- exit;
- }
-
- if ($action === 'charge_balance') {
- $id = (int)($_POST['id'] ?? 0);
- $stmt = db()->prepare("SELECT * FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $b = $stmt->fetch();
- if (!$b) { echo json_encode(['error'=>'Not found']); exit; }
- $cardId = $b['square_card_id'] ?? '';
- $customerId = $b['square_customer_id'] ?? '';
- if (!$cardId) { echo json_encode(['error'=>'No card on file']); exit; }
- $balance = (float)$b['amount'] - DEPOSIT_AMOUNT;
- if ($balance <= 0) { echo json_encode(['error'=>'No balance due']); exit; }
- $cents = (int)($balance * 100);
- $payBody = [
- 'source_id' => $cardId,
- 'idempotency_key' => $b['booking_ref'] . '-bal-' . time(),
- 'amount_money' => ['amount' => $cents, 'currency' => 'USD'],
- 'autocomplete' => true,
- 'location_id' => SQUARE_LOCATION_ID,
- 'note' => "Balance charge — booking " . $b['booking_ref'],
- 'reference_id' => $b['booking_ref'],
- ];
- if ($customerId) $payBody['customer_id'] = $customerId;
- $resp = squareApi('POST', '/payments', $payBody);
- if (!empty($resp['payment']['id'])) {
- $pid = $resp['payment']['id'];
- db()->prepare("UPDATE bookings SET square_payment_status='BAL_COMPLETED', deposit_received=1 WHERE id=?")
- ->execute([$id]);
- echo json_encode(['ok'=>true,'payment_id'=>$pid,'amount'=>$balance]);
- } else {
- $errCode = $resp['errors'][0]['code'] ?? '';
- $errMsg = match($errCode) {
- 'CARD_DECLINED','CARD_DECLINED_VERIFICATION_REQUIRED' => 'Card was declined.',
- 'INSUFFICIENT_FUNDS' => 'Insufficient funds.',
- default => $resp['errors'][0]['detail'] ?? 'Charge failed.',
- };
- echo json_encode(['error'=>$errMsg]);
- }
- exit;
- }
-
- if ($action === 'update_card') {
- $id = (int)($_POST['id'] ?? 0);
- $nonce = trim($_POST['nonce'] ?? '');
- if (!$id || !$nonce) { echo json_encode(['error'=>'Missing data']); exit; }
- $stmt = db()->prepare("SELECT * FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $b = $stmt->fetch();
- if (!$b) { echo json_encode(['error'=>'Not found']); exit; }
-
- // Disable old card if exists
- $oldCardId = $b['square_card_id'] ?? '';
- if ($oldCardId) squareApi('POST', "/cards/{$oldCardId}/disable");
-
- // Get or create Square customer
- $customerId = $b['square_customer_id'] ?? '';
- if (!$customerId) {
- $custResp = squareApi('POST', '/customers', [
- 'idempotency_key' => $b['booking_ref'] . '-cust2',
- 'given_name' => $b['name'],
- 'email_address' => $b['email'],
- 'phone_number' => $b['phone'] ?: null,
- 'reference_id' => $b['booking_ref'],
- ]);
- $customerId = $custResp['customer']['id'] ?? null;
- }
-
- // Create new card on file
- $cardBody = ['idempotency_key'=>$b['booking_ref'].'-card-'.time(),'source_id'=>$nonce,'card'=>['cardholder_name'=>$b['name']]];
- if ($customerId) $cardBody['card']['customer_id'] = $customerId;
- $cardResp = squareApi('POST', '/cards', $cardBody);
- $newCardId = $cardResp['card']['id'] ?? null;
- $last4 = $cardResp['card']['last_4'] ?? null;
- $brand = $cardResp['card']['card_brand'] ?? null;
- if (!$newCardId) {
- echo json_encode(['error' => $cardResp['errors'][0]['detail'] ?? 'Could not save card']); exit;
- }
- db()->prepare("UPDATE bookings SET square_customer_id=?, square_card_id=?, card_last4=?, card_brand=? WHERE id=?")
- ->execute([$customerId, $newCardId, $last4, $brand, $id]);
- echo json_encode(['ok'=>true,'last4'=>$last4,'brand'=>$brand]);
- exit;
- }
-
- if ($action === 'mark_returned') {
- $id = (int)($_POST['id'] ?? 0);
- if (!$id) { echo json_encode(['error'=>'Invalid']); exit; }
- $stmt = db()->prepare("SELECT * FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $b = $stmt->fetch();
- if (!$b) { echo json_encode(['error'=>'Not found']); exit; }
- // Mark returned, set completed, wipe card data
- db()->prepare("UPDATE bookings SET slingshot_returned=1, returned_at=NOW(), status='completed',
- square_card_id=NULL, card_last4=NULL, card_brand=NULL, square_customer_id=NULL
- WHERE id=?")
- ->execute([$id]);
- echo json_encode(['ok'=>true]);
- exit;
- }
-
- if ($action === 'block_date') {
- $date = $_POST['date'] ?? '';
- $reason = substr($_POST['reason'] ?? '', 0, 200);
- if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
- db()->prepare("INSERT IGNORE INTO blocked_dates (block_date, reason) VALUES (?,?)")->execute([$date, $reason]);
- $newId = (int)db()->lastInsertId();
- echo json_encode(['ok'=>true, 'id'=>$newId, 'date'=>$date, 'reason'=>$reason]);
- } else { echo json_encode(['error'=>'Invalid date']); }
- exit;
- }
- if ($action === 'unblock_date') {
- $id = (int)($_POST['id'] ?? 0);
- db()->prepare("DELETE FROM blocked_dates WHERE id=?")->execute([$id]);
- echo json_encode(['ok'=>true]);
- exit;
- }
-
- if ($action === 'update_email') {
- $id = (int)($_POST['id'] ?? 0);
- $email = trim($_POST['email'] ?? '');
- if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { echo json_encode(['error'=>'Invalid email']); exit; }
- db()->prepare("UPDATE bookings SET email=? WHERE id=?")->execute([$email, $id]);
- echo json_encode(['ok'=>true,'email'=>$email]);
- exit;
- }
-
- if ($action === 'resend_confirmation') {
- $id = (int)($_POST['id'] ?? 0);
- $email = trim($_POST['email'] ?? '');
- $stmt = db()->prepare("SELECT * FROM bookings WHERE id=?");
- $stmt->execute([$id]);
- $b = $stmt->fetch();
- if (!$b) { echo json_encode(['error'=>'Not found']); exit; }
- if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $email = $b['email'];
- $pkg = PACKAGES[$b['package']] ?? ['label'=>$b['package'],'price'=>$b['amount']];
- $dateLabel = date('F j, Y', strtotime($b['rental_date']));
- $ref = $b['booking_ref'];
- $amtLabel = '$' . number_format((float)$b['amount'], 2);
- $depLabel = '$' . number_format(DEPOSIT_AMOUNT, 2);
- $balLabel = '$' . number_format(max(0, (float)$b['amount'] - DEPOSIT_AMOUNT), 2);
- $confirmHtml = "
-
-
Parker County Slingshot Rentals
-
-
-
Booking Confirmation
-
Hey " . htmlspecialchars($b['name']) . ", here's a copy of your booking confirmation.
-
-
Booking Reference
-
{$ref}
-
Package: " . htmlspecialchars($pkg['label']) . "
-
Date: {$dateLabel}
-
Total: {$amtLabel}
-
Deposit hold: {$depLabel}
-
Balance at pickup: {$balLabel}
-
-
-
Questions? Call or text " . ADMIN_PHONE . " or reply to this email.
-
Ride on,The Parker County Slingshot Team
-
-
-
© " . date('Y') . " Parker County Slingshot Rentals — Weatherford, TX
-
-
";
- $sent = sendEmail($email, $b['name'], "Booking Confirmation {$ref} — Parker County Slingshot Rentals", $confirmHtml);
- echo json_encode($sent ? ['ok'=>true,'email'=>$email] : ['error'=>'Email send failed — check Mailjet credentials']);
- exit;
- }
-
- if ($action === 'customer_save') {
- $cid = (int)($_POST['id'] ?? 0);
- $name = substr(trim($_POST['name'] ?? ''), 0, 150);
- $email = trim($_POST['email'] ?? '');
- $phone = substr(trim($_POST['phone'] ?? ''), 0, 30);
- $dob = preg_match('/^\d{4}-\d{2}-\d{2}$/', $_POST['dob'] ?? '') ? $_POST['dob'] : null;
- $addr = substr(trim($_POST['address'] ?? ''), 0, 500);
- $notes = substr(trim($_POST['notes'] ?? ''), 0, 1000);
- $active = (int)($_POST['is_active'] ?? 1);
- if (!$name || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
- echo json_encode(['error' => 'Name and valid email are required']); exit;
- }
- if ($cid) {
- db()->prepare("UPDATE pcs_customers SET name=?,email=?,phone=?,dob=?,address=?,notes=?,is_active=? WHERE id=?")
- ->execute([$name,$email,$phone,$dob,$addr,$notes,$active,$cid]);
- } else {
- db()->prepare("INSERT INTO pcs_customers (name,email,phone,dob,address,notes,is_active) VALUES (?,?,?,?,?,?,?)")
- ->execute([$name,$email,$phone,$dob,$addr,$notes,1]);
- $cid = (int)db()->lastInsertId();
- }
- echo json_encode(['ok'=>true,'id'=>$cid]); exit;
- }
-
- if ($action === 'customer_delete') {
- $cid = (int)($_POST['id'] ?? 0);
- if ($cid) db()->prepare("DELETE FROM pcs_customers WHERE id=?")->execute([$cid]);
- echo json_encode(['ok'=>true]); exit;
- }
-
- exit;
-}
-
-// ── Login page ─────────────────────────────────────────────────────────────────
-if (!$authed) { ?>
-
-
-
-
-Admin Login — Parker County Slingshot Rentals
-
-
-
-
-
Parker Admin
-
Slingshot Rentals Management
-
-
Invalid username or password.
-
-
-
-
-
-query("SELECT * FROM bookings ORDER BY rental_date ASC, created_at DESC")->fetchAll();
-$blocked = db()->query("SELECT * FROM blocked_dates ORDER BY block_date ASC")->fetchAll();
-$customers = db()->query("
- SELECT c.*
- FROM pcs_customers c ORDER BY c.created_at DESC
-")->fetchAll();
-// Group bookings by customer email in PHP (avoids cross-table collation issues)
-$bookingsByEmail = [];
-foreach ($bookings as $_b) {
- $bookingsByEmail[strtolower(trim($_b['email']))][] = $_b;
-}
-
-$stats = db()->query("
- SELECT
- COUNT(*) AS total,
- SUM(status='pending') AS pending,
- SUM(status='confirmed') AS confirmed,
- SUM(status='completed') AS completed,
- SUM(status='cancelled') AS cancelled,
- SUM(CASE WHEN status IN ('confirmed','completed') THEN amount ELSE 0 END) AS revenue,
- SUM(waiver_signed) AS waivers_signed,
- SUM(insurance_verified) AS insurance_done,
- SUM(deposit_received) AS deposits_done
- FROM bookings
-")->fetch();
-?>
-
-
-
-
-Admin — Parker County Slingshot Rentals
-
-
-
-
- Parker County Slingshot — Admin
- Sign Out
-
-
-
-
-
-
= (int)$stats['total'] ?>
Total Bookings
-
= (int)$stats['pending'] ?>
Pending
-
= (int)$stats['confirmed'] ?>
Confirmed
-
= (int)$stats['completed'] ?>
Completed
-
$= number_format((float)$stats['revenue'],0) ?>
Revenue
-
= (int)$stats['waivers_signed'] ?>
Waivers Signed
-
= (int)$stats['insurance_done'] ?>
Insurance OK
-
= (int)$stats['deposits_done'] ?>
Deposits Rcvd
-
-
-
-
-
-
-
-
No bookings found.
-
-
-
-
-
-
- Customer
- Rental Date
- Package
- Amount
- Status
- Progress
- Submitted
-
-
-
- $b['package']];
-
- // Determine each step's state
- $stepConfirmed = in_array($b['status'], ['confirmed','completed']);
- $stepWaiver = (bool)$b['waiver_signed'];
- $stepInsurance = (bool)$b['insurance_verified'];
- $insFile = $b['insurance_file'] ?? '';
- $stepDeposit = (bool)$b['deposit_received'];
- $stepLicense = (bool)$b['license_verified'];
- $licFile = $b['license_file'] ?? '';
- $stepHelmet = (bool)$b['helmet_provided'];
- $stepSafety = (bool)$b['safety_course'];
- $stepOps = (bool)$b['operational_course'];
- $stepReturned = (bool)$b['slingshot_returned'];
-
- // Dot colors: done=green, if cancelled skip all
- $cancelled = $b['status'] === 'cancelled';
- $dotClass = function($done) use ($cancelled) {
- if ($cancelled) return 'dot-skip';
- return $done ? 'dot-done' : 'dot-pending';
- };
-
- $allDone = $stepConfirmed && $stepWaiver && $stepInsurance && $stepDeposit && $stepLicense && $stepHelmet && $stepSafety && $stepOps && $stepReturned;
- $pendingCount = ($cancelled ? 0 : (
- (!$stepConfirmed?1:0)+(!$stepWaiver?1:0)+(!$stepInsurance?1:0)+(!$stepDeposit?1:0)+(!$stepLicense?1:0)+
- (!$stepHelmet?1:0)+(!$stepSafety?1:0)+(!$stepOps?1:0)+(!$stepReturned?1:0)
- ));
- ?>
-
-
- ►
-
-
- = htmlspecialchars($b['name']) ?>
- = htmlspecialchars($b['email']) ?>
-
-
- = date('M j, Y', strtotime($b['rental_date'])) ?>
-
- → = date('M j', strtotime($b['end_date'])) ?>
-
-
- = htmlspecialchars($pkg['label']) ?>
- $= number_format($b['amount'],2) ?>
-
-
-
- >= ucfirst($s) ?>
-
-
-
-
-
-
- = $pendingCount ?> pending
-
- All done ✓
-
-
- = date('M j g:ia', strtotime($b['created_at'])) ?>
-
-
-
-
-
-
-
-
-
-
Customer
-
= htmlspecialchars($b['booking_ref']) ?>
-
= htmlspecialchars($b['name']) ?>
-
-
-
-
-
Package
-
= htmlspecialchars($pkg['label']) ?>
-
$= number_format($b['amount'],2) ?>
-
Rental Date
-
= date('F j, Y', strtotime($b['rental_date'])) ?>
-
-
Customer Message
-
= nl2br(htmlspecialchars($b['notes'])) ?>
-
-
-
-
Admin Notes
-
-
Save Notes
-
-
-
-
-
-
Booking Flow
-
-
-
-
-
✓
-
- Booking Submitted
- = date('M j, Y g:ia', strtotime($b['created_at'])) ?>
-
-
-
-
-
-
- = $stepConfirmed?'✓':($cancelled?'—':'2') ?>
-
-
- Booking Confirmed
-
- Confirmed — status: = ucfirst($b['status']) ?>
- Cancelled
- Awaiting confirmation — change status above
-
-
-
-
-
-
-
-
- = $stepWaiver?'✓':($cancelled?'—':'3') ?>
-
-
-
Rental Waiver Signed
-
-
- Signed by = htmlspecialchars($b['waiver_name'] ?? $b['name']) ?>
- on = date('M j g:ia', strtotime($b['waiver_signed_at'])) ?>
- N/A
- Not yet signed
-
-
-
-
-
-
-
-
-
-
-
- = $stepInsurance?'✓':($cancelled?'—':'4') ?>
-
-
-
Proof of Insurance Received
-
- = $stepInsurance?'Verified — on file':($cancelled?'N/A':($insFile?'Doc submitted — verify at pickup':'Pending — verify at pickup')) ?>
-
-
-
📄 View Submitted Doc ↗
-
-
-
-
- = $stepInsurance?'✓ Verified at Pickup':'Mark Verified at Pickup' ?>
-
-
- 📎 Copy Upload Link
-
-
-
-
-
-
-
-
-
- = $stepLicense?'✓':($cancelled?'—':'5') ?>
-
-
-
Driver's License Verified
-
- = $stepLicense?'Verified at pickup':($cancelled?'N/A':($licFile?'Doc submitted — verify at pickup':'Verify at pickup')) ?>
-
-
-
📄 View Submitted Doc ↗
-
-
-
-
- = $stepLicense?'✓ Verified at Pickup':'Mark Verified at Pickup' ?>
-
-
- 📎 Copy Upload Link
-
-
-
-
-
-
-
-
-
-
- = $depositLabel ?>
-
-
-
Deposit & Balance — $= number_format(DEPOSIT_AMOUNT,2) ?> held · $= number_format($b['amount']-DEPOSIT_AMOUNT,2) ?> at pickup
-
-
- = htmlspecialchars($cardBrand) ?> •••• = htmlspecialchars($cardLast4) ?> on file
- Update Card
-
-
-
- N/A
- Balance charged to card on file
- Captured — $= number_format((float)($b['deposit_paid']??DEPOSIT_AMOUNT),2) ?> charged
- Refunded — $= number_format((float)($b['deposit_paid']??DEPOSIT_AMOUNT),2) ?>
- Hold voided — no charge
- Hold active — card authorized, not yet charged
- Card was declined — contact customer
- Deposit marked received (manual)
- Pending — no card on file yet
-
-
-
-
-
- Capture $= number_format(DEPOSIT_AMOUNT,0) ?>
- Void & Cancel Booking
-
- Charge Balance $= number_format($b['amount']-DEPOSIT_AMOUNT,2) ?>
-
- Charge Balance $= number_format($b['amount']-DEPOSIT_AMOUNT,2) ?>
-
-
- Refund & Cancel Booking
-
- Charge Balance $= number_format($b['amount']-DEPOSIT_AMOUNT,2) ?>
-
- Charge Balance $= number_format($b['amount']-DEPOSIT_AMOUNT,2) ?>
-
-
-
- = $stepDeposit?'✓ Deposit Received':'Mark Deposit Received' ?>
-
-
-
-
-
-
-
-
-
-
- Pre-Departure Checklist
-
-
-
-
-
- = $stepHelmet?'✓':'7' ?>
-
-
-
DOT Helmet Provided & Fits
-
- = $stepHelmet?'Helmet provided and fitted':'Provide DOT helmet — verify fit before departure' ?>
-
-
-
- = $stepHelmet?'✓ Helmet Provided':'Mark Helmet Provided' ?>
-
-
-
-
-
-
-
-
- = $stepSafety?'✓':'8' ?>
-
-
-
Safety Course Completed
-
- = $stepSafety?'Safety course completed':'Complete safety briefing before departure' ?>
-
-
-
- = $stepSafety?'✓ Safety Course Done':'Mark Safety Course Done' ?>
-
-
-
-
-
-
-
-
- = $stepOps?'✓':'9' ?>
-
-
-
Slingshot Operational Course Done
-
- = $stepOps?'Operational course completed':'Walk customer through Slingshot controls before departure' ?>
-
-
-
- = $stepOps?'✓ Ops Course Done':'Mark Ops Course Done' ?>
-
-
-
-
-
-
-
-
- = $stepReturned?'✓':'10' ?>
-
-
-
Slingshot Returned — Close Out
-
-
- Returned = $b['returned_at'] ? date('M j, Y g:ia', strtotime($b['returned_at'])) : '' ?> — booking closed, card data wiped
-
- Mark when slingshot is safely returned — closes booking & wipes card data
-
-
-
-
-
- ✓ Mark Slingshot Returned
-
-
-
-
-
-
-
-
-
-
-
-
-
Send Reminder Email
-
Select what the customer still needs to do, then send them a nudge email with clear instructions.
-
-
-
Not applicable for cancelled bookings.
-
-
-
-
- Waiver Link
- https://parkerslingshot.epictravelexpeditions.com/waiver.php?ref== htmlspecialchars($b['booking_ref']) ?>
-
-
-
-
Resend Confirmation Email
-
-
- Resend
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
No dates blocked.
-
-
-
- ✕
- = date('M j, Y', strtotime($bl['block_date'])) ?>
- — = htmlspecialchars($bl['reason']) ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
No customers yet.
-
-
-
-
-
-
- Name
- Email
- Phone
- Bookings
- Status
- Added
-
-
-
-
-
-
-
- ►
-
- = htmlspecialchars($c['name']) ?>
- = htmlspecialchars($c['email']) ?>
- = htmlspecialchars($c['phone'] ?? '—') ?>
- = count($custBookings) ?>
- = $c['is_active']?'Active':'Inactive' ?>
- = date('M j, Y', strtotime($c['created_at'])) ?>
-
- Edit
- Del
-
-
-
-
-
-
-
-
-
-
-
Customer Profile
-
= htmlspecialchars($c['name']) ?>
-
-
-
-
-
-
Date of Birth
-
= date('F j, Y', strtotime($c['dob'])) ?>
-
-
-
Address
-
= nl2br(htmlspecialchars($c['address'])) ?>
-
-
-
Notes
-
= nl2br(htmlspecialchars($c['notes'])) ?>
-
-
- = $c['is_active']?'Active':'Inactive' ?>
- Edit Profile
-
-
-
-
-
-
Booking History (= count($custBookings) ?>)
-
-
No bookings yet.
-
- $cb['package']];
- $stepConfirmed = in_array($cb['status'], ['confirmed','completed']);
- $stepWaiver = (bool)$cb['waiver_signed'];
- $stepInsurance = (bool)$cb['insurance_verified'];
- $stepDeposit = (bool)$cb['deposit_received'];
- $stepLicense = (bool)$cb['license_verified'];
- $stepHelmet = (bool)$cb['helmet_provided'];
- $stepSafety = (bool)$cb['safety_course'];
- $stepOps = (bool)$cb['operational_course'];
- $stepReturned = (bool)$cb['slingshot_returned'];
- $cancelled = $cb['status'] === 'cancelled';
- $sqStatus = $cb['square_payment_status'] ?? '';
- $sqId = $cb['square_payment_id'] ?? '';
- $sqCardId = $cb['square_card_id'] ?? '';
- $cardLast4 = $cb['card_last4'] ?? '';
- $cardBrand = $cb['card_brand'] ?? '';
- ?>
-
-
-
-
-
-
-
-
-
-
-
✓
-
- Booking Submitted
- = date('M j, Y g:ia', strtotime($cb['created_at'])) ?>
-
-
-
-
-
- = $stepConfirmed?'✓':($cancelled?'—':'2') ?>
-
-
- Booking Confirmed
- = $stepConfirmed?('Confirmed — '.ucfirst($cb['status'])):($cancelled?'Cancelled':'Awaiting confirmation — change status above') ?>
-
-
-
-
-
- = $stepWaiver?'✓':($cancelled?'—':'3') ?>
-
-
-
Rental Waiver Signed
-
- Signed= $cb['waiver_signed_at']?' on '.date('M j g:ia',strtotime($cb['waiver_signed_at'])):''; ?>
- N/A
- Not yet signed
-
-
-
-
-
-
-
-
-
- = $stepInsurance?'✓':($cancelled?'—':'4') ?>
-
-
-
Insurance Received
-
- = $stepInsurance?'Verified — on file':($cancelled?'N/A':'Pending — verify at pickup') ?>
-
-
-
-
- = $stepInsurance?'✓ Marked Received':'Mark Received' ?>
-
-
-
-
-
-
-
-
- = $stepLicense?'✓':($cancelled?'—':'5') ?>
-
-
-
Driver's License Verified
-
- = $stepLicense?'Verified — on file':($cancelled?'N/A':'Verify at pickup') ?>
-
-
-
-
- = $stepLicense?'✓ License Verified':'Mark License Verified' ?>
-
-
-
-
-
-
-
-
-
- = $cvDepLabel ?>
-
-
-
Deposit & Balance — $= number_format(DEPOSIT_AMOUNT,2) ?> held · $= number_format($cb['amount']-DEPOSIT_AMOUNT,2) ?> at pickup
-
- N/A
- Captured — $= number_format((float)($cb['deposit_paid']??DEPOSIT_AMOUNT),2) ?> charged
- Refunded — deposit returned
- Hold voided — no charge
- Hold active — card authorized, not yet charged
- Marked received (manual)
- Pending — no card on file
-
-
-
-
-
- Capture $= number_format(DEPOSIT_AMOUNT,0) ?>
- Void & Cancel Booking
-
- Refund & Cancel Booking
-
-
- = $stepDeposit?'✓ Deposit Received':'Mark Deposit Received' ?>
-
-
-
-
-
-
-
-
-
Pre-Departure
-
-
-
- = $stepHelmet?'✓':'7' ?>
-
-
-
DOT Helmet Provided & Fits
-
= $stepHelmet?'Helmet provided':'Pending' ?>
-
-
- = $stepHelmet?'✓ Helmet Provided':'Mark Helmet Provided' ?>
-
-
-
-
-
-
-
- = $stepSafety?'✓':'8' ?>
-
-
-
Safety Course Completed
-
= $stepSafety?'Done':'Pending' ?>
-
-
- = $stepSafety?'✓ Safety Course Done':'Mark Safety Course Done' ?>
-
-
-
-
-
-
-
- = $stepOps?'✓':'9' ?>
-
-
-
Operational Course Done
-
= $stepOps?'Done':'Pending' ?>
-
-
- = $stepOps?'✓ Ops Course Done':'Mark Ops Course Done' ?>
-
-
-
-
-
-
-
- = $stepReturned?'✓':'10' ?>
-
-
-
Slingshot Returned
-
= $stepReturned?'Returned — booking closed':'Mark when returned to close out & wipe card' ?>
-
-
- ✓ Mark Returned
-
-
-
-
-
-
-
-
-
-
-
-
Admin Notes
-
-
Save Notes
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Update Card on File
- ✕
-
-
Enter the customer's new card. The old card will be removed and replaced.
-
-
-
- Save New Card
- Cancel
-
-
-
-
-
-