@dataemergencia/emergency 0.4.0 → 0.5.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/dist/index.cjs CHANGED
@@ -763,6 +763,7 @@ function createEmergencyStore(config) {
763
763
  lastError: null,
764
764
  geolocation: null,
765
765
  geolocationError: null,
766
+ contactPhone: null,
766
767
  realtimeStatus: "idle",
767
768
  abortResult: null,
768
769
  simulationResult: null,
@@ -1205,7 +1206,8 @@ function createEmergencyController(deps) {
1205
1206
  patch({
1206
1207
  panelOpen: false,
1207
1208
  abortConfirmation: false,
1208
- simulationConfirmation: false
1209
+ simulationConfirmation: false,
1210
+ contactPhone: null
1209
1211
  });
1210
1212
  events.emit("panel:closed", { reason });
1211
1213
  }
@@ -1254,6 +1256,7 @@ function createEmergencyController(deps) {
1254
1256
  lastError: null,
1255
1257
  geolocation: null,
1256
1258
  geolocationError: null,
1259
+ contactPhone: null,
1257
1260
  realtimeStatus: "idle",
1258
1261
  abortResult: null,
1259
1262
  simulationResult: null,
@@ -1295,7 +1298,8 @@ function createEmergencyController(deps) {
1295
1298
  geolocationError: null,
1296
1299
  ...state.geolocationError !== null || state.abortResult?.ok === false || state.simulationResult?.ok === false || state.phase.kind === "ready" && state.lastError !== null ? { lastError: null } : {}
1297
1300
  });
1298
- }
1301
+ },
1302
+ setContactPhone: (phone) => patch({ contactPhone: phone })
1299
1303
  },
1300
1304
  store,
1301
1305
  events
@@ -1526,6 +1530,11 @@ const paths = {
1526
1530
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 7h.01" })
1527
1531
  ] }),
1528
1532
  "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" })] }),
1533
+ "map-pin": /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 22s7-6.2 7-12a7 7 0 1 0-14 0c0 5.8 7 12 7 12z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1534
+ cx: "12",
1535
+ cy: "10",
1536
+ r: "2.5"
1537
+ })] }),
1529
1538
  "credit-card-plus": /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1530
1539
  /* @__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
1540
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M18 12h.01" }),
@@ -1603,6 +1612,7 @@ var panel_module_default = {
1603
1612
  "emergency-panel": "de-emergency-emergency-panel-nA5Hwa",
1604
1613
  "emergency-panel__availability-region": "de-emergency-emergency-panel__availability-region-nA5Hwa",
1605
1614
  "emergency-panel__body": "de-emergency-emergency-panel__body-nA5Hwa",
1615
+ "emergency-panel__body--pre-emergency": "de-emergency-emergency-panel__body--pre-emergency-nA5Hwa",
1606
1616
  "emergency-panel__body--pricing": "de-emergency-emergency-panel__body--pricing-nA5Hwa",
1607
1617
  "emergency-panel__body-split": "de-emergency-emergency-panel__body-split-nA5Hwa",
1608
1618
  "emergency-panel__body-split--with-availability": "de-emergency-emergency-panel__body-split--with-availability-nA5Hwa",
@@ -1613,18 +1623,35 @@ var panel_module_default = {
1613
1623
  "emergency-panel__button--simulation": "de-emergency-emergency-panel__button--simulation-nA5Hwa",
1614
1624
  "emergency-panel__close-button": "de-emergency-emergency-panel__close-button-nA5Hwa",
1615
1625
  "emergency-panel__close-icon": "de-emergency-emergency-panel__close-icon-nA5Hwa",
1626
+ "emergency-panel__divider": "de-emergency-emergency-panel__divider-nA5Hwa",
1616
1627
  "emergency-panel__footer": "de-emergency-emergency-panel__footer-nA5Hwa",
1628
+ "emergency-panel__footer--single": "de-emergency-emergency-panel__footer--single-nA5Hwa",
1617
1629
  "emergency-panel__header": "de-emergency-emergency-panel__header-nA5Hwa",
1630
+ "emergency-panel__header--close-only": "de-emergency-emergency-panel__header--close-only-nA5Hwa",
1618
1631
  "emergency-panel__prompt-region": "de-emergency-emergency-panel__prompt-region-nA5Hwa",
1632
+ "emergency-panel__sr-only": "de-emergency-emergency-panel__sr-only-nA5Hwa",
1619
1633
  "emergency-panel__title": "de-emergency-emergency-panel__title-nA5Hwa",
1620
1634
  "emergency-panel--hidden": "de-emergency-emergency-panel--hidden-nA5Hwa",
1635
+ "emergency-pre-emergency": "de-emergency-emergency-pre-emergency-nA5Hwa",
1636
+ "emergency-pre-emergency__error": "de-emergency-emergency-pre-emergency__error-nA5Hwa",
1637
+ "emergency-pre-emergency__form": "de-emergency-emergency-pre-emergency__form-nA5Hwa",
1638
+ "emergency-pre-emergency__input": "de-emergency-emergency-pre-emergency__input-nA5Hwa",
1639
+ "emergency-pre-emergency__input--area-code": "de-emergency-emergency-pre-emergency__input--area-code-nA5Hwa",
1640
+ "emergency-pre-emergency__input--invalid": "de-emergency-emergency-pre-emergency__input--invalid-nA5Hwa",
1641
+ "emergency-pre-emergency__input--number": "de-emergency-emergency-pre-emergency__input--number-nA5Hwa",
1642
+ "emergency-pre-emergency__input--valid": "de-emergency-emergency-pre-emergency__input--valid-nA5Hwa",
1643
+ "emergency-pre-emergency__label": "de-emergency-emergency-pre-emergency__label-nA5Hwa",
1644
+ "emergency-pre-emergency__notice": "de-emergency-emergency-pre-emergency__notice-nA5Hwa",
1645
+ "emergency-pre-emergency__notice-icon": "de-emergency-emergency-pre-emergency__notice-icon-nA5Hwa",
1646
+ "emergency-pre-emergency__notice-text": "de-emergency-emergency-pre-emergency__notice-text-nA5Hwa",
1647
+ "emergency-pre-emergency__phone-row": "de-emergency-emergency-pre-emergency__phone-row-nA5Hwa",
1621
1648
  "emergency-pricing": "de-emergency-emergency-pricing-nA5Hwa",
1622
1649
  "emergency-pricing__badge": "de-emergency-emergency-pricing__badge-nA5Hwa",
1623
- "emergency-pricing__footnote": "de-emergency-emergency-pricing__footnote-nA5Hwa",
1624
1650
  "emergency-pricing__heading": "de-emergency-emergency-pricing__heading-nA5Hwa",
1625
1651
  "emergency-pricing__package": "de-emergency-emergency-pricing__package-nA5Hwa",
1626
1652
  "emergency-pricing__package--highlighted": "de-emergency-emergency-pricing__package--highlighted-nA5Hwa",
1627
1653
  "emergency-pricing__package-caption": "de-emergency-emergency-pricing__package-caption-nA5Hwa",
1654
+ "emergency-pricing__package-footnote": "de-emergency-emergency-pricing__package-footnote-nA5Hwa",
1628
1655
  "emergency-pricing__package-header": "de-emergency-emergency-pricing__package-header-nA5Hwa",
1629
1656
  "emergency-pricing__package-label": "de-emergency-emergency-pricing__package-label-nA5Hwa",
1630
1657
  "emergency-pricing__package-name": "de-emergency-emergency-pricing__package-name-nA5Hwa",
@@ -1879,11 +1906,12 @@ function useScreenNavigation() {
1879
1906
  }
1880
1907
 
1881
1908
  // src/react/components/EmergencyHeader/index.tsx
1882
- function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack }) {
1909
+ function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack, variant = "default" }) {
1910
+ const closeOnly = variant === "close-only";
1883
1911
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
1884
- className: cls("emergency-panel__header"),
1912
+ className: cls("emergency-panel__header", closeOnly && "emergency-panel__header--close-only"),
1885
1913
  children: [
1886
- onBack ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1914
+ onBack && !closeOnly ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1887
1915
  type: "button",
1888
1916
  className: cls("emergency-panel__close-button"),
1889
1917
  "aria-label": copy.back,
@@ -1894,7 +1922,7 @@ function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack })
1894
1922
  })
1895
1923
  }) : null,
1896
1924
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
1897
- className: cls("emergency-panel__title"),
1925
+ className: cls("emergency-panel__title", closeOnly && "emergency-panel__sr-only"),
1898
1926
  id: titleId,
1899
1927
  tabIndex: -1,
1900
1928
  children: title
@@ -1976,6 +2004,182 @@ function DetailsScreen({ titleId, onClose }) {
1976
2004
  });
1977
2005
  }
1978
2006
 
2007
+ // src/core/phone.ts
2008
+ const VENEZUELA_DIALLING_CODE = "+58";
2009
+ const VENEZUELAN_MOBILE_PATTERN = /^4\d{9}$/;
2010
+ function normalizeVenezuelanPhone(input) {
2011
+ return input.replace(/\D/g, "").replace(/^0+/, "");
2012
+ }
2013
+ function formatVenezuelanPhone(input) {
2014
+ const digits = normalizeVenezuelanPhone(input).slice(0, 10);
2015
+ if (digits.length <= 3) return digits;
2016
+ return `${digits.slice(0, 3)} ${digits.slice(3)}`;
2017
+ }
2018
+ function isValidVenezuelanPhone(input) {
2019
+ return VENEZUELAN_MOBILE_PATTERN.test(normalizeVenezuelanPhone(input));
2020
+ }
2021
+ function toVenezuelanE164(input) {
2022
+ const digits = normalizeVenezuelanPhone(input);
2023
+ if (!VENEZUELAN_MOBILE_PATTERN.test(digits)) return null;
2024
+ return `${"+58"}${digits}`;
2025
+ }
2026
+
2027
+ // src/react/components/EmergencyFooter/index.tsx
2028
+ function EmergencyFooter(props) {
2029
+ const { active, busy, aborting, feedbackVisible, showSimulation = true, emergencyDisabled = false, onActivate, onRequestAbort, onRequestSimulation } = props;
2030
+ if (active) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("footer", {
2031
+ className: cls("emergency-panel__footer"),
2032
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2033
+ type: "button",
2034
+ className: cls("emergency-status__abort-btn"),
2035
+ "aria-label": copy.abort,
2036
+ disabled: aborting || feedbackVisible,
2037
+ onClick: onRequestAbort,
2038
+ children: [copy.abort, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "alert-triangle" })]
2039
+ })
2040
+ });
2041
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
2042
+ className: cls("emergency-panel__footer", !showSimulation && "emergency-panel__footer--single"),
2043
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2044
+ type: "button",
2045
+ className: cls("emergency-panel__button", "emergency-panel__button--emergency"),
2046
+ "aria-label": copy.emergencyAria,
2047
+ disabled: busy || feedbackVisible || emergencyDisabled,
2048
+ onClick: onActivate,
2049
+ children: [copy.emergency, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "emergency" })]
2050
+ }), showSimulation ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2051
+ type: "button",
2052
+ className: cls("emergency-panel__button", "emergency-panel__button--simulation"),
2053
+ "aria-label": copy.testAria,
2054
+ disabled: busy || feedbackVisible,
2055
+ onClick: onRequestSimulation,
2056
+ children: [copy.test, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "list-check" })]
2057
+ }) : null]
2058
+ });
2059
+ }
2060
+
2061
+ // src/react/screens/pre-emergency/copy.ts
2062
+ const preEmergencyCopy = {
2063
+ title: "Pre-emergencia",
2064
+ permissionNotice: "Debes autorizar todos los permisos de ubicación",
2065
+ phoneLabel: "Indique su número de teléfono",
2066
+ phonePlaceholder: "Ej. 0412 000 0000",
2067
+ areaCodeLabel: "Código de país",
2068
+ areaCode: "+58",
2069
+ invalidPhone: "Ingresa un número móvil venezolano válido. Ej. 412 1301234"
2070
+ };
2071
+
2072
+ // src/react/screens/pre-emergency/index.tsx
2073
+ function PreEmergencyScreen(props) {
2074
+ const { back } = useScreenNavigation();
2075
+ const phoneId = (0, react.useId)();
2076
+ const errorId = `${phoneId}-error`;
2077
+ const permissionId = `${phoneId}-permission`;
2078
+ const [digits, setDigits] = (0, react.useState)("");
2079
+ const [touched, setTouched] = (0, react.useState)(false);
2080
+ const valid = isValidVenezuelanPhone(digits);
2081
+ const invalid = touched && digits.length > 0 && !valid;
2082
+ const handleChange = (event) => {
2083
+ const next = normalizeVenezuelanPhone(event.target.value).slice(0, 10);
2084
+ setDigits(next);
2085
+ };
2086
+ const handleSubmit = () => {
2087
+ setTouched(true);
2088
+ if (!valid) return;
2089
+ const phone = toVenezuelanE164(digits);
2090
+ if (phone === null) return;
2091
+ props.onSetContactPhone(phone);
2092
+ props.onActivate();
2093
+ };
2094
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyScreenLayout, {
2095
+ screen: "pre-emergency",
2096
+ titleId: props.titleId,
2097
+ bodyClassName: "emergency-panel__body--pre-emergency",
2098
+ header: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyHeader, {
2099
+ titleId: props.titleId,
2100
+ title: preEmergencyCopy.title,
2101
+ onClose: () => props.onClose("close"),
2102
+ onBack: back
2103
+ }),
2104
+ footer: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyFooter, {
2105
+ active: props.active,
2106
+ busy: props.busy,
2107
+ aborting: props.aborting,
2108
+ feedbackVisible: props.feedbackVisible,
2109
+ emergencyDisabled: !valid,
2110
+ showSimulation: false,
2111
+ onActivate: handleSubmit,
2112
+ onRequestAbort: props.onRequestAbort,
2113
+ onRequestSimulation: props.onRequestSimulation
2114
+ }),
2115
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2116
+ className: cls("emergency-pre-emergency"),
2117
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2118
+ role: "note",
2119
+ "aria-labelledby": permissionId,
2120
+ className: cls("emergency-pre-emergency__notice"),
2121
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
2122
+ name: "map-pin",
2123
+ className: cls("emergency-pre-emergency__notice-icon")
2124
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2125
+ id: permissionId,
2126
+ className: cls("emergency-pre-emergency__notice-text"),
2127
+ children: preEmergencyCopy.permissionNotice
2128
+ })]
2129
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
2130
+ className: cls("emergency-pre-emergency__form"),
2131
+ noValidate: true,
2132
+ onSubmit: (event) => {
2133
+ event.preventDefault();
2134
+ handleSubmit();
2135
+ },
2136
+ onKeyDown: (event) => {
2137
+ if (event.key === "Enter") {
2138
+ event.preventDefault();
2139
+ handleSubmit();
2140
+ }
2141
+ },
2142
+ children: [
2143
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
2144
+ htmlFor: phoneId,
2145
+ className: cls("emergency-pre-emergency__label"),
2146
+ children: preEmergencyCopy.phoneLabel
2147
+ }),
2148
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2149
+ className: cls("emergency-pre-emergency__phone-row"),
2150
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2151
+ type: "tel",
2152
+ "aria-label": preEmergencyCopy.areaCodeLabel,
2153
+ className: cls("emergency-pre-emergency__input", "emergency-pre-emergency__input--area-code", valid && "emergency-pre-emergency__input--valid"),
2154
+ value: preEmergencyCopy.areaCode,
2155
+ disabled: true,
2156
+ readOnly: true
2157
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2158
+ id: phoneId,
2159
+ type: "tel",
2160
+ inputMode: "tel",
2161
+ autoComplete: "tel-national",
2162
+ placeholder: preEmergencyCopy.phonePlaceholder,
2163
+ className: cls("emergency-pre-emergency__input", "emergency-pre-emergency__input--number", valid && "emergency-pre-emergency__input--valid", invalid && "emergency-pre-emergency__input--invalid"),
2164
+ value: formatVenezuelanPhone(digits),
2165
+ "aria-invalid": invalid,
2166
+ "aria-describedby": invalid ? errorId : void 0,
2167
+ onChange: handleChange,
2168
+ onBlur: () => setTouched(true)
2169
+ })]
2170
+ }),
2171
+ invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2172
+ id: errorId,
2173
+ role: "alert",
2174
+ className: cls("emergency-pre-emergency__error"),
2175
+ children: preEmergencyCopy.invalidPhone
2176
+ }) : null
2177
+ ]
2178
+ })]
2179
+ })
2180
+ });
2181
+ }
2182
+
1979
2183
  // src/react/components/icons/paramedical-mark.tsx
1980
2184
  /**
1981
2185
  * Neutral inline illustration used by the idle panel.
@@ -2447,13 +2651,16 @@ function EmergencyBody(props) {
2447
2651
  const idle = !active && !loading && !showingFeedback && error === null;
2448
2652
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2449
2653
  className: cls("emergency-panel__body-split", idle && "emergency-panel__body-split--with-availability"),
2450
- children: [idle ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2654
+ children: [idle ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2451
2655
  className: cls("emergency-panel__availability-region"),
2452
2656
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Availability, {
2453
2657
  onRecharge,
2454
2658
  onDetails
2455
2659
  })
2456
- }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2660
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("hr", {
2661
+ className: cls("emergency-panel__divider"),
2662
+ "aria-hidden": "true"
2663
+ })] }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2457
2664
  className: cls("emergency-panel__prompt-region"),
2458
2665
  children: [
2459
2666
  !loading && !showingFeedback ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -2494,48 +2701,17 @@ function EmergencyBody(props) {
2494
2701
  });
2495
2702
  }
2496
2703
 
2497
- // src/react/components/EmergencyFooter/index.tsx
2498
- function EmergencyFooter(props) {
2499
- const { active, busy, aborting, feedbackVisible, onActivate, onRequestAbort, onRequestSimulation } = props;
2500
- if (active) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("footer", {
2501
- className: cls("emergency-panel__footer"),
2502
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2503
- type: "button",
2504
- className: cls("emergency-status__abort-btn"),
2505
- "aria-label": copy.abort,
2506
- disabled: aborting || feedbackVisible,
2507
- onClick: onRequestAbort,
2508
- children: [copy.abort, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "alert-triangle" })]
2509
- })
2510
- });
2511
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
2512
- className: cls("emergency-panel__footer"),
2513
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2514
- type: "button",
2515
- className: cls("emergency-panel__button", "emergency-panel__button--emergency"),
2516
- "aria-label": copy.emergencyAria,
2517
- disabled: busy || feedbackVisible,
2518
- onClick: onActivate,
2519
- children: [copy.emergency, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "emergency" })]
2520
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2521
- type: "button",
2522
- className: cls("emergency-panel__button", "emergency-panel__button--simulation"),
2523
- "aria-label": copy.testAria,
2524
- disabled: busy || feedbackVisible,
2525
- onClick: onRequestSimulation,
2526
- children: [copy.test, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "list-check" })]
2527
- })]
2528
- });
2529
- }
2530
-
2531
2704
  // src/react/screens/primary/index.tsx
2532
2705
  function PrimaryScreen(props) {
2533
2706
  const { navigate } = useScreenNavigation();
2707
+ const idle = !props.active && !props.loading && !props.feedbackVisible && props.error === null;
2708
+ const needsContactPhone = props.contactPhone === null;
2534
2709
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyScreenLayout, {
2535
2710
  screen: "primary",
2536
2711
  titleId: props.titleId,
2537
2712
  header: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyHeader, {
2538
2713
  titleId: props.titleId,
2714
+ variant: idle ? "close-only" : "default",
2539
2715
  onClose: () => props.onClose("close")
2540
2716
  }),
2541
2717
  footer: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmergencyFooter, {
@@ -2543,7 +2719,7 @@ function PrimaryScreen(props) {
2543
2719
  busy: props.busy,
2544
2720
  aborting: props.aborting,
2545
2721
  feedbackVisible: props.feedbackVisible,
2546
- onActivate: props.onActivate,
2722
+ onActivate: needsContactPhone ? () => navigate("pre-emergency") : props.onActivate,
2547
2723
  onRequestAbort: props.onRequestAbort,
2548
2724
  onRequestSimulation: props.onRequestSimulation
2549
2725
  }),
@@ -2577,7 +2753,7 @@ const pricingCopy = {
2577
2753
  chosen: "Seleccionado",
2578
2754
  whatsapp: "de WhatsApp",
2579
2755
  rounds: "rondas de alerta",
2580
- perMessage: "por mensaje + IVA",
2756
+ perMessage: "IVA Incluido",
2581
2757
  footnote: "Rondas calculadas con 3 contactos de emergencia. Válidas para pruebas y emergencias."
2582
2758
  };
2583
2759
 
@@ -2591,17 +2767,16 @@ const PRICING_PACKAGES = [{
2591
2767
  label: "PAQUETE 1",
2592
2768
  messages: 100,
2593
2769
  priceLabel: "$7",
2594
- priceCaption: "IVA incluido",
2595
- perMessageLabel: "$0.06",
2770
+ priceCaption: "IVA incluído",
2771
+ perMessageLabel: "$0.07",
2596
2772
  highlighted: false
2597
2773
  }, {
2598
2774
  id: "package-2",
2599
2775
  label: "PAQUETE 2",
2600
2776
  messages: 200,
2601
2777
  priceLabel: "12$",
2602
- priceNote: "($10 + IVA)",
2603
- priceCaption: "IVA incluido",
2604
- perMessageLabel: "$0.05",
2778
+ priceCaption: "IVA incluído",
2779
+ perMessageLabel: "$0.06",
2605
2780
  highlighted: true,
2606
2781
  badge: "MEJOR VALOR"
2607
2782
  }];
@@ -2678,6 +2853,10 @@ function PackageCard({ pkg, selected, onSelect }) {
2678
2853
  })
2679
2854
  ]
2680
2855
  }),
2856
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2857
+ className: cls("emergency-pricing__package-footnote"),
2858
+ children: pricingCopy.footnote
2859
+ }),
2681
2860
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2682
2861
  type: "button",
2683
2862
  className: cls("emergency-pricing__select"),
@@ -2706,30 +2885,23 @@ function PricingScreen(props) {
2706
2885
  footer: null,
2707
2886
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2708
2887
  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
2888
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2889
+ className: cls("emergency-pricing__heading"),
2890
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2891
+ className: cls("emergency-pricing__titles"),
2892
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2893
+ className: cls("emergency-pricing__title"),
2894
+ children: pricingCopy.heading
2895
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2896
+ className: cls("emergency-pricing__subtitle"),
2897
+ children: pricingCopy.subtitle
2898
+ })]
2731
2899
  })
2732
- ]
2900
+ }), PRICING_PACKAGES.map((pkg) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PackageCard, {
2901
+ pkg,
2902
+ selected: selected === pkg.id,
2903
+ onSelect: setSelected
2904
+ }, pkg.id))]
2733
2905
  })
2734
2906
  });
2735
2907
  }
@@ -2738,6 +2910,7 @@ function PricingScreen(props) {
2738
2910
  /** Every screen the panel can render. Add one entry to add a screen. */
2739
2911
  const screenRegistry = {
2740
2912
  primary: PrimaryScreen,
2913
+ "pre-emergency": PreEmergencyScreen,
2741
2914
  pricing: PricingScreen,
2742
2915
  details: DetailsScreen
2743
2916
  };
@@ -2768,7 +2941,7 @@ function ActiveScreen({ screenProps, open, forcePrimary }) {
2768
2941
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Screen, { ...screenProps });
2769
2942
  }
2770
2943
  function EmergencyPanel(props) {
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;
2944
+ const { open, theme, active, busy, aborting, loading, locale, responders, refreshing, geolocationError, contactPhone, activationError, error, abortResult, simulationResult, abortConfirmation, simulationConfirmation, onClose, onActivate, onRefresh, onRetry, onDismissFeedback, onRequestAbort, onRequestSimulation, onCancelAbort, onCancelSimulation, onConfirmAbort, onConfirmSimulation, onSetContactPhone } = props;
2772
2945
  const titleId = (0, react.useId)();
2773
2946
  const dialogRef = (0, react.useRef)(null);
2774
2947
  const feedbackVisible = geolocationError !== null || Boolean(activationError) || abortResult !== null || simulationResult !== null;
@@ -2793,13 +2966,15 @@ function EmergencyPanel(props) {
2793
2966
  abortResult,
2794
2967
  simulationResult,
2795
2968
  feedbackVisible,
2969
+ contactPhone,
2796
2970
  onClose,
2797
2971
  onActivate,
2798
2972
  onRefresh,
2799
2973
  onRetry,
2800
2974
  onDismissFeedback,
2801
2975
  onRequestAbort,
2802
- onRequestSimulation
2976
+ onRequestSimulation,
2977
+ onSetContactPhone
2803
2978
  };
2804
2979
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2805
2980
  ref: dialogRef,
@@ -2906,6 +3081,7 @@ function EmergencyRoot() {
2906
3081
  const responders = useEmergencyStore((state) => state.responders);
2907
3082
  const resumeAvailable = useEmergencyStore((state) => state.resumeAvailable);
2908
3083
  const geolocationError = useEmergencyStore((state) => state.geolocationError);
3084
+ const contactPhone = useEmergencyStore((state) => state.contactPhone);
2909
3085
  const lastError = useEmergencyStore((state) => state.lastError);
2910
3086
  const abortResult = useEmergencyStore((state) => state.abortResult);
2911
3087
  const simulationResult = useEmergencyStore((state) => state.simulationResult);
@@ -2931,6 +3107,7 @@ function EmergencyRoot() {
2931
3107
  responders,
2932
3108
  refreshing: phase.kind === "refreshing",
2933
3109
  geolocationError,
3110
+ contactPhone,
2934
3111
  activationError,
2935
3112
  error: showError ? error : null,
2936
3113
  abortResult,
@@ -2957,7 +3134,8 @@ function EmergencyRoot() {
2957
3134
  },
2958
3135
  onConfirmSimulation: () => {
2959
3136
  client.simulate();
2960
- }
3137
+ },
3138
+ onSetContactPhone: (phone) => client.setContactPhone(phone)
2961
3139
  })] });
2962
3140
  }
2963
3141
 
@@ -2989,6 +3167,7 @@ function createFailedClient(error) {
2989
3167
  lastError: error,
2990
3168
  geolocation: null,
2991
3169
  geolocationError: null,
3170
+ contactPhone: null,
2992
3171
  realtimeStatus: "idle",
2993
3172
  abortResult: null,
2994
3173
  simulationResult: null,
@@ -3017,7 +3196,8 @@ function createFailedClient(error) {
3017
3196
  cancelAbortConfirmation: noop,
3018
3197
  requestSimulationConfirmation: noop,
3019
3198
  cancelSimulationConfirmation: noop,
3020
- dismissFeedback: noop
3199
+ dismissFeedback: noop,
3200
+ setContactPhone: noop
3021
3201
  };
3022
3202
  }
3023
3203
  function attachTrigger(trigger, client) {
@@ -3106,6 +3286,7 @@ function mount(options) {
3106
3286
  requestSimulationConfirmation: () => client.requestSimulationConfirmation(),
3107
3287
  cancelSimulationConfirmation: () => client.cancelSimulationConfirmation(),
3108
3288
  dismissFeedback: () => client.dismissFeedback(),
3289
+ setContactPhone: (phone) => client.setContactPhone(phone),
3109
3290
  destroy
3110
3291
  };
3111
3292
  }
package/dist/index.d.cts CHANGED
@@ -215,6 +215,7 @@ interface EmergencyClientState {
215
215
  readonly lastError: EmergencyError | null;
216
216
  readonly geolocation: EmergencyGeolocation | null;
217
217
  readonly geolocationError: EmergencyError | null;
218
+ readonly contactPhone: string | null;
218
219
  readonly realtimeStatus: RealtimeStatus;
219
220
  readonly abortResult: AbortResult | null;
220
221
  readonly simulationResult: SimulationResult | null;
@@ -242,6 +243,7 @@ interface EmergencyClient {
242
243
  requestSimulationConfirmation(): void;
243
244
  cancelSimulationConfirmation(): void;
244
245
  dismissFeedback(): void;
246
+ setContactPhone(phone: string | null): void;
245
247
  }
246
248
  type EmergencyTrigger = string | HTMLElement | ((open: () => void) => void | (() => void));
247
249
  interface EmergencyMountOptions extends EmergencyConfig {
package/dist/index.d.ts CHANGED
@@ -215,6 +215,7 @@ interface EmergencyClientState {
215
215
  readonly lastError: EmergencyError | null;
216
216
  readonly geolocation: EmergencyGeolocation | null;
217
217
  readonly geolocationError: EmergencyError | null;
218
+ readonly contactPhone: string | null;
218
219
  readonly realtimeStatus: RealtimeStatus;
219
220
  readonly abortResult: AbortResult | null;
220
221
  readonly simulationResult: SimulationResult | null;
@@ -242,6 +243,7 @@ interface EmergencyClient {
242
243
  requestSimulationConfirmation(): void;
243
244
  cancelSimulationConfirmation(): void;
244
245
  dismissFeedback(): void;
246
+ setContactPhone(phone: string | null): void;
245
247
  }
246
248
  type EmergencyTrigger = string | HTMLElement | ((open: () => void) => void | (() => void));
247
249
  interface EmergencyMountOptions extends EmergencyConfig {