@dataemergencia/emergency 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -9
- package/dist/iife/emergency.iife.global.js +24 -24
- package/dist/index.cjs +926 -398
- package/dist/index.d.cts +22 -14
- package/dist/index.d.ts +22 -14
- package/dist/index.js +927 -399
- package/dist/styles.css +418 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -84,13 +84,8 @@ function isFiniteNumber(value) {
|
|
|
84
84
|
function isArrayOf(value, guard) {
|
|
85
85
|
return Array.isArray(value) && value.every(guard);
|
|
86
86
|
}
|
|
87
|
-
function isRealtimeConfig(value) {
|
|
88
|
-
if (!isRecord(value) || value["mode"] !== "public" || !isRecord(value["pusher"])) return false;
|
|
89
|
-
const pusher = value["pusher"];
|
|
90
|
-
return isString(pusher["key"]) && isString(pusher["cluster"]) && isString(pusher["channel_pattern"]);
|
|
91
|
-
}
|
|
92
87
|
function isConfigResponse(value) {
|
|
93
|
-
return isRecord(value) && isString(value["route_prefix"]) && isString(value["csrf_token"])
|
|
88
|
+
return isRecord(value) && isString(value["route_prefix"]) && isString(value["csrf_token"]);
|
|
94
89
|
}
|
|
95
90
|
function isSessionResponse(value) {
|
|
96
91
|
return isRecord(value) && isString(value["code"]) && isString(value["csrf_token"]) && isFiniteNumber(value["expires_in"]);
|
|
@@ -108,7 +103,7 @@ function isEmergencyResultPayload(value) {
|
|
|
108
103
|
return (value["emergency_id"] === null || isString(value["emergency_id"])) && isBoolean(value["simulated"]) && isArrayOf(value["responders"], isResponderPayload) && isArrayOf(value["failures"], isFailurePayload);
|
|
109
104
|
}
|
|
110
105
|
function isCurrentResponse(value) {
|
|
111
|
-
if (!isRecord(value) || !isBoolean(value["active"])
|
|
106
|
+
if (!isRecord(value) || !isBoolean(value["active"])) return false;
|
|
112
107
|
return value["emergency"] === null || isRecord(value["emergency"]) && !Array.isArray(value["emergency"]);
|
|
113
108
|
}
|
|
114
109
|
function isRefreshResponse(value) {
|
|
@@ -396,6 +391,7 @@ function createBffClient(options) {
|
|
|
396
391
|
const copy = {
|
|
397
392
|
panelLabel: "Panel de emergencia",
|
|
398
393
|
close: "Cerrar panel de emergencia",
|
|
394
|
+
back: "Volver",
|
|
399
395
|
question: "¿Tiene usted una emergencia?",
|
|
400
396
|
illustrationAlt: "Ícono paramédico",
|
|
401
397
|
emergency: "Emergencia",
|
|
@@ -634,8 +630,9 @@ function themeToCssVariables(theme) {
|
|
|
634
630
|
}
|
|
635
631
|
|
|
636
632
|
// src/core/realtime.ts
|
|
633
|
+
const DEFAULT_CHANNEL_PATTERN = "whatsapp.{phone}";
|
|
637
634
|
function channelForPhone(pattern, phone) {
|
|
638
|
-
return pattern.replace("{phone}", phone.replace(
|
|
635
|
+
return pattern.replace("{phone}", phone.replace(/\D/g, ""));
|
|
639
636
|
}
|
|
640
637
|
function toStatus(state) {
|
|
641
638
|
switch (state) {
|
|
@@ -650,11 +647,11 @@ function toStatus(state) {
|
|
|
650
647
|
}
|
|
651
648
|
function createPusherRealtimeProvider() {
|
|
652
649
|
return { subscribe(config, phones, handlers) {
|
|
653
|
-
if (typeof window === "undefined" || !config.
|
|
650
|
+
if (typeof window === "undefined" || !config.key || !config.cluster) return null;
|
|
654
651
|
let pusher;
|
|
655
652
|
try {
|
|
656
|
-
pusher = new pusher_js.default(config.
|
|
657
|
-
cluster: config.
|
|
653
|
+
pusher = new pusher_js.default(config.key, {
|
|
654
|
+
cluster: config.cluster,
|
|
658
655
|
forceTLS: true
|
|
659
656
|
});
|
|
660
657
|
} catch {
|
|
@@ -666,7 +663,7 @@ function createPusherRealtimeProvider() {
|
|
|
666
663
|
handlers.onStatus(toStatus(change.current));
|
|
667
664
|
});
|
|
668
665
|
const channels = [...new Set(phones.filter((phone) => phone !== ""))].map((phone) => {
|
|
669
|
-
const channelName = channelForPhone(config.
|
|
666
|
+
const channelName = channelForPhone(config.channelPattern ?? DEFAULT_CHANNEL_PATTERN, phone);
|
|
670
667
|
pusher.subscribe(channelName).bind_global((eventName, data) => {
|
|
671
668
|
handlers.onEvent(channelName, eventName, data);
|
|
672
669
|
});
|
|
@@ -795,7 +792,6 @@ function createEmergencyController(deps) {
|
|
|
795
792
|
let sessionPromise = null;
|
|
796
793
|
let refreshing = false;
|
|
797
794
|
let realtimeSubscription = null;
|
|
798
|
-
let realtimeConfig = null;
|
|
799
795
|
let subscribedPhones = [];
|
|
800
796
|
let messageSequence = 0;
|
|
801
797
|
let lastReconcileAt = 0;
|
|
@@ -853,9 +849,12 @@ function createEmergencyController(deps) {
|
|
|
853
849
|
realtimeSubscription = null;
|
|
854
850
|
subscribedPhones = [];
|
|
855
851
|
}
|
|
856
|
-
function startRealtime(
|
|
857
|
-
|
|
858
|
-
|
|
852
|
+
function startRealtime(responders) {
|
|
853
|
+
const realtime = config.realtime ?? null;
|
|
854
|
+
if (!realtime) {
|
|
855
|
+
if (responders.length > 0) patch({ realtimeStatus: "unavailable" });
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
859
858
|
const phones = [...new Set(responders.map((responder) => responder.phone))];
|
|
860
859
|
if (realtimeSubscription && phones.length === subscribedPhones.length && phones.every((phone, index) => phone === subscribedPhones[index])) return;
|
|
861
860
|
realtimeSubscription?.disconnect();
|
|
@@ -889,7 +888,7 @@ function createEmergencyController(deps) {
|
|
|
889
888
|
const phase = get().phase.kind;
|
|
890
889
|
if (phase === "idle" || phase === "error") transition({ kind: "initializing" });
|
|
891
890
|
try {
|
|
892
|
-
|
|
891
|
+
await bff.config();
|
|
893
892
|
const session = await bff.session(config.code);
|
|
894
893
|
patch({
|
|
895
894
|
sessionReady: true,
|
|
@@ -919,7 +918,6 @@ function createEmergencyController(deps) {
|
|
|
919
918
|
async function hydrateCurrent() {
|
|
920
919
|
try {
|
|
921
920
|
const current = await bff.current();
|
|
922
|
-
realtimeConfig = current.realtime;
|
|
923
921
|
if (current.active && current.emergency) {
|
|
924
922
|
const snapshot = payloadToSnapshot(current.emergency, { code: config.code });
|
|
925
923
|
patch({
|
|
@@ -935,7 +933,7 @@ function createEmergencyController(deps) {
|
|
|
935
933
|
emergencyId: snapshot.emergencyId,
|
|
936
934
|
simulated: snapshot.simulated
|
|
937
935
|
});
|
|
938
|
-
startRealtime(
|
|
936
|
+
startRealtime(snapshot.responders);
|
|
939
937
|
events.emit("emergency:resumed", { snapshot });
|
|
940
938
|
return;
|
|
941
939
|
}
|
|
@@ -1017,7 +1015,7 @@ function createEmergencyController(deps) {
|
|
|
1017
1015
|
});
|
|
1018
1016
|
pushMessage(failures.length > 0 ? "warning" : "success", failures.length > 0 ? copy.partialFailure : copy.activeBanner);
|
|
1019
1017
|
events.emit("emergency:activated", { snapshot: hydrated });
|
|
1020
|
-
startRealtime(
|
|
1018
|
+
startRealtime(responders);
|
|
1021
1019
|
} catch (error) {
|
|
1022
1020
|
const normalized = toEmergencyError(error, "network");
|
|
1023
1021
|
if (normalized.code === "emergency_already_active") {
|
|
@@ -1109,7 +1107,7 @@ function createEmergencyController(deps) {
|
|
|
1109
1107
|
emergencyId: updated.emergencyId,
|
|
1110
1108
|
simulated: updated.simulated
|
|
1111
1109
|
});
|
|
1112
|
-
startRealtime(
|
|
1110
|
+
startRealtime(responders);
|
|
1113
1111
|
events.emit("emergency:updated", { snapshot: updated });
|
|
1114
1112
|
} catch (error) {
|
|
1115
1113
|
const normalized = toEmergencyError(error, "network");
|
|
@@ -1242,7 +1240,6 @@ function createEmergencyController(deps) {
|
|
|
1242
1240
|
bff.destroy();
|
|
1243
1241
|
realtimeSubscription?.disconnect();
|
|
1244
1242
|
realtimeSubscription = null;
|
|
1245
|
-
realtimeConfig = null;
|
|
1246
1243
|
subscribedPhones = [];
|
|
1247
1244
|
patch({
|
|
1248
1245
|
destroyed: true,
|
|
@@ -1373,6 +1370,24 @@ function installEmergencyFonts(input) {
|
|
|
1373
1370
|
|
|
1374
1371
|
// src/core/config.ts
|
|
1375
1372
|
const EMERGENCY_CODE_PATTERN = /^[A-Za-z][A-Za-z0-9]{5}$/;
|
|
1373
|
+
const DEFAULT_REALTIME_CHANNEL_PATTERN = "whatsapp.{phone}";
|
|
1374
|
+
/**
|
|
1375
|
+
* Validates the host-supplied realtime block. Returns `null` when the value is
|
|
1376
|
+
* present but invalid; callers treat `undefined` as "realtime not requested".
|
|
1377
|
+
*/
|
|
1378
|
+
function normalizeRealtimeConfig(value) {
|
|
1379
|
+
if (!isRecord(value)) return null;
|
|
1380
|
+
const key = value["key"];
|
|
1381
|
+
const cluster = value["cluster"];
|
|
1382
|
+
const channelPattern = value["channelPattern"];
|
|
1383
|
+
if (typeof key !== "string" || key.trim() === "" || typeof cluster !== "string" || cluster.trim() === "") return null;
|
|
1384
|
+
if (channelPattern !== void 0 && (typeof channelPattern !== "string" || channelPattern.trim() === "" || !channelPattern.includes("{phone}"))) return null;
|
|
1385
|
+
return {
|
|
1386
|
+
key,
|
|
1387
|
+
cluster,
|
|
1388
|
+
channelPattern: channelPattern ?? "whatsapp.{phone}"
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1376
1391
|
const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
|
|
1377
1392
|
"localhost",
|
|
1378
1393
|
"127.0.0.1",
|
|
@@ -1433,6 +1448,12 @@ function validateConfig(config) {
|
|
|
1433
1448
|
config: null,
|
|
1434
1449
|
error: createEmergencyError("configuration", "The fallback requires a non-empty phone and label.")
|
|
1435
1450
|
};
|
|
1451
|
+
const realtime = config.realtime === void 0 ? void 0 : normalizeRealtimeConfig(config.realtime);
|
|
1452
|
+
if (realtime === null) return {
|
|
1453
|
+
ok: false,
|
|
1454
|
+
config: null,
|
|
1455
|
+
error: createEmergencyError("configuration", "The realtime configuration requires a non-empty key and cluster, and a channel pattern containing {phone}.")
|
|
1456
|
+
};
|
|
1436
1457
|
return {
|
|
1437
1458
|
ok: true,
|
|
1438
1459
|
error: null,
|
|
@@ -1443,79 +1464,12 @@ function validateConfig(config) {
|
|
|
1443
1464
|
locale: config.locale ?? "es",
|
|
1444
1465
|
geolocationTimeoutMs: config.geolocationTimeoutMs ?? 8e3,
|
|
1445
1466
|
requestTimeoutMs: config.requestTimeoutMs ?? 15e3,
|
|
1446
|
-
fontLoading: normalizeFontLoading(config.fontLoading)
|
|
1467
|
+
fontLoading: normalizeFontLoading(config.fontLoading),
|
|
1468
|
+
realtime
|
|
1447
1469
|
}
|
|
1448
1470
|
};
|
|
1449
1471
|
}
|
|
1450
1472
|
|
|
1451
|
-
// src/react/components/icons/paramedical-mark.tsx
|
|
1452
|
-
/**
|
|
1453
|
-
* Neutral inline illustration used by the idle panel.
|
|
1454
|
-
*/
|
|
1455
|
-
function ParamedicalMark({ className, title }) {
|
|
1456
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
1457
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
1458
|
-
version: "1.0",
|
|
1459
|
-
viewBox: "0 0 192 192",
|
|
1460
|
-
width: "192",
|
|
1461
|
-
height: "192",
|
|
1462
|
-
id: "Star of life",
|
|
1463
|
-
className,
|
|
1464
|
-
"aria-label": title,
|
|
1465
|
-
children: [
|
|
1466
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { id: "defs2886" }),
|
|
1467
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
1468
|
-
id: "cross",
|
|
1469
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1470
|
-
d: "m 74,133 0,52 44,0 0,-52 44,26 22,-38 L 140,96 184,70 162,32 117,58 117,7 74,7 74,58 30,32 8,70 52,96 8,121 30,159 z",
|
|
1471
|
-
id: "outline",
|
|
1472
|
-
style: {
|
|
1473
|
-
fill: "none",
|
|
1474
|
-
stroke: "#3333bb",
|
|
1475
|
-
strokeWidth: 6
|
|
1476
|
-
}
|
|
1477
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1478
|
-
d: "m 74,133 0,52 44,0 0,-52 44,26 22,-38 L 140,96 184,70 162,32 117,58 117,7 74,7 74,58 30,32 8,70 52,96 8,121 30,159 z",
|
|
1479
|
-
id: "inner",
|
|
1480
|
-
style: {
|
|
1481
|
-
fill: "#0000bb",
|
|
1482
|
-
fillRule: "evenodd",
|
|
1483
|
-
stroke: "#ffffff",
|
|
1484
|
-
strokeWidth: 2
|
|
1485
|
-
}
|
|
1486
|
-
})]
|
|
1487
|
-
}),
|
|
1488
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
1489
|
-
id: "symbols",
|
|
1490
|
-
style: {
|
|
1491
|
-
fill: "#ffffff",
|
|
1492
|
-
fillRule: "evenodd",
|
|
1493
|
-
stroke: "#3333bb",
|
|
1494
|
-
strokeWidth: 2
|
|
1495
|
-
},
|
|
1496
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1497
|
-
d: "m 93,166 c 0,7 6,7 6,0 l 3,-138 c 0,-8 -12,-8 -12,0 l 3,135 0,3 z",
|
|
1498
|
-
id: "rod"
|
|
1499
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
1500
|
-
id: "snake",
|
|
1501
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1502
|
-
d: "m 100,153 c 7,4 3,15 -3,15 2,-5 3,-9 3,-15 z m 1,-40 c 10,9 4,22 -3,26 -6,3 -6,7 -6,15 -9,-10 -4,-19 4,-24 5,-4 5,-10 5,-17 z m 1,-30 c 0,11 -17,14 -17,22 0,3 1,9 6,12 0,-11 9,-12 15,-18 7,-7 7,-19 -4,-28 0,4 0,8 0,12 z M 90,77 C 80,69 76,55 80,46 c 3,-10 20,-11 20,-3 0,8 -20,3 -13,16 l 3,5 0,13 z",
|
|
1503
|
-
id: "body"
|
|
1504
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1505
|
-
d: "m 95,43 c 7,-3 -7,-3 0,0 z",
|
|
1506
|
-
id: "eye",
|
|
1507
|
-
style: {
|
|
1508
|
-
fill: "#3333bb",
|
|
1509
|
-
fillRule: "evenodd",
|
|
1510
|
-
stroke: "none"
|
|
1511
|
-
}
|
|
1512
|
-
})]
|
|
1513
|
-
})]
|
|
1514
|
-
})
|
|
1515
|
-
]
|
|
1516
|
-
});
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
1473
|
// src/react/components/Icon/index.tsx
|
|
1520
1474
|
/** Icons whose artwork does not fit the default 24x24 grid need their own canvas. */
|
|
1521
1475
|
const viewBoxes = { emergency: "0 0 640 640" };
|
|
@@ -1572,6 +1526,18 @@ const paths = {
|
|
|
1572
1526
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 7h.01" })
|
|
1573
1527
|
] }),
|
|
1574
1528
|
"arrow-left": /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M19 12H5" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m12 19-7-7 7-7" })] }),
|
|
1529
|
+
"credit-card-plus": /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1530
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 18H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5" }),
|
|
1531
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M18 12h.01" }),
|
|
1532
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M19 22v-6" }),
|
|
1533
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m22 19-3-3-3 3" }),
|
|
1534
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M6 12h.01" }),
|
|
1535
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1536
|
+
cx: "12",
|
|
1537
|
+
cy: "12",
|
|
1538
|
+
r: "2"
|
|
1539
|
+
})
|
|
1540
|
+
] }),
|
|
1575
1541
|
emergency: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M272.5 96C272.5 78.3 286.8 64 304.5 64L336.5 64C354.2 64 368.5 78.3 368.5 96L368.5 236.9L490.5 166.5C505.8 157.7 525.4 162.9 534.2 178.2L550.2 205.9C559 221.2 553.8 240.8 538.5 249.6L416.5 320L538.5 390.4C553.8 399.2 559.1 418.8 550.2 434.1L534.2 461.8C525.4 477.1 505.8 482.4 490.5 473.5L368.5 403.1L368.5 544C368.5 561.7 354.2 576 336.5 576L304.5 576C286.8 576 272.5 561.7 272.5 544L272.5 403.1L150.5 473.5C135.2 482.3 115.6 477.1 106.8 461.8L90.8 434.1C82 418.8 87.2 399.2 102.5 390.4L224.5 320L102.5 249.6C87.2 240.8 82 221.2 90.8 205.9L106.8 178.2C115.6 162.9 135.2 157.7 150.5 166.5L272.5 236.9L272.5 96z" }) })
|
|
1576
1542
|
};
|
|
1577
1543
|
function Icon({ name, className, title }) {
|
|
@@ -1601,6 +1567,16 @@ var panel_module_default = {
|
|
|
1601
1567
|
"de-emergency-slide-in": "de-emergency-de-emergency-slide-in-nA5Hwa",
|
|
1602
1568
|
"de-emergency-slide-up": "de-emergency-de-emergency-slide-up-nA5Hwa",
|
|
1603
1569
|
"de-emergency-spin": "de-emergency-de-emergency-spin-nA5Hwa",
|
|
1570
|
+
"emergency-availability": "de-emergency-emergency-availability-nA5Hwa",
|
|
1571
|
+
"emergency-availability__card": "de-emergency-emergency-availability__card-nA5Hwa",
|
|
1572
|
+
"emergency-availability__card-body": "de-emergency-emergency-availability__card-body-nA5Hwa",
|
|
1573
|
+
"emergency-availability__card-header": "de-emergency-emergency-availability__card-header-nA5Hwa",
|
|
1574
|
+
"emergency-availability__card-title": "de-emergency-emergency-availability__card-title-nA5Hwa",
|
|
1575
|
+
"emergency-availability__details": "de-emergency-emergency-availability__details-nA5Hwa",
|
|
1576
|
+
"emergency-availability__label": "de-emergency-emergency-availability__label-nA5Hwa",
|
|
1577
|
+
"emergency-availability__recharge": "de-emergency-emergency-availability__recharge-nA5Hwa",
|
|
1578
|
+
"emergency-availability__rounds": "de-emergency-emergency-availability__rounds-nA5Hwa",
|
|
1579
|
+
"emergency-availability__rounds-group": "de-emergency-emergency-availability__rounds-group-nA5Hwa",
|
|
1604
1580
|
"emergency-confirmation": "de-emergency-emergency-confirmation-nA5Hwa",
|
|
1605
1581
|
"emergency-confirmation__body": "de-emergency-emergency-confirmation__body-nA5Hwa",
|
|
1606
1582
|
"emergency-confirmation__button": "de-emergency-emergency-confirmation__button-nA5Hwa",
|
|
@@ -1625,7 +1601,11 @@ var panel_module_default = {
|
|
|
1625
1601
|
"emergency-feedback": "de-emergency-emergency-feedback-nA5Hwa",
|
|
1626
1602
|
"emergency-feedback__dismiss": "de-emergency-emergency-feedback__dismiss-nA5Hwa",
|
|
1627
1603
|
"emergency-panel": "de-emergency-emergency-panel-nA5Hwa",
|
|
1604
|
+
"emergency-panel__availability-region": "de-emergency-emergency-panel__availability-region-nA5Hwa",
|
|
1628
1605
|
"emergency-panel__body": "de-emergency-emergency-panel__body-nA5Hwa",
|
|
1606
|
+
"emergency-panel__body--pricing": "de-emergency-emergency-panel__body--pricing-nA5Hwa",
|
|
1607
|
+
"emergency-panel__body-split": "de-emergency-emergency-panel__body-split-nA5Hwa",
|
|
1608
|
+
"emergency-panel__body-split--with-availability": "de-emergency-emergency-panel__body-split--with-availability-nA5Hwa",
|
|
1629
1609
|
"emergency-panel__body-title": "de-emergency-emergency-panel__body-title-nA5Hwa",
|
|
1630
1610
|
"emergency-panel__body-title-container": "de-emergency-emergency-panel__body-title-container-nA5Hwa",
|
|
1631
1611
|
"emergency-panel__button": "de-emergency-emergency-panel__button-nA5Hwa",
|
|
@@ -1635,14 +1615,41 @@ var panel_module_default = {
|
|
|
1635
1615
|
"emergency-panel__close-icon": "de-emergency-emergency-panel__close-icon-nA5Hwa",
|
|
1636
1616
|
"emergency-panel__footer": "de-emergency-emergency-panel__footer-nA5Hwa",
|
|
1637
1617
|
"emergency-panel__header": "de-emergency-emergency-panel__header-nA5Hwa",
|
|
1618
|
+
"emergency-panel__prompt-region": "de-emergency-emergency-panel__prompt-region-nA5Hwa",
|
|
1638
1619
|
"emergency-panel__title": "de-emergency-emergency-panel__title-nA5Hwa",
|
|
1639
1620
|
"emergency-panel--hidden": "de-emergency-emergency-panel--hidden-nA5Hwa",
|
|
1621
|
+
"emergency-pricing": "de-emergency-emergency-pricing-nA5Hwa",
|
|
1622
|
+
"emergency-pricing__badge": "de-emergency-emergency-pricing__badge-nA5Hwa",
|
|
1623
|
+
"emergency-pricing__footnote": "de-emergency-emergency-pricing__footnote-nA5Hwa",
|
|
1624
|
+
"emergency-pricing__heading": "de-emergency-emergency-pricing__heading-nA5Hwa",
|
|
1625
|
+
"emergency-pricing__package": "de-emergency-emergency-pricing__package-nA5Hwa",
|
|
1626
|
+
"emergency-pricing__package--highlighted": "de-emergency-emergency-pricing__package--highlighted-nA5Hwa",
|
|
1627
|
+
"emergency-pricing__package-caption": "de-emergency-emergency-pricing__package-caption-nA5Hwa",
|
|
1628
|
+
"emergency-pricing__package-header": "de-emergency-emergency-pricing__package-header-nA5Hwa",
|
|
1629
|
+
"emergency-pricing__package-label": "de-emergency-emergency-pricing__package-label-nA5Hwa",
|
|
1630
|
+
"emergency-pricing__package-name": "de-emergency-emergency-pricing__package-name-nA5Hwa",
|
|
1631
|
+
"emergency-pricing__price": "de-emergency-emergency-pricing__price-nA5Hwa",
|
|
1632
|
+
"emergency-pricing__price-meta": "de-emergency-emergency-pricing__price-meta-nA5Hwa",
|
|
1633
|
+
"emergency-pricing__price-note": "de-emergency-emergency-pricing__price-note-nA5Hwa",
|
|
1634
|
+
"emergency-pricing__price-row": "de-emergency-emergency-pricing__price-row-nA5Hwa",
|
|
1635
|
+
"emergency-pricing__select": "de-emergency-emergency-pricing__select-nA5Hwa",
|
|
1636
|
+
"emergency-pricing__stat": "de-emergency-emergency-pricing__stat-nA5Hwa",
|
|
1637
|
+
"emergency-pricing__stat-divider": "de-emergency-emergency-pricing__stat-divider-nA5Hwa",
|
|
1638
|
+
"emergency-pricing__stat-label": "de-emergency-emergency-pricing__stat-label-nA5Hwa",
|
|
1639
|
+
"emergency-pricing__stat-value": "de-emergency-emergency-pricing__stat-value-nA5Hwa",
|
|
1640
|
+
"emergency-pricing__stats": "de-emergency-emergency-pricing__stats-nA5Hwa",
|
|
1641
|
+
"emergency-pricing__subtitle": "de-emergency-emergency-pricing__subtitle-nA5Hwa",
|
|
1642
|
+
"emergency-pricing__title": "de-emergency-emergency-pricing__title-nA5Hwa",
|
|
1643
|
+
"emergency-pricing__titles": "de-emergency-emergency-pricing__titles-nA5Hwa",
|
|
1640
1644
|
"emergency-resume-notification-button": "de-emergency-emergency-resume-notification-button-nA5Hwa",
|
|
1641
1645
|
"emergency-resume-notification-card": "de-emergency-emergency-resume-notification-card-nA5Hwa",
|
|
1642
1646
|
"emergency-resume-notification-icon": "de-emergency-emergency-resume-notification-icon-nA5Hwa",
|
|
1643
1647
|
"emergency-resume-notification-message": "de-emergency-emergency-resume-notification-message-nA5Hwa",
|
|
1644
1648
|
"emergency-resume-notification-overlay": "de-emergency-emergency-resume-notification-overlay-nA5Hwa",
|
|
1645
1649
|
"emergency-resume-notification-title": "de-emergency-emergency-resume-notification-title-nA5Hwa",
|
|
1650
|
+
"emergency-screen": "de-emergency-emergency-screen-nA5Hwa",
|
|
1651
|
+
"emergency-screen__placeholder": "de-emergency-emergency-screen__placeholder-nA5Hwa",
|
|
1652
|
+
"emergency-screen__placeholder-text": "de-emergency-emergency-screen__placeholder-text-nA5Hwa",
|
|
1646
1653
|
"emergency-status__abort-btn": "de-emergency-emergency-status__abort-btn-nA5Hwa",
|
|
1647
1654
|
"emergency-status__body": "de-emergency-emergency-status__body-nA5Hwa",
|
|
1648
1655
|
"emergency-status__cell": "de-emergency-emergency-status__cell-nA5Hwa",
|
|
@@ -1688,117 +1695,466 @@ function cls(...names) {
|
|
|
1688
1695
|
return names.filter((name) => Boolean(name)).map((name) => panel_module_default[name] ?? "").filter(Boolean).join(" ");
|
|
1689
1696
|
}
|
|
1690
1697
|
|
|
1691
|
-
// src/react/components/
|
|
1692
|
-
function
|
|
1693
|
-
const {
|
|
1694
|
-
const
|
|
1695
|
-
const
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1698
|
+
// src/react/components/EmergencyConfirmation/index.tsx
|
|
1699
|
+
function EmergencyConfirmation(props) {
|
|
1700
|
+
const { abortConfirmation, simulationConfirmation, onCancelAbort, onCancelSimulation, onConfirmAbort, onConfirmSimulation } = props;
|
|
1701
|
+
const cardRef = (0, react.useRef)(null);
|
|
1702
|
+
const titleId = (0, react.useId)();
|
|
1703
|
+
const danger = abortConfirmation;
|
|
1704
|
+
const open = abortConfirmation || simulationConfirmation;
|
|
1705
|
+
(0, react.useEffect)(() => {
|
|
1706
|
+
if (open) cardRef.current?.querySelector("button")?.focus();
|
|
1707
|
+
}, [open]);
|
|
1708
|
+
if (!open) return null;
|
|
1709
|
+
const title = danger ? copy.abortConfirmTitle : copy.simulateConfirmTitle;
|
|
1710
|
+
const text = danger ? copy.abortConfirmText : copy.simulateConfirmText;
|
|
1711
|
+
const tone = danger ? "danger" : "information";
|
|
1712
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1713
|
+
className: cls("emergency-confirmation"),
|
|
1714
|
+
role: "dialog",
|
|
1715
|
+
"aria-modal": "true",
|
|
1716
|
+
"aria-labelledby": titleId,
|
|
1717
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1718
|
+
ref: cardRef,
|
|
1719
|
+
className: cls("emergency-confirmation__card"),
|
|
1720
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1721
|
+
className: cls("emergency-confirmation__body"),
|
|
1710
1722
|
children: [
|
|
1711
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1712
|
-
className: cls(
|
|
1723
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1724
|
+
className: cls("emergency-confirmation__icon", `emergency-confirmation__icon--${tone}`),
|
|
1725
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: danger ? "alert-triangle" : "info" })
|
|
1726
|
+
}),
|
|
1727
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h5", {
|
|
1728
|
+
className: cls("emergency-confirmation__title"),
|
|
1729
|
+
id: titleId,
|
|
1713
1730
|
children: title
|
|
1714
1731
|
}),
|
|
1715
1732
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1716
|
-
className: cls(
|
|
1733
|
+
className: cls("emergency-confirmation__text"),
|
|
1717
1734
|
children: text
|
|
1718
|
-
}),
|
|
1719
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1720
|
-
className: cls(`${prefix}__details`),
|
|
1721
|
-
children: details.map((detail) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1722
|
-
className: cls(`${prefix}__detail`),
|
|
1723
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: detail.icon }), detail.text]
|
|
1724
|
-
}, detail.text))
|
|
1725
1735
|
})
|
|
1726
1736
|
]
|
|
1737
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1738
|
+
className: cls("emergency-confirmation__footer"),
|
|
1739
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1740
|
+
type: "button",
|
|
1741
|
+
className: cls("emergency-confirmation__button", "emergency-confirmation__button--cancel"),
|
|
1742
|
+
onClick: danger ? onCancelAbort : onCancelSimulation,
|
|
1743
|
+
children: danger ? copy.abortCancel : copy.simulateCancel
|
|
1744
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1745
|
+
type: "button",
|
|
1746
|
+
className: cls("emergency-confirmation__button", danger ? "emergency-confirmation__button--danger" : "emergency-confirmation__button--confirm"),
|
|
1747
|
+
onClick: danger ? onConfirmAbort : onConfirmSimulation,
|
|
1748
|
+
children: danger ? copy.abortConfirm : copy.simulateConfirm
|
|
1749
|
+
})]
|
|
1727
1750
|
})]
|
|
1728
|
-
}), children]
|
|
1729
|
-
});
|
|
1730
|
-
}
|
|
1731
|
-
|
|
1732
|
-
// src/react/components/EmergencyError/index.tsx
|
|
1733
|
-
function EmergencyError({ error, onRetry }) {
|
|
1734
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageSurface, {
|
|
1735
|
-
variant: "error",
|
|
1736
|
-
icon: "exclamation-circle",
|
|
1737
|
-
title: copy.errorTitle,
|
|
1738
|
-
text: error.message || copy.errorText,
|
|
1739
|
-
details: [{
|
|
1740
|
-
icon: "info",
|
|
1741
|
-
text: copy.errorDetailInfo
|
|
1742
|
-
}, {
|
|
1743
|
-
icon: "arrow-left",
|
|
1744
|
-
text: copy.errorDetailRetry
|
|
1745
|
-
}],
|
|
1746
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1747
|
-
type: "button",
|
|
1748
|
-
className: cls("emergency-feedback__dismiss"),
|
|
1749
|
-
onClick: onRetry,
|
|
1750
|
-
children: copy.retry
|
|
1751
1751
|
})
|
|
1752
1752
|
});
|
|
1753
1753
|
}
|
|
1754
1754
|
|
|
1755
|
-
// src/react/
|
|
1756
|
-
|
|
1757
|
-
const FEEDBACK_AUTO_DISMISS_MS = 3e3;
|
|
1758
|
-
/** Time the geolocation feedback stays on screen before dismissing itself. */
|
|
1759
|
-
const GEOLOCATION_FEEDBACK_AUTO_DISMISS_MS = 5e3;
|
|
1760
|
-
function geolocationText(error) {
|
|
1761
|
-
switch (error.code) {
|
|
1762
|
-
case "geolocation_denied": return copy.geolocationDenied;
|
|
1763
|
-
case "geolocation_timeout": return copy.geolocationTimeout;
|
|
1764
|
-
case "geolocation_unsupported": return copy.geolocationUnsupported;
|
|
1765
|
-
default: return copy.geolocationUnavailable;
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
function EmergencyFeedback({ abortResult, simulationResult, geolocationError, activationError, onDismiss }) {
|
|
1769
|
-
const result = abortResult ?? simulationResult;
|
|
1770
|
-
const feedbackActivationError = result ? null : activationError ?? null;
|
|
1771
|
-
const feedbackGeolocationError = result || feedbackActivationError ? null : geolocationError;
|
|
1772
|
-
if (!result && !feedbackActivationError && !feedbackGeolocationError) return null;
|
|
1773
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FeedbackSurface, {
|
|
1774
|
-
result,
|
|
1775
|
-
aborting: abortResult !== null,
|
|
1776
|
-
geolocationError: feedbackGeolocationError,
|
|
1777
|
-
activationError: feedbackActivationError,
|
|
1778
|
-
onDismiss
|
|
1779
|
-
});
|
|
1780
|
-
}
|
|
1781
|
-
function FeedbackSurface({ result, aborting, geolocationError, activationError, onDismiss }) {
|
|
1782
|
-
const dismissRef = (0, react.useRef)(onDismiss);
|
|
1755
|
+
// src/react/hooks/useEscapeKey.ts
|
|
1756
|
+
function useEscapeKey(active, onEscape) {
|
|
1783
1757
|
(0, react.useEffect)(() => {
|
|
1784
|
-
|
|
1785
|
-
|
|
1758
|
+
if (!active || typeof document === "undefined") return;
|
|
1759
|
+
const handleKeyDown = (event) => {
|
|
1760
|
+
if (event.key === "Escape") {
|
|
1761
|
+
event.stopPropagation();
|
|
1762
|
+
onEscape();
|
|
1763
|
+
}
|
|
1764
|
+
};
|
|
1765
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1766
|
+
return () => {
|
|
1767
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
1768
|
+
};
|
|
1769
|
+
}, [active, onEscape]);
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
// src/react/hooks/useFocusTrap.ts
|
|
1773
|
+
const FOCUSABLE_SELECTOR = [
|
|
1774
|
+
"a[href]",
|
|
1775
|
+
"button:not([disabled])",
|
|
1776
|
+
"input:not([disabled])",
|
|
1777
|
+
"select:not([disabled])",
|
|
1778
|
+
"textarea:not([disabled])",
|
|
1779
|
+
"[tabindex]:not([tabindex=\"-1\"])"
|
|
1780
|
+
].join(",");
|
|
1781
|
+
/**
|
|
1782
|
+
* Keeps keyboard focus inside the dialog while it is open and restores focus to
|
|
1783
|
+
* the element that opened it when it closes.
|
|
1784
|
+
*/
|
|
1785
|
+
function useFocusTrap(ref, active) {
|
|
1786
1786
|
(0, react.useEffect)(() => {
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1787
|
+
if (!active || typeof document === "undefined") return;
|
|
1788
|
+
const container = ref.current;
|
|
1789
|
+
if (!container) return;
|
|
1790
|
+
const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
1791
|
+
const focusable = () => Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter((element) => !element.hasAttribute("hidden") && element.getAttribute("aria-hidden") !== "true");
|
|
1792
|
+
(focusable()[0] ?? container).focus({ preventScroll: true });
|
|
1793
|
+
const handleKeyDown = (event) => {
|
|
1794
|
+
if (event.key !== "Tab") return;
|
|
1795
|
+
const items = focusable();
|
|
1796
|
+
if (items.length === 0) {
|
|
1797
|
+
event.preventDefault();
|
|
1798
|
+
container.focus({ preventScroll: true });
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
const first = items[0];
|
|
1802
|
+
const last = items[items.length - 1];
|
|
1803
|
+
const current = document.activeElement;
|
|
1804
|
+
if (event.shiftKey && (current === first || !container.contains(current))) {
|
|
1805
|
+
event.preventDefault();
|
|
1806
|
+
if (last) last.focus({ preventScroll: true });
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
if (!event.shiftKey && (current === last || !container.contains(current)) && first) {
|
|
1810
|
+
event.preventDefault();
|
|
1811
|
+
first.focus({ preventScroll: true });
|
|
1812
|
+
}
|
|
1813
|
+
};
|
|
1814
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
1815
|
+
return () => {
|
|
1816
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
1817
|
+
if (previouslyFocused?.isConnected) previouslyFocused.focus({ preventScroll: true });
|
|
1818
|
+
};
|
|
1819
|
+
}, [active, ref]);
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
// src/react/screens/context.tsx
|
|
1823
|
+
const EmergencyScreenContext = (0, react.createContext)(null);
|
|
1824
|
+
function EmergencyScreenProvider({ children, initialScreen = "primary" }) {
|
|
1825
|
+
const [state, setState] = (0, react.useState)({
|
|
1826
|
+
screen: initialScreen,
|
|
1827
|
+
history: []
|
|
1828
|
+
});
|
|
1829
|
+
const navigate = (0, react.useCallback)((next) => {
|
|
1830
|
+
setState((current) => {
|
|
1831
|
+
if (current.screen === next) return current;
|
|
1832
|
+
return {
|
|
1833
|
+
screen: next,
|
|
1834
|
+
history: [...current.history, current.screen]
|
|
1835
|
+
};
|
|
1836
|
+
});
|
|
1837
|
+
}, []);
|
|
1838
|
+
const back = (0, react.useCallback)(() => {
|
|
1839
|
+
setState((current) => {
|
|
1840
|
+
const previous = current.history.at(-1);
|
|
1841
|
+
if (!previous) return current;
|
|
1842
|
+
return {
|
|
1843
|
+
screen: previous,
|
|
1844
|
+
history: current.history.slice(0, -1)
|
|
1845
|
+
};
|
|
1846
|
+
});
|
|
1847
|
+
}, []);
|
|
1848
|
+
const reset = (0, react.useCallback)(() => {
|
|
1849
|
+
setState((current) => {
|
|
1850
|
+
if (current.screen === "primary" && current.history.length === 0) return current;
|
|
1851
|
+
return {
|
|
1852
|
+
screen: "primary",
|
|
1853
|
+
history: []
|
|
1854
|
+
};
|
|
1855
|
+
});
|
|
1856
|
+
}, []);
|
|
1857
|
+
const value = (0, react.useMemo)(() => ({
|
|
1858
|
+
screen: state.screen,
|
|
1859
|
+
history: state.history,
|
|
1860
|
+
navigate,
|
|
1861
|
+
back,
|
|
1862
|
+
reset
|
|
1863
|
+
}), [
|
|
1864
|
+
back,
|
|
1865
|
+
navigate,
|
|
1866
|
+
reset,
|
|
1867
|
+
state.history,
|
|
1868
|
+
state.screen
|
|
1869
|
+
]);
|
|
1870
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyScreenContext.Provider, {
|
|
1871
|
+
value,
|
|
1872
|
+
children
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
function useScreenNavigation() {
|
|
1876
|
+
const value = (0, react.useContext)(EmergencyScreenContext);
|
|
1877
|
+
if (!value) throw new Error("useScreenNavigation must be used inside EmergencyScreenProvider.");
|
|
1878
|
+
return value;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
// src/react/components/EmergencyHeader/index.tsx
|
|
1882
|
+
function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack }) {
|
|
1883
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
1884
|
+
className: cls("emergency-panel__header"),
|
|
1885
|
+
children: [
|
|
1886
|
+
onBack ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1887
|
+
type: "button",
|
|
1888
|
+
className: cls("emergency-panel__close-button"),
|
|
1889
|
+
"aria-label": copy.back,
|
|
1890
|
+
onClick: onBack,
|
|
1891
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
1892
|
+
name: "arrow-left",
|
|
1893
|
+
className: cls("emergency-panel__close-icon")
|
|
1894
|
+
})
|
|
1895
|
+
}) : null,
|
|
1896
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
1897
|
+
className: cls("emergency-panel__title"),
|
|
1898
|
+
id: titleId,
|
|
1899
|
+
tabIndex: -1,
|
|
1900
|
+
children: title
|
|
1901
|
+
}),
|
|
1902
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1903
|
+
type: "button",
|
|
1904
|
+
className: cls("emergency-panel__close-button"),
|
|
1905
|
+
"aria-label": copy.close,
|
|
1906
|
+
onClick: onClose,
|
|
1907
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
1908
|
+
name: "close",
|
|
1909
|
+
className: cls("emergency-panel__close-icon")
|
|
1910
|
+
})
|
|
1911
|
+
})
|
|
1912
|
+
]
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// src/react/screens/layout.tsx
|
|
1917
|
+
/**
|
|
1918
|
+
* Shared shell for every screen. The wrapper is `display: contents` so the
|
|
1919
|
+
* header, body and footer stay direct grid rows of the emergency panel.
|
|
1920
|
+
*/
|
|
1921
|
+
function EmergencyScreenLayout({ screen, titleId, header, footer, children, bodyClassName }) {
|
|
1922
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1923
|
+
className: cls("emergency-screen"),
|
|
1924
|
+
"data-screen": screen,
|
|
1925
|
+
children: [
|
|
1926
|
+
header,
|
|
1927
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
1928
|
+
className: cls("emergency-panel__body", bodyClassName ?? null),
|
|
1929
|
+
"aria-labelledby": titleId,
|
|
1930
|
+
children
|
|
1931
|
+
}),
|
|
1932
|
+
footer
|
|
1933
|
+
]
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
// src/react/screens/PlaceholderScreen.tsx
|
|
1938
|
+
/** Minimal in-design screen used to prove navigation before real designs land. */
|
|
1939
|
+
function PlaceholderScreen({ screen, titleId, title, description, onClose, onBack }) {
|
|
1940
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyScreenLayout, {
|
|
1941
|
+
screen,
|
|
1942
|
+
titleId,
|
|
1943
|
+
header: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyHeader, {
|
|
1944
|
+
titleId,
|
|
1945
|
+
title,
|
|
1946
|
+
onClose,
|
|
1947
|
+
onBack
|
|
1948
|
+
}),
|
|
1949
|
+
footer: null,
|
|
1950
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1951
|
+
className: cls("emergency-screen__placeholder"),
|
|
1952
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1953
|
+
className: cls("emergency-screen__placeholder-text"),
|
|
1954
|
+
children: description
|
|
1955
|
+
})
|
|
1956
|
+
})
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
// src/react/screens/details/copy.ts
|
|
1961
|
+
const detailsCopy = {
|
|
1962
|
+
title: "Detalles",
|
|
1963
|
+
description: "Aquí podrás consultar el detalle de tus alertas disponibles. Esta pantalla estará disponible próximamente."
|
|
1964
|
+
};
|
|
1965
|
+
|
|
1966
|
+
// src/react/screens/details/index.tsx
|
|
1967
|
+
function DetailsScreen({ titleId, onClose }) {
|
|
1968
|
+
const { back } = useScreenNavigation();
|
|
1969
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlaceholderScreen, {
|
|
1970
|
+
screen: "details",
|
|
1971
|
+
titleId,
|
|
1972
|
+
title: detailsCopy.title,
|
|
1973
|
+
description: detailsCopy.description,
|
|
1974
|
+
onClose: () => onClose("close"),
|
|
1975
|
+
onBack: back
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
// src/react/components/icons/paramedical-mark.tsx
|
|
1980
|
+
/**
|
|
1981
|
+
* Neutral inline illustration used by the idle panel.
|
|
1982
|
+
*/
|
|
1983
|
+
function ParamedicalMark({ className, title }) {
|
|
1984
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
1985
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1986
|
+
version: "1.0",
|
|
1987
|
+
viewBox: "0 0 192 192",
|
|
1988
|
+
width: "192",
|
|
1989
|
+
height: "192",
|
|
1990
|
+
id: "Star of life",
|
|
1991
|
+
className,
|
|
1992
|
+
"aria-label": title,
|
|
1993
|
+
children: [
|
|
1994
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { id: "defs2886" }),
|
|
1995
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
1996
|
+
id: "cross",
|
|
1997
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1998
|
+
d: "m 74,133 0,52 44,0 0,-52 44,26 22,-38 L 140,96 184,70 162,32 117,58 117,7 74,7 74,58 30,32 8,70 52,96 8,121 30,159 z",
|
|
1999
|
+
id: "outline",
|
|
2000
|
+
style: {
|
|
2001
|
+
fill: "none",
|
|
2002
|
+
stroke: "#3333bb",
|
|
2003
|
+
strokeWidth: 6
|
|
2004
|
+
}
|
|
2005
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2006
|
+
d: "m 74,133 0,52 44,0 0,-52 44,26 22,-38 L 140,96 184,70 162,32 117,58 117,7 74,7 74,58 30,32 8,70 52,96 8,121 30,159 z",
|
|
2007
|
+
id: "inner",
|
|
2008
|
+
style: {
|
|
2009
|
+
fill: "#0000bb",
|
|
2010
|
+
fillRule: "evenodd",
|
|
2011
|
+
stroke: "#ffffff",
|
|
2012
|
+
strokeWidth: 2
|
|
2013
|
+
}
|
|
2014
|
+
})]
|
|
2015
|
+
}),
|
|
2016
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
2017
|
+
id: "symbols",
|
|
2018
|
+
style: {
|
|
2019
|
+
fill: "#ffffff",
|
|
2020
|
+
fillRule: "evenodd",
|
|
2021
|
+
stroke: "#3333bb",
|
|
2022
|
+
strokeWidth: 2
|
|
2023
|
+
},
|
|
2024
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2025
|
+
d: "m 93,166 c 0,7 6,7 6,0 l 3,-138 c 0,-8 -12,-8 -12,0 l 3,135 0,3 z",
|
|
2026
|
+
id: "rod"
|
|
2027
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
2028
|
+
id: "snake",
|
|
2029
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2030
|
+
d: "m 100,153 c 7,4 3,15 -3,15 2,-5 3,-9 3,-15 z m 1,-40 c 10,9 4,22 -3,26 -6,3 -6,7 -6,15 -9,-10 -4,-19 4,-24 5,-4 5,-10 5,-17 z m 1,-30 c 0,11 -17,14 -17,22 0,3 1,9 6,12 0,-11 9,-12 15,-18 7,-7 7,-19 -4,-28 0,4 0,8 0,12 z M 90,77 C 80,69 76,55 80,46 c 3,-10 20,-11 20,-3 0,8 -20,3 -13,16 l 3,5 0,13 z",
|
|
2031
|
+
id: "body"
|
|
2032
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2033
|
+
d: "m 95,43 c 7,-3 -7,-3 0,0 z",
|
|
2034
|
+
id: "eye",
|
|
2035
|
+
style: {
|
|
2036
|
+
fill: "#3333bb",
|
|
2037
|
+
fillRule: "evenodd",
|
|
2038
|
+
stroke: "none"
|
|
2039
|
+
}
|
|
2040
|
+
})]
|
|
2041
|
+
})]
|
|
2042
|
+
})
|
|
2043
|
+
]
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
// src/react/components/MessageSurface/index.tsx
|
|
2048
|
+
function MessageSurface(props) {
|
|
2049
|
+
const { variant, icon, title, text, details, className, children } = props;
|
|
2050
|
+
const prefix = variant === "success" ? "simulacrum-success-message" : "emergency-error-message";
|
|
2051
|
+
const success = variant === "success";
|
|
2052
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2053
|
+
className: [cls(prefix), className].filter(Boolean).join(" "),
|
|
2054
|
+
role: success ? "status" : "alert",
|
|
2055
|
+
"aria-live": success ? "polite" : "assertive",
|
|
2056
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2057
|
+
className: cls(`${prefix}__container`),
|
|
2058
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2059
|
+
className: cls(`${prefix}__icon`),
|
|
2060
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
2061
|
+
name: icon,
|
|
2062
|
+
className: "status-icon"
|
|
2063
|
+
})
|
|
2064
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2065
|
+
className: cls(`${prefix}__content`),
|
|
2066
|
+
children: [
|
|
2067
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
2068
|
+
className: cls(`${prefix}__title`),
|
|
2069
|
+
children: title
|
|
2070
|
+
}),
|
|
2071
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2072
|
+
className: cls(`${prefix}__text`),
|
|
2073
|
+
children: text
|
|
2074
|
+
}),
|
|
2075
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2076
|
+
className: cls(`${prefix}__details`),
|
|
2077
|
+
children: details.map((detail) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2078
|
+
className: cls(`${prefix}__detail`),
|
|
2079
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: detail.icon }), detail.text]
|
|
2080
|
+
}, detail.text))
|
|
2081
|
+
})
|
|
2082
|
+
]
|
|
2083
|
+
})]
|
|
2084
|
+
}), children]
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
// src/react/components/EmergencyError/index.tsx
|
|
2089
|
+
function EmergencyError({ error, onRetry }) {
|
|
2090
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageSurface, {
|
|
2091
|
+
variant: "error",
|
|
2092
|
+
icon: "exclamation-circle",
|
|
2093
|
+
title: copy.errorTitle,
|
|
2094
|
+
text: error.message || copy.errorText,
|
|
2095
|
+
details: [{
|
|
2096
|
+
icon: "info",
|
|
2097
|
+
text: copy.errorDetailInfo
|
|
2098
|
+
}, {
|
|
2099
|
+
icon: "arrow-left",
|
|
2100
|
+
text: copy.errorDetailRetry
|
|
2101
|
+
}],
|
|
2102
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2103
|
+
type: "button",
|
|
2104
|
+
className: cls("emergency-feedback__dismiss"),
|
|
2105
|
+
onClick: onRetry,
|
|
2106
|
+
children: copy.retry
|
|
2107
|
+
})
|
|
2108
|
+
});
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
// src/react/components/EmergencyFeedback/index.tsx
|
|
2112
|
+
/** Time the feedback stays on screen before dismissing itself. */
|
|
2113
|
+
const FEEDBACK_AUTO_DISMISS_MS = 3e3;
|
|
2114
|
+
/** Time the geolocation feedback stays on screen before dismissing itself. */
|
|
2115
|
+
const GEOLOCATION_FEEDBACK_AUTO_DISMISS_MS = 5e3;
|
|
2116
|
+
function geolocationText(error) {
|
|
2117
|
+
switch (error.code) {
|
|
2118
|
+
case "geolocation_denied": return copy.geolocationDenied;
|
|
2119
|
+
case "geolocation_timeout": return copy.geolocationTimeout;
|
|
2120
|
+
case "geolocation_unsupported": return copy.geolocationUnsupported;
|
|
2121
|
+
default: return copy.geolocationUnavailable;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
function EmergencyFeedback({ abortResult, simulationResult, geolocationError, activationError, onDismiss }) {
|
|
2125
|
+
const result = abortResult ?? simulationResult;
|
|
2126
|
+
const feedbackActivationError = result ? null : activationError ?? null;
|
|
2127
|
+
const feedbackGeolocationError = result || feedbackActivationError ? null : geolocationError;
|
|
2128
|
+
if (!result && !feedbackActivationError && !feedbackGeolocationError) return null;
|
|
2129
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FeedbackSurface, {
|
|
2130
|
+
result,
|
|
2131
|
+
aborting: abortResult !== null,
|
|
2132
|
+
geolocationError: feedbackGeolocationError,
|
|
2133
|
+
activationError: feedbackActivationError,
|
|
2134
|
+
onDismiss
|
|
2135
|
+
});
|
|
2136
|
+
}
|
|
2137
|
+
function FeedbackSurface({ result, aborting, geolocationError, activationError, onDismiss }) {
|
|
2138
|
+
const dismissRef = (0, react.useRef)(onDismiss);
|
|
2139
|
+
(0, react.useEffect)(() => {
|
|
2140
|
+
dismissRef.current = onDismiss;
|
|
2141
|
+
}, [onDismiss]);
|
|
2142
|
+
(0, react.useEffect)(() => {
|
|
2143
|
+
const timeout = setTimeout(() => dismissRef.current(), geolocationError || activationError ? GEOLOCATION_FEEDBACK_AUTO_DISMISS_MS : FEEDBACK_AUTO_DISMISS_MS);
|
|
2144
|
+
return () => clearTimeout(timeout);
|
|
2145
|
+
}, [
|
|
2146
|
+
result?.at,
|
|
2147
|
+
geolocationError,
|
|
2148
|
+
activationError
|
|
2149
|
+
]);
|
|
2150
|
+
const success = result?.ok === true;
|
|
2151
|
+
const title = success ? aborting ? copy.abortSuccessTitle : copy.simulateSuccessTitle : copy.errorTitle;
|
|
2152
|
+
const text = success ? result?.message ?? "" : geolocationError ? geolocationText(geolocationError) : activationError ? activationError.message || copy.errorText : result?.message ?? copy.errorText;
|
|
2153
|
+
const details = success ? aborting ? [{
|
|
2154
|
+
icon: "message",
|
|
2155
|
+
text: copy.abortSuccessDetails
|
|
2156
|
+
}] : [{
|
|
2157
|
+
icon: "message",
|
|
1802
2158
|
text: copy.simulateSuccessDetails
|
|
1803
2159
|
}, {
|
|
1804
2160
|
icon: "clock",
|
|
@@ -2012,101 +2368,129 @@ function EmergencyStatusPanel({ responders, refreshing, locale, onRefresh }) {
|
|
|
2012
2368
|
});
|
|
2013
2369
|
}
|
|
2014
2370
|
|
|
2015
|
-
// src/react/
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
className: cls("emergency-panel__body-title-container"),
|
|
2030
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
2031
|
-
className: cls("emergency-panel__body-title"),
|
|
2032
|
-
children: copy.question
|
|
2033
|
-
})
|
|
2034
|
-
}),
|
|
2035
|
-
active && !showingFeedback ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyStatusPanel, {
|
|
2036
|
-
responders,
|
|
2037
|
-
refreshing,
|
|
2038
|
-
locale,
|
|
2039
|
-
onRefresh
|
|
2040
|
-
}) : null,
|
|
2041
|
-
loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyLoading, {}) : null,
|
|
2042
|
-
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyError, {
|
|
2043
|
-
error,
|
|
2044
|
-
onRetry
|
|
2045
|
-
}) : null,
|
|
2046
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyFeedback, {
|
|
2047
|
-
abortResult,
|
|
2048
|
-
simulationResult,
|
|
2049
|
-
geolocationError,
|
|
2050
|
-
activationError,
|
|
2051
|
-
onDismiss: onDismissFeedback
|
|
2052
|
-
})
|
|
2053
|
-
] });
|
|
2371
|
+
// src/react/screens/primary/copy.ts
|
|
2372
|
+
const primaryCopy = {
|
|
2373
|
+
availabilityTitle: "Alertas Disponibles",
|
|
2374
|
+
recharge: "Recargar",
|
|
2375
|
+
details: "Detalles",
|
|
2376
|
+
roundSingular: "ronda disponible",
|
|
2377
|
+
roundPlural: "rondas disponibles"
|
|
2378
|
+
};
|
|
2379
|
+
/** Singular/plural label for the remaining rounds. */
|
|
2380
|
+
function roundsUnit(rounds) {
|
|
2381
|
+
return rounds === 1 ? primaryCopy.roundSingular : primaryCopy.roundPlural;
|
|
2382
|
+
}
|
|
2383
|
+
function formatRounds(rounds) {
|
|
2384
|
+
return `${rounds} ${roundsUnit(rounds)}`;
|
|
2054
2385
|
}
|
|
2055
2386
|
|
|
2056
|
-
// src/react/
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
(
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
if (
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
"
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
}),
|
|
2090
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2091
|
-
className: cls("emergency-confirmation__text"),
|
|
2092
|
-
children: text
|
|
2093
|
-
})
|
|
2094
|
-
]
|
|
2387
|
+
// src/react/screens/primary/data.ts
|
|
2388
|
+
/**
|
|
2389
|
+
* Derives the remaining alert rounds from available messages and designated
|
|
2390
|
+
* responders. Invalid or non-positive input collapses to the minimum of one
|
|
2391
|
+
* round instead of producing `Infinity`, `NaN` or a negative value.
|
|
2392
|
+
*/
|
|
2393
|
+
function calculateRounds(messages, responders) {
|
|
2394
|
+
if (!Number.isFinite(messages) || !Number.isFinite(responders)) return 1;
|
|
2395
|
+
const availableMessages = Math.floor(messages);
|
|
2396
|
+
const designatedResponders = Math.floor(responders);
|
|
2397
|
+
if (availableMessages <= 0 || designatedResponders <= 0) return 1;
|
|
2398
|
+
return Math.max(1, Math.floor(availableMessages / designatedResponders));
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
// src/react/screens/primary/Availability.tsx
|
|
2402
|
+
function Availability({ onRecharge, onDetails }) {
|
|
2403
|
+
const rounds = calculateRounds(100, 3);
|
|
2404
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2405
|
+
className: cls("emergency-availability"),
|
|
2406
|
+
"aria-label": primaryCopy.availabilityTitle,
|
|
2407
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2408
|
+
type: "button",
|
|
2409
|
+
className: cls("emergency-availability__recharge"),
|
|
2410
|
+
onClick: onRecharge,
|
|
2411
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "credit-card-plus" }), primaryCopy.recharge]
|
|
2412
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2413
|
+
className: cls("emergency-availability__card"),
|
|
2414
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2415
|
+
className: cls("emergency-availability__card-header"),
|
|
2416
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
2417
|
+
className: cls("emergency-availability__card-title"),
|
|
2418
|
+
children: primaryCopy.availabilityTitle
|
|
2419
|
+
})
|
|
2095
2420
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2096
|
-
className: cls("emergency-
|
|
2097
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2421
|
+
className: cls("emergency-availability__card-body"),
|
|
2422
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2423
|
+
className: cls("emergency-availability__rounds-group"),
|
|
2424
|
+
"aria-label": formatRounds(rounds),
|
|
2425
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2426
|
+
className: cls("emergency-availability__rounds"),
|
|
2427
|
+
children: rounds
|
|
2428
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2429
|
+
className: cls("emergency-availability__label"),
|
|
2430
|
+
children: roundsUnit(rounds)
|
|
2431
|
+
})]
|
|
2102
2432
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2103
2433
|
type: "button",
|
|
2104
|
-
className: cls("emergency-
|
|
2105
|
-
onClick:
|
|
2106
|
-
children:
|
|
2434
|
+
className: cls("emergency-availability__details"),
|
|
2435
|
+
onClick: onDetails,
|
|
2436
|
+
children: primaryCopy.details
|
|
2107
2437
|
})]
|
|
2108
2438
|
})]
|
|
2109
|
-
})
|
|
2439
|
+
})]
|
|
2440
|
+
});
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
// src/react/components/EmergencyBody/index.tsx
|
|
2444
|
+
function EmergencyBody(props) {
|
|
2445
|
+
const { active, responders, refreshing, loading, locale, geolocationError, activationError, error, abortResult, simulationResult, onRefresh, onRetry, onDismissFeedback, onRecharge, onDetails } = props;
|
|
2446
|
+
const showingFeedback = geolocationError !== null || Boolean(activationError) || abortResult !== null || simulationResult !== null;
|
|
2447
|
+
const idle = !active && !loading && !showingFeedback && error === null;
|
|
2448
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2449
|
+
className: cls("emergency-panel__body-split", idle && "emergency-panel__body-split--with-availability"),
|
|
2450
|
+
children: [idle ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2451
|
+
className: cls("emergency-panel__availability-region"),
|
|
2452
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Availability, {
|
|
2453
|
+
onRecharge,
|
|
2454
|
+
onDetails
|
|
2455
|
+
})
|
|
2456
|
+
}) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2457
|
+
className: cls("emergency-panel__prompt-region"),
|
|
2458
|
+
children: [
|
|
2459
|
+
!loading && !showingFeedback ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2460
|
+
className: cls("sos-img__container"),
|
|
2461
|
+
id: "sos-img__container",
|
|
2462
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ParamedicalMark, {
|
|
2463
|
+
className: cls("sos-img"),
|
|
2464
|
+
title: copy.illustrationAlt
|
|
2465
|
+
})
|
|
2466
|
+
}) : null,
|
|
2467
|
+
active || loading || showingFeedback ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2468
|
+
className: cls("emergency-panel__body-title-container"),
|
|
2469
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
2470
|
+
className: cls("emergency-panel__body-title"),
|
|
2471
|
+
children: copy.question
|
|
2472
|
+
})
|
|
2473
|
+
}),
|
|
2474
|
+
active && !showingFeedback ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyStatusPanel, {
|
|
2475
|
+
responders,
|
|
2476
|
+
refreshing,
|
|
2477
|
+
locale,
|
|
2478
|
+
onRefresh
|
|
2479
|
+
}) : null,
|
|
2480
|
+
loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyLoading, {}) : null,
|
|
2481
|
+
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyError, {
|
|
2482
|
+
error,
|
|
2483
|
+
onRetry
|
|
2484
|
+
}) : null,
|
|
2485
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyFeedback, {
|
|
2486
|
+
abortResult,
|
|
2487
|
+
simulationResult,
|
|
2488
|
+
geolocationError,
|
|
2489
|
+
activationError,
|
|
2490
|
+
onDismiss: onDismissFeedback
|
|
2491
|
+
})
|
|
2492
|
+
]
|
|
2493
|
+
})]
|
|
2110
2494
|
});
|
|
2111
2495
|
}
|
|
2112
2496
|
|
|
@@ -2144,105 +2528,279 @@ function EmergencyFooter(props) {
|
|
|
2144
2528
|
});
|
|
2145
2529
|
}
|
|
2146
2530
|
|
|
2147
|
-
// src/react/
|
|
2148
|
-
function
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2531
|
+
// src/react/screens/primary/index.tsx
|
|
2532
|
+
function PrimaryScreen(props) {
|
|
2533
|
+
const { navigate } = useScreenNavigation();
|
|
2534
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyScreenLayout, {
|
|
2535
|
+
screen: "primary",
|
|
2536
|
+
titleId: props.titleId,
|
|
2537
|
+
header: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyHeader, {
|
|
2538
|
+
titleId: props.titleId,
|
|
2539
|
+
onClose: () => props.onClose("close")
|
|
2540
|
+
}),
|
|
2541
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyFooter, {
|
|
2542
|
+
active: props.active,
|
|
2543
|
+
busy: props.busy,
|
|
2544
|
+
aborting: props.aborting,
|
|
2545
|
+
feedbackVisible: props.feedbackVisible,
|
|
2546
|
+
onActivate: props.onActivate,
|
|
2547
|
+
onRequestAbort: props.onRequestAbort,
|
|
2548
|
+
onRequestSimulation: props.onRequestSimulation
|
|
2549
|
+
}),
|
|
2550
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyBody, {
|
|
2551
|
+
active: props.active,
|
|
2552
|
+
responders: props.responders,
|
|
2553
|
+
refreshing: props.refreshing,
|
|
2554
|
+
loading: props.loading,
|
|
2555
|
+
locale: props.locale,
|
|
2556
|
+
geolocationError: props.geolocationError,
|
|
2557
|
+
activationError: props.activationError,
|
|
2558
|
+
error: props.error,
|
|
2559
|
+
abortResult: props.abortResult,
|
|
2560
|
+
simulationResult: props.simulationResult,
|
|
2561
|
+
onRefresh: props.onRefresh,
|
|
2562
|
+
onRetry: props.onRetry,
|
|
2563
|
+
onDismissFeedback: props.onDismissFeedback,
|
|
2564
|
+
onRecharge: () => navigate("pricing"),
|
|
2565
|
+
onDetails: () => navigate("details")
|
|
2566
|
+
})
|
|
2165
2567
|
});
|
|
2166
2568
|
}
|
|
2167
2569
|
|
|
2168
|
-
// src/react/
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
};
|
|
2182
|
-
}, [active, onEscape]);
|
|
2183
|
-
}
|
|
2570
|
+
// src/react/screens/pricing/copy.ts
|
|
2571
|
+
const pricingCopy = {
|
|
2572
|
+
title: "Recargar",
|
|
2573
|
+
heading: "Elige tu paquete",
|
|
2574
|
+
subtitle: "Alertas de WhatsApp para tus contactos",
|
|
2575
|
+
bestValue: "MEJOR VALOR",
|
|
2576
|
+
choose: "Seleccionar",
|
|
2577
|
+
chosen: "Seleccionado",
|
|
2578
|
+
whatsapp: "de WhatsApp",
|
|
2579
|
+
rounds: "rondas de alerta",
|
|
2580
|
+
perMessage: "por mensaje + IVA",
|
|
2581
|
+
footnote: "Rondas calculadas con 3 contactos de emergencia. Válidas para pruebas y emergencias."
|
|
2582
|
+
};
|
|
2184
2583
|
|
|
2185
|
-
// src/react/
|
|
2186
|
-
const FOCUSABLE_SELECTOR = [
|
|
2187
|
-
"a[href]",
|
|
2188
|
-
"button:not([disabled])",
|
|
2189
|
-
"input:not([disabled])",
|
|
2190
|
-
"select:not([disabled])",
|
|
2191
|
-
"textarea:not([disabled])",
|
|
2192
|
-
"[tabindex]:not([tabindex=\"-1\"])"
|
|
2193
|
-
].join(",");
|
|
2584
|
+
// src/react/screens/pricing/data.ts
|
|
2194
2585
|
/**
|
|
2195
|
-
*
|
|
2196
|
-
*
|
|
2586
|
+
* Local demo catalog. Prices and per-message labels are literal values from the
|
|
2587
|
+
* mock; they are not derived from the package totals.
|
|
2197
2588
|
*/
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2589
|
+
const PRICING_PACKAGES = [{
|
|
2590
|
+
id: "package-1",
|
|
2591
|
+
label: "PAQUETE 1",
|
|
2592
|
+
messages: 100,
|
|
2593
|
+
priceLabel: "$7",
|
|
2594
|
+
priceCaption: "IVA incluido",
|
|
2595
|
+
perMessageLabel: "$0.06",
|
|
2596
|
+
highlighted: false
|
|
2597
|
+
}, {
|
|
2598
|
+
id: "package-2",
|
|
2599
|
+
label: "PAQUETE 2",
|
|
2600
|
+
messages: 200,
|
|
2601
|
+
priceLabel: "12$",
|
|
2602
|
+
priceNote: "($10 + IVA)",
|
|
2603
|
+
priceCaption: "IVA incluido",
|
|
2604
|
+
perMessageLabel: "$0.05",
|
|
2605
|
+
highlighted: true,
|
|
2606
|
+
badge: "MEJOR VALOR"
|
|
2607
|
+
}];
|
|
2608
|
+
/** Derives the alert rounds a package provides for the demo responder count. */
|
|
2609
|
+
function packageRounds(pkg) {
|
|
2610
|
+
return calculateRounds(pkg.messages, 3);
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
// src/react/screens/pricing/PackageCard.tsx
|
|
2614
|
+
function PackageCard({ pkg, selected, onSelect }) {
|
|
2615
|
+
const labelId = (0, react.useId)();
|
|
2616
|
+
const rounds = packageRounds(pkg);
|
|
2617
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2618
|
+
className: cls("emergency-pricing__package", pkg.highlighted && "emergency-pricing__package--highlighted"),
|
|
2619
|
+
"aria-labelledby": labelId,
|
|
2620
|
+
"data-selected": selected ? "true" : void 0,
|
|
2621
|
+
children: [
|
|
2622
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2623
|
+
className: cls("emergency-pricing__package-header"),
|
|
2624
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2625
|
+
className: cls("emergency-pricing__package-label"),
|
|
2626
|
+
id: labelId,
|
|
2627
|
+
children: pkg.label
|
|
2628
|
+
}), pkg.badge ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2629
|
+
className: cls("emergency-pricing__badge"),
|
|
2630
|
+
children: pkg.badge
|
|
2631
|
+
}) : null]
|
|
2632
|
+
}),
|
|
2633
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2634
|
+
className: cls("emergency-pricing__price-row"),
|
|
2635
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h4", {
|
|
2636
|
+
className: cls("emergency-pricing__package-name"),
|
|
2637
|
+
children: [pkg.messages, " alertas"]
|
|
2638
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2639
|
+
className: cls("emergency-pricing__package-caption"),
|
|
2640
|
+
children: pricingCopy.whatsapp
|
|
2641
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2642
|
+
className: cls("emergency-pricing__price-meta"),
|
|
2643
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2644
|
+
className: cls("emergency-pricing__price"),
|
|
2645
|
+
children: pkg.priceLabel
|
|
2646
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2647
|
+
className: cls("emergency-pricing__price-note"),
|
|
2648
|
+
children: [pkg.priceCaption, pkg.priceNote ? ` ${pkg.priceNote}` : null]
|
|
2649
|
+
})]
|
|
2650
|
+
})]
|
|
2651
|
+
}),
|
|
2652
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2653
|
+
className: cls("emergency-pricing__stats"),
|
|
2654
|
+
children: [
|
|
2655
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2656
|
+
className: cls("emergency-pricing__stat"),
|
|
2657
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2658
|
+
className: cls("emergency-pricing__stat-value"),
|
|
2659
|
+
children: rounds
|
|
2660
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2661
|
+
className: cls("emergency-pricing__stat-label"),
|
|
2662
|
+
children: pricingCopy.rounds
|
|
2663
|
+
})]
|
|
2664
|
+
}),
|
|
2665
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2666
|
+
className: cls("emergency-pricing__stat-divider"),
|
|
2667
|
+
"aria-hidden": "true"
|
|
2668
|
+
}),
|
|
2669
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2670
|
+
className: cls("emergency-pricing__stat"),
|
|
2671
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2672
|
+
className: cls("emergency-pricing__stat-value"),
|
|
2673
|
+
children: pkg.perMessageLabel
|
|
2674
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2675
|
+
className: cls("emergency-pricing__stat-label"),
|
|
2676
|
+
children: pricingCopy.perMessage
|
|
2677
|
+
})]
|
|
2678
|
+
})
|
|
2679
|
+
]
|
|
2680
|
+
}),
|
|
2681
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2682
|
+
type: "button",
|
|
2683
|
+
className: cls("emergency-pricing__select"),
|
|
2684
|
+
"aria-pressed": selected,
|
|
2685
|
+
onClick: () => onSelect(pkg.id),
|
|
2686
|
+
children: selected ? pricingCopy.chosen : pricingCopy.choose
|
|
2687
|
+
})
|
|
2688
|
+
]
|
|
2689
|
+
});
|
|
2233
2690
|
}
|
|
2234
2691
|
|
|
2692
|
+
// src/react/screens/pricing/index.tsx
|
|
2693
|
+
function PricingScreen(props) {
|
|
2694
|
+
const { back } = useScreenNavigation();
|
|
2695
|
+
const [selected, setSelected] = (0, react.useState)(null);
|
|
2696
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyScreenLayout, {
|
|
2697
|
+
screen: "pricing",
|
|
2698
|
+
titleId: props.titleId,
|
|
2699
|
+
bodyClassName: "emergency-panel__body--pricing",
|
|
2700
|
+
header: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyHeader, {
|
|
2701
|
+
titleId: props.titleId,
|
|
2702
|
+
title: pricingCopy.title,
|
|
2703
|
+
onClose: () => props.onClose("close"),
|
|
2704
|
+
onBack: back
|
|
2705
|
+
}),
|
|
2706
|
+
footer: null,
|
|
2707
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2708
|
+
className: cls("emergency-pricing"),
|
|
2709
|
+
children: [
|
|
2710
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2711
|
+
className: cls("emergency-pricing__heading"),
|
|
2712
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2713
|
+
className: cls("emergency-pricing__titles"),
|
|
2714
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
2715
|
+
className: cls("emergency-pricing__title"),
|
|
2716
|
+
children: pricingCopy.heading
|
|
2717
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2718
|
+
className: cls("emergency-pricing__subtitle"),
|
|
2719
|
+
children: pricingCopy.subtitle
|
|
2720
|
+
})]
|
|
2721
|
+
})
|
|
2722
|
+
}),
|
|
2723
|
+
PRICING_PACKAGES.map((pkg) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PackageCard, {
|
|
2724
|
+
pkg,
|
|
2725
|
+
selected: selected === pkg.id,
|
|
2726
|
+
onSelect: setSelected
|
|
2727
|
+
}, pkg.id)),
|
|
2728
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2729
|
+
className: cls("emergency-pricing__footnote"),
|
|
2730
|
+
children: pricingCopy.footnote
|
|
2731
|
+
})
|
|
2732
|
+
]
|
|
2733
|
+
})
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2737
|
+
// src/react/screens/registry.ts
|
|
2738
|
+
/** Every screen the panel can render. Add one entry to add a screen. */
|
|
2739
|
+
const screenRegistry = {
|
|
2740
|
+
primary: PrimaryScreen,
|
|
2741
|
+
pricing: PricingScreen,
|
|
2742
|
+
details: DetailsScreen
|
|
2743
|
+
};
|
|
2744
|
+
|
|
2235
2745
|
// src/react/components/EmergencyPanel/index.tsx
|
|
2746
|
+
function ActiveScreen({ screenProps, open, forcePrimary }) {
|
|
2747
|
+
const { screen, reset } = useScreenNavigation();
|
|
2748
|
+
const shouldReset = !open || forcePrimary;
|
|
2749
|
+
const effectiveScreen = shouldReset ? "primary" : screen;
|
|
2750
|
+
const previousOpen = (0, react.useRef)(open);
|
|
2751
|
+
const previousScreen = (0, react.useRef)(effectiveScreen);
|
|
2752
|
+
(0, react.useEffect)(() => {
|
|
2753
|
+
if (shouldReset) reset();
|
|
2754
|
+
}, [reset, shouldReset]);
|
|
2755
|
+
(0, react.useEffect)(() => {
|
|
2756
|
+
const wasOpen = previousOpen.current;
|
|
2757
|
+
const previousEffectiveScreen = previousScreen.current;
|
|
2758
|
+
previousOpen.current = open;
|
|
2759
|
+
previousScreen.current = effectiveScreen;
|
|
2760
|
+
if (!open || !wasOpen || previousEffectiveScreen === effectiveScreen) return;
|
|
2761
|
+
document.getElementById(screenProps.titleId)?.focus({ preventScroll: true });
|
|
2762
|
+
}, [
|
|
2763
|
+
effectiveScreen,
|
|
2764
|
+
open,
|
|
2765
|
+
screenProps.titleId
|
|
2766
|
+
]);
|
|
2767
|
+
const Screen = screenRegistry[effectiveScreen];
|
|
2768
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Screen, { ...screenProps });
|
|
2769
|
+
}
|
|
2236
2770
|
function EmergencyPanel(props) {
|
|
2237
2771
|
const { open, theme, active, busy, aborting, loading, locale, responders, refreshing, geolocationError, activationError, error, abortResult, simulationResult, abortConfirmation, simulationConfirmation, onClose, onActivate, onRefresh, onRetry, onDismissFeedback, onRequestAbort, onRequestSimulation, onCancelAbort, onCancelSimulation, onConfirmAbort, onConfirmSimulation } = props;
|
|
2238
2772
|
const titleId = (0, react.useId)();
|
|
2239
2773
|
const dialogRef = (0, react.useRef)(null);
|
|
2240
2774
|
const feedbackVisible = geolocationError !== null || Boolean(activationError) || abortResult !== null || simulationResult !== null;
|
|
2775
|
+
const forcePrimary = active || loading || error !== null || feedbackVisible;
|
|
2241
2776
|
const closeOnEscape = (0, react.useCallback)(() => {
|
|
2242
2777
|
onClose("escape");
|
|
2243
2778
|
}, [onClose]);
|
|
2244
2779
|
useFocusTrap(dialogRef, open);
|
|
2245
2780
|
useEscapeKey(open, closeOnEscape);
|
|
2781
|
+
const screenProps = {
|
|
2782
|
+
titleId,
|
|
2783
|
+
active,
|
|
2784
|
+
busy,
|
|
2785
|
+
aborting,
|
|
2786
|
+
loading,
|
|
2787
|
+
locale,
|
|
2788
|
+
responders,
|
|
2789
|
+
refreshing,
|
|
2790
|
+
geolocationError,
|
|
2791
|
+
activationError,
|
|
2792
|
+
error,
|
|
2793
|
+
abortResult,
|
|
2794
|
+
simulationResult,
|
|
2795
|
+
feedbackVisible,
|
|
2796
|
+
onClose,
|
|
2797
|
+
onActivate,
|
|
2798
|
+
onRefresh,
|
|
2799
|
+
onRetry,
|
|
2800
|
+
onDismissFeedback,
|
|
2801
|
+
onRequestAbort,
|
|
2802
|
+
onRequestSimulation
|
|
2803
|
+
};
|
|
2246
2804
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2247
2805
|
ref: dialogRef,
|
|
2248
2806
|
className: cls("emergency-panel", !open && "emergency-panel--hidden"),
|
|
@@ -2253,48 +2811,18 @@ function EmergencyPanel(props) {
|
|
|
2253
2811
|
"aria-hidden": !open,
|
|
2254
2812
|
inert: !open,
|
|
2255
2813
|
tabIndex: -1,
|
|
2256
|
-
children: [
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
loading,
|
|
2269
|
-
locale,
|
|
2270
|
-
geolocationError,
|
|
2271
|
-
activationError,
|
|
2272
|
-
error,
|
|
2273
|
-
abortResult,
|
|
2274
|
-
simulationResult,
|
|
2275
|
-
onRefresh,
|
|
2276
|
-
onRetry,
|
|
2277
|
-
onDismissFeedback
|
|
2278
|
-
})
|
|
2279
|
-
}),
|
|
2280
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyFooter, {
|
|
2281
|
-
active,
|
|
2282
|
-
busy,
|
|
2283
|
-
aborting,
|
|
2284
|
-
feedbackVisible,
|
|
2285
|
-
onActivate,
|
|
2286
|
-
onRequestAbort,
|
|
2287
|
-
onRequestSimulation
|
|
2288
|
-
}),
|
|
2289
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyConfirmation, {
|
|
2290
|
-
abortConfirmation,
|
|
2291
|
-
simulationConfirmation,
|
|
2292
|
-
onCancelAbort,
|
|
2293
|
-
onCancelSimulation,
|
|
2294
|
-
onConfirmAbort,
|
|
2295
|
-
onConfirmSimulation
|
|
2296
|
-
})
|
|
2297
|
-
]
|
|
2814
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyScreenProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActiveScreen, {
|
|
2815
|
+
screenProps,
|
|
2816
|
+
open,
|
|
2817
|
+
forcePrimary
|
|
2818
|
+
}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyConfirmation, {
|
|
2819
|
+
abortConfirmation,
|
|
2820
|
+
simulationConfirmation,
|
|
2821
|
+
onCancelAbort,
|
|
2822
|
+
onCancelSimulation,
|
|
2823
|
+
onConfirmAbort,
|
|
2824
|
+
onConfirmSimulation
|
|
2825
|
+
})]
|
|
2298
2826
|
});
|
|
2299
2827
|
}
|
|
2300
2828
|
|