fix(intake): repair order wizard — checkout was fully broken on trucking/HC
Diagnosed via live browser E2E why campaign clicks (25 checkout-page-views,
36h) produced 0 conversions. Four bugs, all blocking checkout:
1. DOTIntakeStep: a missing `});` (DFWP hydration block, commit 9718ab9
Jun 2) left the pw:step-shown listener unclosed -> 'missing ) after
argument list' SYNTAX ERROR killed the whole DOT intake script. Effect:
?dot= prefill silently failed for ~3 weeks (exactly the campaign window),
so every carrier had to re-type all their details.
2. ReviewStep: service slug read from `.pw-step[data-slug]` (first match),
which on trucking/HC is the INTAKE step's slug ('dot-intake'/'npi-intake'),
not the order. The cold-visitor order-create POST sent
service_slug='dot-intake' -> API 501/400 -> 'Could not validate order',
blocking checkout at the review step on EVERY multi-step vertical. Now
reads `.pw-wizard[data-service]` (authoritative). Confirmed against prod:
bad slug=400, correct slug=201.
3. Shared-bundle null derefs: every step's <script> is bundled onto every
order page, so steps whose anchor element is absent threw at top level and
could abort siblings:
- ClassificationWizard: top-level renderQuestion(0) -> appendChild on
null (errored on 47/67 order pages)
- BDCDataStep: (querySelector as HTMLElement).getAttribute on null
- STIRShakenStep / EarthStationStep: top-level addEventListener on null
- ForeignQualStep: many top-level getElementById(...)! lookups
Each now guarded to no-op when its step isn't present.
Verified by browser E2E: full flow dot-intake -> review -> payment ->
live Stripe Checkout session, and a 67-page scan now reports 0 JS errors
(was 47 pages erroring). Real human clicks are tracked via Umami; these
were pure functional breakages of the conversion path.
This commit is contained in:
parent
3325259af7
commit
5546c58bf0
7 changed files with 36 additions and 7 deletions
|
|
@ -46,7 +46,13 @@ const mode = service_slug === "bdc-voice" ? "voice" : service_slug === "bdc-broa
|
|||
</style>
|
||||
|
||||
<script>
|
||||
const mode = (document.querySelector(".pw-step[data-mode]") as HTMLElement).getAttribute("data-mode")!;
|
||||
// Guard: only run on pages that actually have the BDC data step. Without this
|
||||
// the top-level querySelector returns null on every other order page and the
|
||||
// `.getAttribute` throws, killing this script (a harmless-looking but real
|
||||
// page error). The cast `as HTMLElement` masked the null at compile time.
|
||||
const bdcRoot = document.querySelector(".pw-step[data-mode]") as HTMLElement | null;
|
||||
if (bdcRoot) {
|
||||
const mode = bdcRoot.getAttribute("data-mode")!;
|
||||
const voice = document.getElementById("pw-voice-subs") as HTMLInputElement | null;
|
||||
const snap = document.getElementById("pw-snapshot") as HTMLInputElement | null;
|
||||
const file = document.getElementById("pw-bdc-file") as HTMLInputElement | null;
|
||||
|
|
@ -86,4 +92,5 @@ const mode = service_slug === "bdc-voice" ? "voice" : service_slug === "bdc-broa
|
|||
}
|
||||
PW.patchIntakeData(patch);
|
||||
});
|
||||
} // end BDC step guard
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -214,8 +214,11 @@
|
|||
return { primary, categories: [...new Set(cats)], reason };
|
||||
}
|
||||
|
||||
// Render Q&A
|
||||
const container = document.getElementById("cw-questions")!;
|
||||
// Render Q&A. This script is bundled into every order page, so the container
|
||||
// is absent on pages without the classification step — bail rather than throw
|
||||
// on the top-level renderQuestion(0) call below (container.appendChild → null).
|
||||
const container = document.getElementById("cw-questions");
|
||||
if (container) {
|
||||
const answers: Record<string, string> = {};
|
||||
let questionIndex = 0;
|
||||
|
||||
|
|
@ -306,4 +309,5 @@
|
|||
|
||||
// Also start immediately if this is the current step
|
||||
renderQuestion(0);
|
||||
} // end classification step guard
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -465,6 +465,7 @@
|
|||
if (dfwpRow) dfwpRow.hidden = false;
|
||||
if (dfwpStateEl && d.state_dfwp) dfwpStateEl.value = d.state_dfwp;
|
||||
}
|
||||
});
|
||||
|
||||
// Save all data on step-next
|
||||
window.addEventListener("pw:step-next", (evt) => {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,8 @@
|
|||
return row;
|
||||
}
|
||||
|
||||
document.getElementById("pw-add-circuit")!.addEventListener("click", () => {
|
||||
const addCircuitBtn = document.getElementById("pw-add-circuit");
|
||||
if (addCircuitBtn) addCircuitBtn.addEventListener("click", () => {
|
||||
circuitsDiv.appendChild(newCircuitRow());
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,13 @@
|
|||
</style>
|
||||
|
||||
<script>
|
||||
const grid = document.getElementById("pw-fq-grid")!;
|
||||
// Guard: this step's script is bundled into every order page. Only initialize
|
||||
// when the foreign-qualification grid is actually present, otherwise the many
|
||||
// top-level getElementById(...)! lookups below return null and throw, killing
|
||||
// the shared bundle (and any sibling step wired after it).
|
||||
const fqGrid = document.getElementById("pw-fq-grid");
|
||||
if (fqGrid) {
|
||||
const grid = fqGrid as HTMLElement;
|
||||
const countEl = document.getElementById("pw-fq-count")!;
|
||||
const quoteDiv = document.getElementById("pw-fq-quote") as HTMLElement;
|
||||
const quoteBody = document.getElementById("pw-fq-quote-body")!;
|
||||
|
|
@ -238,4 +244,5 @@
|
|||
});
|
||||
|
||||
loadJurisdictions();
|
||||
} // end foreign_qual step guard
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,15 @@ const vertical = slugVertical(service_slug);
|
|||
</style>
|
||||
|
||||
<script>
|
||||
const slug = document.querySelector(".pw-step[data-slug]")!.getAttribute("data-slug")!;
|
||||
// The service slug MUST come from the wizard root, not the first
|
||||
// `.pw-step[data-slug]`: on multi-step verticals (e.g. trucking) the DOT intake
|
||||
// step renders before the review step and carries its own data-slug
|
||||
// ("dot-intake"), so querySelector(".pw-step[data-slug]") returned the wrong
|
||||
// value and the order-create POST sent service_slug="dot-intake" → HTTP 501,
|
||||
// blocking every cold-visitor checkout on those pages.
|
||||
const slug = document.querySelector(".pw-wizard[data-service]")?.getAttribute("data-service")
|
||||
|| document.querySelector(".pw-step[data-slug]")?.getAttribute("data-slug")
|
||||
|| "";
|
||||
const entDiv = document.getElementById("pw-summary-entity")!;
|
||||
const intakeDiv = document.getElementById("pw-summary-intake")!;
|
||||
const errDiv = document.getElementById("pw-review-errors") as HTMLDivElement;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@
|
|||
upstreamInput.style.display = showUpstream ? "" : "none";
|
||||
}
|
||||
|
||||
g<HTMLSelectElement>("pw-ss-status").addEventListener("change", updateSSFields);
|
||||
const ssStatusEl = g<HTMLSelectElement>("pw-ss-status");
|
||||
if (ssStatusEl) ssStatusEl.addEventListener("change", updateSSFields);
|
||||
|
||||
window.addEventListener("pw:step-shown", (evt: any) => {
|
||||
if (evt.detail.step !== "stir_shaken") return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue