emergency: 911 demoted to very last resort — page now leads with event-help share card; emergency-services number moved to collapsed 'If none of the above is working' disclosure at the very bottom, no alert styling
Some checks failed
ci / check (push) Has been cancelled
Some checks failed
ci / check (push) Has been cancelled
This commit is contained in:
parent
5b5d1857c3
commit
1c49b8a4a8
3 changed files with 85 additions and 17 deletions
|
|
@ -661,16 +661,35 @@ html.dark .app-main__icon {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.emergency-fallback {
|
.emergency-share-card {
|
||||||
background: var(--emergency);
|
border: 1px solid var(--border);
|
||||||
border: 1px solid var(--emergency);
|
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
color: var(--emergency-contrast);
|
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
.emergency-fallback h2 {
|
.emergency-share-card h2 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
.emergency-last-resort {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
}
|
||||||
|
.emergency-last-resort summary {
|
||||||
|
color: var(--muted);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.emergency-last-resort p {
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
.emergency-call-last {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--foreground);
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.4rem 1rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
.emergency-service p {
|
.emergency-service p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,13 +129,18 @@ export function createEmergencyView(
|
||||||
const address = detail?.address ?? resolved.floor.address;
|
const address = detail?.address ?? resolved.floor.address;
|
||||||
const procedures = detail?.procedures?.length ? detail.procedures : resolved.floor.procedures;
|
const procedures = detail?.procedures?.length ? detail.procedures : resolved.floor.procedures;
|
||||||
|
|
||||||
const urgent = document.createElement("div");
|
// Share card at top: the primary self-help action. The emergency-services
|
||||||
urgent.className = "emergency-fallback";
|
// number is deliberately NOT here — per product rule it is the very last
|
||||||
urgent.append(heading("emergency-call-heading", "Can't reach event help?"));
|
// resort and lives behind an explicit disclosure at the page bottom.
|
||||||
|
const shareCard = document.createElement("div");
|
||||||
// Share first: the practical action (send your location + numbers to your
|
shareCard.className = "emergency-share-card";
|
||||||
// group) belongs above the emergency-services number, which the procedures
|
shareCard.append(heading("emergency-share-heading", "Start with event help"));
|
||||||
// now frame as the fallback.
|
shareCard.append(
|
||||||
|
text(
|
||||||
|
"p",
|
||||||
|
"Event staff, security, and first aid are your first responders here. Share your situation and location with them or your group.",
|
||||||
|
),
|
||||||
|
);
|
||||||
const shareBtn = document.createElement("button");
|
const shareBtn = document.createElement("button");
|
||||||
shareBtn.className = "emergency-share-btn";
|
shareBtn.className = "emergency-share-btn";
|
||||||
shareBtn.textContent = "Share emergency info";
|
shareBtn.textContent = "Share emergency info";
|
||||||
|
|
@ -153,11 +158,8 @@ export function createEmergencyView(
|
||||||
alert("Copied to clipboard: " + textToShare.slice(0, 80) + "...");
|
alert("Copied to clipboard: " + textToShare.slice(0, 80) + "...");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
urgent.append(shareBtn);
|
shareCard.append(shareBtn);
|
||||||
|
section.append(shareCard);
|
||||||
addService(urgent, "Emergency services", services.emergencyNumber, true);
|
|
||||||
urgent.append(text("p", "Call only when event staff and first aid can't respond. Tap to call."));
|
|
||||||
section.append(urgent);
|
|
||||||
|
|
||||||
const contacts = document.createElement("section");
|
const contacts = document.createElement("section");
|
||||||
contacts.setAttribute("aria-labelledby", "emergency-services-heading");
|
contacts.setAttribute("aria-labelledby", "emergency-services-heading");
|
||||||
|
|
@ -241,5 +243,31 @@ export function createEmergencyView(
|
||||||
section.append(notices);
|
section.append(notices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Very last resort: the emergency-services number sits at the BOTTOM of
|
||||||
|
// the page behind an explicit disclosure, deliberately not styled as an
|
||||||
|
// alert. The dial link stays in the DOM for accessibility; it just is not
|
||||||
|
// presented until asked for.
|
||||||
|
const lastResort = document.createElement("details");
|
||||||
|
lastResort.className = "emergency-last-resort";
|
||||||
|
const summary = document.createElement("summary");
|
||||||
|
summary.textContent = "If none of the above is working";
|
||||||
|
lastResort.append(summary);
|
||||||
|
lastResort.append(
|
||||||
|
text(
|
||||||
|
"p",
|
||||||
|
`Only when event staff, security, and first aid are unreachable and someone is in immediate danger: call ${services.emergencyNumber}.`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const dialLink = document.createElement("a");
|
||||||
|
dialLink.className = "emergency-call-last";
|
||||||
|
dialLink.href = `tel:${services.emergencyNumber}`;
|
||||||
|
dialLink.textContent = `Call ${services.emergencyNumber}`;
|
||||||
|
dialLink.setAttribute(
|
||||||
|
"aria-label",
|
||||||
|
`As a last resort, call emergency services at ${services.emergencyNumber}`,
|
||||||
|
);
|
||||||
|
lastResort.append(dialLink);
|
||||||
|
section.append(lastResort);
|
||||||
|
|
||||||
return section;
|
return section;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,27 @@ describe("emergency view", () => {
|
||||||
expect(view.textContent).toContain("isn't on this device yet");
|
expect(view.textContent).toContain("isn't on this device yet");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("emergency number is last-resort: bottom of page, collapsed, after procedures", () => {
|
||||||
|
const view = createEmergencyView(undefined, NOW);
|
||||||
|
const last = view.querySelector(".emergency-last-resort");
|
||||||
|
expect(last).toBeTruthy();
|
||||||
|
// collapsed by default — the number is not presented until asked
|
||||||
|
expect(last?.hasAttribute("open")).toBe(false);
|
||||||
|
// it is the very last element of the view
|
||||||
|
expect(view.lastElementChild).toBe(last);
|
||||||
|
// ...it comes after the procedures section...
|
||||||
|
const idx = (selector: string): number => {
|
||||||
|
const el = view.querySelector(selector);
|
||||||
|
return el ? [...view.children].indexOf(el) : -1;
|
||||||
|
};
|
||||||
|
expect(idx(".emergency-last-resort")).toBeGreaterThan(
|
||||||
|
idx('[aria-labelledby="emergency-procedures-heading"]'),
|
||||||
|
);
|
||||||
|
// ...and the page leads with event help, not the dial number
|
||||||
|
expect(idx(".emergency-share-card")).toBeGreaterThanOrEqual(1);
|
||||||
|
expect(view.querySelector(".emergency-share-card")?.textContent).toContain("event help");
|
||||||
|
});
|
||||||
|
|
||||||
it("dataset tier renders locations with map handoffs and notices", () => {
|
it("dataset tier renders locations with map handoffs and notices", () => {
|
||||||
const view = createEmergencyView(dataset(), NOW);
|
const view = createEmergencyView(dataset(), NOW);
|
||||||
expect(view.textContent).toContain("FESTIVAL DATA v3");
|
expect(view.textContent).toContain("FESTIVAL DATA v3");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue