Add doc upload/view, resend confirmation, update email for license/insurance steps

This commit is contained in:
2026-05-25 19:05:37 +00:00
parent a5e35dc362
commit f3ad36818d
4 changed files with 2609 additions and 11 deletions
+126 -11
View File
@@ -106,8 +106,8 @@ if ($isAjax) {
],
'insurance' => [
'label' => 'Proof of Personal Auto Insurance',
'detail' => 'You\'ll need to bring proof of valid personal auto insurance to pickup. A photo on your phone of your insurance card is fine. This is required before we can hand over the keys.',
'cta' => '',
'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' => "<div style='margin-top:10px'><a href='" . SITE_URL . "/upload-docs.php?ref={$ref}&type=insurance' style='display:inline-block;background:#f97316;color:#fff;text-decoration:none;padding:9px 20px;border-radius:6px;font-weight:700;font-size:13px'>Upload Insurance Card &rarr;</a></div>",
],
'deposit' => [
'label' => 'Balance Due at Pickup',
@@ -116,8 +116,8 @@ if ($isAjax) {
],
'license' => [
'label' => "Valid Driver's License",
'detail' => "Please bring your valid driver's license to pickup. We're required to verify it before you take the Slingshot out. Must match the name on the booking.",
'cta' => '',
'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' => "<div style='margin-top:10px'><a href='" . SITE_URL . "/upload-docs.php?ref={$ref}&type=license' style='display:inline-block;background:#f97316;color:#fff;text-decoration:none;padding:9px 20px;border-radius:6px;font-weight:700;font-size:13px'>Upload License Photo &rarr;</a></div>",
],
];
@@ -345,6 +345,61 @@ if ($isAjax) {
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 = "<div style='max-width:600px;margin:0 auto;font-family:Arial,sans-serif'>
<div style='background:#0d0d0d;padding:24px;text-align:center'>
<h1 style='color:#f97316;margin:0;font-size:20px'>Parker County Slingshot Rentals</h1>
</div>
<div style='padding:32px;background:#fff'>
<h2 style='margin-top:0;color:#0d0d0d'>Booking Confirmation</h2>
<p style='color:#374151'>Hey " . htmlspecialchars($b['name']) . ", here's a copy of your booking confirmation.</p>
<div style='background:#fff7ed;border:1px solid #fed7aa;border-radius:10px;padding:20px;margin:20px 0'>
<p style='margin:0 0 6px;font-size:13px;color:#9ca3af;text-transform:uppercase;letter-spacing:1px'>Booking Reference</p>
<p style='margin:0 0 16px;font-size:22px;font-weight:700;color:#f97316'>{$ref}</p>
<p style='margin:4px 0;font-size:14px;color:#374151'><strong>Package:</strong> " . htmlspecialchars($pkg['label']) . "</p>
<p style='margin:4px 0;font-size:14px;color:#374151'><strong>Date:</strong> {$dateLabel}</p>
<p style='margin:4px 0;font-size:14px;color:#374151'><strong>Total:</strong> {$amtLabel}</p>
<p style='margin:4px 0;font-size:14px;color:#374151'><strong>Deposit hold:</strong> {$depLabel}</p>
<p style='margin:4px 0;font-size:14px;color:#374151'><strong>Balance at pickup:</strong> <span style='font-weight:700;color:#16a34a'>{$balLabel}</span></p>
</div>
<div style='margin:20px 0;padding:16px;background:#fff7ed;border:1px solid #fed7aa;border-radius:10px;text-align:center'>
<p style='margin:0 0 10px;font-size:14px;font-weight:700;color:#111'>Sign Your Rental Agreement</p>
<a href='" . SITE_URL . "/waiver.php?ref={$ref}' style='display:inline-block;background:#f97316;color:#fff;text-decoration:none;padding:10px 24px;border-radius:6px;font-weight:700;font-size:14px'>Sign Rental Agreement &rarr;</a>
</div>
<p style='color:#374151'>Questions? Call or text <strong>" . ADMIN_PHONE . "</strong> or reply to this email.</p>
<p style='color:#374151'>Ride on,<br><strong>The Parker County Slingshot Team</strong></p>
</div>
<div style='background:#f3f4f6;padding:16px;text-align:center'>
<p style='margin:0;font-size:12px;color:#9ca3af'>&copy; " . date('Y') . " Parker County Slingshot Rentals &mdash; Weatherford, TX</p>
</div>
</div>";
$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);
@@ -642,8 +697,10 @@ textarea.notes-ta:focus{border-color:#f97316}
$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'];
@@ -792,21 +849,27 @@ textarea.notes-ta:focus{border-color:#f97316}
<!-- Step 4: Insurance -->
<div class="flow-step">
<div class="flow-icon <?= $stepInsurance?'done':($cancelled?'skip':'pending') ?>" id="icon-<?= $bid ?>-insurance_verified">
<div class="flow-icon <?= $stepInsurance?'done':($cancelled?'skip':($insFile?'pending':'pending')) ?>" id="icon-<?= $bid ?>-insurance_verified">
<?= $stepInsurance?'✓':($cancelled?'—':'4') ?>
</div>
<div class="flow-body">
<span class="flow-label">Proof of Insurance Received</span>
<span class="flow-meta" id="meta-<?= $bid ?>-insurance_verified">
<?= $stepInsurance?'Verified — on file':($cancelled?'N/A':'Pending — verify at pickup') ?>
<?= $stepInsurance?'Verified — on file':($cancelled?'N/A':($insFile?'Doc submitted — verify at pickup':'Pending — verify at pickup')) ?>
</span>
<?php if ($insFile && !$cancelled): ?>
<a class="flow-link" href="/view-doc.php?ref=<?= urlencode($b['booking_ref']) ?>&type=insurance&_t=<?= $token ?>" target="_blank" style="margin-right:8px">📄 View Submitted Doc ↗</a>
<?php endif; ?>
<?php if (!$cancelled): ?>
<div class="flow-action">
<div class="flow-action" style="margin-top:4px">
<button class="flow-toggle <?= $stepInsurance?'active':'' ?>"
id="btn-<?= $bid ?>-insurance_verified"
onclick="toggleReq(<?= $bid ?>,'insurance_verified',this)">
<?= $stepInsurance?'✓ Marked Received':'Mark Received' ?>
<?= $stepInsurance?'✓ Verified at Pickup':'Mark Verified at Pickup' ?>
</button>
<?php if (!$insFile): ?>
<button class="flow-toggle" style="margin-left:6px" onclick="copyUploadLink('<?= htmlspecialchars($b['booking_ref']) ?>','insurance',this)">📎 Copy Upload Link</button>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
@@ -820,15 +883,21 @@ textarea.notes-ta:focus{border-color:#f97316}
<div class="flow-body">
<span class="flow-label">Driver's License Verified</span>
<span class="flow-meta" id="meta-<?= $bid ?>-license_verified">
<?= $stepLicense?'License verified':($cancelled?'N/A':'Verify at pickup') ?>
<?= $stepLicense?'Verified at pickup':($cancelled?'N/A':($licFile?'Doc submitted — verify at pickup':'Verify at pickup')) ?>
</span>
<?php if ($licFile && !$cancelled): ?>
<a class="flow-link" href="/view-doc.php?ref=<?= urlencode($b['booking_ref']) ?>&type=license&_t=<?= $token ?>" target="_blank" style="margin-right:8px">📄 View Submitted Doc ↗</a>
<?php endif; ?>
<?php if (!$cancelled): ?>
<div class="flow-action">
<div class="flow-action" style="margin-top:4px">
<button class="flow-toggle <?= $stepLicense?'active':'' ?>"
id="btn-<?= $bid ?>-license_verified"
onclick="toggleReq(<?= $bid ?>,'license_verified',this)">
<?= $stepLicense?'✓ License Verified':'Mark License Verified' ?>
<?= $stepLicense?'✓ Verified at Pickup':'Mark Verified at Pickup' ?>
</button>
<?php if (!$licFile): ?>
<button class="flow-toggle" style="margin-left:6px" onclick="copyUploadLink('<?= htmlspecialchars($b['booking_ref']) ?>','license',this)">📎 Copy Upload Link</button>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
@@ -1034,6 +1103,16 @@ textarea.notes-ta:focus{border-color:#f97316}
<strong style="color:#111;display:block;margin-bottom:.35rem">Waiver Link</strong>
<code style="word-break:break-all;font-size:.72rem">https://parkerslingshot.epictravelexpeditions.com/waiver.php?ref=<?= htmlspecialchars($b['booking_ref']) ?></code>
</div>
<div style="margin-top:1.25rem;padding:1rem;background:#f9fafb;border-radius:8px">
<strong style="color:#111;font-size:.8rem;display:block;margin-bottom:.5rem">Resend Confirmation Email</strong>
<div style="display:flex;gap:.5rem;align-items:center;flex-wrap:wrap">
<input type="email" id="resend-email-<?= $bid ?>" value="<?= htmlspecialchars($b['email']) ?>"
style="flex:1;min-width:180px;font-size:.82rem;padding:.45rem .65rem;border:1px solid #d1d5db;border-radius:6px;font-family:inherit" />
<button class="flow-toggle" onclick="resendConfirmation(<?= $bid ?>,this)" style="white-space:nowrap">Resend</button>
</div>
<div id="resend-status-<?= $bid ?>" style="margin-top:.4rem;font-size:.75rem;display:none"></div>
</div>
<?php endif; ?>
</div>
@@ -1586,6 +1665,42 @@ function saveNotes(id) {
}
// ── Send reminder email ───────────────────────────────────────────────────────
function copyUploadLink(ref, type, btn) {
const url = 'https://parkerslingshot.epictravelexpeditions.com/upload-docs.php?ref=' + encodeURIComponent(ref) + '&type=' + type;
navigator.clipboard.writeText(url).then(() => {
const orig = btn.textContent;
btn.textContent = '✓ Copied!';
setTimeout(() => btn.textContent = orig, 2000);
}).catch(() => prompt('Copy this link:', url));
}
function resendConfirmation(id, btn) {
const emailInput = document.getElementById('resend-email-' + id);
const status = document.getElementById('resend-status-' + id);
const email = emailInput ? emailInput.value.trim() : '';
if (!email) { alert('Enter an email address.'); return; }
if (!confirm('Resend booking confirmation to ' + email + '?')) return;
btn.disabled = true;
btn.textContent = 'Sending…';
fetch('/admin/', {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded','X-Requested-With':'XMLHttpRequest'},
body: 'action=resend_confirmation&id=' + id + '&email=' + encodeURIComponent(email) + '&_t=' + ADMIN_TOKEN
}).then(r => r.json()).then(d => {
btn.disabled = false;
btn.textContent = 'Resend';
if (d.ok) {
status.textContent = '✓ Sent to ' + d.email;
status.style.color = '#16a34a';
} else {
status.textContent = '✗ ' + (d.error || 'Failed');
status.style.color = '#dc2626';
}
status.style.display = 'block';
setTimeout(() => status.style.display = 'none', 4000);
}).catch(() => { btn.disabled = false; btn.textContent = 'Resend'; alert('Request failed.'); });
}
function sendReminder(id) {
const box = document.getElementById('reminder-' + id);
const btn = document.getElementById('remind-btn-' + id);