@dataemergencia/emergency 0.4.0 → 0.6.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 +1 -1
- package/dist/iife/emergency.iife.global.js +3 -3
- package/dist/index.cjs +819 -149
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +819 -149
- package/dist/styles.css +540 -71
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -734,6 +734,7 @@ function createEmergencyStore(config) {
|
|
|
734
734
|
lastError: null,
|
|
735
735
|
geolocation: null,
|
|
736
736
|
geolocationError: null,
|
|
737
|
+
contactPhone: null,
|
|
737
738
|
realtimeStatus: "idle",
|
|
738
739
|
abortResult: null,
|
|
739
740
|
simulationResult: null,
|
|
@@ -1176,7 +1177,8 @@ function createEmergencyController(deps) {
|
|
|
1176
1177
|
patch({
|
|
1177
1178
|
panelOpen: false,
|
|
1178
1179
|
abortConfirmation: false,
|
|
1179
|
-
simulationConfirmation: false
|
|
1180
|
+
simulationConfirmation: false,
|
|
1181
|
+
contactPhone: null
|
|
1180
1182
|
});
|
|
1181
1183
|
events.emit("panel:closed", { reason });
|
|
1182
1184
|
}
|
|
@@ -1225,6 +1227,7 @@ function createEmergencyController(deps) {
|
|
|
1225
1227
|
lastError: null,
|
|
1226
1228
|
geolocation: null,
|
|
1227
1229
|
geolocationError: null,
|
|
1230
|
+
contactPhone: null,
|
|
1228
1231
|
realtimeStatus: "idle",
|
|
1229
1232
|
abortResult: null,
|
|
1230
1233
|
simulationResult: null,
|
|
@@ -1266,7 +1269,8 @@ function createEmergencyController(deps) {
|
|
|
1266
1269
|
geolocationError: null,
|
|
1267
1270
|
...state.geolocationError !== null || state.abortResult?.ok === false || state.simulationResult?.ok === false || state.phase.kind === "ready" && state.lastError !== null ? { lastError: null } : {}
|
|
1268
1271
|
});
|
|
1269
|
-
}
|
|
1272
|
+
},
|
|
1273
|
+
setContactPhone: (phone) => patch({ contactPhone: phone })
|
|
1270
1274
|
},
|
|
1271
1275
|
store,
|
|
1272
1276
|
events
|
|
@@ -1497,6 +1501,11 @@ const paths = {
|
|
|
1497
1501
|
/* @__PURE__ */ jsx("path", { d: "M12 7h.01" })
|
|
1498
1502
|
] }),
|
|
1499
1503
|
"arrow-left": /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M19 12H5" }), /* @__PURE__ */ jsx("path", { d: "m12 19-7-7 7-7" })] }),
|
|
1504
|
+
"map-pin": /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M12 22s7-6.2 7-12a7 7 0 1 0-14 0c0 5.8 7 12 7 12z" }), /* @__PURE__ */ jsx("circle", {
|
|
1505
|
+
cx: "12",
|
|
1506
|
+
cy: "10",
|
|
1507
|
+
r: "2.5"
|
|
1508
|
+
})] }),
|
|
1500
1509
|
"credit-card-plus": /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1501
1510
|
/* @__PURE__ */ jsx("path", { d: "M12 18H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5" }),
|
|
1502
1511
|
/* @__PURE__ */ jsx("path", { d: "M18 12h.01" }),
|
|
@@ -1538,6 +1547,12 @@ var panel_module_default = {
|
|
|
1538
1547
|
"de-emergency-slide-in": "de-emergency-de-emergency-slide-in-nA5Hwa",
|
|
1539
1548
|
"de-emergency-slide-up": "de-emergency-de-emergency-slide-up-nA5Hwa",
|
|
1540
1549
|
"de-emergency-spin": "de-emergency-de-emergency-spin-nA5Hwa",
|
|
1550
|
+
"emergency-alert-row__badge": "de-emergency-emergency-alert-row__badge-nA5Hwa",
|
|
1551
|
+
"emergency-alert-row__button": "de-emergency-emergency-alert-row__button-nA5Hwa",
|
|
1552
|
+
"emergency-alert-row__stat": "de-emergency-emergency-alert-row__stat-nA5Hwa",
|
|
1553
|
+
"emergency-alert-row__stats": "de-emergency-emergency-alert-row__stats-nA5Hwa",
|
|
1554
|
+
"emergency-alert-row__time": "de-emergency-emergency-alert-row__time-nA5Hwa",
|
|
1555
|
+
"emergency-alert-row__top": "de-emergency-emergency-alert-row__top-nA5Hwa",
|
|
1541
1556
|
"emergency-availability": "de-emergency-emergency-availability-nA5Hwa",
|
|
1542
1557
|
"emergency-availability__card": "de-emergency-emergency-availability__card-nA5Hwa",
|
|
1543
1558
|
"emergency-availability__card-body": "de-emergency-emergency-availability__card-body-nA5Hwa",
|
|
@@ -1561,6 +1576,19 @@ var panel_module_default = {
|
|
|
1561
1576
|
"emergency-confirmation__icon--information": "de-emergency-emergency-confirmation__icon--information-nA5Hwa",
|
|
1562
1577
|
"emergency-confirmation__text": "de-emergency-emergency-confirmation__text-nA5Hwa",
|
|
1563
1578
|
"emergency-confirmation__title": "de-emergency-emergency-confirmation__title-nA5Hwa",
|
|
1579
|
+
"emergency-details": "de-emergency-emergency-details-nA5Hwa",
|
|
1580
|
+
"emergency-details__balance": "de-emergency-emergency-details__balance-nA5Hwa",
|
|
1581
|
+
"emergency-details__card": "de-emergency-emergency-details__card-nA5Hwa",
|
|
1582
|
+
"emergency-details__card-body": "de-emergency-emergency-details__card-body-nA5Hwa",
|
|
1583
|
+
"emergency-details__card-header": "de-emergency-emergency-details__card-header-nA5Hwa",
|
|
1584
|
+
"emergency-details__card-title": "de-emergency-emergency-details__card-title-nA5Hwa",
|
|
1585
|
+
"emergency-details__empty": "de-emergency-emergency-details__empty-nA5Hwa",
|
|
1586
|
+
"emergency-details__heading": "de-emergency-emergency-details__heading-nA5Hwa",
|
|
1587
|
+
"emergency-details__history-button": "de-emergency-emergency-details__history-button-nA5Hwa",
|
|
1588
|
+
"emergency-details__list": "de-emergency-emergency-details__list-nA5Hwa",
|
|
1589
|
+
"emergency-details__section": "de-emergency-emergency-details__section-nA5Hwa",
|
|
1590
|
+
"emergency-details__subtitle": "de-emergency-emergency-details__subtitle-nA5Hwa",
|
|
1591
|
+
"emergency-details__title": "de-emergency-emergency-details__title-nA5Hwa",
|
|
1564
1592
|
"emergency-error-message": "de-emergency-emergency-error-message-nA5Hwa",
|
|
1565
1593
|
"emergency-error-message__container": "de-emergency-emergency-error-message__container-nA5Hwa",
|
|
1566
1594
|
"emergency-error-message__content": "de-emergency-emergency-error-message__content-nA5Hwa",
|
|
@@ -1571,10 +1599,33 @@ var panel_module_default = {
|
|
|
1571
1599
|
"emergency-error-message__title": "de-emergency-emergency-error-message__title-nA5Hwa",
|
|
1572
1600
|
"emergency-feedback": "de-emergency-emergency-feedback-nA5Hwa",
|
|
1573
1601
|
"emergency-feedback__dismiss": "de-emergency-emergency-feedback__dismiss-nA5Hwa",
|
|
1602
|
+
"emergency-history": "de-emergency-emergency-history-nA5Hwa",
|
|
1603
|
+
"emergency-history__empty": "de-emergency-emergency-history__empty-nA5Hwa",
|
|
1604
|
+
"emergency-history__heading": "de-emergency-emergency-history__heading-nA5Hwa",
|
|
1605
|
+
"emergency-history__list": "de-emergency-emergency-history__list-nA5Hwa",
|
|
1606
|
+
"emergency-history__more": "de-emergency-emergency-history__more-nA5Hwa",
|
|
1607
|
+
"emergency-history__subtitle": "de-emergency-emergency-history__subtitle-nA5Hwa",
|
|
1608
|
+
"emergency-history__title": "de-emergency-emergency-history__title-nA5Hwa",
|
|
1609
|
+
"emergency-message-detail": "de-emergency-emergency-message-detail-nA5Hwa",
|
|
1610
|
+
"emergency-message-detail__back": "de-emergency-emergency-message-detail__back-nA5Hwa",
|
|
1611
|
+
"emergency-message-detail__card": "de-emergency-emergency-message-detail__card-nA5Hwa",
|
|
1612
|
+
"emergency-message-detail__card-header": "de-emergency-emergency-message-detail__card-header-nA5Hwa",
|
|
1613
|
+
"emergency-message-detail__card-title": "de-emergency-emergency-message-detail__card-title-nA5Hwa",
|
|
1614
|
+
"emergency-message-detail__empty": "de-emergency-emergency-message-detail__empty-nA5Hwa",
|
|
1615
|
+
"emergency-message-detail__empty-text": "de-emergency-emergency-message-detail__empty-text-nA5Hwa",
|
|
1616
|
+
"emergency-message-detail__label": "de-emergency-emergency-message-detail__label-nA5Hwa",
|
|
1617
|
+
"emergency-message-detail__list": "de-emergency-emergency-message-detail__list-nA5Hwa",
|
|
1618
|
+
"emergency-message-detail__row": "de-emergency-emergency-message-detail__row-nA5Hwa",
|
|
1619
|
+
"emergency-message-detail__value": "de-emergency-emergency-message-detail__value-nA5Hwa",
|
|
1574
1620
|
"emergency-panel": "de-emergency-emergency-panel-nA5Hwa",
|
|
1575
1621
|
"emergency-panel__availability-region": "de-emergency-emergency-panel__availability-region-nA5Hwa",
|
|
1576
1622
|
"emergency-panel__body": "de-emergency-emergency-panel__body-nA5Hwa",
|
|
1623
|
+
"emergency-panel__body--details": "de-emergency-emergency-panel__body--details-nA5Hwa",
|
|
1624
|
+
"emergency-panel__body--history": "de-emergency-emergency-panel__body--history-nA5Hwa",
|
|
1625
|
+
"emergency-panel__body--message-detail": "de-emergency-emergency-panel__body--message-detail-nA5Hwa",
|
|
1626
|
+
"emergency-panel__body--pre-emergency": "de-emergency-emergency-panel__body--pre-emergency-nA5Hwa",
|
|
1577
1627
|
"emergency-panel__body--pricing": "de-emergency-emergency-panel__body--pricing-nA5Hwa",
|
|
1628
|
+
"emergency-panel__body--primary": "de-emergency-emergency-panel__body--primary-nA5Hwa",
|
|
1578
1629
|
"emergency-panel__body-split": "de-emergency-emergency-panel__body-split-nA5Hwa",
|
|
1579
1630
|
"emergency-panel__body-split--with-availability": "de-emergency-emergency-panel__body-split--with-availability-nA5Hwa",
|
|
1580
1631
|
"emergency-panel__body-title": "de-emergency-emergency-panel__body-title-nA5Hwa",
|
|
@@ -1583,19 +1634,37 @@ var panel_module_default = {
|
|
|
1583
1634
|
"emergency-panel__button--emergency": "de-emergency-emergency-panel__button--emergency-nA5Hwa",
|
|
1584
1635
|
"emergency-panel__button--simulation": "de-emergency-emergency-panel__button--simulation-nA5Hwa",
|
|
1585
1636
|
"emergency-panel__close-button": "de-emergency-emergency-panel__close-button-nA5Hwa",
|
|
1637
|
+
"emergency-panel__close-button--prompt": "de-emergency-emergency-panel__close-button--prompt-nA5Hwa",
|
|
1586
1638
|
"emergency-panel__close-icon": "de-emergency-emergency-panel__close-icon-nA5Hwa",
|
|
1587
1639
|
"emergency-panel__footer": "de-emergency-emergency-panel__footer-nA5Hwa",
|
|
1640
|
+
"emergency-panel__footer--single": "de-emergency-emergency-panel__footer--single-nA5Hwa",
|
|
1641
|
+
"emergency-panel__footer--square": "de-emergency-emergency-panel__footer--square-nA5Hwa",
|
|
1588
1642
|
"emergency-panel__header": "de-emergency-emergency-panel__header-nA5Hwa",
|
|
1589
1643
|
"emergency-panel__prompt-region": "de-emergency-emergency-panel__prompt-region-nA5Hwa",
|
|
1644
|
+
"emergency-panel__prompt-region--idle": "de-emergency-emergency-panel__prompt-region--idle-nA5Hwa",
|
|
1645
|
+
"emergency-panel__sr-only": "de-emergency-emergency-panel__sr-only-nA5Hwa",
|
|
1590
1646
|
"emergency-panel__title": "de-emergency-emergency-panel__title-nA5Hwa",
|
|
1591
1647
|
"emergency-panel--hidden": "de-emergency-emergency-panel--hidden-nA5Hwa",
|
|
1648
|
+
"emergency-pre-emergency": "de-emergency-emergency-pre-emergency-nA5Hwa",
|
|
1649
|
+
"emergency-pre-emergency__error": "de-emergency-emergency-pre-emergency__error-nA5Hwa",
|
|
1650
|
+
"emergency-pre-emergency__form": "de-emergency-emergency-pre-emergency__form-nA5Hwa",
|
|
1651
|
+
"emergency-pre-emergency__input": "de-emergency-emergency-pre-emergency__input-nA5Hwa",
|
|
1652
|
+
"emergency-pre-emergency__input--area-code": "de-emergency-emergency-pre-emergency__input--area-code-nA5Hwa",
|
|
1653
|
+
"emergency-pre-emergency__input--invalid": "de-emergency-emergency-pre-emergency__input--invalid-nA5Hwa",
|
|
1654
|
+
"emergency-pre-emergency__input--number": "de-emergency-emergency-pre-emergency__input--number-nA5Hwa",
|
|
1655
|
+
"emergency-pre-emergency__input--valid": "de-emergency-emergency-pre-emergency__input--valid-nA5Hwa",
|
|
1656
|
+
"emergency-pre-emergency__label": "de-emergency-emergency-pre-emergency__label-nA5Hwa",
|
|
1657
|
+
"emergency-pre-emergency__notice": "de-emergency-emergency-pre-emergency__notice-nA5Hwa",
|
|
1658
|
+
"emergency-pre-emergency__notice-icon": "de-emergency-emergency-pre-emergency__notice-icon-nA5Hwa",
|
|
1659
|
+
"emergency-pre-emergency__notice-text": "de-emergency-emergency-pre-emergency__notice-text-nA5Hwa",
|
|
1660
|
+
"emergency-pre-emergency__phone-row": "de-emergency-emergency-pre-emergency__phone-row-nA5Hwa",
|
|
1592
1661
|
"emergency-pricing": "de-emergency-emergency-pricing-nA5Hwa",
|
|
1593
1662
|
"emergency-pricing__badge": "de-emergency-emergency-pricing__badge-nA5Hwa",
|
|
1594
|
-
"emergency-pricing__footnote": "de-emergency-emergency-pricing__footnote-nA5Hwa",
|
|
1595
1663
|
"emergency-pricing__heading": "de-emergency-emergency-pricing__heading-nA5Hwa",
|
|
1596
1664
|
"emergency-pricing__package": "de-emergency-emergency-pricing__package-nA5Hwa",
|
|
1597
1665
|
"emergency-pricing__package--highlighted": "de-emergency-emergency-pricing__package--highlighted-nA5Hwa",
|
|
1598
1666
|
"emergency-pricing__package-caption": "de-emergency-emergency-pricing__package-caption-nA5Hwa",
|
|
1667
|
+
"emergency-pricing__package-footnote": "de-emergency-emergency-pricing__package-footnote-nA5Hwa",
|
|
1599
1668
|
"emergency-pricing__package-header": "de-emergency-emergency-pricing__package-header-nA5Hwa",
|
|
1600
1669
|
"emergency-pricing__package-label": "de-emergency-emergency-pricing__package-label-nA5Hwa",
|
|
1601
1670
|
"emergency-pricing__package-name": "de-emergency-emergency-pricing__package-name-nA5Hwa",
|
|
@@ -1791,18 +1860,27 @@ function useFocusTrap(ref, active) {
|
|
|
1791
1860
|
}
|
|
1792
1861
|
|
|
1793
1862
|
// src/react/screens/context.tsx
|
|
1863
|
+
const EMPTY_PARAMS = {};
|
|
1794
1864
|
const EmergencyScreenContext = createContext(null);
|
|
1865
|
+
function paramsEqual(first, second) {
|
|
1866
|
+
return first.messageId === second.messageId;
|
|
1867
|
+
}
|
|
1795
1868
|
function EmergencyScreenProvider({ children, initialScreen = "primary" }) {
|
|
1796
1869
|
const [state, setState] = useState({
|
|
1797
1870
|
screen: initialScreen,
|
|
1871
|
+
params: EMPTY_PARAMS,
|
|
1798
1872
|
history: []
|
|
1799
1873
|
});
|
|
1800
|
-
const navigate = useCallback((next) => {
|
|
1874
|
+
const navigate = useCallback((next, params = EMPTY_PARAMS) => {
|
|
1801
1875
|
setState((current) => {
|
|
1802
|
-
if (current.screen === next) return current;
|
|
1876
|
+
if (current.screen === next && paramsEqual(current.params, params)) return current;
|
|
1803
1877
|
return {
|
|
1804
1878
|
screen: next,
|
|
1805
|
-
|
|
1879
|
+
params,
|
|
1880
|
+
history: [...current.history, {
|
|
1881
|
+
screen: current.screen,
|
|
1882
|
+
params: current.params
|
|
1883
|
+
}]
|
|
1806
1884
|
};
|
|
1807
1885
|
});
|
|
1808
1886
|
}, []);
|
|
@@ -1811,31 +1889,47 @@ function EmergencyScreenProvider({ children, initialScreen = "primary" }) {
|
|
|
1811
1889
|
const previous = current.history.at(-1);
|
|
1812
1890
|
if (!previous) return current;
|
|
1813
1891
|
return {
|
|
1814
|
-
screen: previous,
|
|
1892
|
+
screen: previous.screen,
|
|
1893
|
+
params: previous.params,
|
|
1815
1894
|
history: current.history.slice(0, -1)
|
|
1816
1895
|
};
|
|
1817
1896
|
});
|
|
1818
1897
|
}, []);
|
|
1898
|
+
const replace = useCallback((next, params = EMPTY_PARAMS) => {
|
|
1899
|
+
setState((current) => {
|
|
1900
|
+
if (current.screen === next && paramsEqual(current.params, params)) return current;
|
|
1901
|
+
return {
|
|
1902
|
+
screen: next,
|
|
1903
|
+
params,
|
|
1904
|
+
history: current.history.at(-1)?.screen === next ? current.history.slice(0, -1) : current.history
|
|
1905
|
+
};
|
|
1906
|
+
});
|
|
1907
|
+
}, []);
|
|
1819
1908
|
const reset = useCallback(() => {
|
|
1820
1909
|
setState((current) => {
|
|
1821
|
-
if (current.screen === "primary" && current.history.length === 0) return current;
|
|
1910
|
+
if (current.screen === "primary" && current.params.messageId === void 0 && current.history.length === 0) return current;
|
|
1822
1911
|
return {
|
|
1823
1912
|
screen: "primary",
|
|
1913
|
+
params: EMPTY_PARAMS,
|
|
1824
1914
|
history: []
|
|
1825
1915
|
};
|
|
1826
1916
|
});
|
|
1827
1917
|
}, []);
|
|
1828
1918
|
const value = useMemo(() => ({
|
|
1829
1919
|
screen: state.screen,
|
|
1920
|
+
params: state.params,
|
|
1830
1921
|
history: state.history,
|
|
1831
1922
|
navigate,
|
|
1923
|
+
replace,
|
|
1832
1924
|
back,
|
|
1833
1925
|
reset
|
|
1834
1926
|
}), [
|
|
1835
1927
|
back,
|
|
1836
1928
|
navigate,
|
|
1929
|
+
replace,
|
|
1837
1930
|
reset,
|
|
1838
1931
|
state.history,
|
|
1932
|
+
state.params,
|
|
1839
1933
|
state.screen
|
|
1840
1934
|
]);
|
|
1841
1935
|
return /* @__PURE__ */ jsx(EmergencyScreenContext.Provider, {
|
|
@@ -1884,6 +1978,245 @@ function EmergencyHeader({ titleId, onClose, title = copy.panelLabel, onBack })
|
|
|
1884
1978
|
});
|
|
1885
1979
|
}
|
|
1886
1980
|
|
|
1981
|
+
// src/react/screens/primary/data.ts
|
|
1982
|
+
/**
|
|
1983
|
+
* Derives the remaining alert rounds from available messages and designated
|
|
1984
|
+
* responders. Invalid or non-positive input collapses to the minimum of one
|
|
1985
|
+
* round instead of producing `Infinity`, `NaN` or a negative value.
|
|
1986
|
+
*/
|
|
1987
|
+
function calculateRounds(messages, responders) {
|
|
1988
|
+
if (!Number.isFinite(messages) || !Number.isFinite(responders)) return 1;
|
|
1989
|
+
const availableMessages = Math.floor(messages);
|
|
1990
|
+
const designatedResponders = Math.floor(responders);
|
|
1991
|
+
if (availableMessages <= 0 || designatedResponders <= 0) return 1;
|
|
1992
|
+
return Math.max(1, Math.floor(availableMessages / designatedResponders));
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
// src/react/screens/details/copy.ts
|
|
1996
|
+
const detailsCopy = {
|
|
1997
|
+
title: "Detalles",
|
|
1998
|
+
summaryTitle: "Alertas Disponibles",
|
|
1999
|
+
historyTitle: "Historial de alertas",
|
|
2000
|
+
historySubtitle: "Tus últimas alertas y recargas.",
|
|
2001
|
+
historyEmpty: "Todavía no tienes alertas en tu historial.",
|
|
2002
|
+
summaryEmpty: "Todavía no tienes un saldo de alertas disponible.",
|
|
2003
|
+
viewHistory: "Ver historial",
|
|
2004
|
+
messagesSingular: "mensaje de alerta",
|
|
2005
|
+
messagesPlural: "mensajes de alerta",
|
|
2006
|
+
contactsSingular: "contacto de emergencia",
|
|
2007
|
+
contactsPlural: "contactos de emergencia",
|
|
2008
|
+
roundsSingular: "ronda de avisos",
|
|
2009
|
+
roundsPlural: "rondas de avisos"
|
|
2010
|
+
};
|
|
2011
|
+
/** Returns the balance sentence split into text and emphasized number parts. */
|
|
2012
|
+
function alertBalanceParts(messages, responders) {
|
|
2013
|
+
if (!Number.isFinite(messages) || !Number.isFinite(responders) || messages < 0 || responders < 0) return [];
|
|
2014
|
+
const rounds = calculateRounds(messages, responders);
|
|
2015
|
+
const messagesUnit = messages === 1 ? detailsCopy.messagesSingular : detailsCopy.messagesPlural;
|
|
2016
|
+
const contactsUnit = responders === 1 ? detailsCopy.contactsSingular : detailsCopy.contactsPlural;
|
|
2017
|
+
const roundsUnit = rounds === 1 ? detailsCopy.roundsSingular : detailsCopy.roundsPlural;
|
|
2018
|
+
return [
|
|
2019
|
+
messages === 1 ? "Te queda " : "Te quedan ",
|
|
2020
|
+
messages,
|
|
2021
|
+
` ${messagesUnit}, dado que tienes `,
|
|
2022
|
+
responders,
|
|
2023
|
+
` ${contactsUnit}, `,
|
|
2024
|
+
rounds === 1 ? "te queda " : "te quedan ",
|
|
2025
|
+
rounds,
|
|
2026
|
+
` ${roundsUnit}.`
|
|
2027
|
+
];
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
// src/react/screens/details/AlertBalanceSentence.tsx
|
|
2031
|
+
/** Renders the balance sentence with its numbers visually emphasized. */
|
|
2032
|
+
function AlertBalanceSentence({ messages, responders }) {
|
|
2033
|
+
const parts = alertBalanceParts(messages, responders);
|
|
2034
|
+
return /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, index) => typeof part === "number" ? /* @__PURE__ */ jsx("strong", { children: part }, index) : part) });
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
// src/core/date.ts
|
|
2038
|
+
/**
|
|
2039
|
+
* Formats a timestamp as `h:mmam` or `h:mmpm` in local time, without a space
|
|
2040
|
+
* or leading zero.
|
|
2041
|
+
*/
|
|
2042
|
+
function formatShortTime(value, locale = "es") {
|
|
2043
|
+
if (value === null) return "";
|
|
2044
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
2045
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
2046
|
+
const parts = new Intl.DateTimeFormat(locale, {
|
|
2047
|
+
hour: "numeric",
|
|
2048
|
+
minute: "2-digit",
|
|
2049
|
+
hour12: true
|
|
2050
|
+
}).formatToParts(date);
|
|
2051
|
+
const hour = parts.find((part) => part.type === "hour")?.value;
|
|
2052
|
+
const minute = parts.find((part) => part.type === "minute")?.value;
|
|
2053
|
+
const dayPeriod = parts.find((part) => part.type === "dayPeriod")?.value;
|
|
2054
|
+
if (!hour || !minute) return "";
|
|
2055
|
+
return `${hour}:${minute}${normalizePeriod(dayPeriod)}`;
|
|
2056
|
+
}
|
|
2057
|
+
/**
|
|
2058
|
+
* Formats a timestamp as `dd/mm/yyyy hh:mm` in local time, using 24-hour time
|
|
2059
|
+
* and zero-padded parts. Missing or invalid input collapses to an empty string.
|
|
2060
|
+
*/
|
|
2061
|
+
function formatDateTime(value, locale = "es") {
|
|
2062
|
+
if (value === null) return "";
|
|
2063
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
2064
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
2065
|
+
const parts = new Intl.DateTimeFormat(locale, {
|
|
2066
|
+
day: "2-digit",
|
|
2067
|
+
month: "2-digit",
|
|
2068
|
+
year: "numeric",
|
|
2069
|
+
hour: "2-digit",
|
|
2070
|
+
minute: "2-digit",
|
|
2071
|
+
hourCycle: "h23"
|
|
2072
|
+
}).formatToParts(date);
|
|
2073
|
+
const day = parts.find((part) => part.type === "day")?.value;
|
|
2074
|
+
const month = parts.find((part) => part.type === "month")?.value;
|
|
2075
|
+
const year = parts.find((part) => part.type === "year")?.value;
|
|
2076
|
+
const hour = parts.find((part) => part.type === "hour")?.value;
|
|
2077
|
+
const minute = parts.find((part) => part.type === "minute")?.value;
|
|
2078
|
+
if (!day || !month || !year || !hour || !minute) return "";
|
|
2079
|
+
return `${day}/${month}/${year} ${hour}:${minute}`;
|
|
2080
|
+
}
|
|
2081
|
+
function normalizePeriod(dayPeriod) {
|
|
2082
|
+
if (!dayPeriod) return "";
|
|
2083
|
+
if (/^p/i.test(dayPeriod)) return "pm";
|
|
2084
|
+
return /^a/i.test(dayPeriod) ? "am" : "";
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
// src/react/screens/history/copy.ts
|
|
2088
|
+
const historyCopy = {
|
|
2089
|
+
title: "Historial de alertas",
|
|
2090
|
+
subtitle: "Consulta tus alertas, pruebas y recargas.",
|
|
2091
|
+
empty: "Todavía no tienes alertas en tu historial.",
|
|
2092
|
+
showMore: "Ver más",
|
|
2093
|
+
kindLabels: {
|
|
2094
|
+
emergency: "Emergencia",
|
|
2095
|
+
test: "Prueba",
|
|
2096
|
+
recharge: "Recarga"
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
function formatContacts(count) {
|
|
2100
|
+
return count === 1 ? "1 contacto" : `${count} contactos`;
|
|
2101
|
+
}
|
|
2102
|
+
function formatMessages(count) {
|
|
2103
|
+
return count === 1 ? "1 mensaje" : `${count} mensajes`;
|
|
2104
|
+
}
|
|
2105
|
+
function formatHistoryRounds(count) {
|
|
2106
|
+
return count === 1 ? "1 ronda" : `${count} rondas`;
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
// src/react/screens/history/data.ts
|
|
2110
|
+
/** Local demo alert history, newest first. */
|
|
2111
|
+
const DEMO_ALERT_HISTORY = [
|
|
2112
|
+
{
|
|
2113
|
+
id: "alert-2026-10-31",
|
|
2114
|
+
kind: "emergency",
|
|
2115
|
+
occurredAt: "2026-10-31T13:50:00",
|
|
2116
|
+
responders: 3,
|
|
2117
|
+
remainingMessages: 27
|
|
2118
|
+
},
|
|
2119
|
+
{
|
|
2120
|
+
id: "alert-2026-10-20",
|
|
2121
|
+
kind: "recharge",
|
|
2122
|
+
occurredAt: "2026-10-20T09:15:00",
|
|
2123
|
+
responders: 3,
|
|
2124
|
+
remainingMessages: 100
|
|
2125
|
+
},
|
|
2126
|
+
{
|
|
2127
|
+
id: "alert-2026-10-12",
|
|
2128
|
+
kind: "test",
|
|
2129
|
+
occurredAt: "2026-10-12T18:40:00",
|
|
2130
|
+
responders: 3,
|
|
2131
|
+
remainingMessages: 73
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
2134
|
+
id: "alert-2026-10-01",
|
|
2135
|
+
kind: "recharge",
|
|
2136
|
+
occurredAt: "2026-10-01T11:05:00",
|
|
2137
|
+
responders: 3,
|
|
2138
|
+
remainingMessages: 76
|
|
2139
|
+
}
|
|
2140
|
+
];
|
|
2141
|
+
/** Returns a newest-first copy of the history. */
|
|
2142
|
+
function sortedHistoryEntries(entries = DEMO_ALERT_HISTORY) {
|
|
2143
|
+
return [...entries].sort((first, second) => new Date(second.occurredAt).getTime() - new Date(first.occurredAt).getTime());
|
|
2144
|
+
}
|
|
2145
|
+
/** Newest entry, used as the source of the current balance. */
|
|
2146
|
+
function latestHistoryEntry(entries = DEMO_ALERT_HISTORY) {
|
|
2147
|
+
return sortedHistoryEntries(entries)[0] ?? null;
|
|
2148
|
+
}
|
|
2149
|
+
/** Resolves a single history entry by id. */
|
|
2150
|
+
function historyEntryById(id, entries = DEMO_ALERT_HISTORY) {
|
|
2151
|
+
if (!id) return null;
|
|
2152
|
+
return entries.find((entry) => entry.id === id) ?? null;
|
|
2153
|
+
}
|
|
2154
|
+
/** Rounds represented by the entry's remaining messages and responders. */
|
|
2155
|
+
function historyEntryRounds(entry) {
|
|
2156
|
+
return calculateRounds(entry.remainingMessages, entry.responders);
|
|
2157
|
+
}
|
|
2158
|
+
/** Current balance derived from the newest history entry. */
|
|
2159
|
+
function currentAlertBalance(entries = DEMO_ALERT_HISTORY) {
|
|
2160
|
+
const latest = latestHistoryEntry(entries);
|
|
2161
|
+
if (!latest) return null;
|
|
2162
|
+
return {
|
|
2163
|
+
messages: latest.remainingMessages,
|
|
2164
|
+
responders: latest.responders,
|
|
2165
|
+
rounds: historyEntryRounds(latest)
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
// src/react/screens/history/AlertHistoryRow.tsx
|
|
2170
|
+
/** Reusable history row. The whole row is a button with a full text label. */
|
|
2171
|
+
function AlertHistoryRow({ entry, locale, onOpen }) {
|
|
2172
|
+
const occurredAt = formatDateTime(entry.occurredAt, locale);
|
|
2173
|
+
const rounds = historyEntryRounds(entry);
|
|
2174
|
+
const label = [
|
|
2175
|
+
historyCopy.kindLabels[entry.kind],
|
|
2176
|
+
occurredAt,
|
|
2177
|
+
formatContacts(entry.responders),
|
|
2178
|
+
`${formatMessages(entry.remainingMessages)} restantes`,
|
|
2179
|
+
`${formatHistoryRounds(rounds)} de avisos`
|
|
2180
|
+
].join(", ");
|
|
2181
|
+
return /* @__PURE__ */ jsx("li", {
|
|
2182
|
+
className: cls("emergency-alert-row"),
|
|
2183
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
2184
|
+
type: "button",
|
|
2185
|
+
className: cls("emergency-alert-row__button"),
|
|
2186
|
+
"aria-label": label,
|
|
2187
|
+
onClick: () => onOpen(entry.id),
|
|
2188
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
2189
|
+
className: cls("emergency-alert-row__top"),
|
|
2190
|
+
children: [/* @__PURE__ */ jsx("time", {
|
|
2191
|
+
className: cls("emergency-alert-row__time"),
|
|
2192
|
+
dateTime: entry.occurredAt,
|
|
2193
|
+
children: occurredAt
|
|
2194
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2195
|
+
className: cls("emergency-alert-row__badge"),
|
|
2196
|
+
"data-kind": entry.kind,
|
|
2197
|
+
children: historyCopy.kindLabels[entry.kind]
|
|
2198
|
+
})]
|
|
2199
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
2200
|
+
className: cls("emergency-alert-row__stats"),
|
|
2201
|
+
children: [
|
|
2202
|
+
/* @__PURE__ */ jsx("span", {
|
|
2203
|
+
className: cls("emergency-alert-row__stat"),
|
|
2204
|
+
children: formatContacts(entry.responders)
|
|
2205
|
+
}),
|
|
2206
|
+
/* @__PURE__ */ jsx("span", {
|
|
2207
|
+
className: cls("emergency-alert-row__stat"),
|
|
2208
|
+
children: formatMessages(entry.remainingMessages)
|
|
2209
|
+
}),
|
|
2210
|
+
/* @__PURE__ */ jsx("span", {
|
|
2211
|
+
className: cls("emergency-alert-row__stat"),
|
|
2212
|
+
children: formatHistoryRounds(rounds)
|
|
2213
|
+
})
|
|
2214
|
+
]
|
|
2215
|
+
})]
|
|
2216
|
+
})
|
|
2217
|
+
});
|
|
2218
|
+
}
|
|
2219
|
+
|
|
1887
2220
|
// src/react/screens/layout.tsx
|
|
1888
2221
|
/**
|
|
1889
2222
|
* Shared shell for every screen. The wrapper is `display: contents` so the
|
|
@@ -1905,45 +2238,429 @@ function EmergencyScreenLayout({ screen, titleId, header, footer, children, body
|
|
|
1905
2238
|
});
|
|
1906
2239
|
}
|
|
1907
2240
|
|
|
1908
|
-
// src/react/screens/
|
|
1909
|
-
|
|
1910
|
-
|
|
2241
|
+
// src/react/screens/details/index.tsx
|
|
2242
|
+
function DetailsScreen({ titleId, locale, onClose }) {
|
|
2243
|
+
const { back, navigate } = useScreenNavigation();
|
|
2244
|
+
const balance = currentAlertBalance();
|
|
2245
|
+
const preview = sortedHistoryEntries().slice(0, 2);
|
|
1911
2246
|
return /* @__PURE__ */ jsx(EmergencyScreenLayout, {
|
|
1912
|
-
screen,
|
|
2247
|
+
screen: "details",
|
|
1913
2248
|
titleId,
|
|
2249
|
+
bodyClassName: "emergency-panel__body--details",
|
|
1914
2250
|
header: /* @__PURE__ */ jsx(EmergencyHeader, {
|
|
1915
2251
|
titleId,
|
|
1916
|
-
title,
|
|
1917
|
-
onClose,
|
|
1918
|
-
onBack
|
|
2252
|
+
title: detailsCopy.title,
|
|
2253
|
+
onClose: () => onClose("close"),
|
|
2254
|
+
onBack: back
|
|
1919
2255
|
}),
|
|
1920
2256
|
footer: null,
|
|
2257
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2258
|
+
className: cls("emergency-details"),
|
|
2259
|
+
children: [/* @__PURE__ */ jsx("section", {
|
|
2260
|
+
className: cls("emergency-details__section"),
|
|
2261
|
+
"aria-label": detailsCopy.summaryTitle,
|
|
2262
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2263
|
+
className: cls("emergency-details__card"),
|
|
2264
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2265
|
+
className: cls("emergency-details__card-header"),
|
|
2266
|
+
children: /* @__PURE__ */ jsx("h3", {
|
|
2267
|
+
className: cls("emergency-details__card-title"),
|
|
2268
|
+
children: detailsCopy.summaryTitle
|
|
2269
|
+
})
|
|
2270
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2271
|
+
className: cls("emergency-details__card-body"),
|
|
2272
|
+
children: balance ? /* @__PURE__ */ jsx("p", {
|
|
2273
|
+
className: cls("emergency-details__balance"),
|
|
2274
|
+
children: /* @__PURE__ */ jsx(AlertBalanceSentence, {
|
|
2275
|
+
messages: balance.messages,
|
|
2276
|
+
responders: balance.responders
|
|
2277
|
+
})
|
|
2278
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
2279
|
+
className: cls("emergency-details__empty"),
|
|
2280
|
+
children: detailsCopy.summaryEmpty
|
|
2281
|
+
})
|
|
2282
|
+
})]
|
|
2283
|
+
})
|
|
2284
|
+
}), /* @__PURE__ */ jsxs("section", {
|
|
2285
|
+
className: cls("emergency-details__section"),
|
|
2286
|
+
"aria-label": detailsCopy.historyTitle,
|
|
2287
|
+
children: [
|
|
2288
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2289
|
+
className: cls("emergency-details__heading"),
|
|
2290
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
2291
|
+
className: cls("emergency-details__title"),
|
|
2292
|
+
children: detailsCopy.historyTitle
|
|
2293
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
2294
|
+
className: cls("emergency-details__subtitle"),
|
|
2295
|
+
children: detailsCopy.historySubtitle
|
|
2296
|
+
})]
|
|
2297
|
+
}),
|
|
2298
|
+
preview.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
2299
|
+
className: cls("emergency-details__list"),
|
|
2300
|
+
children: preview.map((entry) => /* @__PURE__ */ jsx(AlertHistoryRow, {
|
|
2301
|
+
entry,
|
|
2302
|
+
locale,
|
|
2303
|
+
onOpen: (messageId) => navigate("message-detail", { messageId })
|
|
2304
|
+
}, entry.id))
|
|
2305
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
2306
|
+
className: cls("emergency-details__empty"),
|
|
2307
|
+
children: detailsCopy.historyEmpty
|
|
2308
|
+
}),
|
|
2309
|
+
/* @__PURE__ */ jsx("button", {
|
|
2310
|
+
type: "button",
|
|
2311
|
+
className: cls("emergency-details__history-button"),
|
|
2312
|
+
onClick: () => navigate("history"),
|
|
2313
|
+
children: detailsCopy.viewHistory
|
|
2314
|
+
})
|
|
2315
|
+
]
|
|
2316
|
+
})]
|
|
2317
|
+
})
|
|
2318
|
+
});
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
// src/react/screens/history/index.tsx
|
|
2322
|
+
function HistoryScreen({ titleId, locale, onClose }) {
|
|
2323
|
+
const { back, navigate } = useScreenNavigation();
|
|
2324
|
+
const listId = useId();
|
|
2325
|
+
const [expanded, setExpanded] = useState(false);
|
|
2326
|
+
const entries = sortedHistoryEntries();
|
|
2327
|
+
const hiddenCount = Math.max(0, entries.length - 2);
|
|
2328
|
+
const visibleEntries = expanded ? entries : entries.slice(0, 2);
|
|
2329
|
+
const showMore = hiddenCount > 0 && !expanded;
|
|
2330
|
+
return /* @__PURE__ */ jsx(EmergencyScreenLayout, {
|
|
2331
|
+
screen: "history",
|
|
2332
|
+
titleId,
|
|
2333
|
+
bodyClassName: "emergency-panel__body--history",
|
|
2334
|
+
header: /* @__PURE__ */ jsx(EmergencyHeader, {
|
|
2335
|
+
titleId,
|
|
2336
|
+
title: historyCopy.title,
|
|
2337
|
+
onClose: () => onClose("close"),
|
|
2338
|
+
onBack: back
|
|
2339
|
+
}),
|
|
2340
|
+
footer: null,
|
|
2341
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2342
|
+
className: cls("emergency-history"),
|
|
2343
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2344
|
+
className: cls("emergency-history__heading"),
|
|
2345
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
2346
|
+
className: cls("emergency-history__title"),
|
|
2347
|
+
children: historyCopy.title
|
|
2348
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
2349
|
+
className: cls("emergency-history__subtitle"),
|
|
2350
|
+
children: historyCopy.subtitle
|
|
2351
|
+
})]
|
|
2352
|
+
}), entries.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("ul", {
|
|
2353
|
+
className: cls("emergency-history__list"),
|
|
2354
|
+
id: listId,
|
|
2355
|
+
children: visibleEntries.map((entry) => /* @__PURE__ */ jsx(AlertHistoryRow, {
|
|
2356
|
+
entry,
|
|
2357
|
+
locale,
|
|
2358
|
+
onOpen: (messageId) => navigate("message-detail", { messageId })
|
|
2359
|
+
}, entry.id))
|
|
2360
|
+
}), showMore ? /* @__PURE__ */ jsx("button", {
|
|
2361
|
+
type: "button",
|
|
2362
|
+
className: cls("emergency-history__more"),
|
|
2363
|
+
"aria-expanded": expanded,
|
|
2364
|
+
"aria-controls": listId,
|
|
2365
|
+
onClick: () => setExpanded(true),
|
|
2366
|
+
children: historyCopy.showMore
|
|
2367
|
+
}) : null] }) : /* @__PURE__ */ jsx("p", {
|
|
2368
|
+
className: cls("emergency-history__empty"),
|
|
2369
|
+
children: historyCopy.empty
|
|
2370
|
+
})]
|
|
2371
|
+
})
|
|
2372
|
+
});
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
// src/react/screens/message-detail/index.tsx
|
|
2376
|
+
const messageDetailCopy = {
|
|
2377
|
+
title: "Detalle del mensaje",
|
|
2378
|
+
dateTime: "Fecha y hora",
|
|
2379
|
+
kind: "Tipo",
|
|
2380
|
+
responders: "Contactos de emergencia",
|
|
2381
|
+
messages: "Mensajes restantes",
|
|
2382
|
+
rounds: "Rondas de avisos",
|
|
2383
|
+
notFound: "No encontramos este mensaje. Puede que ya no esté disponible en tu historial.",
|
|
2384
|
+
backToHistory: "Volver al historial"
|
|
2385
|
+
};
|
|
2386
|
+
function MessageDetailScreen({ titleId, locale, onClose }) {
|
|
2387
|
+
const { back, params, replace } = useScreenNavigation();
|
|
2388
|
+
const entry = historyEntryById(params.messageId);
|
|
2389
|
+
const header = /* @__PURE__ */ jsx(EmergencyHeader, {
|
|
2390
|
+
titleId,
|
|
2391
|
+
title: messageDetailCopy.title,
|
|
2392
|
+
onClose: () => onClose("close"),
|
|
2393
|
+
onBack: back
|
|
2394
|
+
});
|
|
2395
|
+
if (!entry) return /* @__PURE__ */ jsx(EmergencyScreenLayout, {
|
|
2396
|
+
screen: "message-detail",
|
|
2397
|
+
titleId,
|
|
2398
|
+
bodyClassName: "emergency-panel__body--message-detail",
|
|
2399
|
+
header,
|
|
2400
|
+
footer: null,
|
|
2401
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2402
|
+
className: cls("emergency-message-detail__empty"),
|
|
2403
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
2404
|
+
className: cls("emergency-message-detail__empty-text"),
|
|
2405
|
+
children: messageDetailCopy.notFound
|
|
2406
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
2407
|
+
type: "button",
|
|
2408
|
+
className: cls("emergency-message-detail__back"),
|
|
2409
|
+
onClick: () => replace("history"),
|
|
2410
|
+
children: messageDetailCopy.backToHistory
|
|
2411
|
+
})]
|
|
2412
|
+
})
|
|
2413
|
+
});
|
|
2414
|
+
const rounds = historyEntryRounds(entry);
|
|
2415
|
+
return /* @__PURE__ */ jsx(EmergencyScreenLayout, {
|
|
2416
|
+
screen: "message-detail",
|
|
2417
|
+
titleId,
|
|
2418
|
+
bodyClassName: "emergency-panel__body--message-detail",
|
|
2419
|
+
header,
|
|
2420
|
+
footer: null,
|
|
1921
2421
|
children: /* @__PURE__ */ jsx("div", {
|
|
1922
|
-
className: cls("emergency-
|
|
1923
|
-
children: /* @__PURE__ */
|
|
1924
|
-
className: cls("emergency-
|
|
1925
|
-
children:
|
|
2422
|
+
className: cls("emergency-message-detail"),
|
|
2423
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2424
|
+
className: cls("emergency-message-detail__card"),
|
|
2425
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2426
|
+
className: cls("emergency-message-detail__card-header"),
|
|
2427
|
+
children: /* @__PURE__ */ jsx("h3", {
|
|
2428
|
+
className: cls("emergency-message-detail__card-title"),
|
|
2429
|
+
children: messageDetailCopy.title
|
|
2430
|
+
})
|
|
2431
|
+
}), /* @__PURE__ */ jsxs("dl", {
|
|
2432
|
+
className: cls("emergency-message-detail__list"),
|
|
2433
|
+
children: [
|
|
2434
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2435
|
+
className: cls("emergency-message-detail__row"),
|
|
2436
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
2437
|
+
className: cls("emergency-message-detail__label"),
|
|
2438
|
+
children: messageDetailCopy.dateTime
|
|
2439
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2440
|
+
className: cls("emergency-message-detail__value"),
|
|
2441
|
+
children: formatDateTime(entry.occurredAt, locale)
|
|
2442
|
+
})]
|
|
2443
|
+
}),
|
|
2444
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2445
|
+
className: cls("emergency-message-detail__row"),
|
|
2446
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
2447
|
+
className: cls("emergency-message-detail__label"),
|
|
2448
|
+
children: messageDetailCopy.kind
|
|
2449
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2450
|
+
className: cls("emergency-message-detail__value"),
|
|
2451
|
+
children: historyCopy.kindLabels[entry.kind]
|
|
2452
|
+
})]
|
|
2453
|
+
}),
|
|
2454
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2455
|
+
className: cls("emergency-message-detail__row"),
|
|
2456
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
2457
|
+
className: cls("emergency-message-detail__label"),
|
|
2458
|
+
children: messageDetailCopy.responders
|
|
2459
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2460
|
+
className: cls("emergency-message-detail__value"),
|
|
2461
|
+
children: formatContacts(entry.responders)
|
|
2462
|
+
})]
|
|
2463
|
+
}),
|
|
2464
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2465
|
+
className: cls("emergency-message-detail__row"),
|
|
2466
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
2467
|
+
className: cls("emergency-message-detail__label"),
|
|
2468
|
+
children: messageDetailCopy.messages
|
|
2469
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2470
|
+
className: cls("emergency-message-detail__value"),
|
|
2471
|
+
children: formatMessages(entry.remainingMessages)
|
|
2472
|
+
})]
|
|
2473
|
+
}),
|
|
2474
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2475
|
+
className: cls("emergency-message-detail__row"),
|
|
2476
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
2477
|
+
className: cls("emergency-message-detail__label"),
|
|
2478
|
+
children: messageDetailCopy.rounds
|
|
2479
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2480
|
+
className: cls("emergency-message-detail__value"),
|
|
2481
|
+
children: formatHistoryRounds(rounds)
|
|
2482
|
+
})]
|
|
2483
|
+
})
|
|
2484
|
+
]
|
|
2485
|
+
})]
|
|
1926
2486
|
})
|
|
1927
2487
|
})
|
|
1928
2488
|
});
|
|
1929
2489
|
}
|
|
1930
2490
|
|
|
1931
|
-
// src/
|
|
1932
|
-
const
|
|
1933
|
-
|
|
1934
|
-
|
|
2491
|
+
// src/core/phone.ts
|
|
2492
|
+
const VENEZUELA_DIALLING_CODE = "+58";
|
|
2493
|
+
const VENEZUELAN_MOBILE_PATTERN = /^4\d{9}$/;
|
|
2494
|
+
function normalizeVenezuelanPhone(input) {
|
|
2495
|
+
return input.replace(/\D/g, "").replace(/^0+/, "");
|
|
2496
|
+
}
|
|
2497
|
+
function formatVenezuelanPhone(input) {
|
|
2498
|
+
const digits = normalizeVenezuelanPhone(input).slice(0, 10);
|
|
2499
|
+
if (digits.length <= 3) return digits;
|
|
2500
|
+
return `${digits.slice(0, 3)} ${digits.slice(3)}`;
|
|
2501
|
+
}
|
|
2502
|
+
function isValidVenezuelanPhone(input) {
|
|
2503
|
+
return VENEZUELAN_MOBILE_PATTERN.test(normalizeVenezuelanPhone(input));
|
|
2504
|
+
}
|
|
2505
|
+
function toVenezuelanE164(input) {
|
|
2506
|
+
const digits = normalizeVenezuelanPhone(input);
|
|
2507
|
+
if (!VENEZUELAN_MOBILE_PATTERN.test(digits)) return null;
|
|
2508
|
+
return `${"+58"}${digits}`;
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
// src/react/components/EmergencyFooter/index.tsx
|
|
2512
|
+
function EmergencyFooter(props) {
|
|
2513
|
+
const { active, busy, aborting, feedbackVisible, showSimulation = true, emergencyDisabled = false, square = false, onActivate, onRequestAbort, onRequestSimulation } = props;
|
|
2514
|
+
if (active) return /* @__PURE__ */ jsx("footer", {
|
|
2515
|
+
className: cls("emergency-panel__footer", square && "emergency-panel__footer--square"),
|
|
2516
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
2517
|
+
type: "button",
|
|
2518
|
+
className: cls("emergency-status__abort-btn"),
|
|
2519
|
+
"aria-label": copy.abort,
|
|
2520
|
+
disabled: aborting || feedbackVisible,
|
|
2521
|
+
onClick: onRequestAbort,
|
|
2522
|
+
children: [copy.abort, /* @__PURE__ */ jsx(Icon, { name: "alert-triangle" })]
|
|
2523
|
+
})
|
|
2524
|
+
});
|
|
2525
|
+
return /* @__PURE__ */ jsxs("footer", {
|
|
2526
|
+
className: cls("emergency-panel__footer", !showSimulation && "emergency-panel__footer--single", square && "emergency-panel__footer--square"),
|
|
2527
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
2528
|
+
type: "button",
|
|
2529
|
+
className: cls("emergency-panel__button", "emergency-panel__button--emergency"),
|
|
2530
|
+
"aria-label": copy.emergencyAria,
|
|
2531
|
+
disabled: busy || feedbackVisible || emergencyDisabled,
|
|
2532
|
+
onClick: onActivate,
|
|
2533
|
+
children: [copy.emergency, /* @__PURE__ */ jsx(Icon, { name: "emergency" })]
|
|
2534
|
+
}), showSimulation ? /* @__PURE__ */ jsxs("button", {
|
|
2535
|
+
type: "button",
|
|
2536
|
+
className: cls("emergency-panel__button", "emergency-panel__button--simulation"),
|
|
2537
|
+
"aria-label": copy.testAria,
|
|
2538
|
+
disabled: busy || feedbackVisible,
|
|
2539
|
+
onClick: onRequestSimulation,
|
|
2540
|
+
children: [copy.test, /* @__PURE__ */ jsx(Icon, { name: "list-check" })]
|
|
2541
|
+
}) : null]
|
|
2542
|
+
});
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
// src/react/screens/pre-emergency/copy.ts
|
|
2546
|
+
const preEmergencyCopy = {
|
|
2547
|
+
title: "Pre-emergencia",
|
|
2548
|
+
permissionNotice: "Debes autorizar todos los permisos de ubicación",
|
|
2549
|
+
phoneLabel: "Indique su número de teléfono",
|
|
2550
|
+
phonePlaceholder: "Ej. 0412 000 0000",
|
|
2551
|
+
areaCodeLabel: "Código de país",
|
|
2552
|
+
areaCode: "+58",
|
|
2553
|
+
invalidPhone: "Ingresa un número móvil venezolano válido. Ej. 412 1301234"
|
|
1935
2554
|
};
|
|
1936
2555
|
|
|
1937
|
-
// src/react/screens/
|
|
1938
|
-
function
|
|
2556
|
+
// src/react/screens/pre-emergency/index.tsx
|
|
2557
|
+
function PreEmergencyScreen(props) {
|
|
1939
2558
|
const { back } = useScreenNavigation();
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2559
|
+
const phoneId = useId();
|
|
2560
|
+
const errorId = `${phoneId}-error`;
|
|
2561
|
+
const permissionId = `${phoneId}-permission`;
|
|
2562
|
+
const [digits, setDigits] = useState("");
|
|
2563
|
+
const [touched, setTouched] = useState(false);
|
|
2564
|
+
const valid = isValidVenezuelanPhone(digits);
|
|
2565
|
+
const invalid = touched && digits.length > 0 && !valid;
|
|
2566
|
+
const handleChange = (event) => {
|
|
2567
|
+
const next = normalizeVenezuelanPhone(event.target.value).slice(0, 10);
|
|
2568
|
+
setDigits(next);
|
|
2569
|
+
};
|
|
2570
|
+
const handleSubmit = () => {
|
|
2571
|
+
setTouched(true);
|
|
2572
|
+
if (!valid) return;
|
|
2573
|
+
const phone = toVenezuelanE164(digits);
|
|
2574
|
+
if (phone === null) return;
|
|
2575
|
+
props.onSetContactPhone(phone);
|
|
2576
|
+
props.onActivate();
|
|
2577
|
+
};
|
|
2578
|
+
return /* @__PURE__ */ jsx(EmergencyScreenLayout, {
|
|
2579
|
+
screen: "pre-emergency",
|
|
2580
|
+
titleId: props.titleId,
|
|
2581
|
+
bodyClassName: "emergency-panel__body--pre-emergency",
|
|
2582
|
+
header: /* @__PURE__ */ jsx(EmergencyHeader, {
|
|
2583
|
+
titleId: props.titleId,
|
|
2584
|
+
title: preEmergencyCopy.title,
|
|
2585
|
+
onClose: () => props.onClose("close"),
|
|
2586
|
+
onBack: back
|
|
2587
|
+
}),
|
|
2588
|
+
footer: /* @__PURE__ */ jsx(EmergencyFooter, {
|
|
2589
|
+
active: props.active,
|
|
2590
|
+
busy: props.busy,
|
|
2591
|
+
aborting: props.aborting,
|
|
2592
|
+
feedbackVisible: props.feedbackVisible,
|
|
2593
|
+
emergencyDisabled: !valid,
|
|
2594
|
+
showSimulation: false,
|
|
2595
|
+
onActivate: handleSubmit,
|
|
2596
|
+
onRequestAbort: props.onRequestAbort,
|
|
2597
|
+
onRequestSimulation: props.onRequestSimulation
|
|
2598
|
+
}),
|
|
2599
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2600
|
+
className: cls("emergency-pre-emergency"),
|
|
2601
|
+
children: [/* @__PURE__ */ jsxs("section", {
|
|
2602
|
+
role: "note",
|
|
2603
|
+
"aria-labelledby": permissionId,
|
|
2604
|
+
className: cls("emergency-pre-emergency__notice"),
|
|
2605
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
2606
|
+
name: "map-pin",
|
|
2607
|
+
className: cls("emergency-pre-emergency__notice-icon")
|
|
2608
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
2609
|
+
id: permissionId,
|
|
2610
|
+
className: cls("emergency-pre-emergency__notice-text"),
|
|
2611
|
+
children: preEmergencyCopy.permissionNotice
|
|
2612
|
+
})]
|
|
2613
|
+
}), /* @__PURE__ */ jsxs("form", {
|
|
2614
|
+
className: cls("emergency-pre-emergency__form"),
|
|
2615
|
+
noValidate: true,
|
|
2616
|
+
onSubmit: (event) => {
|
|
2617
|
+
event.preventDefault();
|
|
2618
|
+
handleSubmit();
|
|
2619
|
+
},
|
|
2620
|
+
onKeyDown: (event) => {
|
|
2621
|
+
if (event.key === "Enter") {
|
|
2622
|
+
event.preventDefault();
|
|
2623
|
+
handleSubmit();
|
|
2624
|
+
}
|
|
2625
|
+
},
|
|
2626
|
+
children: [
|
|
2627
|
+
/* @__PURE__ */ jsx("label", {
|
|
2628
|
+
htmlFor: phoneId,
|
|
2629
|
+
className: cls("emergency-pre-emergency__label"),
|
|
2630
|
+
children: preEmergencyCopy.phoneLabel
|
|
2631
|
+
}),
|
|
2632
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2633
|
+
className: cls("emergency-pre-emergency__phone-row"),
|
|
2634
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
2635
|
+
type: "tel",
|
|
2636
|
+
"aria-label": preEmergencyCopy.areaCodeLabel,
|
|
2637
|
+
className: cls("emergency-pre-emergency__input", "emergency-pre-emergency__input--area-code", valid && "emergency-pre-emergency__input--valid"),
|
|
2638
|
+
value: preEmergencyCopy.areaCode,
|
|
2639
|
+
disabled: true,
|
|
2640
|
+
readOnly: true
|
|
2641
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
2642
|
+
id: phoneId,
|
|
2643
|
+
type: "tel",
|
|
2644
|
+
inputMode: "tel",
|
|
2645
|
+
autoComplete: "tel-national",
|
|
2646
|
+
placeholder: preEmergencyCopy.phonePlaceholder,
|
|
2647
|
+
className: cls("emergency-pre-emergency__input", "emergency-pre-emergency__input--number", valid && "emergency-pre-emergency__input--valid", invalid && "emergency-pre-emergency__input--invalid"),
|
|
2648
|
+
value: formatVenezuelanPhone(digits),
|
|
2649
|
+
"aria-invalid": invalid,
|
|
2650
|
+
"aria-describedby": invalid ? errorId : void 0,
|
|
2651
|
+
onChange: handleChange,
|
|
2652
|
+
onBlur: () => setTouched(true)
|
|
2653
|
+
})]
|
|
2654
|
+
}),
|
|
2655
|
+
invalid ? /* @__PURE__ */ jsx("p", {
|
|
2656
|
+
id: errorId,
|
|
2657
|
+
role: "alert",
|
|
2658
|
+
className: cls("emergency-pre-emergency__error"),
|
|
2659
|
+
children: preEmergencyCopy.invalidPhone
|
|
2660
|
+
}) : null
|
|
2661
|
+
]
|
|
2662
|
+
})]
|
|
2663
|
+
})
|
|
1947
2664
|
});
|
|
1948
2665
|
}
|
|
1949
2666
|
|
|
@@ -2169,32 +2886,6 @@ function EmergencyLoading() {
|
|
|
2169
2886
|
});
|
|
2170
2887
|
}
|
|
2171
2888
|
|
|
2172
|
-
// src/core/date.ts
|
|
2173
|
-
/**
|
|
2174
|
-
* Formats a timestamp as `h:mmam` or `h:mmpm` in local time, without a space
|
|
2175
|
-
* or leading zero.
|
|
2176
|
-
*/
|
|
2177
|
-
function formatShortTime(value, locale = "es") {
|
|
2178
|
-
if (value === null) return "";
|
|
2179
|
-
const date = value instanceof Date ? value : new Date(value);
|
|
2180
|
-
if (Number.isNaN(date.getTime())) return "";
|
|
2181
|
-
const parts = new Intl.DateTimeFormat(locale, {
|
|
2182
|
-
hour: "numeric",
|
|
2183
|
-
minute: "2-digit",
|
|
2184
|
-
hour12: true
|
|
2185
|
-
}).formatToParts(date);
|
|
2186
|
-
const hour = parts.find((part) => part.type === "hour")?.value;
|
|
2187
|
-
const minute = parts.find((part) => part.type === "minute")?.value;
|
|
2188
|
-
const dayPeriod = parts.find((part) => part.type === "dayPeriod")?.value;
|
|
2189
|
-
if (!hour || !minute) return "";
|
|
2190
|
-
return `${hour}:${minute}${normalizePeriod(dayPeriod)}`;
|
|
2191
|
-
}
|
|
2192
|
-
function normalizePeriod(dayPeriod) {
|
|
2193
|
-
if (!dayPeriod) return "";
|
|
2194
|
-
if (/^p/i.test(dayPeriod)) return "pm";
|
|
2195
|
-
return /^a/i.test(dayPeriod) ? "am" : "";
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
2889
|
// src/react/components/StatusIcon/index.tsx
|
|
2199
2890
|
/**
|
|
2200
2891
|
* Explicit responder state model:
|
|
@@ -2355,23 +3046,9 @@ function formatRounds(rounds) {
|
|
|
2355
3046
|
return `${rounds} ${roundsUnit(rounds)}`;
|
|
2356
3047
|
}
|
|
2357
3048
|
|
|
2358
|
-
// src/react/screens/primary/data.ts
|
|
2359
|
-
/**
|
|
2360
|
-
* Derives the remaining alert rounds from available messages and designated
|
|
2361
|
-
* responders. Invalid or non-positive input collapses to the minimum of one
|
|
2362
|
-
* round instead of producing `Infinity`, `NaN` or a negative value.
|
|
2363
|
-
*/
|
|
2364
|
-
function calculateRounds(messages, responders) {
|
|
2365
|
-
if (!Number.isFinite(messages) || !Number.isFinite(responders)) return 1;
|
|
2366
|
-
const availableMessages = Math.floor(messages);
|
|
2367
|
-
const designatedResponders = Math.floor(responders);
|
|
2368
|
-
if (availableMessages <= 0 || designatedResponders <= 0) return 1;
|
|
2369
|
-
return Math.max(1, Math.floor(availableMessages / designatedResponders));
|
|
2370
|
-
}
|
|
2371
|
-
|
|
2372
3049
|
// src/react/screens/primary/Availability.tsx
|
|
2373
3050
|
function Availability({ onRecharge, onDetails }) {
|
|
2374
|
-
const rounds = calculateRounds(
|
|
3051
|
+
const rounds = calculateRounds(27, 3);
|
|
2375
3052
|
return /* @__PURE__ */ jsxs("section", {
|
|
2376
3053
|
className: cls("emergency-availability"),
|
|
2377
3054
|
"aria-label": primaryCopy.availabilityTitle,
|
|
@@ -2413,7 +3090,7 @@ function Availability({ onRecharge, onDetails }) {
|
|
|
2413
3090
|
|
|
2414
3091
|
// src/react/components/EmergencyBody/index.tsx
|
|
2415
3092
|
function EmergencyBody(props) {
|
|
2416
|
-
const { active, responders, refreshing, loading, locale, geolocationError, activationError, error, abortResult, simulationResult, onRefresh, onRetry, onDismissFeedback, onRecharge, onDetails } = props;
|
|
3093
|
+
const { active, responders, refreshing, loading, locale, geolocationError, activationError, error, abortResult, simulationResult, onRefresh, onRetry, onDismissFeedback, onRecharge, onDetails, onClose } = props;
|
|
2417
3094
|
const showingFeedback = geolocationError !== null || Boolean(activationError) || abortResult !== null || simulationResult !== null;
|
|
2418
3095
|
const idle = !active && !loading && !showingFeedback && error === null;
|
|
2419
3096
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -2425,8 +3102,18 @@ function EmergencyBody(props) {
|
|
|
2425
3102
|
onDetails
|
|
2426
3103
|
})
|
|
2427
3104
|
}) : null, /* @__PURE__ */ jsxs("div", {
|
|
2428
|
-
className: cls("emergency-panel__prompt-region"),
|
|
3105
|
+
className: cls("emergency-panel__prompt-region", idle && "emergency-panel__prompt-region--idle"),
|
|
2429
3106
|
children: [
|
|
3107
|
+
idle ? /* @__PURE__ */ jsx("button", {
|
|
3108
|
+
type: "button",
|
|
3109
|
+
className: cls("emergency-panel__close-button", "emergency-panel__close-button--prompt"),
|
|
3110
|
+
"aria-label": copy.close,
|
|
3111
|
+
onClick: onClose,
|
|
3112
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
3113
|
+
name: "close",
|
|
3114
|
+
className: cls("emergency-panel__close-icon")
|
|
3115
|
+
})
|
|
3116
|
+
}) : null,
|
|
2430
3117
|
!loading && !showingFeedback ? /* @__PURE__ */ jsx("div", {
|
|
2431
3118
|
className: cls("sos-img__container"),
|
|
2432
3119
|
id: "sos-img__container",
|
|
@@ -2465,47 +3152,16 @@ function EmergencyBody(props) {
|
|
|
2465
3152
|
});
|
|
2466
3153
|
}
|
|
2467
3154
|
|
|
2468
|
-
// src/react/components/EmergencyFooter/index.tsx
|
|
2469
|
-
function EmergencyFooter(props) {
|
|
2470
|
-
const { active, busy, aborting, feedbackVisible, onActivate, onRequestAbort, onRequestSimulation } = props;
|
|
2471
|
-
if (active) return /* @__PURE__ */ jsx("footer", {
|
|
2472
|
-
className: cls("emergency-panel__footer"),
|
|
2473
|
-
children: /* @__PURE__ */ jsxs("button", {
|
|
2474
|
-
type: "button",
|
|
2475
|
-
className: cls("emergency-status__abort-btn"),
|
|
2476
|
-
"aria-label": copy.abort,
|
|
2477
|
-
disabled: aborting || feedbackVisible,
|
|
2478
|
-
onClick: onRequestAbort,
|
|
2479
|
-
children: [copy.abort, /* @__PURE__ */ jsx(Icon, { name: "alert-triangle" })]
|
|
2480
|
-
})
|
|
2481
|
-
});
|
|
2482
|
-
return /* @__PURE__ */ jsxs("footer", {
|
|
2483
|
-
className: cls("emergency-panel__footer"),
|
|
2484
|
-
children: [/* @__PURE__ */ jsxs("button", {
|
|
2485
|
-
type: "button",
|
|
2486
|
-
className: cls("emergency-panel__button", "emergency-panel__button--emergency"),
|
|
2487
|
-
"aria-label": copy.emergencyAria,
|
|
2488
|
-
disabled: busy || feedbackVisible,
|
|
2489
|
-
onClick: onActivate,
|
|
2490
|
-
children: [copy.emergency, /* @__PURE__ */ jsx(Icon, { name: "emergency" })]
|
|
2491
|
-
}), /* @__PURE__ */ jsxs("button", {
|
|
2492
|
-
type: "button",
|
|
2493
|
-
className: cls("emergency-panel__button", "emergency-panel__button--simulation"),
|
|
2494
|
-
"aria-label": copy.testAria,
|
|
2495
|
-
disabled: busy || feedbackVisible,
|
|
2496
|
-
onClick: onRequestSimulation,
|
|
2497
|
-
children: [copy.test, /* @__PURE__ */ jsx(Icon, { name: "list-check" })]
|
|
2498
|
-
})]
|
|
2499
|
-
});
|
|
2500
|
-
}
|
|
2501
|
-
|
|
2502
3155
|
// src/react/screens/primary/index.tsx
|
|
2503
3156
|
function PrimaryScreen(props) {
|
|
2504
3157
|
const { navigate } = useScreenNavigation();
|
|
2505
|
-
|
|
3158
|
+
const idle = !props.active && !props.loading && !props.feedbackVisible && props.error === null;
|
|
3159
|
+
const needsContactPhone = props.contactPhone === null;
|
|
3160
|
+
return /* @__PURE__ */ jsxs(EmergencyScreenLayout, {
|
|
2506
3161
|
screen: "primary",
|
|
2507
3162
|
titleId: props.titleId,
|
|
2508
|
-
|
|
3163
|
+
bodyClassName: idle ? "emergency-panel__body--primary" : void 0,
|
|
3164
|
+
header: idle ? null : /* @__PURE__ */ jsx(EmergencyHeader, {
|
|
2509
3165
|
titleId: props.titleId,
|
|
2510
3166
|
onClose: () => props.onClose("close")
|
|
2511
3167
|
}),
|
|
@@ -2514,11 +3170,17 @@ function PrimaryScreen(props) {
|
|
|
2514
3170
|
busy: props.busy,
|
|
2515
3171
|
aborting: props.aborting,
|
|
2516
3172
|
feedbackVisible: props.feedbackVisible,
|
|
2517
|
-
|
|
3173
|
+
square: idle,
|
|
3174
|
+
onActivate: needsContactPhone ? () => navigate("pre-emergency") : props.onActivate,
|
|
2518
3175
|
onRequestAbort: props.onRequestAbort,
|
|
2519
3176
|
onRequestSimulation: props.onRequestSimulation
|
|
2520
3177
|
}),
|
|
2521
|
-
children: /* @__PURE__ */ jsx(
|
|
3178
|
+
children: [idle ? /* @__PURE__ */ jsx("h2", {
|
|
3179
|
+
className: cls("emergency-panel__sr-only"),
|
|
3180
|
+
id: props.titleId,
|
|
3181
|
+
tabIndex: -1,
|
|
3182
|
+
children: copy.panelLabel
|
|
3183
|
+
}) : null, /* @__PURE__ */ jsx(EmergencyBody, {
|
|
2522
3184
|
active: props.active,
|
|
2523
3185
|
responders: props.responders,
|
|
2524
3186
|
refreshing: props.refreshing,
|
|
@@ -2533,8 +3195,9 @@ function PrimaryScreen(props) {
|
|
|
2533
3195
|
onRetry: props.onRetry,
|
|
2534
3196
|
onDismissFeedback: props.onDismissFeedback,
|
|
2535
3197
|
onRecharge: () => navigate("pricing"),
|
|
2536
|
-
onDetails: () => navigate("details")
|
|
2537
|
-
|
|
3198
|
+
onDetails: () => navigate("details"),
|
|
3199
|
+
onClose: () => props.onClose("close")
|
|
3200
|
+
})]
|
|
2538
3201
|
});
|
|
2539
3202
|
}
|
|
2540
3203
|
|
|
@@ -2548,7 +3211,7 @@ const pricingCopy = {
|
|
|
2548
3211
|
chosen: "Seleccionado",
|
|
2549
3212
|
whatsapp: "de WhatsApp",
|
|
2550
3213
|
rounds: "rondas de alerta",
|
|
2551
|
-
perMessage: "
|
|
3214
|
+
perMessage: "IVA Incluido",
|
|
2552
3215
|
footnote: "Rondas calculadas con 3 contactos de emergencia. Válidas para pruebas y emergencias."
|
|
2553
3216
|
};
|
|
2554
3217
|
|
|
@@ -2562,17 +3225,16 @@ const PRICING_PACKAGES = [{
|
|
|
2562
3225
|
label: "PAQUETE 1",
|
|
2563
3226
|
messages: 100,
|
|
2564
3227
|
priceLabel: "$7",
|
|
2565
|
-
priceCaption: "IVA
|
|
2566
|
-
perMessageLabel: "$0.
|
|
3228
|
+
priceCaption: "IVA incluído",
|
|
3229
|
+
perMessageLabel: "$0.07",
|
|
2567
3230
|
highlighted: false
|
|
2568
3231
|
}, {
|
|
2569
3232
|
id: "package-2",
|
|
2570
3233
|
label: "PAQUETE 2",
|
|
2571
3234
|
messages: 200,
|
|
2572
3235
|
priceLabel: "12$",
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
perMessageLabel: "$0.05",
|
|
3236
|
+
priceCaption: "IVA incluído",
|
|
3237
|
+
perMessageLabel: "$0.06",
|
|
2576
3238
|
highlighted: true,
|
|
2577
3239
|
badge: "MEJOR VALOR"
|
|
2578
3240
|
}];
|
|
@@ -2649,6 +3311,10 @@ function PackageCard({ pkg, selected, onSelect }) {
|
|
|
2649
3311
|
})
|
|
2650
3312
|
]
|
|
2651
3313
|
}),
|
|
3314
|
+
/* @__PURE__ */ jsx("p", {
|
|
3315
|
+
className: cls("emergency-pricing__package-footnote"),
|
|
3316
|
+
children: pricingCopy.footnote
|
|
3317
|
+
}),
|
|
2652
3318
|
/* @__PURE__ */ jsx("button", {
|
|
2653
3319
|
type: "button",
|
|
2654
3320
|
className: cls("emergency-pricing__select"),
|
|
@@ -2677,30 +3343,23 @@ function PricingScreen(props) {
|
|
|
2677
3343
|
footer: null,
|
|
2678
3344
|
children: /* @__PURE__ */ jsxs("div", {
|
|
2679
3345
|
className: cls("emergency-pricing"),
|
|
2680
|
-
children: [
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
})]
|
|
2692
|
-
})
|
|
2693
|
-
}),
|
|
2694
|
-
PRICING_PACKAGES.map((pkg) => /* @__PURE__ */ jsx(PackageCard, {
|
|
2695
|
-
pkg,
|
|
2696
|
-
selected: selected === pkg.id,
|
|
2697
|
-
onSelect: setSelected
|
|
2698
|
-
}, pkg.id)),
|
|
2699
|
-
/* @__PURE__ */ jsx("p", {
|
|
2700
|
-
className: cls("emergency-pricing__footnote"),
|
|
2701
|
-
children: pricingCopy.footnote
|
|
3346
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
3347
|
+
className: cls("emergency-pricing__heading"),
|
|
3348
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
3349
|
+
className: cls("emergency-pricing__titles"),
|
|
3350
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
3351
|
+
className: cls("emergency-pricing__title"),
|
|
3352
|
+
children: pricingCopy.heading
|
|
3353
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3354
|
+
className: cls("emergency-pricing__subtitle"),
|
|
3355
|
+
children: pricingCopy.subtitle
|
|
3356
|
+
})]
|
|
2702
3357
|
})
|
|
2703
|
-
|
|
3358
|
+
}), PRICING_PACKAGES.map((pkg) => /* @__PURE__ */ jsx(PackageCard, {
|
|
3359
|
+
pkg,
|
|
3360
|
+
selected: selected === pkg.id,
|
|
3361
|
+
onSelect: setSelected
|
|
3362
|
+
}, pkg.id))]
|
|
2704
3363
|
})
|
|
2705
3364
|
});
|
|
2706
3365
|
}
|
|
@@ -2709,8 +3368,11 @@ function PricingScreen(props) {
|
|
|
2709
3368
|
/** Every screen the panel can render. Add one entry to add a screen. */
|
|
2710
3369
|
const screenRegistry = {
|
|
2711
3370
|
primary: PrimaryScreen,
|
|
3371
|
+
"pre-emergency": PreEmergencyScreen,
|
|
2712
3372
|
pricing: PricingScreen,
|
|
2713
|
-
details: DetailsScreen
|
|
3373
|
+
details: DetailsScreen,
|
|
3374
|
+
history: HistoryScreen,
|
|
3375
|
+
"message-detail": MessageDetailScreen
|
|
2714
3376
|
};
|
|
2715
3377
|
|
|
2716
3378
|
// src/react/components/EmergencyPanel/index.tsx
|
|
@@ -2739,7 +3401,7 @@ function ActiveScreen({ screenProps, open, forcePrimary }) {
|
|
|
2739
3401
|
return /* @__PURE__ */ jsx(Screen, { ...screenProps });
|
|
2740
3402
|
}
|
|
2741
3403
|
function EmergencyPanel(props) {
|
|
2742
|
-
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;
|
|
3404
|
+
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;
|
|
2743
3405
|
const titleId = useId();
|
|
2744
3406
|
const dialogRef = useRef(null);
|
|
2745
3407
|
const feedbackVisible = geolocationError !== null || Boolean(activationError) || abortResult !== null || simulationResult !== null;
|
|
@@ -2764,13 +3426,15 @@ function EmergencyPanel(props) {
|
|
|
2764
3426
|
abortResult,
|
|
2765
3427
|
simulationResult,
|
|
2766
3428
|
feedbackVisible,
|
|
3429
|
+
contactPhone,
|
|
2767
3430
|
onClose,
|
|
2768
3431
|
onActivate,
|
|
2769
3432
|
onRefresh,
|
|
2770
3433
|
onRetry,
|
|
2771
3434
|
onDismissFeedback,
|
|
2772
3435
|
onRequestAbort,
|
|
2773
|
-
onRequestSimulation
|
|
3436
|
+
onRequestSimulation,
|
|
3437
|
+
onSetContactPhone
|
|
2774
3438
|
};
|
|
2775
3439
|
return /* @__PURE__ */ jsxs("div", {
|
|
2776
3440
|
ref: dialogRef,
|
|
@@ -2877,6 +3541,7 @@ function EmergencyRoot() {
|
|
|
2877
3541
|
const responders = useEmergencyStore((state) => state.responders);
|
|
2878
3542
|
const resumeAvailable = useEmergencyStore((state) => state.resumeAvailable);
|
|
2879
3543
|
const geolocationError = useEmergencyStore((state) => state.geolocationError);
|
|
3544
|
+
const contactPhone = useEmergencyStore((state) => state.contactPhone);
|
|
2880
3545
|
const lastError = useEmergencyStore((state) => state.lastError);
|
|
2881
3546
|
const abortResult = useEmergencyStore((state) => state.abortResult);
|
|
2882
3547
|
const simulationResult = useEmergencyStore((state) => state.simulationResult);
|
|
@@ -2902,6 +3567,7 @@ function EmergencyRoot() {
|
|
|
2902
3567
|
responders,
|
|
2903
3568
|
refreshing: phase.kind === "refreshing",
|
|
2904
3569
|
geolocationError,
|
|
3570
|
+
contactPhone,
|
|
2905
3571
|
activationError,
|
|
2906
3572
|
error: showError ? error : null,
|
|
2907
3573
|
abortResult,
|
|
@@ -2928,7 +3594,8 @@ function EmergencyRoot() {
|
|
|
2928
3594
|
},
|
|
2929
3595
|
onConfirmSimulation: () => {
|
|
2930
3596
|
client.simulate();
|
|
2931
|
-
}
|
|
3597
|
+
},
|
|
3598
|
+
onSetContactPhone: (phone) => client.setContactPhone(phone)
|
|
2932
3599
|
})] });
|
|
2933
3600
|
}
|
|
2934
3601
|
|
|
@@ -2960,6 +3627,7 @@ function createFailedClient(error) {
|
|
|
2960
3627
|
lastError: error,
|
|
2961
3628
|
geolocation: null,
|
|
2962
3629
|
geolocationError: null,
|
|
3630
|
+
contactPhone: null,
|
|
2963
3631
|
realtimeStatus: "idle",
|
|
2964
3632
|
abortResult: null,
|
|
2965
3633
|
simulationResult: null,
|
|
@@ -2988,7 +3656,8 @@ function createFailedClient(error) {
|
|
|
2988
3656
|
cancelAbortConfirmation: noop,
|
|
2989
3657
|
requestSimulationConfirmation: noop,
|
|
2990
3658
|
cancelSimulationConfirmation: noop,
|
|
2991
|
-
dismissFeedback: noop
|
|
3659
|
+
dismissFeedback: noop,
|
|
3660
|
+
setContactPhone: noop
|
|
2992
3661
|
};
|
|
2993
3662
|
}
|
|
2994
3663
|
function attachTrigger(trigger, client) {
|
|
@@ -3077,6 +3746,7 @@ function mount(options) {
|
|
|
3077
3746
|
requestSimulationConfirmation: () => client.requestSimulationConfirmation(),
|
|
3078
3747
|
cancelSimulationConfirmation: () => client.cancelSimulationConfirmation(),
|
|
3079
3748
|
dismissFeedback: () => client.dismissFeedback(),
|
|
3749
|
+
setContactPhone: (phone) => client.setContactPhone(phone),
|
|
3080
3750
|
destroy
|
|
3081
3751
|
};
|
|
3082
3752
|
}
|