mirror of
https://github.com/myronblair/parkerslingshotrentals
synced 2026-06-30 17:50:31 -05:00
85448d18c5
- waiver.php: full rental agreement with canvas e-signature pad, 6 required checkboxes, typed name field; stores sig image + IP + timestamp in DB; emails signed confirmation to customer and admin - bookings table: add waiver_signed, waiver_signed_at, waiver_ip, waiver_name, waiver_sig columns - contact.php: confirmation email now includes Sign Rental Agreement button/link - admin/index.php: Waiver column shows Signed (date) or Pending + Send Link - index.html: How It Works expanded to 5 steps (added Get Approved + Sign Waiver before Hit the Road); insurance updated to Proof of insurance required; FAQ and JSON-LD updated to match Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
366 lines
21 KiB
PHP
366 lines
21 KiB
PHP
<?php
|
|
require_once __DIR__ . '/db.php';
|
|
|
|
header('X-Frame-Options: DENY');
|
|
header('X-Content-Type-Options: nosniff');
|
|
|
|
$ref = strtoupper(trim($_GET['ref'] ?? ''));
|
|
$error = '';
|
|
$booking = null;
|
|
$signed = false;
|
|
|
|
if ($ref) {
|
|
$stmt = db()->prepare("SELECT * FROM bookings WHERE booking_ref = ?");
|
|
$stmt->execute([$ref]);
|
|
$booking = $stmt->fetch();
|
|
if (!$booking) {
|
|
$error = 'Booking reference not found. Please check your confirmation email.';
|
|
} elseif ($booking['status'] === 'cancelled') {
|
|
$error = 'This booking has been cancelled. Please contact us if you have questions.';
|
|
} elseif ($booking['waiver_signed']) {
|
|
$signed = true;
|
|
}
|
|
}
|
|
|
|
// Handle submission
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $booking && !$signed) {
|
|
$sigName = trim(strip_tags($_POST['sig_name'] ?? ''));
|
|
$sigData = $_POST['sig_data'] ?? ''; // base64 canvas PNG
|
|
$checks = (array)($_POST['checks'] ?? []);
|
|
$required = ['age','license','insurance','rules','damage','waiver'];
|
|
|
|
$missing = array_diff($required, $checks);
|
|
if (!$sigName) {
|
|
$error = 'Please type your full name to sign.';
|
|
} elseif ($missing) {
|
|
$error = 'Please check all required boxes before signing.';
|
|
} elseif (!$sigData || strpos($sigData, 'data:image/png;base64,') !== 0) {
|
|
$error = 'Please draw your signature in the box above.';
|
|
} else {
|
|
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
|
|
$ip = explode(',', $ip)[0];
|
|
db()->prepare(
|
|
"UPDATE bookings SET waiver_signed=1, waiver_signed_at=NOW(), waiver_ip=?, waiver_name=?, waiver_sig=? WHERE booking_ref=?"
|
|
)->execute([trim($ip), $sigName, $sigData, $ref]);
|
|
|
|
$pkg = PACKAGES[$booking['package']] ?? ['label'=>$booking['package']];
|
|
$dateLabel = date('F j, Y', strtotime($booking['rental_date']));
|
|
|
|
$adminHtml = "<div style='font-family:Arial,sans-serif;max-width:600px;margin:0 auto'>
|
|
<div style='background:#f97316;padding:20px;text-align:center'>
|
|
<h1 style='color:#fff;margin:0;font-size:18px'>Waiver Signed — {$ref}</h1>
|
|
</div>
|
|
<div style='padding:24px;background:#fff;border:1px solid #e5e7eb'>
|
|
<p><strong>" . htmlspecialchars($booking['name']) . "</strong> signed the rental waiver for booking <strong>{$ref}</strong>.</p>
|
|
<table style='width:100%;font-size:14px'>
|
|
<tr><td style='color:#6b7280;padding:6px 0;width:110px'>Package</td><td style='padding:6px 0'>" . htmlspecialchars($pkg['label']) . "</td></tr>
|
|
<tr><td style='color:#6b7280;padding:6px 0'>Date</td><td style='padding:6px 0'>{$dateLabel}</td></tr>
|
|
<tr><td style='color:#6b7280;padding:6px 0'>Signed by</td><td style='padding:6px 0'>" . htmlspecialchars($sigName) . "</td></tr>
|
|
<tr><td style='color:#6b7280;padding:6px 0'>IP</td><td style='padding:6px 0'>" . htmlspecialchars($ip) . "</td></tr>
|
|
<tr><td style='color:#6b7280;padding:6px 0'>Timestamp</td><td style='padding:6px 0'>" . date('F j, Y g:i A') . " CT</td></tr>
|
|
</table>
|
|
<img src='{$sigData}' style='margin-top:16px;border:1px solid #e5e7eb;border-radius:6px;max-width:100%;height:auto' alt='Signature' />
|
|
</div>
|
|
</div>";
|
|
|
|
$custHtml = "<div style='font-family:Arial,sans-serif;max-width:600px;margin:0 auto'>
|
|
<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'>Waiver Signed — You're All Set!</h2>
|
|
<p style='color:#374151'>Hey " . htmlspecialchars($booking['name']) . ", your rental agreement for booking <strong>{$ref}</strong> is signed and on file. See you on <strong>{$dateLabel}</strong>!</p>
|
|
<p style='color:#374151'>Remember to bring:</p>
|
|
<ul style='color:#374151'>
|
|
<li>Valid driver's license</li>
|
|
<li>Proof of personal auto insurance</li>
|
|
</ul>
|
|
<p style='color:#374151'>Questions? Call or text <strong>(817) 555-0199</strong>.</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'>© " . date('Y') . " Parker County Slingshot Rentals — Weatherford, TX</p>
|
|
</div>
|
|
</div>";
|
|
|
|
sendEmail(ADMIN_EMAIL, 'Parker Slingshot Admin', "Waiver Signed: {$ref} — " . $booking['name'], $adminHtml);
|
|
sendEmail($booking['email'], $booking['name'], "Rental Agreement Signed — {$ref}", $custHtml);
|
|
|
|
$signed = true;
|
|
}
|
|
}
|
|
|
|
$pkgLabel = $booking ? (PACKAGES[$booking['package']]['label'] ?? $booking['package']) : '';
|
|
$dateLabel = $booking ? date('F j, Y', strtotime($booking['rental_date'])) : '';
|
|
?><!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Rental Agreement — Parker County Slingshot Rentals</title>
|
|
<meta name="robots" content="noindex,nofollow" />
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Barlow+Condensed:wght@700;800&display=swap" rel="stylesheet" />
|
|
<style>
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
:root { --orange: #f97316; --orange-dark: #ea580c; --black: #0d0d0d; }
|
|
body { font-family: 'Inter', sans-serif; background: #f3f4f6; color: #111; line-height: 1.6; }
|
|
header { background: var(--black); padding: 1.25rem 2rem; display: flex; align-items: center; justify-content: space-between; }
|
|
header a { font-family: 'Barlow Condensed', sans-serif; font-size: 1.3rem; font-weight: 800; color: var(--orange); text-decoration: none; }
|
|
header span { font-size: 0.85rem; color: rgba(255,255,255,0.4); }
|
|
.wrap { max-width: 760px; margin: 2.5rem auto; padding: 0 1rem 4rem; }
|
|
.card { background: #fff; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); padding: 2rem 2.5rem; margin-bottom: 1.5rem; }
|
|
@media (max-width: 600px) { .card { padding: 1.5rem; } }
|
|
h1 { font-family: 'Barlow Condensed', sans-serif; font-size: 2rem; font-weight: 800; margin-bottom: 0.25rem; }
|
|
h2 { font-size: 1rem; font-weight: 700; color: var(--orange); text-transform: uppercase; letter-spacing: 1px; margin: 1.75rem 0 0.75rem; }
|
|
p { color: #374151; font-size: 0.95rem; margin-bottom: 0.75rem; }
|
|
.booking-banner { background: #fff7ed; border: 1px solid #fed7aa; border-radius: 10px; padding: 1.25rem 1.5rem; margin-bottom: 1.75rem; display: flex; gap: 2rem; flex-wrap: wrap; }
|
|
.bb-item { font-size: 0.9rem; }
|
|
.bb-label { color: #9ca3af; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 0.2rem; }
|
|
.bb-value { font-weight: 700; color: #111; }
|
|
.bb-ref { color: var(--orange); font-size: 1.1rem; }
|
|
.clause { display: flex; gap: 0.85rem; align-items: flex-start; padding: 0.85rem 0; border-bottom: 1px solid #f3f4f6; }
|
|
.clause:last-child { border-bottom: none; }
|
|
.clause input[type=checkbox] { margin-top: 3px; width: 18px; height: 18px; accent-color: var(--orange); flex-shrink: 0; cursor: pointer; }
|
|
.clause label { font-size: 0.92rem; color: #374151; cursor: pointer; }
|
|
.clause label strong { color: #111; }
|
|
.sig-wrap { border: 2px dashed #d1d5db; border-radius: 8px; overflow: hidden; position: relative; background: #fafafa; margin-top: 0.5rem; }
|
|
#sigCanvas { display: block; width: 100%; height: 160px; cursor: crosshair; touch-action: none; }
|
|
.sig-clear { position: absolute; top: 8px; right: 8px; background: rgba(0,0,0,0.06); border: none; border-radius: 6px; padding: 4px 10px; font-size: 0.78rem; cursor: pointer; color: #6b7280; }
|
|
.sig-clear:hover { background: rgba(239,68,68,0.1); color: #ef4444; }
|
|
.sig-hint { font-size: 0.78rem; color: #9ca3af; margin-top: 0.4rem; }
|
|
input[type=text] { width: 100%; border: 1px solid #d1d5db; border-radius: 8px; padding: 0.75rem 1rem; font-size: 1rem; font-family: inherit; outline: none; transition: border-color 0.2s; margin-top: 0.4rem; }
|
|
input[type=text]:focus { border-color: var(--orange); }
|
|
.btn-sign { display: block; width: 100%; background: var(--orange); color: white; border: none; border-radius: 8px; padding: 1rem; font-size: 1.05rem; font-weight: 700; cursor: pointer; transition: background 0.2s; margin-top: 1.5rem; }
|
|
.btn-sign:hover { background: var(--orange-dark); }
|
|
.btn-sign:disabled { background: #d1d5db; cursor: not-allowed; }
|
|
.alert { padding: 0.9rem 1.1rem; border-radius: 8px; font-size: 0.9rem; margin-bottom: 1rem; }
|
|
.alert-error { background: rgba(239,68,68,0.08); border: 1px solid rgba(239,68,68,0.25); color: #dc2626; }
|
|
.alert-success { background: rgba(34,197,94,0.08); border: 1px solid rgba(34,197,94,0.25); color: #16a34a; }
|
|
.success-icon { font-size: 3rem; text-align: center; margin-bottom: 1rem; }
|
|
.success-box { text-align: center; padding: 1rem 0; }
|
|
.success-box h1 { color: #16a34a; margin-bottom: 0.5rem; }
|
|
.success-box p { color: #374151; max-width: 480px; margin: 0 auto 1rem; }
|
|
.checklist { text-align: left; display: inline-block; margin: 1rem auto; }
|
|
.checklist li { padding: 0.35rem 0; color: #374151; font-size: 0.95rem; list-style: none; }
|
|
.checklist li::before { content: '✓ '; color: #16a34a; font-weight: 700; }
|
|
.back-link { text-align: center; margin-top: 1.5rem; }
|
|
.back-link a { color: var(--orange); text-decoration: none; font-weight: 600; font-size: 0.9rem; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<header>
|
|
<a href="/">Parker County Slingshot Rentals</a>
|
|
<span>Rental Agreement</span>
|
|
</header>
|
|
|
|
<div class="wrap">
|
|
|
|
<?php if (!$ref || $error === 'Booking reference not found. Please check your confirmation email.'): ?>
|
|
<!-- No valid ref — show lookup form -->
|
|
<div class="card">
|
|
<h1>Rental Agreement</h1>
|
|
<p style="margin:0.75rem 0 1.5rem;color:#6b7280;">Enter your booking reference from your confirmation email to access your rental agreement.</p>
|
|
<?php if ($error): ?><div class="alert alert-error"><?= htmlspecialchars($error) ?></div><?php endif; ?>
|
|
<form method="get" action="/waiver.php">
|
|
<label style="font-weight:600;font-size:0.9rem;display:block;margin-bottom:0.4rem;">Booking Reference</label>
|
|
<input type="text" name="ref" placeholder="PSR-XXXXXX" value="<?= htmlspecialchars($ref) ?>" style="text-transform:uppercase" maxlength="12" required />
|
|
<button type="submit" class="btn-sign" style="margin-top:1rem;">Look Up My Booking</button>
|
|
</form>
|
|
</div>
|
|
|
|
<?php elseif ($signed): ?>
|
|
<!-- Already signed or just signed -->
|
|
<div class="card">
|
|
<div class="success-icon">✅</div>
|
|
<div class="success-box">
|
|
<h1>You're All Set!</h1>
|
|
<p>Your rental agreement for booking <strong><?= htmlspecialchars($ref) ?></strong> is signed and on file. We'll see you on <strong><?= htmlspecialchars($dateLabel) ?></strong>!</p>
|
|
<p style="color:#6b7280;font-size:0.88rem;">A confirmation was sent to <?= htmlspecialchars($booking['email']) ?>.</p>
|
|
<p style="font-weight:700;margin-top:1rem;margin-bottom:0.25rem;">Remember to bring:</p>
|
|
<ul class="checklist">
|
|
<li>Valid driver's license</li>
|
|
<li>Proof of personal auto insurance</li>
|
|
</ul>
|
|
</div>
|
|
<div class="back-link"><a href="/">← Back to parkerslingshotrentals.com</a></div>
|
|
</div>
|
|
|
|
<?php elseif ($booking): ?>
|
|
<!-- Waiver form -->
|
|
<?php if ($error): ?><div class="alert alert-error"><?= htmlspecialchars($error) ?></div><?php endif; ?>
|
|
|
|
<div class="card">
|
|
<h1>Rental Agreement</h1>
|
|
<p style="color:#6b7280;margin-top:0.25rem;margin-bottom:1.5rem;">Please read and sign the agreement below for your upcoming rental.</p>
|
|
|
|
<div class="booking-banner">
|
|
<div class="bb-item"><div class="bb-label">Booking Ref</div><div class="bb-value bb-ref"><?= htmlspecialchars($booking['booking_ref']) ?></div></div>
|
|
<div class="bb-item"><div class="bb-label">Name</div><div class="bb-value"><?= htmlspecialchars($booking['name']) ?></div></div>
|
|
<div class="bb-item"><div class="bb-label">Package</div><div class="bb-value"><?= htmlspecialchars($pkgLabel) ?></div></div>
|
|
<div class="bb-item"><div class="bb-label">Rental Date</div><div class="bb-value"><?= htmlspecialchars($dateLabel) ?></div></div>
|
|
</div>
|
|
|
|
<h2>Rental Terms & Conditions</h2>
|
|
<p>This Rental Agreement ("Agreement") is entered into between Parker County Slingshot Rentals ("Company") and the renter identified above ("Renter"). By signing below, Renter agrees to all terms stated herein.</p>
|
|
|
|
<h2>Eligibility Requirements</h2>
|
|
<p>Renter must be at least 25 years of age and hold a valid Class C driver's license (or equivalent) issued by a U.S. state or territory. Renter must not have any DUI/DWI convictions within the past 5 years.</p>
|
|
|
|
<h2>Insurance Requirement</h2>
|
|
<p>Renter is required to carry and provide proof of valid personal auto insurance at the time of vehicle pickup. The Company maintains a fleet insurance policy covering the vehicle; however, Renter's personal insurance is primary for liability arising from Renter's operation of the vehicle. Renter accepts financial responsibility for any deductible, damages, or losses not covered by either policy.</p>
|
|
|
|
<h2>Vehicle Use & Rules</h2>
|
|
<p>Renter agrees to operate the Polaris Slingshot in a safe, lawful manner and specifically agrees to:</p>
|
|
<ul style="color:#374151;font-size:0.92rem;padding-left:1.25rem;margin-bottom:0.75rem;">
|
|
<li style="margin-bottom:0.35rem;">Obey all applicable traffic laws and speed limits</li>
|
|
<li style="margin-bottom:0.35rem;">Never operate the vehicle under the influence of alcohol, drugs, or any impairing substance</li>
|
|
<li style="margin-bottom:0.35rem;">Never allow an unauthorized third party to operate the vehicle</li>
|
|
<li style="margin-bottom:0.35rem;">Wear the provided DOT-approved helmet at all times while operating the vehicle</li>
|
|
<li style="margin-bottom:0.35rem;">Not take the vehicle off paved roads or outside the approved driving area</li>
|
|
<li>Return the vehicle at the agreed-upon time and location in the same condition it was received</li>
|
|
</ul>
|
|
|
|
<h2>Damage & Security Deposit</h2>
|
|
<p>A refundable security deposit is required at pickup. Renter is financially responsible for any damage to the vehicle, including but not limited to collision damage, tire damage, interior damage, and any fines or citations incurred during the rental period. The Company reserves the right to apply the security deposit toward any such costs.</p>
|
|
|
|
<h2>Assumption of Risk & Release of Liability</h2>
|
|
<p>Renter acknowledges that operating a Polaris Slingshot involves inherent risks including, but not limited to, physical injury or death. Renter voluntarily assumes all such risks and, to the fullest extent permitted by Texas law, releases and holds harmless Parker County Slingshot Rentals, its owners, employees, and agents from any and all claims, damages, or liability arising out of Renter's use of the vehicle.</p>
|
|
|
|
<h2>Cancellation Policy</h2>
|
|
<p>Cancellations made more than 24 hours before the rental start time are fully refunded. Cancellations within 24 hours of the rental start time are subject to a 50% cancellation fee.</p>
|
|
</div>
|
|
|
|
<form method="post" action="/waiver.php?ref=<?= urlencode($ref) ?>" id="waiverForm">
|
|
<input type="hidden" name="sig_data" id="sigDataInput" />
|
|
<div class="card">
|
|
<h2 style="margin-top:0">Acknowledgments</h2>
|
|
<p style="margin-bottom:1rem;color:#6b7280;font-size:0.88rem;">Check each box to confirm you have read and agree to that section.</p>
|
|
|
|
<div class="clause">
|
|
<input type="checkbox" name="checks[]" value="age" id="ck_age" required />
|
|
<label for="ck_age"><strong>Age & License:</strong> I confirm I am 25 years of age or older and hold a valid driver's license.</label>
|
|
</div>
|
|
<div class="clause">
|
|
<input type="checkbox" name="checks[]" value="insurance" id="ck_ins" required />
|
|
<label for="ck_ins"><strong>Insurance:</strong> I will provide proof of valid personal auto insurance at pickup and understand it is required.</label>
|
|
</div>
|
|
<div class="clause">
|
|
<input type="checkbox" name="checks[]" value="rules" id="ck_rules" required />
|
|
<label for="ck_rules"><strong>Vehicle Rules:</strong> I agree to operate the Slingshot safely, lawfully, and sober, and to wear the provided helmet at all times.</label>
|
|
</div>
|
|
<div class="clause">
|
|
<input type="checkbox" name="checks[]" value="damage" id="ck_dmg" required />
|
|
<label for="ck_dmg"><strong>Damage Responsibility:</strong> I understand I am financially responsible for any damage or fines incurred during my rental period.</label>
|
|
</div>
|
|
<div class="clause">
|
|
<input type="checkbox" name="checks[]" value="license" id="ck_lic" required />
|
|
<label for="ck_lic"><strong>License Verification:</strong> I consent to Parker County Slingshot Rentals verifying my driver's license at pickup.</label>
|
|
</div>
|
|
<div class="clause">
|
|
<input type="checkbox" name="checks[]" value="waiver" id="ck_waiver" required />
|
|
<label for="ck_waiver"><strong>Assumption of Risk:</strong> I have read and understand the Assumption of Risk and Release of Liability section and agree to its terms.</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2 style="margin-top:0">Your Signature</h2>
|
|
|
|
<label style="font-weight:600;font-size:0.9rem;display:block;margin-bottom:0.2rem;">Full Legal Name</label>
|
|
<input type="text" name="sig_name" id="sigName" placeholder="Type your full name as it appears on your license" required />
|
|
|
|
<p style="margin:1.25rem 0 0.4rem;font-weight:600;font-size:0.9rem;">Draw Your Signature</p>
|
|
<div class="sig-wrap">
|
|
<canvas id="sigCanvas"></canvas>
|
|
<button type="button" class="sig-clear" id="clearBtn">Clear</button>
|
|
</div>
|
|
<p class="sig-hint">Use your mouse or finger to sign in the box above.</p>
|
|
|
|
<p style="margin-top:1.5rem;font-size:0.82rem;color:#9ca3af;">
|
|
By clicking "Sign & Submit" below, you confirm that you have read this entire Rental Agreement, that all acknowledgments above are checked, and that your typed name and drawn signature constitute a legally binding electronic signature under the ESIGN Act and Texas law. Signed: <span id="sigDateDisplay"><?= date('F j, Y') ?></span>.
|
|
</p>
|
|
|
|
<button type="submit" class="btn-sign" id="submitBtn">Sign & Submit Rental Agreement</button>
|
|
</div>
|
|
</form>
|
|
|
|
<?php endif; ?>
|
|
|
|
</div><!-- /.wrap -->
|
|
|
|
<script>
|
|
(function() {
|
|
const canvas = document.getElementById('sigCanvas');
|
|
if (!canvas) return;
|
|
|
|
// Size canvas to its CSS width
|
|
function resizeCanvas() {
|
|
const rect = canvas.getBoundingClientRect();
|
|
canvas.width = rect.width * window.devicePixelRatio;
|
|
canvas.height = rect.height * window.devicePixelRatio;
|
|
canvas.getContext('2d').scale(window.devicePixelRatio, window.devicePixelRatio);
|
|
}
|
|
resizeCanvas();
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
let drawing = false;
|
|
let hasDrawn = false;
|
|
|
|
ctx.strokeStyle = '#111';
|
|
ctx.lineWidth = 2.2;
|
|
ctx.lineCap = 'round';
|
|
ctx.lineJoin = 'round';
|
|
|
|
function getPos(e) {
|
|
const r = canvas.getBoundingClientRect();
|
|
const src = e.touches ? e.touches[0] : e;
|
|
return { x: src.clientX - r.left, y: src.clientY - r.top };
|
|
}
|
|
|
|
function startDraw(e) {
|
|
e.preventDefault();
|
|
drawing = true;
|
|
const p = getPos(e);
|
|
ctx.beginPath();
|
|
ctx.moveTo(p.x, p.y);
|
|
}
|
|
function draw(e) {
|
|
if (!drawing) return;
|
|
e.preventDefault();
|
|
const p = getPos(e);
|
|
ctx.lineTo(p.x, p.y);
|
|
ctx.stroke();
|
|
hasDrawn = true;
|
|
}
|
|
function endDraw() { drawing = false; }
|
|
|
|
canvas.addEventListener('mousedown', startDraw);
|
|
canvas.addEventListener('mousemove', draw);
|
|
canvas.addEventListener('mouseup', endDraw);
|
|
canvas.addEventListener('mouseleave', endDraw);
|
|
canvas.addEventListener('touchstart', startDraw, { passive: false });
|
|
canvas.addEventListener('touchmove', draw, { passive: false });
|
|
canvas.addEventListener('touchend', endDraw);
|
|
|
|
document.getElementById('clearBtn').addEventListener('click', () => {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
hasDrawn = false;
|
|
document.getElementById('sigDataInput').value = '';
|
|
});
|
|
|
|
document.getElementById('waiverForm').addEventListener('submit', function(e) {
|
|
if (!hasDrawn) {
|
|
e.preventDefault();
|
|
alert('Please draw your signature before submitting.');
|
|
canvas.style.borderColor = '#ef4444';
|
|
return;
|
|
}
|
|
// Export canvas to base64 PNG
|
|
document.getElementById('sigDataInput').value = canvas.toDataURL('image/png');
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|