new-site/site/src/components/intake/steps/DOTIntakeStep.astro
justin e8769e4d5d Photo ID upload: add QR code for phone + scanner device support
Three upload methods:
- Upload File: standard file picker
- Camera / Scanner: uses capture attribute for camera on mobile
  or TWAIN/WIA scanner devices on desktop
- QR Code: generates QR with current page URL so user can scan
  with phone and take a photo of their ID on mobile

QR generated via api.qrserver.com (no library dependency).
Remove button restores all upload options.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 15:56:00 -05:00

500 lines
30 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
// Unified DOT intake form — shows relevant sections based on services ordered.
// Handles: MCS-150, UCR, D&A, BOC-3, USDOT, MC Authority, Audit Prep, bundles.
---
<div class="pw-step" data-slug="dot-intake">
<h2>DOT Filing Information</h2>
<p class="pw-help">
Provide your carrier information. We will prepare and submit your filings on your behalf.
</p>
<div class="pw-security-notice">
<svg style="width:16px;height:16px;flex-shrink:0;margin-top:2px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z"/></svg>
<span>All personal information is transmitted over 256-bit SSL encryption and stored encrypted at rest. We never share your data with third parties.</span>
</div>
<div class="pw-form-grid">
<!-- ═══ SECTION: Company Info (always shown) ═══ -->
<h3>Company Information</h3>
<div class="pw-row">
<label class="pw-field"><span>Legal Entity Name <em>*</em></span>
<input type="text" id="dot-legal-name" required placeholder="As registered with FMCSA" /></label>
</div>
<div class="pw-row">
<label class="pw-field"><span>DBA / Trade Name</span>
<input type="text" id="dot-dba" placeholder="If different from legal name" /></label>
</div>
<div class="pw-row-3">
<label class="pw-field"><span>USDOT Number <em>*</em></span>
<input type="text" id="dot-dot" required placeholder="e.g. 1234567" /></label>
<label class="pw-field"><span>MC/MX/FF Number</span>
<input type="text" id="dot-mc" placeholder="e.g. MC-123456" /></label>
<label class="pw-field"><span>EIN (Tax ID)</span>
<input type="text" id="dot-ein" placeholder="XX-XXXXXXX" maxlength="12" /></label>
</div>
<h3>Principal Business Address</h3>
<div class="pw-row">
<label class="pw-field"><span>Street Address <em>*</em></span>
<input type="text" id="dot-street" required placeholder="123 Main St" /></label>
</div>
<div class="pw-row-3">
<label class="pw-field"><span>City <em>*</em></span>
<input type="text" id="dot-city" required /></label>
<label class="pw-field"><span>State <em>*</em></span>
<select id="dot-state" required>
<option value="">--</option>
<option value="AL">AL</option><option value="AK">AK</option><option value="AZ">AZ</option><option value="AR">AR</option><option value="CA">CA</option><option value="CO">CO</option><option value="CT">CT</option><option value="DE">DE</option><option value="FL">FL</option><option value="GA">GA</option><option value="HI">HI</option><option value="ID">ID</option><option value="IL">IL</option><option value="IN">IN</option><option value="IA">IA</option><option value="KS">KS</option><option value="KY">KY</option><option value="LA">LA</option><option value="ME">ME</option><option value="MD">MD</option><option value="MA">MA</option><option value="MI">MI</option><option value="MN">MN</option><option value="MS">MS</option><option value="MO">MO</option><option value="MT">MT</option><option value="NE">NE</option><option value="NV">NV</option><option value="NH">NH</option><option value="NJ">NJ</option><option value="NM">NM</option><option value="NY">NY</option><option value="NC">NC</option><option value="ND">ND</option><option value="OH">OH</option><option value="OK">OK</option><option value="OR">OR</option><option value="PA">PA</option><option value="RI">RI</option><option value="SC">SC</option><option value="SD">SD</option><option value="TN">TN</option><option value="TX">TX</option><option value="UT">UT</option><option value="VT">VT</option><option value="VA">VA</option><option value="WA">WA</option><option value="WV">WV</option><option value="WI">WI</option><option value="WY">WY</option><option value="DC">DC</option>
</select></label>
<label class="pw-field"><span>ZIP <em>*</em></span>
<input type="text" id="dot-zip" required maxlength="10" placeholder="12345" /></label>
</div>
<div class="pw-row-2">
<label class="pw-field"><span>Phone <em>*</em></span>
<input type="tel" id="dot-phone" required placeholder="(555) 123-4567" /></label>
<label class="pw-field"><span>Email <em>*</em></span>
<input type="email" id="dot-email" required placeholder="you@company.com" /></label>
</div>
<!-- ═══ SECTION: Entity & Operations (MCS-150, USDOT, MC Auth, bundles) ═══ -->
<div id="dot-sec-operations" hidden>
<h3>Entity & Operations</h3>
<div class="pw-row-2">
<label class="pw-field"><span>Entity Type <em>*</em></span>
<select id="dot-entity-type" required>
<option value="">Select...</option>
<option value="sole_proprietorship">Sole Proprietorship</option>
<option value="partnership">Partnership</option>
<option value="corporation">Corporation</option>
<option value="llc">LLC</option>
<option value="other">Other</option>
</select></label>
<label class="pw-field"><span>Carrier Operation <em>*</em></span>
<select id="dot-carrier-op" required>
<option value="">Select...</option>
<option value="authorized_for_hire">Authorized For-Hire</option>
<option value="exempt_for_hire">Exempt For-Hire</option>
<option value="private_property">Private (Property)</option>
<option value="private_passengers">Private (Passengers)</option>
</select></label>
</div>
<div class="pw-row-2">
<label class="pw-field"><span>Interstate / Intrastate <em>*</em></span>
<select id="dot-interstate" required>
<option value="">Select...</option>
<option value="interstate">Interstate (across state lines)</option>
<option value="intrastate_hazmat">Intrastate — Hazmat</option>
<option value="intrastate_non_hazmat">Intrastate — Non-hazmat</option>
</select></label>
<label class="pw-field"><span>Hazmat? <em>*</em></span>
<select id="dot-hazmat" required>
<option value="">Select...</option>
<option value="no">No</option>
<option value="yes">Yes</option>
</select></label>
</div>
</div>
<!-- ═══ SECTION: Fleet (MCS-150, UCR, bundles) ═══ -->
<div id="dot-sec-fleet" hidden>
<h3>Fleet Information</h3>
<div class="pw-row-3">
<label class="pw-field"><span>Power Units (trucks) <em>*</em></span>
<input type="number" id="dot-power-units" required min="0" placeholder="e.g. 5" /></label>
<label class="pw-field"><span>Drivers <em>*</em></span>
<input type="number" id="dot-drivers" required min="0" placeholder="e.g. 6" /></label>
<label class="pw-field"><span>Annual Miles</span>
<input type="number" id="dot-miles" min="0" placeholder="e.g. 250000" /></label>
</div>
</div>
<!-- ═══ SECTION: UCR Fleet Bracket (UCR only) ═══ -->
<div id="dot-sec-ucr" hidden>
<h3>UCR Registration</h3>
<p class="pw-field-help">UCR fees are based on the number of qualifying commercial motor vehicles (over 10,001 lbs GVWR, 10+ passengers, or placardable hazmat).</p>
<div class="pw-row-2">
<label class="pw-field"><span>Fleet Size Bracket <em>*</em></span>
<select id="dot-ucr-bracket">
<option value="">Select...</option>
<option value="0-2">02 vehicles ($76 gov fee)</option>
<option value="3-5">35 vehicles ($227 gov fee)</option>
<option value="6-20">620 vehicles ($452 gov fee)</option>
<option value="21-100">21100 vehicles ($1,576 gov fee)</option>
<option value="101-1000">1011,000 vehicles ($7,511 gov fee)</option>
<option value="1001+">1,001+ vehicles ($73,346 gov fee)</option>
</select></label>
<label class="pw-field"><span>Base State <em>*</em></span>
<input type="text" id="dot-ucr-state" readonly placeholder="From address above" /></label>
</div>
</div>
<!-- ═══ SECTION: Cargo Types (MCS-150, bundles) ═══ -->
<div id="dot-sec-cargo" hidden>
<h3>Cargo Types (check all that apply)</h3>
<div class="pw-cargo-grid">
<label><input type="checkbox" data-cargo="general" /> General Freight</label>
<label><input type="checkbox" data-cargo="household" /> Household Goods</label>
<label><input type="checkbox" data-cargo="metal" /> Metal/Sheets/Coils</label>
<label><input type="checkbox" data-cargo="motor_vehicles" /> Motor Vehicles</label>
<label><input type="checkbox" data-cargo="drivetow" /> Drive/Tow Away</label>
<label><input type="checkbox" data-cargo="logs" /> Logs/Poles/Lumber</label>
<label><input type="checkbox" data-cargo="building_materials" /> Building Materials</label>
<label><input type="checkbox" data-cargo="mobile_homes" /> Mobile Homes</label>
<label><input type="checkbox" data-cargo="machinery" /> Machinery/Large Objects</label>
<label><input type="checkbox" data-cargo="fresh_produce" /> Fresh Produce</label>
<label><input type="checkbox" data-cargo="liquids" /> Liquids/Gases</label>
<label><input type="checkbox" data-cargo="intermodal" /> Intermodal Containers</label>
<label><input type="checkbox" data-cargo="passengers" /> Passengers</label>
<label><input type="checkbox" data-cargo="oilfield" /> Oilfield Equipment</label>
<label><input type="checkbox" data-cargo="livestock" /> Livestock</label>
<label><input type="checkbox" data-cargo="grain" /> Grain/Feed/Hay</label>
<label><input type="checkbox" data-cargo="coal" /> Coal/Coke</label>
<label><input type="checkbox" data-cargo="meat" /> Meat</label>
<label><input type="checkbox" data-cargo="garbage" /> Garbage/Refuse</label>
<label><input type="checkbox" data-cargo="chemicals" /> Chemicals</label>
<label><input type="checkbox" data-cargo="refrigerated" /> Refrigerated Food</label>
<label><input type="checkbox" data-cargo="beverages" /> Beverages</label>
<label><input type="checkbox" data-cargo="construction" /> Construction</label>
<label><input type="checkbox" data-cargo="other" /> Other</label>
</div>
</div>
<!-- ═══ SECTION: D&A Program (D&A, bundles) ═══ -->
<div id="dot-sec-da" hidden>
<h3>Drug & Alcohol Compliance Program</h3>
<p class="pw-field-help">Required for all carriers with CDL drivers. We will enroll you in a DOT-compliant consortium and set up your program.</p>
<div class="pw-row-3">
<label class="pw-field"><span>CDL Drivers <em>*</em></span>
<input type="number" id="dot-cdl-drivers" min="0" placeholder="Number of CDL holders" /></label>
<label class="pw-field"><span>Owner-Operators <em>*</em></span>
<input type="number" id="dot-owner-ops" min="0" value="0" /></label>
<label class="pw-field"><span>DER Name</span>
<input type="text" id="dot-der-name" placeholder="Designated Employer Rep (optional)" /></label>
</div>
<div class="pw-row">
<label class="pw-field"><span>Current D&A Program Provider</span>
<input type="text" id="dot-current-da" placeholder="Leave blank if none / first time" /></label>
</div>
</div>
<!-- ═══ SECTION: BOC-3 (BOC-3, bundles) ═══ -->
<div id="dot-sec-boc3" hidden>
<h3>BOC-3 Process Agent</h3>
<p class="pw-field-help">We will designate a blanket process agent covering all 48 contiguous states + DC.</p>
<div class="pw-row-2">
<label class="pw-field"><span>Docket Type</span>
<select id="dot-docket-type">
<option value="">Select if applicable...</option>
<option value="MC">MC (Motor Carrier)</option>
<option value="FF">FF (Freight Forwarder)</option>
<option value="MX">MX (Mexican Carrier)</option>
</select></label>
<label class="pw-field"><span>Docket Number</span>
<input type="text" id="dot-docket-num" placeholder="e.g. 123456" /></label>
</div>
</div>
<!-- ═══ SECTION: Authorized Signer (always shown) ═══ -->
<h3>Authorized Signer</h3>
<div class="pw-row-2">
<label class="pw-field"><span>Full Name <em>*</em></span>
<input type="text" id="dot-signer-name" required placeholder="Owner or officer" /></label>
<label class="pw-field"><span>Title <em>*</em></span>
<input type="text" id="dot-signer-title" required placeholder="e.g. Owner, President" /></label>
</div>
<!-- ═══ SECTION: Photo ID (MCS-150, MC Auth) ═══ -->
<div id="dot-sec-photo-id" hidden>
<h3>Government-Issued Photo ID</h3>
<p class="pw-field-help">Required for FMCSA filings. Driver's license, passport, or state ID.</p>
<div class="pw-upload-area">
<input type="file" id="dot-photo-id" accept="image/*,.pdf" capture="environment" style="display:none" />
<div id="dot-id-preview" hidden style="display:flex;align-items:center;gap:12px;justify-content:center">
<img id="dot-id-img" style="max-width:200px;max-height:150px;border-radius:6px;border:1px solid #d1d5db" />
<button type="button" id="dot-id-remove" style="background:#fee2e2;color:#991b1b;border:none;padding:4px 12px;border-radius:4px;font-size:12px;cursor:pointer">Remove</button>
</div>
<div id="dot-id-upload-options">
<div style="display:flex;flex-wrap:wrap;gap:8px;justify-content:center">
<button type="button" id="dot-id-btn" style="display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border:1px solid #d1d5db;border-radius:8px;cursor:pointer;color:#374151;font-size:13px;font-weight:500">
<svg style="width:20px;height:20px;color:#64748b" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5"/></svg>
Upload File
</button>
<button type="button" id="dot-id-scan-btn" style="display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border:1px solid #d1d5db;border-radius:8px;cursor:pointer;color:#374151;font-size:13px;font-weight:500">
<svg style="width:20px;height:20px;color:#64748b" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M6.827 6.175A2.31 2.31 0 015.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 00-1.134-.175 2.31 2.31 0 01-1.64-1.055l-.822-1.316a2.192 2.192 0 00-1.736-1.039 48.774 48.774 0 00-5.232 0 2.192 2.192 0 00-1.736 1.039l-.821 1.316z"/><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 12.75a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zM18.75 10.5h.008v.008h-.008V10.5z"/></svg>
Camera / Scanner
</button>
</div>
<input type="file" id="dot-photo-id-scan" accept="image/*" capture="environment" style="display:none" />
<div style="text-align:center;margin:12px 0 0">
<div style="display:flex;align-items:center;gap:12px;justify-content:center;margin-bottom:8px">
<div style="flex:1;height:1px;background:#d1d5db"></div>
<span style="font-size:11px;color:#94a3b8;white-space:nowrap">or use your phone</span>
<div style="flex:1;height:1px;background:#d1d5db"></div>
</div>
<button type="button" id="dot-id-qr-btn" style="display:inline-flex;align-items:center;gap:8px;padding:8px 16px;background:#f8fafc;border:1px solid #d1d5db;border-radius:6px;cursor:pointer;font-size:12px;color:#374151">
<svg style="width:16px;height:16px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 4.875c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5A1.125 1.125 0 013.75 9.375v-4.5zM3.75 14.625c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5a1.125 1.125 0 01-1.125-1.125v-4.5zM13.5 4.875c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5A1.125 1.125 0 0113.5 9.375v-4.5z"/><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 6.75h.75v.75h-.75v-.75zM6.75 16.5h.75v.75h-.75v-.75zM16.5 6.75h.75v.75h-.75v-.75zM13.5 13.5h.75v.75h-.75v-.75zM13.5 19.5h.75v.75h-.75v-.75zM19.5 13.5h.75v.75h-.75v-.75zM19.5 19.5h.75v.75h-.75v-.75zM16.5 16.5h.75v.75h-.75v-.75z"/></svg>
Scan QR code to upload from phone
</button>
</div>
<div id="dot-id-qr-container" hidden style="text-align:center;margin:16px 0 0;padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px">
<canvas id="dot-id-qr-canvas" style="margin:0 auto;display:block"></canvas>
<p style="font-size:12px;color:#64748b;margin:10px 0 0">Scan this QR code with your phone's camera to open this form on your mobile device and take a photo of your ID.</p>
</div>
</div>
</div>
<div class="pw-security-notice" style="margin-top:8px">
<svg style="width:14px;height:14px;flex-shrink:0;margin-top:2px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z"/></svg>
<span style="font-size:11px">Your ID is encrypted in transit and at rest. Used only for FMCSA identity verification and automatically deleted after filing.</span>
</div>
</div>
</div>
<div id="pw-dot-errors" class="pw-err" hidden></div>
</div>
<style>
.pw-step h2 { margin: 0 0 0.5rem; color: #1a2744; }
.pw-step h3 { color: #1a2744; margin: 1.25rem 0 0.5rem; font-size: 0.95rem; border-bottom: 1px solid #e2e8f0; padding-bottom: 0.3rem; }
.pw-help { color: #64748b; font-size: 0.9rem; margin-bottom: 1rem; }
.pw-form-grid { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 1rem 1.25rem; }
.pw-row, .pw-row-2, .pw-row-3 { margin-bottom: 0.75rem; }
.pw-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
.pw-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0.75rem; }
.pw-field { display: flex; flex-direction: column; gap: 0.2rem; }
.pw-field span { font-size: 0.8rem; font-weight: 600; color: #374151; }
.pw-field em { color: #dc2626; font-style: normal; }
.pw-field input, .pw-field select { padding: 0.5rem; border: 1px solid #d1d5db; border-radius: 6px; font-size: 0.85rem; }
.pw-field input:focus, .pw-field select:focus { outline: none; border-color: #f97316; box-shadow: 0 0 0 2px rgba(249,115,22,0.2); }
.pw-field-help { font-size: 0.8rem; color: #64748b; margin: 0 0 0.5rem; }
.pw-cargo-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0.3rem 1rem; font-size: 0.85rem; color: #374151; }
.pw-cargo-grid label { display: flex; align-items: center; gap: 0.4rem; cursor: pointer; }
.pw-security-notice { display: flex; gap: 8px; align-items: flex-start; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 10px 14px; margin-bottom: 1rem; font-size: 12px; color: #1e40af; line-height: 1.5; }
.pw-upload-area { border: 2px dashed #d1d5db; border-radius: 8px; padding: 1rem; text-align: center; }
.pw-err { color: #b91c1c; margin-top: 0.75rem; font-size: 0.9rem; background: #fee2e2; padding: 0.5rem 0.75rem; border-radius: 6px; }
@media (max-width: 640px) { .pw-row-2, .pw-row-3 { grid-template-columns: 1fr; } .pw-cargo-grid { grid-template-columns: 1fr 1fr; } }
</style>
<script is:inline>
// Guard: only run on pages that have the DOT intake step
if (!document.querySelector('[data-slug="dot-intake"], [data-step="dot-intake"]')) {
// Not a DOT intake page — skip all initialization
} else {
// Determine which sections to show based on services in the batch
const DOT_SECTIONS = {
"mcs150-update": ["dot-sec-operations","dot-sec-fleet","dot-sec-cargo","dot-sec-photo-id"],
"ucr-registration": ["dot-sec-fleet","dot-sec-ucr"],
"dot-drug-alcohol": ["dot-sec-da"],
"boc3-filing": ["dot-sec-boc3"],
"dot-registration": ["dot-sec-operations"],
"mc-authority": ["dot-sec-operations","dot-sec-photo-id"],
"dot-audit-prep": ["dot-sec-operations","dot-sec-fleet","dot-sec-da"],
"dot-full-compliance": ["dot-sec-operations","dot-sec-fleet","dot-sec-cargo","dot-sec-ucr","dot-sec-da","dot-sec-boc3","dot-sec-photo-id"],
};
function showRelevantSections() {
const PW = (window).PWIntake;
const state = PW?.get?.() || {};
// Get service slug from wizard element or state
const wizardEl = document.querySelector(".pw-wizard[data-service]");
const pageSlug = wizardEl?.getAttribute("data-service") || "";
const slugs = state.batch_slugs || [pageSlug || state.service_slug || ""];
// Collect all sections to show
const show = new Set();
for (const slug of slugs) {
for (const sec of (DOT_SECTIONS[slug] || [])) {
show.add(sec);
}
}
// Default: always show operations + fleet if nothing specific
if (show.size === 0) {
show.add("dot-sec-operations");
show.add("dot-sec-fleet");
}
// Show/hide sections
for (const id of Object.keys(DOT_SECTIONS).flatMap(k => DOT_SECTIONS[k])) {
const el = document.getElementById(id);
if (el) el.hidden = !show.has(id);
}
// Auto-fill UCR base state from address
const stateEl = document.getElementById("dot-state");
const ucrState = document.getElementById("dot-ucr-state");
if (stateEl && ucrState) {
ucrState.value = stateEl.value;
stateEl.addEventListener("change", () => { ucrState.value = stateEl.value; });
}
}
// Show sections — retry until wizard element is found
function initSections() {
const wizardEl = document.querySelector(".pw-wizard[data-service]");
if (!wizardEl) { setTimeout(initSections, 100); return; }
showRelevantSections();
}
initSections();
window.addEventListener("pw:step-shown", (evt) => {
if (evt.detail.step !== "dot-intake") return;
showRelevantSections();
// Hydrate from existing intake data
const s = (window).PWIntake.get();
const d = s.intake_data || {};
const map = {
"dot-legal-name": d.legal_name || "", "dot-dba": d.dba_name || "",
"dot-dot": d.dot_number || "", "dot-mc": d.mc_number || "", "dot-ein": d.ein || "",
"dot-street": d.address_street || "", "dot-city": d.address_city || "",
"dot-state": d.address_state || "", "dot-zip": d.address_zip || "",
"dot-phone": d.phone || "", "dot-email": d.email || s.email || "",
"dot-entity-type": d.entity_type || "", "dot-carrier-op": d.carrier_operation || "",
"dot-interstate": d.interstate_intrastate || "", "dot-hazmat": d.hazmat || "",
"dot-power-units": d.power_units || "", "dot-drivers": d.drivers || "",
"dot-miles": d.annual_miles || "", "dot-signer-name": d.signer_name || "",
"dot-signer-title": d.signer_title || "", "dot-cdl-drivers": d.cdl_drivers || "",
"dot-owner-ops": d.owner_operators || "0", "dot-der-name": d.der_name || "",
"dot-current-da": d.current_da_provider || "", "dot-ucr-bracket": d.fleet_size_bracket || "",
};
for (const [id, val] of Object.entries(map)) {
const el = document.getElementById(id);
if (el && val) el.value = val;
}
});
// Save all data on step-next
window.addEventListener("pw:step-next", (evt) => {
const PW = (window).PWIntake;
if (PW.steps[PW.get().step_index] !== "dot-intake") return;
const errDiv = document.getElementById("pw-dot-errors");
errDiv.hidden = true;
// Validate required fields (only visible ones)
const required = ["dot-legal-name","dot-dot","dot-street","dot-city","dot-state","dot-zip","dot-phone","dot-email","dot-signer-name","dot-signer-title"];
const missing = [];
for (const id of required) {
const el = document.getElementById(id);
if (!el || !el.value.trim()) missing.push(el?.parentElement?.querySelector("span")?.textContent || id);
}
// Validate visible-section-specific required fields
const visibleRequired = {
"dot-sec-operations": ["dot-entity-type","dot-carrier-op","dot-interstate","dot-hazmat"],
"dot-sec-fleet": ["dot-power-units","dot-drivers"],
};
for (const [secId, fields] of Object.entries(visibleRequired)) {
const sec = document.getElementById(secId);
if (sec && !sec.hidden) {
for (const id of fields) {
const el = document.getElementById(id);
if (!el || !el.value.trim()) missing.push(el?.parentElement?.querySelector("span")?.textContent || id);
}
}
}
if (missing.length) { evt.preventDefault(); errDiv.hidden = false; errDiv.textContent = "Please fill in: " + missing.join(", "); return; }
// Collect cargo types
const cargoTypes = [];
document.querySelectorAll("[data-cargo]").forEach(function(cb) {
if (cb.checked) cargoTypes.push(cb.dataset.cargo);
});
const val = (id) => (document.getElementById(id))?.value?.trim() || "";
const state = PW.get();
PW.set({ ...state, intake_data: { ...state.intake_data,
legal_name: val("dot-legal-name"), dba_name: val("dot-dba"),
dot_number: val("dot-dot"), mc_number: val("dot-mc"), ein: val("dot-ein"),
address_street: val("dot-street"), address_city: val("dot-city"),
address_state: val("dot-state"), address_zip: val("dot-zip"),
phone: val("dot-phone"), email: val("dot-email"),
entity_type: val("dot-entity-type"), carrier_operation: val("dot-carrier-op"),
interstate_intrastate: val("dot-interstate"), hazmat: val("dot-hazmat"),
power_units: val("dot-power-units"), drivers: val("dot-drivers"),
annual_miles: val("dot-miles"), cargo_types: cargoTypes,
signer_name: val("dot-signer-name"), signer_title: val("dot-signer-title"),
fleet_size_bracket: val("dot-ucr-bracket"), base_state: val("dot-ucr-state"),
cdl_drivers: val("dot-cdl-drivers"), owner_operators: val("dot-owner-ops"),
der_name: val("dot-der-name"), current_da_provider: val("dot-current-da"),
docket_type: val("dot-docket-type"), docket_number: val("dot-docket-num"),
photo_id_uploaded: !!(window).__dotPhotoId,
}});
});
// Photo ID upload (elements may not exist if section is hidden)
const idBtn = document.getElementById("dot-id-btn");
const idInput = document.getElementById("dot-photo-id");
const idPreview = document.getElementById("dot-id-preview");
const idImg = document.getElementById("dot-id-img");
const idRemove = document.getElementById("dot-id-remove");
const idQrBtn = document.getElementById("dot-id-qr-btn");
const idQrContainer = document.getElementById("dot-id-qr-container");
const idUploadOpts = document.getElementById("dot-id-upload-options");
// Upload button — opens file picker
idBtn?.addEventListener("click", function() { if (idInput) idInput.click(); });
// Scanner/camera button — uses capture attribute to trigger camera or scanner
var idScanBtn = document.getElementById("dot-id-scan-btn");
var idScanInput = document.getElementById("dot-photo-id-scan");
idScanBtn?.addEventListener("click", function() { if (idScanInput) idScanInput.click(); });
idScanInput?.addEventListener("change", function() {
var file = idScanInput.files?.[0];
if (!file) return;
// Copy to main input handler
window.__dotPhotoId = file;
if (file.type.startsWith("image/") && idImg) {
var reader = new FileReader();
reader.onload = function(e) { idImg.src = e.target?.result; };
reader.readAsDataURL(file);
}
if (idPreview) idPreview.hidden = false;
if (idUploadOpts) idUploadOpts.style.display = "none";
});
// QR code button — show QR with current page URL for phone upload
idQrBtn?.addEventListener("click", function() {
if (!idQrContainer) return;
var showing = !idQrContainer.hidden;
idQrContainer.hidden = showing;
if (!showing) {
// Generate QR code using canvas
var canvas = document.getElementById("dot-id-qr-canvas");
if (canvas && !canvas.dataset.rendered) {
var url = window.location.href;
// Use a simple QR code API (Google Charts - no library needed)
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = function() {
canvas.width = 200;
canvas.height = 200;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, 200, 200);
canvas.dataset.rendered = "1";
};
img.src = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" + encodeURIComponent(url);
}
}
});
idInput?.addEventListener("change", function() {
var file = idInput.files?.[0];
if (!file) return;
window.__dotPhotoId = file;
if (file.type.startsWith("image/")) {
const reader = new FileReader();
reader.onload = (e) => { idImg.src = e.target?.result; };
reader.readAsDataURL(file);
}
if (idPreview) idPreview.hidden = false;
if (idUploadOpts) idUploadOpts.style.display = "none";
});
idRemove?.addEventListener("click", () => {
(window).__dotPhotoId = null;
if (idInput) idInput.value = "";
if (idScanInput) idScanInput.value = "";
if (idPreview) idPreview.hidden = true;
if (idUploadOpts) idUploadOpts.style.display = "";
});
} // end guard
</script>